galaxy-commits
Threads by month
- ----- 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
February 2013
- 2 participants
- 189 discussions
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/305680a482c3/
changeset: 305680a482c3
user: greg
date: 2013-02-19 21:01:09
summary: Handle all Galaxy utilitiy types when reinstalling an uninstalled tool shed repository. The shed-related config file can now be selected when reinstalling repositories with any contents so that a differnt "tool_path" location can be selected for the location of the reinstalled repository.
affected #: 5 files
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -951,6 +951,7 @@
.first()
def get_update_to_changeset_revision_and_ctx_rev( trans, repository ):
"""Return the changeset revision hash to which the repository can be updated."""
+ changeset_revision_dict = {}
tool_shed_url = suc.get_url_from_repository_tool_shed( trans.app, repository )
url = suc.url_join( tool_shed_url, 'repository/get_changeset_revision_and_ctx_rev?name=%s&owner=%s&changeset_revision=%s' % \
( repository.name, repository.owner, repository.installed_changeset_revision ) )
@@ -959,18 +960,34 @@
encoded_update_dict = response.read()
if encoded_update_dict:
update_dict = encoding_util.tool_shed_decode( encoded_update_dict )
- changeset_revision = update_dict[ 'changeset_revision' ]
- ctx_rev = update_dict[ 'ctx_rev' ]
+ includes_data_managers = update_dict.get( 'includes_data_managers', False )
+ includes_datatypes = update_dict.get( 'includes_datatypes', False )
includes_tools = update_dict.get( 'includes_tools', False )
+ includes_tool_dependencies = update_dict.get( 'includes_tool_dependencies', False )
+ includes_workflows = update_dict.get( 'includes_workflows', False )
has_repository_dependencies = update_dict.get( 'has_repository_dependencies', False )
+ changeset_revision = update_dict.get( 'changeset_revision', None )
+ ctx_rev = update_dict.get( 'ctx_rev', None )
response.close()
+ changeset_revision_dict[ 'includes_data_managers' ] = includes_data_managers
+ changeset_revision_dict[ 'includes_datatypes' ] = includes_datatypes
+ changeset_revision_dict[ 'includes_tools' ] = includes_tools
+ changeset_revision_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies
+ changeset_revision_dict[ 'includes_workflows' ] = includes_workflows
+ changeset_revision_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
+ changeset_revision_dict[ 'changeset_revision' ] = changeset_revision
+ changeset_revision_dict[ 'ctx_rev' ] = ctx_rev
except Exception, e:
log.debug( "Error getting change set revision for update from the tool shed for repository '%s': %s" % ( repository.name, str( e ) ) )
- includes_tools = False
- has_repository_dependencies = False
- changeset_revision = None
- ctx_rev = None
- return changeset_revision, ctx_rev, includes_tools, has_repository_dependencies
+ changeset_revision_dict[ 'includes_data_managers' ] = False
+ changeset_revision_dict[ 'includes_datatypes' ] = False
+ changeset_revision_dict[ 'includes_tools' ] = False
+ changeset_revision_dict[ 'includes_tool_dependencies' ] = False
+ changeset_revision_dict[ 'includes_workflows' ] = False
+ changeset_revision_dict[ 'has_repository_dependencies' ] = False
+ changeset_revision_dict[ 'changeset_revision' ] = None
+ changeset_revision_dict[ 'ctx_rev' ] = None
+ return changeset_revision_dict
def handle_missing_data_table_entry( app, relative_install_dir, tool_path, repository_tools_tups ):
"""
Inspect each tool to see if any have input parameters that are dynamically generated select lists that require entries in the
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1298,21 +1298,29 @@
@web.expose
def get_changeset_revision_and_ctx_rev( self, trans, **kwd ):
"""Handle a request from a local Galaxy instance to retrieve the changeset revision hash to which an installed repository can be updated."""
- def has_tools_and_repository_dependencies( repository_metadata ):
+ def has_galaxy_utilities( repository_metadata ):
+ includes_data_managers = False
+ includes_datatypes = False
includes_tools = False
has_repository_dependencies = False
+ includes_tool_dependencies = False
+ includes_workflows = False
if repository_metadata:
metadata = repository_metadata.metadata
if metadata:
+ if 'data_manager' in metadata:
+ includes_data_managers = True
+ if 'datatypes' in metadata:
+ includes_datatypes = True
if 'tools' in metadata:
includes_tools = True
- else:
- includes_tools = False
+ if 'tool_dependencies' in metadata:
+ includes_tool_dependencies = True
if 'repository_dependencies' in metadata:
has_repository_dependencies = True
- else:
- has_repository_dependencies = False
- return includes_tools, has_repository_dependencies
+ if 'workflows' in metadata:
+ includes_workflows = True
+ return includes_data_managers, includes_datatypes, includes_tools, includes_tool_dependencies, has_repository_dependencies, includes_workflows
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
status = params.get( 'status', 'done' )
@@ -1324,7 +1332,8 @@
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
trans.security.encode_id( repository.id ),
changeset_revision )
- includes_tools, has_repository_dependencies = has_tools_and_repository_dependencies( repository_metadata )
+ includes_data_managers, includes_datatypes, includes_tools, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \
+ has_galaxy_utilities( repository_metadata )
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
# Default to the received changeset revision and ctx_rev.
@@ -1333,8 +1342,12 @@
latest_changeset_revision = changeset_revision
update_dict = dict( changeset_revision=changeset_revision,
ctx_rev=ctx_rev,
+ includes_data_managers=includes_data_managers,
+ includes_datatypes=includes_datatypes,
includes_tools=includes_tools,
- has_repository_dependencies=has_repository_dependencies )
+ includes_tool_dependencies=includes_tool_dependencies,
+ has_repository_dependencies=has_repository_dependencies,
+ includes_workflows=includes_workflows )
if changeset_revision == repository.tip( trans.app ):
# If changeset_revision is the repository tip, there are no additional updates.
return encoding_util.tool_shed_encode( update_dict )
@@ -1356,7 +1369,8 @@
trans.security.encode_id( repository.id ),
changeset_hash )
if update_to_repository_metadata:
- includes_tools, has_repository_dependencies = has_tools_and_repository_dependencies( update_to_repository_metadata )
+ includes_data_managers, includes_datatypes, includes_tools, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \
+ has_galaxy_utilities( update_to_repository_metadata )
# We found a RepositoryMetadata record.
if changeset_hash == repository.tip( trans.app ):
# The current ctx is the repository tip, so use it.
@@ -1369,7 +1383,11 @@
elif not update_to_changeset_hash and changeset_hash == changeset_revision:
# We've found the changeset in the changelog for which we need to get the next update.
update_to_changeset_hash = changeset_hash
+ update_dict[ 'includes_data_managers' ] = includes_data_managers
+ update_dict[ 'includes_datatypes' ] = includes_datatypes
update_dict[ 'includes_tools' ] = includes_tools
+ update_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies
+ update_dict[ 'includes_workflows' ] = includes_workflows
update_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
update_dict[ 'changeset_revision' ] = str( latest_changeset_revision )
update_dict[ 'ctx_rev' ] = str( update_to_ctx.rev() )
@@ -1601,16 +1619,22 @@
repository_metadata=repository_metadata,
tool_dependencies=None,
repository_dependencies=None )
+ includes_data_managers = False
+ includes_datatypes = False
+ includes_tools = False
+ includes_workflows = False
+ readme_files_dict = None
metadata = repository_metadata.metadata
if metadata:
- readme_files_dict = suc.build_readme_files_dict( metadata )
+ if 'data_manager' in metadata:
+ includes_data_managers = True
+ if 'datatypes' in metadata:
+ includes_datatypes = True
if 'tools' in metadata:
includes_tools = True
- else:
- includes_tools = False
- else:
- readme_files_dict = None
- includes_tools = False
+ if 'workflows' in metadata:
+ includes_workflows = True
+ readme_files_dict = suc.build_readme_files_dict( metadata )
# See if the repo_info_dict was populated with repository_dependencies or tool_dependencies.
for name, repo_info_tuple in repo_info_dict.items():
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
@@ -1623,9 +1647,12 @@
includes_tool_dependencies = True
else:
includes_tool_dependencies = False
- return dict( includes_tools=includes_tools,
+ return dict( includes_data_managers=includes_data_managers,
+ includes_datatypes=includes_datatypes,
+ includes_tools=includes_tools,
has_repository_dependencies=has_repository_dependencies,
includes_tool_dependencies=includes_tool_dependencies,
+ includes_workflows=includes_workflows,
readme_files_dict=readme_files_dict,
repo_info_dict=repo_info_dict )
def get_versions_of_tool( self, trans, repository, repository_metadata, guid ):
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -383,29 +383,23 @@
if repository.uninstalled:
# Since we're reinstalling the repository we need to find the latest changeset revision to which it can be updated so that we
# can reset the metadata if necessary. This will ensure that information about repository dependencies and tool dependencies
- # will be current. Only allow selecting a different section in the tool panel if the repository was uninstalled.
- current_changeset_revision, current_ctx_rev, includes_tools, has_repository_dependencies = \
- shed_util.get_update_to_changeset_revision_and_ctx_rev( trans, repository )
- if current_ctx_rev == repository.ctx_rev:
- # The uninstalled repository is current.
- if repository.includes_tools or repository.has_repository_dependencies:
+ # will be current. Only allow selecting a different section in the tool panel if the repository was uninstalled.
+ changeset_revision_dict = shed_util.get_update_to_changeset_revision_and_ctx_rev( trans, repository )
+ current_changeset_revision = changeset_revision_dict.get( 'changeset_revision', None )
+ current_ctx_rev = changeset_revision_dict.get( 'ctx_rev', None )
+ if current_changeset_revision and current_ctx_rev:
+ if current_ctx_rev == repository.ctx_rev:
+ # The uninstalled repository is current.
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='reselect_tool_panel_section',
**kwd ) )
else:
- return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
- action='reinstall_repository',
- **kwd ) )
- else:
- # The uninstalled repository has updates available in the tool shed.
- updated_repo_info_dict = self.get_updated_repository_information( trans=trans,
- repository_id=trans.security.encode_id( repository.id ),
- repository_name=repository.name,
- repository_owner=repository.owner,
- changeset_revision=current_changeset_revision )
- has_repository_dependencies = updated_repo_info_dict.get( 'has_repository_dependencies', False )
- includes_tool_dependencies = updated_repo_info_dict.get( 'includes_tool_dependencies', False )
- if has_repository_dependencies or includes_tool_dependencies:
+ # The uninstalled repository has updates available in the tool shed.
+ updated_repo_info_dict = self.get_updated_repository_information( trans=trans,
+ repository_id=trans.security.encode_id( repository.id ),
+ repository_name=repository.name,
+ repository_owner=repository.owner,
+ changeset_revision=current_changeset_revision )
json_repo_info_dict = json.to_json_string( updated_repo_info_dict )
encoded_repo_info_dict = encoding_util.tool_shed_encode( json_repo_info_dict )
kwd[ 'latest_changeset_revision' ] = current_changeset_revision
@@ -414,10 +408,14 @@
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='reselect_tool_panel_section',
**kwd ) )
- else:
- return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
- action='reinstall_repository',
- **kwd ) )
+ else:
+ message = "Unable to get latest revision for repository <b>%s</b> from the tool shed, so repository " % str( repository.name )
+ message += "reinstallation is not possible at this time."
+ status = "error"
+ return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
+ action='browse_repositories',
+ message=message,
+ status=status ) )
else:
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='activate_repository',
@@ -903,8 +901,9 @@
if cloned_ok:
if reinstalling:
# Since we're reinstalling the repository we need to find the latest changeset revision to which is can be updated.
- current_changeset_revision, current_ctx_rev, includes_tools, has_repository_dependencies = \
- shed_util.get_update_to_changeset_revision_and_ctx_rev( trans, tool_shed_repository )
+ changeset_revision_dict = shed_util.get_update_to_changeset_revision_and_ctx_rev( trans, tool_shed_repository )
+ current_changeset_revision = changeset_revision_dict.get( 'changeset_revision', None )
+ current_ctx_rev = changeset_revision_dict.get( 'ctx_rev', None )
if current_ctx_rev != ctx_rev:
repo = hg.repository( suc.get_configured_ui(), path=os.path.abspath( install_dir ) )
shed_util.pull_repository( repo, repository_clone_url, current_changeset_revision )
@@ -1367,7 +1366,7 @@
containers_dicts.append( containers_dict )
# Merge all containers into a single container.
containers_dict = shed_util.merge_containers_dicts_for_new_install( containers_dicts )
- # Handle tool dependencies chack box.
+ # Handle tool dependencies check box.
if trans.app.config.tool_dependency_dir is None:
if includes_tool_dependencies:
message = "Tool dependencies defined in this repository can be automatically installed if you set the value of your <b>tool_dependency_dir</b> "
@@ -1566,6 +1565,7 @@
Galaxy database will not be used since it is outdated.
"""
message = ''
+ status = 'done'
repository_id = kwd.get( 'id', None )
latest_changeset_revision = kwd.get( 'latest_changeset_revision', None )
latest_ctx_rev = kwd.get( 'latest_ctx_rev', None )
@@ -1580,19 +1580,36 @@
encoded_updated_repo_info_dict = kwd.get( 'updated_repo_info_dict', None )
updated_repo_info_dict = encoding_util.tool_shed_decode( encoded_updated_repo_info_dict )
readme_files_dict = updated_repo_info_dict.get( 'readme_files_dict', None )
+ includes_data_managers = updated_repo_info_dict.get( 'includes_data_managers', False )
+ includes_datatypes = updated_repo_info_dict.get( 'includes_datatypes', False )
includes_tools = updated_repo_info_dict.get( 'includes_tools', False )
+ includes_workflows = updated_repo_info_dict.get( 'includes_workflows', False )
has_repository_dependencies = updated_repo_info_dict.get( 'has_repository_dependencies', False )
includes_tool_dependencies = updated_repo_info_dict.get( 'includes_tool_dependencies', False )
repo_info_dict = updated_repo_info_dict[ 'repo_info_dict' ]
else:
# There are no updates available from the tool shed for the repository, so use it's locally stored metadata.
+ has_repository_dependencies = False
+ includes_data_managers = False
+ includes_datatypes = False
+ includes_tool_dependencies = False
+ includes_tools = False
+ includes_workflows = False
+ readme_files_dict = None
+ tool_dependencies = None
if metadata:
+ if 'data_manager' in metadata:
+ includes_data_managers = True
+ if 'datatypes' in metadata:
+ includes_datatypes = True
+ if 'tools' in metadata:
+ includes_tools = True
+ if 'tool_dependencies' in metadata:
+ includes_tool_dependencies = True
+ if 'workflows' in metadata:
+ includes_workflows = True
readme_files_dict = suc.build_readme_files_dict( metadata )
tool_dependencies = metadata.get( 'tool_dependencies', None )
- else:
- readme_files_dict = None
- tool_dependencies = None
- includes_tool_dependencies = tool_shed_repository.includes_tool_dependencies
repository_dependencies = self.get_repository_dependencies( trans=trans,
repository_id=repository_id,
repository_name=tool_shed_repository.name,
@@ -1615,33 +1632,39 @@
has_repository_dependencies = True
else:
has_repository_dependencies = False
- # Get the location in the tool panel in which the tool was originally loaded.
- if 'tool_panel_section' in metadata:
- tool_panel_dict = metadata[ 'tool_panel_section' ]
- if tool_panel_dict:
- if shed_util.panel_entry_per_tool( tool_panel_dict ):
- # The following forces everything to be loaded into 1 section (or no section) in the tool panel.
- tool_section_dicts = tool_panel_dict[ tool_panel_dict.keys()[ 0 ] ]
- tool_section_dict = tool_section_dicts[ 0 ]
- original_section_name = tool_section_dict[ 'name' ]
+ if includes_tools:
+ # Get the location in the tool panel in which the tools were originally loaded.
+ if 'tool_panel_section' in metadata:
+ tool_panel_dict = metadata[ 'tool_panel_section' ]
+ if tool_panel_dict:
+ if shed_util.panel_entry_per_tool( tool_panel_dict ):
+ # The following forces everything to be loaded into 1 section (or no section) in the tool panel.
+ tool_section_dicts = tool_panel_dict[ tool_panel_dict.keys()[ 0 ] ]
+ tool_section_dict = tool_section_dicts[ 0 ]
+ original_section_name = tool_section_dict[ 'name' ]
+ else:
+ original_section_name = tool_panel_dict[ 'name' ]
else:
- original_section_name = tool_panel_dict[ 'name' ]
+ original_section_name = ''
else:
original_section_name = ''
+ tool_panel_section_select_field = build_tool_panel_section_select_field( trans )
+ no_changes_check_box = CheckboxField( 'no_changes', checked=True )
+ if original_section_name:
+ message += "The tools contained in your <b>%s</b> repository were last loaded into the tool panel section <b>%s</b>. " \
+ % ( tool_shed_repository.name, original_section_name )
+ message += "Uncheck the <b>No changes</b> check box and select a different tool panel section to load the tools in a "
+ message += "different section in the tool panel. "
+ status = 'warning'
+ else:
+ message += "The tools contained in your <b>%s</b> repository were last loaded into the tool panel outside of any sections. " % tool_shed_repository.name
+ message += "Uncheck the <b>No changes</b> check box and select a tool panel section to load the tools into that section. "
+ status = 'warning'
else:
+ no_changes_check_box = None
original_section_name = ''
- tool_panel_section_select_field = build_tool_panel_section_select_field( trans )
- no_changes_check_box = CheckboxField( 'no_changes', checked=True )
- if original_section_name:
- message += "The tools contained in your <b>%s</b> repository were last loaded into the tool panel section <b>%s</b>. " \
- % ( tool_shed_repository.name, original_section_name )
- message += "Uncheck the <b>No changes</b> check box and select a different tool panel section to load the tools in a "
- message += "different section in the tool panel. "
- status = 'warning'
- else:
- message += "The tools contained in your <b>%s</b> repository were last loaded into the tool panel outside of any sections. " % tool_shed_repository.name
- message += "Uncheck the <b>No changes</b> check box and select a tool panel section to load the tools into that section. "
- status = 'warning'
+ tool_panel_section_select_field = None
+ shed_tool_conf_select_field = build_shed_tool_conf_select_field( trans )
containers_dict = shed_util.populate_containers_dict_for_new_install( trans=trans,
tool_shed_url=tool_shed_url,
tool_path=tool_path,
@@ -1669,12 +1692,17 @@
repository=tool_shed_repository,
no_changes_check_box=no_changes_check_box,
original_section_name=original_section_name,
+ includes_data_managers=includes_data_managers,
+ includes_datatypes=includes_datatypes,
+ includes_tools=includes_tools,
includes_tool_dependencies=includes_tool_dependencies,
+ includes_workflows=includes_workflows,
has_repository_dependencies=has_repository_dependencies,
install_repository_dependencies_check_box=install_repository_dependencies_check_box,
install_tool_dependencies_check_box=install_tool_dependencies_check_box,
containers_dict=containers_dict,
tool_panel_section_select_field=tool_panel_section_select_field,
+ shed_tool_conf_select_field=shed_tool_conf_select_field,
encoded_repo_info_dict=encoding_util.tool_shed_encode( repo_info_dict ),
repo_info_dict=repo_info_dict,
message=message,
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
--- a/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
+++ b/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
@@ -41,28 +41,55 @@
</div>
${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict )}
%endif
- <div style="clear: both"></div>
- <div class="form-row">
- ${no_changes_check_box.get_html()}
- <label style="display: inline;">No changes</label>
- <div class="toolParamHelp" style="clear: both;">
- Uncheck and select a different tool panel section to load the tools into a different section in the tool panel.
+ %if shed_tool_conf_select_field:
+ <div class="form-row">
+ <table class="colored" width="100%">
+ <th bgcolor="#EBD9B2">Choose the configuration file whose tool_path setting will be used for installing repositories</th>
+ </table></div>
- </div>
- <div class="form-row">
- <label>Add new tool panel section:</label>
- <input name="new_tool_panel_section" type="textfield" value="" size="40"/>
- <div class="toolParamHelp" style="clear: both;">
- Add a new tool panel section to contain the installed tools (optional).
+ <%
+ if len( shed_tool_conf_select_field.options ) == 1:
+ select_help = "Your Galaxy instance is configured with 1 shed-related tool configuration file, so repositories will be "
+ select_help += "installed using it's <b>tool_path</b> setting."
+ else:
+ select_help = "Your Galaxy instance is configured with %d shed-related tool configuration files, " % len( shed_tool_conf_select_field.options )
+ select_help += "so select the file whose <b>tool_path</b> setting you want used for installing repositories."
+ %>
+ <div class="form-row">
+ <label>Shed tool configuration file:</label>
+ ${shed_tool_conf_select_field.get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ ${select_help}
+ </div></div>
- </div>
- <div class="form-row">
- <label>Select existing tool panel section:</label>
- ${tool_panel_section_select_field.get_html()}
- <div class="toolParamHelp" style="clear: both;">
- Choose an existing section in your tool panel to contain the installed tools (optional).
+ <div style="clear: both"></div>
+ %else:
+ <input type="hidden" name="shed_tool_conf" value="${shed_tool_conf}"/>
+ %endif
+ %if includes_tools:
+ <div style="clear: both"></div>
+ <div class="form-row">
+ ${no_changes_check_box.get_html()}
+ <label style="display: inline;">No changes</label>
+ <div class="toolParamHelp" style="clear: both;">
+ Uncheck and select a different tool panel section to load the tools into a different section in the tool panel.
+ </div></div>
- </div>
+ <div class="form-row">
+ <label>Add new tool panel section:</label>
+ <input name="new_tool_panel_section" type="textfield" value="" size="40"/>
+ <div class="toolParamHelp" style="clear: both;">
+ Add a new tool panel section to contain the installed tools (optional).
+ </div>
+ </div>
+ <div class="form-row">
+ <label>Select existing tool panel section:</label>
+ ${tool_panel_section_select_field.get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ Choose an existing section in your tool panel to contain the installed tools (optional).
+ </div>
+ </div>
+ %endif
<div class="form-row"><input type="submit" name="select_tool_panel_section_button" value="Install"/></div>
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 templates/admin/tool_shed_repository/select_tool_panel_section.mako
--- a/templates/admin/tool_shed_repository/select_tool_panel_section.mako
+++ b/templates/admin/tool_shed_repository/select_tool_panel_section.mako
@@ -81,12 +81,12 @@
${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict )}
<div style="clear: both"></div>
%endif
- <div class="form-row">
- <table class="colored" width="100%">
- <th bgcolor="#EBD9B2">Choose the tool panel section to contain the installed tools (optional)</th>
- </table>
- </div>
%if shed_tool_conf_select_field:
+ <div class="form-row">
+ <table class="colored" width="100%">
+ <th bgcolor="#EBD9B2">Choose the tool panel section to contain the installed tools (optional)</th>
+ </table>
+ </div><%
if len( shed_tool_conf_select_field.options ) == 1:
select_help = "Your Galaxy instance is configured with 1 shed-related tool configuration file, so repositories will be "
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: functional_tests.py: add debugging statement for app config
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/32fc25b89000/
changeset: 32fc25b89000
user: carlfeberhard
date: 2013-02-19 20:31:56
summary: functional_tests.py: add debugging statement for app config
affected #: 1 file
diff -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 -r 32fc25b8900059f63b0d41d52aa582f06426928c scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -84,7 +84,6 @@
global_conf.update( get_static_settings() )
return global_conf
-
def parse_tool_panel_config( config, shed_tools_dict ):
"""
Parse a shed-related tool panel config to generate the shed_tools_dict. This only happens when testing tools installed from the tool shed.
@@ -293,6 +292,7 @@
kwargs[ 'object_store' ] = 'distributed'
kwargs[ 'distributed_object_store_config_file' ] = 'distributed_object_store_conf.xml.sample'
# Build the Universe Application
+ log.debug( 'app.kwargs:\n%s', pprint.pformat( kwargs ) )
app = UniverseApplication( job_queue_workers = 5,
id_secret = 'changethisinproductiontoo',
template_path = "templates",
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: browser tests: refactor framework into modules; add history panel tests, anon-user history panel tests
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/973b8d73409f/
changeset: 973b8d73409f
user: carlfeberhard
date: 2013-02-19 20:04:41
summary: browser tests: refactor framework into modules; add history panel tests, anon-user history panel tests
affected #: 10 files
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/anon-history-tests.js
--- /dev/null
+++ b/test/casperjs/anon-history-tests.js
@@ -0,0 +1,181 @@
+// have to handle errors here - or phantom/casper won't bail but _HANG_
+try {
+ var utils = require( 'utils' ),
+ xpath = require( 'casper' ).selectXPath,
+ format = utils.format,
+
+ //...if there's a better way - please let me know, universe
+ scriptDir = require( 'system' ).args[3]
+ // remove the script filename
+ .replace( /[\w|\.|\-|_]*$/, '' )
+ // if given rel. path, prepend the curr dir
+ .replace( /^(?!\/)/, './' ),
+ spaceghost = require( scriptDir + 'spaceghost' ).create({
+ // script options here (can be overridden by CLI)
+ //verbose: true,
+ //logLevel: debug,
+ scriptDir: scriptDir
+ });
+
+ spaceghost.start();
+
+} catch( error ){
+ console.debug( error );
+ phantom.exit( 1 );
+}
+
+
+// -------------------------------------------------------------------
+/* TODO:
+ run a tool
+
+*/
+// =================================================================== globals and helpers
+var email = spaceghost.user.getRandomEmail(),
+ password = '123456';
+if( spaceghost.fixtureData.testUser ){
+ email = spaceghost.fixtureData.testUser.email;
+ password = spaceghost.fixtureData.testUser.password;
+}
+
+var galaxyCookieName = 'galaxysession',
+
+ nameSelector = 'div#history-name',
+ unnamedName = 'Unnamed history',
+ subtitleSelector = 'div#history-subtitle-area',
+ initialSizeStr = '0 bytes',
+ tagIconSelector = '#history-tag.icon-button',
+ annoIconSelector = '#history-annotate.icon-button',
+ //emptyMsgSelector = '#emptyHistoryMessage';
+ emptyMsgSelector = '.infomessagesmall',
+ emptyMsgStr = "Your history is empty. Click 'Get Data' on the left pane to start",
+
+ tooltipSelector = '.bs-tooltip',
+ anonNameTooltip = 'You must be logged in to edit your history name',
+
+ editableTextClass = 'editable-text',
+ editableTextInputSelector = 'input#renaming-active';
+
+var historyFrameInfo = {},
+ testUploadInfo = {};
+
+
+// =================================================================== TESTS
+// ------------------------------------------------------------------- anonymous new, history
+// open galaxy - ensure not logged in
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ var loggedInAs = spaceghost.user.loggedInAs();
+ this.debug( 'loggedInAs: ' + loggedInAs );
+ if( loggedInAs ){ this.logout(); }
+});
+
+// ------------------------------------------------------------------- check anon cookies
+spaceghost.then( function testAnonCookies(){
+ this.test.comment( 'session cookie for anon-user should be present and well formed' );
+ var cookies = this.page.cookies;
+ this.debug( this.jsonStr( this.page.cookies ) );
+ //??: what are 'well formed' values?
+ this.test.assert( cookies.length === 1, "Has one cookie" );
+ var galaxyCookie = cookies[0];
+ this.test.assert( galaxyCookie.name === galaxyCookieName, "Cookie named: " + galaxyCookieName );
+ this.test.assert( !galaxyCookie.secure, "Cookie.secure is false" );
+});
+
+// ------------------------------------------------------------------- check the empty history for well formedness
+// grab the history frame bounds for mouse later tests
+spaceghost.then( function(){
+ historyFrameInfo = this.getElementInfo( 'iframe[name="galaxy_history"]' );
+ //this.debug( 'historyFrameInfo:' + this.jsonStr( historyFrameInfo ) );
+});
+
+spaceghost.thenOpen( spaceghost.baseUrl, function testPanelStructure(){
+ this.test.comment( 'history panel for anonymous user, new history' );
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( "frame should have proper url and title: 'History'" );
+ this.test.assertMatch( this.getCurrentUrl(), /\/history/, 'Found history frame url' );
+ this.test.assertTitle( this.getTitle(), 'History', 'Found history frame title' );
+
+ this.test.comment( "history name should exist, be visible, and have text " + unnamedName );
+ this.test.assertExists( nameSelector, nameSelector + ' exists' );
+ this.test.assertVisible( nameSelector, 'History name is visible' );
+ this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName );
+
+ this.test.comment( "history subtitle should display size and size should be 0 bytes" );
+ this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector );
+ this.test.assertVisible( subtitleSelector, 'History subtitle is visible' );
+ this.test.assertSelectorHasText( subtitleSelector, initialSizeStr,
+ 'History subtitle has "' + initialSizeStr + '"' );
+
+ this.test.comment( "NO tags or annotations icons should be available for an anonymous user" );
+ this.test.assertDoesntExist( tagIconSelector, 'Tag icon button not found' );
+ this.test.assertDoesntExist( annoIconSelector, 'Annotation icon button not found' );
+
+ this.test.comment( "A message about the current history being empty should be displayed" );
+ this.test.assertExists( emptyMsgSelector, emptyMsgSelector + ' exists' );
+ this.test.assertVisible( emptyMsgSelector, 'Empty history message is visible' );
+ this.test.assertSelectorHasText( emptyMsgSelector, emptyMsgStr,
+ 'Message contains "' + emptyMsgStr + '"' );
+
+ this.test.comment( 'name should have a tooltip with info on anon-user name editing' );
+ // mouse over to find tooltip
+ //NOTE!!: bounds are returned relative to containing frame - need to adjust using historyFrameInfo
+ //TODO: into conv. fn
+ var nameInfo = this.getElementInfo( nameSelector );
+ //this.debug( 'nameInfo:' + this.jsonStr( nameInfo ) );
+ this.page.sendEvent( 'mousemove',
+ historyFrameInfo.x + nameInfo.x + 1, historyFrameInfo.y + nameInfo.y + 1 );
+ this.test.assertExists( tooltipSelector, "Found tooltip after name hover" );
+ this.test.assertSelectorHasText( tooltipSelector, anonNameTooltip );
+
+ this.test.comment( 'name should NOT be editable when clicked by anon-user' );
+ this.test.assert( nameInfo.attributes[ 'class' ].indexOf( editableTextClass ) === -1,
+ "Name field is not class for editable text" );
+ this.click( nameSelector );
+ this.test.assertDoesntExist( editableTextInputSelector, "Clicking on name does not create an input" );
+ });
+});
+
+// ------------------------------------------------------------------- anon user can upload file
+spaceghost.then( function testAnonUpload(){
+ this.test.comment( 'anon-user should be able to upload files' );
+ spaceghost.tools.uploadFile( '../../test-data/1.txt', function uploadCallback( _uploadInfo ){
+ this.debug( 'uploaded HDA info: ' + this.jsonStr( _uploadInfo ) );
+ var hasHda = _uploadInfo.hdaElement,
+ hasClass = _uploadInfo.hdaElement.attributes[ 'class' ],
+ hasOkClass = _uploadInfo.hdaElement.attributes[ 'class' ].indexOf( 'historyItem-ok' ) !== -1;
+ this.test.assert( ( hasHda && hasClass && hasOkClass ), "Uploaded file: " + _uploadInfo.name );
+ uploadInfo = _uploadInfo;
+ });
+});
+spaceghost.then( function testAnonUpload(){
+ this.test.comment( "empty should be NO LONGER be displayed" );
+ this.test.assertNotVisible( emptyMsgSelector, 'Empty history message is not visible' );
+});
+
+
+// ------------------------------------------------------------------- anon user can run tool on file
+
+// ------------------------------------------------------------------- anon user registers/logs in -> same history
+spaceghost.user.loginOrRegisterUser( email, password );
+//??: why is a reload needed here? If we don't, loggedInAs === '' ...
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
+
+ this.test.comment( 'anon-user should login and be associated with previous history' );
+ var loggedInAs = spaceghost.user.loggedInAs();
+ this.test.assert( loggedInAs === email, 'loggedInAs() matches email: "' + loggedInAs + '"' );
+
+ this.withFrame( this.selectors.frames.history, function(){
+ var hdaInfo = this.historypanel.hdaElementInfoByTitle( uploadInfo.name, uploadInfo.hid );
+ this.test.assert( hdaInfo !== null, "After logging in - found a matching hda by name and hid" );
+ if( hdaInfo ){
+ this.test.assert( uploadInfo.hdaElement.attributes.id === hdaInfo.attributes.id,
+ "After logging in - found a matching hda by hda view id: " + hdaInfo.attributes.id );
+ }
+ });
+});
+
+
+// ===================================================================
+spaceghost.run( function(){
+ this.test.done();
+});
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/casperjs_runner.py
--- a/test/casperjs/casperjs_runner.py
+++ b/test/casperjs/casperjs_runner.py
@@ -95,6 +95,8 @@
stderr_msg = process.stderr.readline()
stderr_msg = self.strip_escape_codes( stderr_msg.strip() )
log.debug( '(%s): %s', rel_script_path, stderr_msg )
+ # HACK: this is the last string displayed using the debug settings - afterwards it hangs
+ # so: bail on this string
if stderr_msg.startswith( self.casper_done_str ):
break
@@ -117,7 +119,7 @@
self.exec_path, self.casper_info )
raise
- self.handle_js_results( stdout_output )
+ return self.handle_js_results( stdout_output )
def build_command_line( self, rel_script_path, *args, **kwargs ):
"""Build the headless browser command line list for subprocess.
@@ -284,35 +286,61 @@
log.debug( '\n--------------- tearing down module' )
+test_user = {
+ 'email': 'test1(a)test.test',
+ 'password': '123456'
+}
+
# ==================================================================== TESTCASE EXAMPLE
-# these could be broken out into other files - shouldn't be necc. ATM
-class UserTests( CasperJSTestCase ):
+# these could be broken out into other py files - shouldn't be necc. ATM
+class Test_01_User( CasperJSTestCase ):
"""TestCase that uses javascript and a headless browser to test dynamic pages.
"""
+ #debug = True
def test_10_registration( self ):
"""User registration tests: register new user, logout, attempt bad registrations.
"""
# all keywords will be compiled into a single JSON obj and passed to the server
- self.run_js_script( 'registration-tests.js', self.env.url,
- testuser={ 'email': 'test1(a)test.test', 'password': '123456' })
+ self.run_js_script( 'registration-tests.js',
+ testuser=test_user )
+
#TODO:?? could theoretically do db cleanup, checks here with SQLALX
#TODO: have run_js_script return other persistant fixture data (uploaded files, etc.)
def test_20_login( self ):
"""User log in tests.
"""
- self.run_js_script( 'login-tests.js', self.env.url,
- testuser={ 'email': 'test1(a)test.test', 'password': '123456' })
+ self.run_js_script( 'login-tests.js',
+ testuser=test_user )
-class ToolTests( CasperJSTestCase ):
+class Test_02_Tools( CasperJSTestCase ):
"""(Minimal) casperjs tests for tools.
"""
#debug = True
def test_10_upload( self ):
"""Tests uploading files
"""
- self.run_js_script( 'upload-tests.js' )
+ self.run_js_script( 'upload-tests.js',
+ testuser=test_user )
+
+
+class Test_03_HistoryPanel( CasperJSTestCase ):
+ """(Minimal) casperjs tests for tools.
+ """
+ #debug = True
+ def test_00_history_panel( self ):
+ """Test history panel basics (controls, structure, refresh, history options menu, etc.).
+ """
+ self.run_js_script( 'history-panel-tests.js',
+ testuser=test_user )
+
+ def test_10_anonymous_histories( self ):
+ """Test history panel basics with an anonymous user.
+ """
+ self.run_js_script( 'anon-history-tests.js',
+ testuser=test_user )
+
# ==================================================================== MAIN
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/history-panel-tests.js
--- /dev/null
+++ b/test/casperjs/history-panel-tests.js
@@ -0,0 +1,252 @@
+// have to handle errors here - or phantom/casper won't bail but _HANG_
+try {
+ var utils = require( 'utils' ),
+ xpath = require( 'casper' ).selectXPath,
+ format = utils.format,
+
+ //...if there's a better way - please let me know, universe
+ scriptDir = require( 'system' ).args[3]
+ // remove the script filename
+ .replace( /[\w|\.|\-|_]*$/, '' )
+ // if given rel. path, prepend the curr dir
+ .replace( /^(?!\/)/, './' ),
+ spaceghost = require( scriptDir + 'spaceghost' ).create({
+ // script options here (can be overridden by CLI)
+ //verbose: true,
+ //logLevel: debug,
+ scriptDir: scriptDir
+ });
+
+ spaceghost.start();
+
+} catch( error ){
+ console.debug( error );
+ phantom.exit( 1 );
+}
+
+
+// ===================================================================
+/* TODO:
+*/
+// =================================================================== globals and helpers
+var email = spaceghost.user.getRandomEmail(),
+ password = '123456';
+if( spaceghost.fixtureData.testUser ){
+ email = spaceghost.fixtureData.testUser.email;
+ password = spaceghost.fixtureData.testUser.password;
+}
+var newHistoryName = "Test History";
+
+var nameSelector = 'div#history-name',
+ unnamedName = 'Unnamed history',
+ subtitleSelector = 'div#history-subtitle-area',
+ initialSizeStr = '0 bytes',
+ tagIconSelector = '#history-tag.icon-button',
+ annoIconSelector = '#history-annotate.icon-button',
+ //emptyMsgSelector = '#emptyHistoryMessage';
+ emptyMsgSelector = '.infomessagesmall',
+ emptyMsgStr = "Your history is empty. Click 'Get Data' on the left pane to start",
+
+ tooltipSelector = '.bs-tooltip',
+ nameTooltip = 'Click to rename history',
+
+ editableTextClass = 'editable-text',
+ editableTextInputSelector = 'input#renaming-active';
+
+var historyFrameInfo = {},
+ testUploadInfo = {};
+
+
+// =================================================================== TESTS
+// ------------------------------------------------------------------- start a new user
+spaceghost.user.loginOrRegisterUser( email, password );
+//??: why is a reload needed here? If we don't, loggedInAs === '' ...
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ var loggedInAs = spaceghost.user.loggedInAs();
+ this.test.assert( loggedInAs === email, 'loggedInAs() matches email: "' + loggedInAs + '"' );
+});
+
+// ------------------------------------------------------------------- check structure of empty history
+// grab the history frame bounds for mouse later tests
+spaceghost.then( function(){
+ historyFrameInfo = this.getElementInfo( 'iframe[name="galaxy_history"]' );
+ //this.debug( 'historyFrameInfo:' + this.jsonStr( historyFrameInfo ) );
+});
+
+spaceghost.thenOpen( spaceghost.baseUrl, function testPanelStructure(){
+ this.test.comment( 'history panel, new history' );
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( "frame should have proper url and title: 'History'" );
+ this.test.assertMatch( this.getCurrentUrl(), /\/history/, 'Found history frame url' );
+ this.test.assertTitle( this.getTitle(), 'History', 'Found history frame title' );
+
+ this.test.comment( "history name should exist, be visible, and have text " + unnamedName );
+ this.test.assertExists( nameSelector, nameSelector + ' exists' );
+ this.test.assertVisible( nameSelector, 'History name is visible' );
+ this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName );
+
+ this.test.comment( "history subtitle should display size and size should be 0 bytes" );
+ this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector );
+ this.test.assertVisible( subtitleSelector, 'History subtitle is visible' );
+ this.test.assertSelectorHasText( subtitleSelector, initialSizeStr,
+ 'History subtitle has "' + initialSizeStr + '"' );
+
+ this.test.comment( "tags and annotation icons should be available" );
+ this.test.assertExists( tagIconSelector, 'Tag icon button found' );
+ this.test.assertExists( annoIconSelector, 'Annotation icon button found' );
+
+ this.test.comment( "A message about the current history being empty should be displayed" );
+ this.test.assertExists( emptyMsgSelector, emptyMsgSelector + ' exists' );
+ this.test.assertVisible( emptyMsgSelector, 'Empty history message is visible' );
+ this.test.assertSelectorHasText( emptyMsgSelector, emptyMsgStr,
+ 'Message contains "' + emptyMsgStr + '"' );
+
+ });
+});
+
+// ------------------------------------------------------------------- name editing
+spaceghost.then( function(){
+ this.test.comment( 'history panel, editing the history name' );
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( 'name should have a tooltip with proper info on name editing' );
+ var nameInfo = this.getElementInfo( nameSelector );
+ this.page.sendEvent( 'mousemove',
+ historyFrameInfo.x + nameInfo.x + 1, historyFrameInfo.y + nameInfo.y + 1 );
+ this.test.assertExists( tooltipSelector, "Found tooltip after name hover" );
+ this.test.assertSelectorHasText( tooltipSelector, nameTooltip );
+
+ this.test.comment( 'name should be create an input when clicked' );
+ this.test.assert( nameInfo.attributes[ 'class' ].indexOf( editableTextClass ) !== -1,
+ "Name field classed for editable text" );
+ this.click( nameSelector );
+ this.test.assertExists( editableTextInputSelector, "Clicking on name creates an input" );
+
+ this.test.comment( 'name should be editable by entering keys and pressing enter' );
+ //NOTE: casperjs.sendKeys adds a click before and a selector.blur after sending - won't work here
+ //TODO: to conv. fn
+ this.page.sendEvent( 'keypress', newHistoryName );
+ this.page.sendEvent( 'keypress', this.page.event.key.Enter );
+ this.wait( 1000, function(){
+ this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is ' + newHistoryName );
+ this.test.assertDoesntExist( editableTextInputSelector, "Input disappears after pressing enter" );
+ });
+ });
+});
+spaceghost.then( function(){
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( 'name should revert if user clicks away while editing' );
+ this.click( nameSelector );
+ this.page.sendEvent( 'keypress', "Woodchipper metagenomics, Fargo, ND" );
+
+ // click above the name input element
+ var inputInfo = this.getElementInfo( editableTextInputSelector );
+ this.page.sendEvent( 'mousedown',
+ historyFrameInfo.x + inputInfo.x + 1, historyFrameInfo.y + inputInfo.y - 5 );
+
+ this.wait( 1000, function(){
+ this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is STILL ' + newHistoryName );
+ this.test.assertDoesntExist( editableTextInputSelector, "Input disappears after clicking away" );
+ });
+ });
+});
+spaceghost.then( function(){
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( 'name should revert if user hits ESC while editing' );
+ this.click( nameSelector );
+ this.page.sendEvent( 'keypress', "Arsenic Bacteria" );
+
+ this.page.sendEvent( 'keypress', this.page.event.key.Escape );
+ this.wait( 1000, function(){
+ this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is STILL ' + newHistoryName );
+ this.test.assertDoesntExist( editableTextInputSelector, "Input disappears after hitting ESC" );
+ });
+ });
+});
+
+
+// ------------------------------------------------------------------- check structure of NON empty history
+/*
+// upload file: 1.txt
+spaceghost.then( function upload(){
+ this.test.comment( 'anon-user should be able to upload files' );
+ spaceghost.uploadFile( '../../test-data/1.txt', function uploadCallback( _uploadInfo ){
+ this.debug( 'uploaded HDA info: ' + this.jsonStr( _uploadInfo ) );
+ var hasHda = _uploadInfo.hdaElement,
+ hasClass = _uploadInfo.hdaElement.attributes[ 'class' ],
+ hasOkClass = _uploadInfo.hdaElement.attributes[ 'class' ].indexOf( 'historyItem-ok' ) !== -1;
+ this.test.assert( ( hasHda && hasClass && hasOkClass ), "Uploaded file: " + _uploadInfo.name );
+ uploadInfo = _uploadInfo;
+ });
+});
+
+//TODO: for each uploaded file: 1 file per (standard) datatype (or some subset)
+// txt, tabular, sam, bam, fasta, fastq, bed, gff,
+*/
+
+// -------------------------------------------------------------------
+//history panel
+ // structure of empty
+ // upload file
+ // structure of not empty
+ // tags
+ // annotation
+ // history refresh
+ // history options
+ // structure
+
+ // deleted
+
+ // hidden
+
+ // persistant expansion (or in hdaView?)
+
+//hdaView
+// with hpanel:
+ // (we assume hda is in the ok state)
+ // with collapsed hda:
+ // can we see the hid?
+ // can we see the title?
+ // three primary action buttons:
+ // they exist?
+ // Do they have good hrefs, targets?
+ // Are they enabled?
+ // do they have proper tooltips?
+ // display
+ // edit
+ // delete
+ //??: click through?
+
+ // with expaned hda:
+ // can we see the hid, title, and primary display buttons?
+
+ // misc info: no dbkey specified - is there a '?' link leading to edit attr?
+ // misc info: uploaded sam file
+ // misc info: format: sam
+
+ // secondary actions:
+ // download
+ // info
+ // rerun
+ // visualizations
+
+ // tags and annotations
+ //TODO: to their own file? tested elsewhere?
+
+ // peek:
+ // proper headers?
+ // lines?
+ // scrollbar?
+
+ // can re-collapse?
+
+
+
+
+
+
+
+
+// ===================================================================
+spaceghost.run( function(){
+ this.test.done();
+});
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/login-tests.js
--- a/test/casperjs/login-tests.js
+++ b/test/casperjs/login-tests.js
@@ -32,7 +32,7 @@
*/
// =================================================================== globals and helpers
-var email = spaceghost.getRandomEmail(),
+var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
email = spaceghost.fixtureData.testUser.email;
@@ -40,51 +40,38 @@
}
// =================================================================== TESTS
+// register a user (again...)
spaceghost.thenOpen( spaceghost.baseUrl, function(){
- this.test.comment( 'loading galaxy homepage' );
- // can we load galaxy?
- this.test.assertTitle( 'Galaxy' );
+ this.test.comment( 'registering: ' + email );
+ spaceghost.user.registerUser( email, password );
});
-// ------------------------------------------------------------------- should work
-
-// register a user (again...)
-spaceghost.then( function(){
- this.test.comment( 'registering: ' + email );
- spaceghost.registerUser( email, password );
-});
-// capture a sshot
-//spaceghost.then( function(){
-// this.clickLabel( 'User' );
-// this.capture( 'register.png' );
-//});
-
// log them out - check for empty logged in text
spaceghost.then( function(){
this.test.comment( 'logging out: ' + email );
- spaceghost.logout();
+ spaceghost.user.logout();
});
spaceghost.then( function(){
this.test.assertSelectorDoesntHaveText(
xpath( '//a[contains(text(),"Logged in as")]/span["id=#user-email"]' ), /\w/ );
- this.test.assert( spaceghost.loggedInAs() === '', 'loggedInAs() is empty string' );
+ this.test.assert( spaceghost.user.loggedInAs() === '', 'loggedInAs() is empty string' );
});
// log them back in - check for email in logged in text
spaceghost.then( function(){
this.test.comment( 'logging back in: ' + email );
- spaceghost._submitLogin( email, password ); //No such user
+ spaceghost.user._submitLogin( email, password ); //No such user
});
-spaceghost.then( function(){
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
this.test.assertSelectorHasText(
xpath( '//a[contains(text(),"Logged in as")]/span["id=#user-email"]' ), email );
- this.test.assert( spaceghost.loggedInAs() === email, 'loggedInAs() matches email' );
+ this.test.assert( spaceghost.user.loggedInAs() === email, 'loggedInAs() matches email' );
});
// finally log back out for next tests
spaceghost.then( function(){
this.test.comment( 'logging out: ' + email );
- spaceghost.logout();
+ spaceghost.user.logout();
});
// ------------------------------------------------------------------- shouldn't work
@@ -93,7 +80,7 @@
spaceghost.each( badEmails, function( self, badEmail ){
self.then( function(){
this.test.comment( 'attempting bad email: ' + badEmail );
- this._submitLogin( badEmail, password );
+ this.user._submitLogin( badEmail, password );
});
self.then(function(){
this.assertErrorMessage( 'No such user' );
@@ -105,7 +92,7 @@
spaceghost.each( badPasswords, function( self, badPassword ){
self.then( function(){
this.test.comment( 'attempting bad password: ' + badPassword );
- this._submitLogin( email, badPassword );
+ this.user._submitLogin( email, badPassword );
});
self.then(function(){
this.assertErrorMessage( 'Invalid password' );
@@ -118,7 +105,7 @@
this.assertStepsRaise( 'GalaxyError: LoginError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad email' );
- this.login( 'nihilist', '1234' );
+ this.user.login( 'nihilist', '1234' );
});
});
});
@@ -127,15 +114,16 @@
this.assertStepsRaise( 'GalaxyError: LoginError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad password' );
- this.login( email, '1234' );
+ this.user.login( email, '1234' );
});
});
});
spaceghost.then( function(){
- this.logout();
+ this.user.logout();
});
-
+/*
+*/
// ===================================================================
spaceghost.run( function(){
this.test.done();
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/modules/historypanel.js
--- /dev/null
+++ b/test/casperjs/modules/historypanel.js
@@ -0,0 +1,118 @@
+// =================================================================== module object, exports
+/** Creates a new tools module object.
+ * @exported
+ */
+exports.create = function createHistoryPanel( spaceghost ){
+ return new HistoryPanel( spaceghost );
+};
+
+/** HistoryPanel object constructor.
+ * @param {SpaceGhost} spaceghost a spaceghost instance
+ */
+var HistoryPanel = function HistoryPanel( spaceghost ){
+ this.options = {
+ progressIntervalDelay : 500
+ };
+ //??: circ ref?
+ this.spaceghost = spaceghost;
+};
+exports.HistoryPanel = HistoryPanel;
+
+HistoryPanel.prototype.toString = function toString(){
+ return this.spaceghost + '.HistoryPanel';
+};
+
+// -------------------------------------------------------------------
+/* TODO:
+ run a tool
+
+*/
+// =================================================================== INTERNAL
+
+// =================================================================== API (external)
+//TODO: to history module
+/** Find the casper element info of the hda wrapper given the hda title and hid.
+ * NOTE: if more than one is found, will return the first found.
+ * precondition: you should wrap this with withFrame( 'galaxy_history' ) :(
+ * @param {String} title the title of the hda
+ * @param {Int} hid (optional) the hid of the hda to look for
+ * @returns {Object|null} ElementInfo of the historyItemWrapper found, null if not found
+ */
+HistoryPanel.prototype.hdaElementInfoByTitle = function hdaElementInfoByTitle( title, hid ){
+ var spaceghost = this.spaceghost,
+ titleContains = ( hid !== undefined )?( hid + ': ' + title ):( title ),
+ wrapperInfo = null;
+
+ //NOTE: depends on jquery
+ wrapperInfo = spaceghost.evaluate( function( titleContains ){
+ // find the title, then the wrapper (2 containers up)
+ var $title = $( '.historyItemTitle:contains(' + titleContains + ')' );
+ var $wrapper = $title.parent().parent();
+ return (( $wrapper.attr( 'id' ) )?( __utils__.getElementInfo( '#' + $wrapper.attr( 'id' ) )):( null ));
+ }, titleContains );
+
+ return wrapperInfo;
+};
+
+/** Wait for the hda with given id to move into the given state.
+ * whenInStateFn and timeoutFn will be passed the hda element info (see Casper#getElementInfo)
+ * @param {String} hdaSelector selector for hda (should be historyItemWrapper)
+ * @param {String} finalState hda state to wait for (e.g. 'ok', 'error', 'running', 'queued', etc.)
+ * @param {Function} whenInStateFn called when hda goes into finalState
+ * @param {Function} timeoutFn called when maxWaitMs have passed without the desired state
+ * @param {Int} maxWaitMs number of milliseconds to wait before timing out (defaults to options.waitTimeout)
+ */
+HistoryPanel.prototype.waitForHdaState = function waitForHdaState( hdaSelector, finalState,
+ whenInStateFn, timeoutFn, maxWaitMs ){
+ //TODO:?? explicitly a historyWrapper id?
+ // we need a larger timeout for these - it can take a bit
+ maxWaitMs = maxWaitMs || this.spaceghost.options.waitTimeout;
+ var spaceghost = this.spaceghost,
+ finalStateClass = '.historyItem-' + finalState;
+
+ spaceghost.then( function(){
+ spaceghost.withFrame( spaceghost.selectors.frames.history, function(){
+
+ // save the old time out
+ var oldWaitTimeout = spaceghost.options.waitTimeout,
+
+ // output some progress indicator within the test (debug)
+ progressIntervalId = setInterval( function progress(){
+ // get the state from the hda wrapper's class
+ var state = spaceghost.evaluate( function( hdaSelector ){
+ if( !$( hdaSelector )[0] ){ return '(no hda found)'; }
+ var $wrapperClasses = $( hdaSelector ).attr( 'class' );
+ //TODO: remove magic string/regex
+ return $wrapperClasses.match( /historyItem\-(\w+)/ )[1];
+ }, hdaSelector );
+ spaceghost.debug( hdaSelector + ': ' + state );
+ }, spaceghost.historypanel.options.progressIntervalDelay ),
+
+ // when done, close down the progress reporter and reset the wait timeout to what it was
+ finallyFn = function(){
+ spaceghost.options.waitTimeout = oldWaitTimeout;
+ clearInterval( progressIntervalId );
+ };
+
+ spaceghost.options.waitTimeout = maxWaitMs;
+ spaceghost.waitForSelector( hdaSelector + finalStateClass,
+
+ // if the hda state became 'ok', call the whenInStateFn and close up
+ function _whenInState(){
+ var hdaInfo = spaceghost.elementInfoOrNull( hdaSelector );
+ spaceghost.debug( 'HDA now in state ' + finalState );
+ //spaceghost.debug( 'HDA:\n' + hdaInfo );
+ whenInStateFn.call( spaceghost, hdaInfo );
+ finallyFn();
+
+ // if we've timed out, call the timeoutFn and close up
+ }, function timeout(){
+ var hdaInfo = spaceghost.elementInfoOrNull( hdaSelector );
+ spaceghost.debug( 'HDA timed out. HDA = ' + spaceghost.jsonStr( hdaInfo ) );
+ timeoutFn.call( spaceghost, hdaInfo );
+ finallyFn();
+ }
+ );
+ });
+ });
+};
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/modules/tools.js
--- /dev/null
+++ b/test/casperjs/modules/tools.js
@@ -0,0 +1,221 @@
+// =================================================================== module object, exports
+/** Creates a new tools module object.
+ * @exported
+ */
+exports.create = function createTools( spaceghost ){
+ return new Tools( spaceghost );
+};
+
+/** Tools object constructor.
+ * @param {SpaceGhost} spaceghost a spaceghost instance
+ */
+var Tools = function Tools( spaceghost ){
+ //??: circ ref?
+ this.options = {
+ defaultUploadWait : ( 30 * 1000 )
+ };
+ this.spaceghost = spaceghost;
+};
+exports.Tools = Tools;
+
+Tools.prototype.toString = function toString(){
+ return this.spaceghost + '.Tools';
+};
+
+
+// =================================================================== INTERNAL
+/** Tests uploading a file.
+ * NOTE: this version does NOT throw an error on a bad upload.
+ * It is meant for testing the upload functionality and, therefore, is marked as private.
+ * Other tests should use uploadFile
+ * @param {String} filepath the local filesystem path of the file to upload (absolute (?))
+ */
+Tools.prototype._uploadFile = function _uploadFile( filepath ){
+ var spaceghost = this.spaceghost,
+ uploadInfo = {};
+ //TODO: check file exists using phantom.fs
+ //TODO: pull from test data
+ uploadInfo[ spaceghost.selectors.tools.upload.fileInput ] = filepath;
+ spaceghost.debug( 'uploading file: ' + filepath );
+
+ spaceghost.then( function(){
+ spaceghost.withFrame( spaceghost.selectors.frames.tools, function(){
+ spaceghost.clickLabel( spaceghost.labels.tools.upload.panelLabel );
+ });
+ });
+
+ spaceghost.then( function beginUpload(){
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function(){
+ spaceghost.fill( spaceghost.selectors.tools.general.form, uploadInfo, false );
+
+ // the following throws:
+ // [error] [remote] Failed dispatching clickmouse event on xpath selector: //input[@value="Execute"]:
+ // PageError: TypeError: 'undefined' is not a function (evaluating '$(spaceghost).formSerialize()')
+ // ...and yet the upload still seems to work
+ spaceghost.click( xpath( spaceghost.selectors.tools.general.executeButton_xpath ) );
+ });
+ });
+
+ // debugging
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function afterUpload(){
+ var messageInfo = spaceghost.elementInfoOrNull( spaceghost.selectors.messages.all );
+ spaceghost.debug( 'post upload message:\n' + spaceghost.jsonStr( messageInfo ) );
+ });
+};
+
+/** Uploads a file.
+ * @param {String} filepath the local filesystem path of the file to upload (absolute (?))
+ */
+//Tools.prototype.uploadFile = function uploadFile( filepath ){
+// this._uploadFile( filepath );
+// this.then( function(){
+// this.withFrame( this.selectors.frames.main, function mainAfterUpload(){
+// var messageInfo = this.elementInfoOrNull( this.selectors.messages.all );
+// if( ( !messageInfo )
+// || ( messageInfo.attributes[ 'class' ] !== 'donemessagelarge' )
+// || ( messageInfo.text.indexOf( this.text.upload.success ) === -1 ) ){
+// throw new GalaxyError( 'UploadError: ' + this.jsonStr( messageInfo ) );
+// }
+// });
+// });
+// return this;
+//};
+
+/** Parses the hid and name of a newly uploaded file from the tool execution donemessagelarge
+ * @param {String} doneMsgText the text extracted from the donemessagelarge after a tool execution
+ */
+Tools.prototype._parseDoneMessageForTool = function parseDoneMessageForTool( doneMsgText ){
+ //TODO: test on non-upload
+ var executionInfo = {};
+ var textMatch = doneMsgText.match( /added to the queue:\n\n(\d+)\: (.*)\n/m );
+ if( textMatch ){
+ if( textMatch.length > 1 ){
+ executionInfo.hid = parseInt( textMatch[1], 10 );
+ }
+ if( textMatch.length > 2 ){
+ executionInfo.name = textMatch[2];
+ }
+ executionInfo.name = textMatch[2];
+ }
+ return executionInfo;
+};
+
+// ------------------------------------------------------------------- get avail. tools
+// list available tools
+//spaceghost.then( function(){
+// spaceghost.withFrame( 'galaxy_tools', function(){
+// //var availableTools = this.fetchText( 'a.tool-link' );
+//
+// var availableTools = this.evaluate( function(){
+// //var toolTitles = __utils__.findAll( 'div.toolTitle' );
+// //return Array.prototype.map.call( toolTitles, function( e ){
+// // //return e.innerHtml;
+// // return e.textContent || e.innerText;
+// //}).join( '\n' );
+//
+// var toolLinks = __utils__.findAll( 'a.tool-link' );
+// return Array.prototype.map.call( toolLinks, function( e ){
+// //return e.innerHtml;
+// return e.textContent || e.innerText;
+// }).join( '\n' );
+// });
+// this.debug( 'availableTools: ' + availableTools );
+// });
+//});
+
+// =================================================================== API (external)
+/** get filename from filepath
+ * @param {String} filepath (POSIX) filepath
+ * @returns {String} filename part of filepath
+ */
+Tools.prototype.filenameFromFilepath = function filenameFromFilepath( filepath ){
+ var lastSepIndex = filepath.lastIndexOf( '/' );
+ if( lastSepIndex !== -1 ){
+ return filepath.slice( lastSepIndex + 1 );
+ }
+ return filepath;
+};
+
+/** Wait for the hda with given id to move into the given state.
+ * callback function will be passed an uploadInfo object in the form:
+ * filepath: the filepath of the uploaded file
+ * filename: the filename of the uploaded file
+ * hid: the hid of the uploaded file hda in the current history
+ * name: the name of the uploaded file hda
+ * hdaElement: the hda DOM (casperjs form) element info object (see Casper#getElementInfo)
+ * @param {String} filepath (POSIX) filepath
+ * @param {Function} callback callback function called after hda moves into ok state (will be passed uploadInfo)
+ * @param {Integer} timeoutAfterMs milliseconds to wait before timing out (defaults to options.defaultUploadWait)
+ */
+Tools.prototype.uploadFile = function uploadFile( filepath, callback, timeoutAfterMs ){
+ timeoutAfterMs = timeoutAfterMs || this.options.defaultUploadWait;
+ var spaceghost = this.spaceghost,
+ filename = this.filenameFromFilepath( filepath ),
+ uploadInfo = {};
+
+ // precondition: filepath is relative to scriptDir
+ filepath = spaceghost.options.scriptDir + '/' + filepath;
+
+ // upload the file erroring if a done message is not displayed, aggregate info about upload
+ spaceghost.info( 'uploading file: ' + filepath + ' (timeout after ' + timeoutAfterMs + ')' );
+ this._uploadFile( filepath );
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function toolExecuted(){
+ spaceghost.debug( 'checking for done message' );
+ var doneElementInfo = spaceghost.elementInfoOrNull( spaceghost.selectors.messages.donelarge );
+ if( !doneElementInfo ){
+ throw new spaceghost.GalaxyError( 'Upload Error: no done message uploading "' + filepath + '"' );
+ }
+ spaceghost.debug( 'doneElementInfo: ' + spaceghost.jsonStr( doneElementInfo ) );
+ // grab the hid and uploaded hda name from the done message
+ uploadInfo = spaceghost.tools._parseDoneMessageForTool( doneElementInfo.text );
+ uploadInfo.filename = filename;
+ uploadInfo.filepath = filepath;
+ spaceghost.debug( 'uploadInfo: ' + spaceghost.jsonStr( uploadInfo ) );
+ });
+
+ // the hpanel should refresh and display the uploading file, wait for that to go into the ok state
+ // throw if uploaded HDA doesn't appear, or it doesn't move to 'ok' after allotted time
+ spaceghost.then( function getNewHda(){
+ spaceghost.debug( 'beginning wait for upload file\'s ok state' );
+ // get the hda view DOM element from the upload name and hid
+ spaceghost.withFrame( spaceghost.selectors.frames.history, function(){
+ var hdaInfo = spaceghost.historypanel.hdaElementInfoByTitle( uploadInfo.name, uploadInfo.hid );
+ if( !hdaInfo ){
+ throw new spaceghost.GalaxyError( 'Upload Error: uploaded file HDA not found: '
+ + uploadInfo.hid + ', ' + uploadInfo.name );
+ }
+ spaceghost.debug( 'hdaInfo: ' + spaceghost.jsonStr( hdaInfo ) );
+ uploadInfo.hdaElement = hdaInfo;
+ // uploadInfo now has filepath, filename, name, hid, and hdaElement
+ });
+
+ spaceghost.then( function waitForOk(){
+ spaceghost.debug( 'beginning wait for upload file\'s ok state' );
+
+ // currently best way to get hda state is using the historyItem-<state> class of the historyItemWrapper
+ var hdaStateClass = uploadInfo.hdaElement.attributes[ 'class' ].match( /historyItem\-(\w+)/ )[0];
+ if( hdaStateClass !== 'historyItem-ok' ){
+
+ spaceghost.historypanel.waitForHdaState( '#' + uploadInfo.hdaElement.attributes.id, 'ok',
+ function whenInStateFn( hdaInfo ){
+ // refresh hdaElement info
+ uploadInfo.hdaElement = hdaInfo;
+ callback.call( spaceghost, uploadInfo );
+
+ }, function timeoutFn( hdaInfo ){
+ var finalClass = (( hdaInfo )?( hdaInfo.attributes[ 'class' ] ):( undefined ));
+ spaceghost.debug( 'final classes: ' + finalClass );
+ throw new spaceghost.GalaxyError( 'Upload Error: timeout waiting for ok state: '
+ + '"' + uploadInfo.hid + ': ' + uploadInfo.name + '"'
+ + ' (waited ' + timeoutAfterMs + ' ms)' );
+
+ }, timeoutAfterMs );
+ }
+ });
+ });
+ return spaceghost;
+};
+//TODO: upload via url
+//TODO: upload by textarea
+
+
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/modules/user.js
--- /dev/null
+++ b/test/casperjs/modules/user.js
@@ -0,0 +1,209 @@
+// =================================================================== module object, exports
+/** Creates a new user module object.
+ * @exported
+ */
+exports.create = function createUser( spaceghost ){
+ return new User( spaceghost );
+};
+
+/** User object constructor.
+ * @param {SpaceGhost} spaceghost a spaceghost instance
+ */
+var User = function User( spaceghost ){
+ //??: circ ref?
+ this.spaceghost = spaceghost;
+};
+exports.User = User;
+
+User.prototype.toString = function toString(){
+ return this.spaceghost + '.User';
+};
+
+
+// =================================================================== INTERNAL
+/** Tests registering a new user on the Galaxy instance by submitting the registration form.
+ * NOTE: this version does NOT throw an error on a bad registration.
+ * It is meant for testing the registration functionality and, therefore, is marked as private.
+ * Other tests should use registerUser
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ * @param {String} username the users ...username! (optional: will use 1st part of email)
+ * @param {String} confirm password confirmation (optional: defaults to password)
+ */
+User.prototype._submitRegistration = function _submitRegistration( email, password, username, confirm ){
+ var spaceghost = this.spaceghost,
+ userInfo = {
+ email : email,
+ password: password,
+ // default username to first part of email
+ username:( !username && email.match( /^\w*/ ) )?( email.match( /^\w*/ ) ):( username ),
+ // default confirm: duplicate of password
+ confirm : ( confirm !== undefined )?( confirm ):( password )
+ };
+
+ spaceghost.debug( 'registering user:\n' + spaceghost.jsonStr( userInfo ) );
+ spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ spaceghost.clickLabel( spaceghost.labels.masthead.menus.user );
+ spaceghost.clickLabel( spaceghost.labels.masthead.userMenu.register );
+
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function mainBeforeRegister(){
+ spaceghost.debug( 'submitting registration... ' + spaceghost.getCurrentUrl() );
+ spaceghost.fill( spaceghost.selectors.registrationPage.form, userInfo, false );
+ // need manual submit (not a normal html form)
+ spaceghost.click( xpath( spaceghost.selectors.registrationPage.submit_xpath ) );
+ });
+
+ //// debugging
+ //spaceghost.withFrame( spaceghost.selectors.frames.main, function mainAfterRegister(){
+ // var messageInfo = spaceghost.getElementInfo( spaceghost.selectors.messages.all );
+ // spaceghost.debug( 'post registration message:\n' + spaceghost.jsonStr( messageInfo ) );
+ //});
+ });
+};
+
+/** Tests logging in a user on the Galaxy instance by submitting the login form.
+ * NOTE: this version does NOT throw an error on a bad login.
+ * It is meant for testing the login functionality and, therefore, is marked as private.
+ * Other tests should use login
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ */
+User.prototype._submitLogin = function logoutUser( email, password ){
+ var spaceghost = this.spaceghost,
+ loginInfo = {
+ //NOTE: keys are used as name selectors in the fill fn - must match the names of the inputs
+ email: email,
+ password: password
+ };
+
+ spaceghost.thenOpen( spaceghost.baseUrl, function(){
+
+ spaceghost.clickLabel( spaceghost.labels.masthead.menus.user );
+ spaceghost.clickLabel( spaceghost.labels.masthead.userMenu.login );
+
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function mainBeforeLogin(){
+ spaceghost.debug( '(' + spaceghost.getCurrentUrl() + ') logging in user:\n'
+ + spaceghost.jsonStr( loginInfo ) );
+ spaceghost.fill( spaceghost.selectors.loginPage.form, loginInfo, false );
+ spaceghost.click( xpath( spaceghost.selectors.loginPage.submit_xpath ) );
+ });
+
+ //// debugging
+ //spaceghost.withFrame( spaceghost.selectors.frames.main, function mainAfterLogin(){
+ // //TODO: prob. could use a more generalized form of this for url breakdown/checking
+ // if( spaceghost.getCurrentUrl().search( spaceghost.selectors.loginPage.url_regex ) != -1 ){
+ // var messageInfo = spaceghost.getElementInfo( spaceghost.selectors.messages.all );
+ // spaceghost.debug( 'post login message:\n' + spaceghost.jsonStr( messageInfo ) );
+ // }
+ //});
+ });
+};
+
+
+// =================================================================== API (external)
+/** Register a new user on the Galaxy instance.
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ * @param {String} username the users ...username! (optional: will use 1st part of email)
+ * @returns {SpaceGhost} the spaceghost instance (for chaining)
+ */
+User.prototype.registerUser = function registerUser( email, password, username ){
+ var spaceghost = this.spaceghost;
+ this._submitRegistration( email, password, username );
+ spaceghost.then( function(){
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function mainAfterRegister(){
+ var messageInfo = spaceghost.getElementInfo( spaceghost.selectors.messages.all );
+ spaceghost.debug( 'post registration message:\n' + this.jsonStr( messageInfo ) );
+
+ if( messageInfo.attributes[ 'class' ] === 'errormessage' ){
+ throw new spaceghost.GalaxyError( 'RegistrationError: ' + messageInfo.html );
+ }
+ });
+ });
+ return spaceghost;
+};
+
+/** Logs in a user. Throws error on bad log in.
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ * @returns {SpaceGhost} the spaceghost instance (for chaining)
+ */
+User.prototype.login = function login( email, password ){
+ var spaceghost = this.spaceghost;
+ this._submitLogin( email, password );
+ spaceghost.then( function(){
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function mainAfterLogin(){
+ if( spaceghost.getCurrentUrl().search( spaceghost.selectors.loginPage.url_regex ) != -1 ){
+ var messageInfo = spaceghost.getElementInfo( spaceghost.selectors.messages.all );
+ if( messageInfo && messageInfo.attributes[ 'class' ] === 'errormessage' ){
+ throw new spaceghost.GalaxyError( 'LoginError: ' + messageInfo.html );
+ }
+ }
+ });
+ if( spaceghost.user.loggedInAs() === email ){
+ spaceghost.debug( 'logged in as ' + email );
+ }
+ });
+ return spaceghost;
+};
+
+/** Fetch the email of the currently logged in user (or '' if not logged in)
+ * @returns {String} email of currently logged in user or '' if no one logged in
+ */
+User.prototype.loggedInAs = function loggedInAs(){
+ var spaceghost = this.spaceghost,
+ userEmail = '';
+ try {
+ var loggedInInfo = spaceghost.getElementInfo( xpath( spaceghost.selectors.masthead.userMenu.userEmail_xpath ) );
+ userEmail = loggedInInfo.text;
+ } catch( err ){
+ spaceghost.error( err );
+ }
+ //console.debug( 'loggedInInfo:', spaceghost.jsonStr( loggedInInfo ) );
+ return userEmail;
+};
+
+/** Log out the current user
+ * @returns {SpaceGhost} the spaceghost instance (for chaining)
+ */
+User.prototype.logout = function logoutUser(){
+ var spaceghost = this.spaceghost;
+ spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ //TODO: handle already logged out
+ spaceghost.clickLabel( spaceghost.labels.masthead.menus.user );
+ spaceghost.clickLabel( spaceghost.labels.masthead.userMenu.logout );
+ });
+ return spaceghost;
+};
+
+/** Attempts to login a user - if that raises an error (LoginError), register the user
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ * @param {String} username the users ...username! (optional: will use 1st part of email)
+ * @returns {SpaceGhost} the spaceghost instance (for chaining)
+ */
+User.prototype.loginOrRegisterUser = function loginOrRegisterUser( email, password, username ){
+ var spaceghost = this.spaceghost;
+ // attempt a login, if that fails - register
+ spaceghost.tryStepsCatch( function tryToLogin(){
+ spaceghost.open( spaceghost.baseUrl ).user.login( email, password );
+
+ }, function failedLoginRegister(){
+ spaceghost.open( spaceghost.baseUrl ).user.registerUser( email, password, username );
+ });
+ return spaceghost;
+};
+
+/** Gets a psuedo-random (unique?) email based on the time stamp.
+ * Helpful for testing registration.
+ * @param {String} username email user (defaults to 'test')
+ * @param {String} domain email domain (defaults to 'test.test')
+ * @returns {String} new email as string
+ */
+User.prototype.getRandomEmail = function getRandomEmail( username, domain ){
+ username = username || 'test';
+ domain = domain || 'test.test';
+ return username + Date.now() + '@' + domain;
+};
+
+
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/registration-tests.js
--- a/test/casperjs/registration-tests.js
+++ b/test/casperjs/registration-tests.js
@@ -24,7 +24,6 @@
phantom.exit( 1 );
}
-
// ===================================================================
/* TODO:
move selectors and assertText strings into global object for easier editing
@@ -33,7 +32,7 @@
*/
// =================================================================== globals and helpers
-var email = spaceghost.getRandomEmail(),
+var email = spaceghost.user.getRandomEmail(),
password = '123456',
confirm = password,
username = 'test' + Date.now();
@@ -60,29 +59,27 @@
// ------------------------------------------------------------------- register a new user
spaceghost.then( function(){
this.test.comment( 'registering user: ' + email );
- this._submitUserRegistration( email, password, username, confirm );
+ this.user._submitRegistration( email, password, username, confirm );
});
spaceghost.thenOpen( spaceghost.baseUrl, function(){
this.clickLabel( 'User' );
this.test.assertSelectorHasText( 'a #user-email', email, '#user-email === ' + email );
});
-
// ------------------------------------------------------------------- log out that user
spaceghost.then( function(){
this.test.comment( 'logging out user: ' + email );
- this.logout();
+ this.user.logout();
});
spaceghost.then( function(){
this.debug( 'email:' + this.getElementInfo( 'a #user-email' ).html );
this.test.assert( !this.getElementInfo( 'a #user-email' ).html, '#user-email is empty' );
});
-
// ------------------------------------------------------------------- bad user registrations
spaceghost.then( function(){
this.test.comment( 'attempting to re-register user: ' + email );
- this._submitUserRegistration( email, password, username, confirm );
+ this.user._submitRegistration( email, password, username, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'User with that email already exists' );
@@ -93,7 +90,7 @@
spaceghost.each( badEmails, function( self, badEmail ){
self.then( function(){
this.test.comment( 'attempting bad email: ' + badEmail );
- this._submitUserRegistration( badEmail, password, username, confirm );
+ this.user._submitRegistration( badEmail, password, username, confirm );
});
self.then(function(){
this.assertErrorMessage( 'Enter a real email address' );
@@ -105,7 +102,7 @@
spaceghost.each( badPasswords, function( self, badPassword ){
self.then( function(){
this.test.comment( 'attempting bad password: ' + badPassword );
- this._submitUserRegistration( spaceghost.getRandomEmail(), badPassword, username, confirm );
+ this.user._submitRegistration( spaceghost.user.getRandomEmail(), badPassword, username, confirm );
});
self.then(function(){
this.assertErrorMessage( 'Use a password of at least 6 characters' );
@@ -117,7 +114,7 @@
spaceghost.each( badConfirms, function( self, badConfirm ){
self.then( function(){
this.test.comment( 'attempting bad password confirmation: ' + badConfirm );
- this._submitUserRegistration( spaceghost.getRandomEmail(), password, username, badConfirm );
+ this.user._submitRegistration( spaceghost.user.getRandomEmail(), password, username, badConfirm );
});
self.then(function(){
this.assertErrorMessage( 'Passwords do not match' );
@@ -128,10 +125,10 @@
//NOTE: that short username errors only show AFTER checking for existing/valid emails
// so: we need to generate new emails for each one
spaceghost.then( function(){
- var newEmail = spaceghost.getRandomEmail(),
+ var newEmail = spaceghost.user.getRandomEmail(),
badUsername = 'bob';
this.test.comment( 'attempting short username: ' + badUsername );
- this._submitUserRegistration( newEmail, password, badUsername, confirm );
+ this.user._submitRegistration( newEmail, password, badUsername, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'Public name must be at least 4 characters in length' );
@@ -141,9 +138,9 @@
var badUsernames = [ 'BOBERT', 'Robert Paulson', 'bobert!', 'bob_dobbs' ];
spaceghost.each( badUsernames, function( self, badUsername ){
self.then( function(){
- var newEmail = spaceghost.getRandomEmail();
+ var newEmail = spaceghost.user.getRandomEmail();
this.test.comment( 'attempting bad username: ' + badUsername );
- this._submitUserRegistration( newEmail, password, badUsername, confirm );
+ this.user._submitRegistration( newEmail, password, badUsername, confirm );
});
self.then(function(){
this.assertErrorMessage( "Public name must contain only lower-case letters, numbers and '-'" );
@@ -152,28 +149,29 @@
// ...and the name can't be used already
spaceghost.then( function(){
- var newEmail = spaceghost.getRandomEmail();
+ var newEmail = spaceghost.user.getRandomEmail();
this.test.comment( 'attempting previously used username with new user: ' + newEmail );
- this._submitUserRegistration( newEmail, password, username, confirm );
+ this.user._submitRegistration( newEmail, password, username, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'Public name is taken; please choose another' );
});
-// ------------------------------------------------------------------- test the tests
+// ------------------------------------------------------------------- test the convenience fns
// these versions are for conv. use in other tests, they should throw errors if used improperly
spaceghost.then( function(){
this.assertStepsRaise( 'GalaxyError: RegistrationError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad email' );
- this.registerUser( '@internet', '123456', 'ignobel' );
+ this.user.registerUser( '@internet', '123456', 'ignobel' );
});
});
});
spaceghost.then( function(){
- this.logout();
+ //??: necessary?
+ this.user.logout();
});
// ===================================================================
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/spaceghost.js
--- a/test/casperjs/spaceghost.js
+++ b/test/casperjs/spaceghost.js
@@ -72,6 +72,14 @@
//console.debug( 'CasperError:' + CasperError );
+// ------------------------------------------------------------------- included libs
+//??: can we require underscore, etc. from the ../../static/scripts/lib?
+// yep!
+//var _ = require( '../../static/scripts/libs/underscore' );
+//var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
+//console.debug( JSON.stringify( _.pluck(stooges, 'name') ) );
+//exports._ = _;
+
// ------------------------------------------------------------------- error types
PageError.prototype = new CasperError();
PageError.prototype.constructor = CasperError;
@@ -79,6 +87,7 @@
CasperError.apply( this, arguments );
this.name = "PageError";
}
+SpaceGhost.prototype.PageError = PageError;
GalaxyError.prototype = new CasperError();
GalaxyError.prototype.constructor = CasperError;
@@ -86,6 +95,7 @@
CasperError.apply( this, arguments );
this.name = "GalaxyError";
}
+SpaceGhost.prototype.GalaxyError = GalaxyError;
AlertError.prototype = new CasperError();
AlertError.prototype.constructor = CasperError;
@@ -93,11 +103,12 @@
CasperError.apply( this, arguments );
this.name = "AlertError";
}
+SpaceGhost.prototype.AlertError = AlertError;
// =================================================================== METHODS / OVERRIDES
// ------------------------------------------------------------------- set up
/** More initialization: cli, event handlers, etc.
- * @param {Object} options option hash
+ * @param {Object} options option hash
*/
SpaceGhost.prototype.init = function init( options ){
//console.debug( 'init, options:', JSON.stringify( options, null, 2 ) );
@@ -122,6 +133,8 @@
].concat( this.options.clientScripts );
this.debug( 'clientScripts:\n' + this.jsonStr( this.options.clientScripts ) );
+ this._loadModules();
+
};
/** Allow CLI arguments to set options if the proper option name is used.
@@ -371,7 +384,16 @@
};
-// ------------------------------------------------------------------- page control
+// ------------------------------------------------------------------- sub modules
+/** Load sub modules (similar to casperjs.test)
+ */
+SpaceGhost.prototype._loadModules = function _loadModules(){
+ this.user = require( this.options.scriptDir + 'modules/user' ).create( this );
+ this.tools = require( this.options.scriptDir + 'modules/tools' ).create( this );
+ this.historypanel = require( this.options.scriptDir + 'modules/historypanel' ).create( this );
+};
+
+// =================================================================== PAGE CONTROL
/** An override of casper.open specifically for Galaxy.
* (Currently only used to change language headers)
*/
@@ -530,327 +552,8 @@
};
+
// =================================================================== GALAXY CONVENIENCE
-/** Gets a psuedo-random (unique?) email based on the time stamp.
- * Helpful for testing registration.
- * @param {String} username email user (defaults to 'test')
- * @param {String} domain email domain (defaults to 'test.test')
- */
-SpaceGhost.prototype.getRandomEmail = function getRandomEmail( username, domain ){
- username = username || 'test';
- domain = domain || 'test.test';
- return username + Date.now() + '@' + domain;
-};
-
-
-/** Tests registering a new user on the Galaxy instance by submitting the registration form.
- * NOTE: this version does NOT throw an error on a bad registration.
- * It is meant for testing the registration functionality and, therefore, is marked as private.
- * Other tests should use registerUser
- * @param {String} email the users email address
- * @param {String} password the users password
- * @param {String} username the users ...username! (optional: will use 1st part of email)
- * @param {String} confirm password confirmation (optional: defaults to password)
- */
-SpaceGhost.prototype._submitUserRegistration = function _submitUserRegistration( email, password, username, confirm ){
- var userInfo = {
- email : email,
- password: password,
- // default username to first part of email
- username:( !username && email.match( /^\w*/ ) )?( email.match( /^\w*/ ) ):( username ),
- // default confirm duplicate of password
- confirm : ( confirm !== undefined )?( confirm ):( password )
- };
- this.debug( 'registering user:\n' + this.jsonStr( userInfo ) );
-
- this.thenOpen( this.baseUrl, function(){
-
- this.clickLabel( this.labels.masthead.menus.user );
- this.clickLabel( this.labels.masthead.userMenu.register );
-
- this.withFrame( this.selectors.frames.main, function mainBeforeRegister(){
- this.debug( 'submitting registration... ' + this.getCurrentUrl() );
- this.fill( this.selectors.registrationPage.form, userInfo, false );
- // need manual up
- this.click( xpath( this.selectors.registrationPage.submit_xpath ) );
- });
-
- this.withFrame( this.selectors.frames.main, function mainAfterRegister(){
- var messageInfo = this.getElementInfo( this.selectors.messages.all );
- this.debug( 'post registration message:\n' + this.jsonStr( messageInfo ) );
- });
- });
-};
-
-/** Register a new user on the Galaxy instance.
- * @param {String} email the users email address
- * @param {String} password the users password
- * @param {String} username the users ...username! (optional: will use 1st part of email)
- */
-SpaceGhost.prototype.registerUser = function registerUser( email, password, username ){
- this._submitUserRegistration( email, password, username );
- this.then( function(){
- this.withFrame( this.selectors.frames.main, function mainAfterRegister(){
- var messageInfo = this.getElementInfo( this.selectors.messages.all );
- this.debug( 'post registration message:\n' + this.jsonStr( messageInfo ) );
-
- if( messageInfo.attributes[ 'class' ] === 'errormessage' ){
- throw new GalaxyError( 'RegistrationError: ' + messageInfo.html );
- }
- });
- });
- return this;
-};
-
-/** Log out the current user
- */
-SpaceGhost.prototype.logout = function logoutUser(){
- this.clickLabel( this.labels.masthead.menus.user );
- this.clickLabel( this.labels.masthead.userMenu.login );
- this.thenOpen( this.baseUrl, function(){
- //TODO: handle already logged out
- this.clickLabel( this.labels.masthead.menus.user );
- this.clickLabel( this.labels.masthead.userMenu.logout );
- });
-};
-
-/** Tests logging in a user on the Galaxy instance by submitting the login form.
- * NOTE: this version does NOT throw an error on a bad login.
- * It is meant for testing the login functionality and, therefore, is marked as private.
- * Other tests should use login
- * @param {String} email the users email address
- * @param {String} password the users password
- */
-SpaceGhost.prototype._submitLogin = function logoutUser( email, password ){
- var loginInfo = {
- //NOTE: keys are used as name selectors in the fill fn - must match the names of the inputs
- email: email,
- password: password
- };
-
- this.thenOpen( this.baseUrl, function(){
-
- this.clickLabel( this.labels.masthead.menus.user );
- this.clickLabel( this.labels.masthead.userMenu.login );
-
- this.withFrame( this.selectors.frames.main, function mainBeforeLogin(){
- this.debug( '(' + this.getCurrentUrl() + ') logging in user:\n' + this.jsonStr( loginInfo ) );
- this.fill( this.selectors.loginPage.form, loginInfo, false );
- this.click( xpath( this.selectors.loginPage.submit_xpath ) );
- });
- this.withFrame( this.selectors.frames.main, function mainAfterLogin(){
- //TODO: prob. could use a more generalized form of this for url breakdown/checking
- if( this.getCurrentUrl().search( this.selectors.loginPage.url_regex ) != -1 ){
- var messageInfo = this.getElementInfo( this.selectors.messages.all );
- this.debug( 'post login message:\n' + this.jsonStr( messageInfo ) );
- }
- });
- });
-};
-
-/** Logs in a user. Throws error on bad log in.
- * @param {String} email the users email address
- * @param {String} password the users password
- */
-SpaceGhost.prototype.login = function login( email, password ){
- this._submitLogin( email, password );
- this.then( function(){
- this.withFrame( this.selectors.frames.main, function mainAfterLogin(){
- if( this.getCurrentUrl().search( this.selectors.loginPage.url_regex ) != -1 ){
- var messageInfo = this.getElementInfo( this.selectors.messages.all );
- if( messageInfo && messageInfo.attributes[ 'class' ] === 'errormessage' ){
- throw new GalaxyError( 'LoginError: ' + messageInfo.html );
- }
- }
- });
- if( this.loggedInAs() === email ){
- this.debug( 'logged in as ' + email );
- }
- });
- return this;
-};
-
-/** Fetch the email of the currently logged in user (or '' if not logged in)
- * @returns {String} email of currently logged in user or '' if no one logged in
- */
-SpaceGhost.prototype.loggedInAs = function loggedInAs(){
- var userEmail = '';
- try {
- var loggedInInfo = this.getElementInfo( xpath( this.selectors.masthead.userMenu.userEmail_xpath ) );
- userEmail = loggedInInfo.text;
- } catch( err ){
- this.error( err );
- }
- //console.debug( 'loggedInInfo:', this.jsonStr( loggedInInfo ) );
- return userEmail;
-};
-
-/** Attempts to login a user - if that raises an error (LoginError), register the user
- * @param {String} email the users email address
- * @param {String} password the users password
- * @param {String} username the users ...username! (optional: will use 1st part of email)
- */
-SpaceGhost.prototype.loginOrRegisterUser = function loginOrRegisterUser( email, password, username ){
- // attempt a login, if that fails - register
- this.tryStepsCatch( function tryToLogin(){
- this.open( this.baseUrl ).login( email, password );
-
- }, function failedLoginRegister(){
- this.open( this.baseUrl ).registerUser( email, password, username );
- });
- return this;
-};
-
-/** Tests uploading a file.
- * NOTE: this version does NOT throw an error on a bad upload.
- * It is meant for testing the upload functionality and, therefore, is marked as private.
- * Other tests should use uploadFile
- * @param {String} filepath the local filesystem path of the file to upload (absolute (?))
- */
-SpaceGhost.prototype._uploadFile = function _uploadFile( filepath ){
- var uploadInfo = {};
- //TODO: check file exists using phantom.fs
- //TODO: pull from test data
- uploadInfo[ this.tools.upload.fileInput ] = filepath;
- this.debug( 'uploading file: ' + filepath );
-
- spaceghost.then( function(){
- spaceghost.withFrame( this.selectors.frames.tools, function(){
- this.clickLabel( this.tools.upload.panelLabel );
- });
- });
-
- this.then( function beginUpload(){
- spaceghost.withFrame( this.selectors.frames.main, function(){
- this.fill( this.tools.general.form, uploadInfo, false );
-
- // the following throws:
- // [error] [remote] Failed dispatching clickmouse event on xpath selector: //input[@value="Execute"]:
- // PageError: TypeError: 'undefined' is not a function (evaluating '$(this).formSerialize()')
-
- // ...and yet the upload still seems to work
- this.click( xpath( this.tools.general.executeButton_xpath ) );
- });
- });
- this.withFrame( this.selectors.frames.main, function afterUpload(){
- var messageInfo = this.elementInfoOrNull( this.selectors.messages.all );
- this.debug( 'post upload message:\n' + this.jsonStr( messageInfo ) );
- });
-};
-
-/** Uploads a file.
- * @param {String} filepath the local filesystem path of the file to upload (absolute (?))
- */
-SpaceGhost.prototype.uploadFile = function uploadFile( filepath ){
- this._uploadFile( filepath );
- this.then( function(){
- this.withFrame( this.selectors.frames.main, function mainAfterUpload(){
- var messageInfo = this.elementInfoOrNull( this.selectors.messages.all );
- if( ( !messageInfo )
- || ( messageInfo.attributes[ 'class' ] !== 'donemessagelarge' )
- || ( messageInfo.text.indexOf( this.text.upload.success ) === -1 ) ){
- throw new GalaxyError( 'UploadError: ' + this.jsonStr( messageInfo ) );
- }
- });
- });
- return this;
-};
-
-/** Parses the hid and name of a newly uploaded file from the tool execution donemessagelarge
- * @param {String} doneMsgText the text extracted from the donemessagelarge after a tool execution
- */
-SpaceGhost.prototype.parseDoneMessageForTool = function parseDoneMessageForTool( doneMsgText ){
- //TODO: test on non-upload
- var executionInfo = {};
- var textMatch = doneMsgText.match( /added to the queue:\n\n(\d+)\: (.*)\n/m );
- if( textMatch ){
- if( textMatch.length > 1 ){
- executionInfo.hid = parseInt( textMatch[1], 10 );
- }
- if( textMatch.length > 2 ){
- executionInfo.name = textMatch[2];
- }
- executionInfo.name = textMatch[2];
- }
- return executionInfo;
-};
-
-/** Find the casper element info of the hda wrapper given the hda title and hid.
- * NOTE: if more than one is found, will return the first found.
- * precondition: you should wrap this with withFrame( 'galaxy_history' ) :(
- * @param {String} title the title of the hda
- * @param {Int} hid (optional) the hid of the hda to look for
- * @returns {Object|null} ElementInfo of the historyItemWrapper found, null if not found
- */
-SpaceGhost.prototype.hdaElementInfoByTitle = function hdaElementInfoByTitle( title, hid ){
- var spaceghost = this,
- titleContains = ( hid !== undefined )?( hid + ': ' + title ):( title ),
- wrapperInfo = null;
-
- wrapperInfo = spaceghost.evaluate( function( titleContains ){
- // find the title, then the wrapper (2 containers up)
- var $title = $( '.historyItemTitle:contains(' + titleContains + ')' );
- var $wrapper = $title.parent().parent();
- return (( $wrapper.attr( 'id' ) )?( __utils__.getElementInfo( '#' + $wrapper.attr( 'id' ) )):( null ));
- }, titleContains );
-
- return wrapperInfo;
-};
-
-/** Wait for the hda with given id to move into the given state.
- * @param {String} hdaSelector selector for hda (should be historyItemWrapper)
- * @param {String} finalState hda state to wait for (e.g. 'ok', 'error', 'running', 'queued', etc.)
- * @param {Function} whenInStateFn called when hda goes into finalState
- * @param {Function} timeoutFn called when maxWaitMs have passed without the desired state
- * @param {Int} maxWaitMs number of milliseconds to wait before timing out (defaults to options.waitTimeout)
- */
-SpaceGhost.prototype.waitForHdaState = function waitForHdaState( hdaSelector, finalState,
- whenInStateFn, timeoutFn, maxWaitMs ){
- //TODO:?? explicitly a historyWrapper id?
- maxWaitMs = maxWaitMs || this.options.waitTimeout;
- var finalStateClass = '.historyItem-' + finalState;
-
- this.then( function(){
- this.withFrame( this.selectors.frames.history, function(){
- // wait for state, preferrably debugging intermediate states
- var spaceghost = this,
-
- // we need a larger timeout for these - it can take a bit
- oldWaitTimeout = this.options.waitTimeout,
-
- // output some progress indicator within the test (debug)
- progressIntervalId = setInterval( function progress(){
- var state = spaceghost.evaluate( function( hdaSelector ){
- var $wrapperClasses = $( hdaSelector ).attr( 'class' );
- return $wrapperClasses.match( /historyItem\-(\w+)/ )[1];
- }, hdaSelector );
- spaceghost.debug( hdaSelector + ': ' + state );
- }, 1000 ),
-
- // when done, close down the progress reporter and reset the wait timeout to what it was
- finallyFn = function(){
- spaceghost.options.waitTimeout = oldWaitTimeout;
- clearInterval( progressIntervalId );
- };
-
- this.options.waitTimeout = maxWaitMs;
- this.waitForSelector( hdaSelector + finalStateClass, function _whenInState(){
- this.debug( 'HDA now in state ' + finalState + ':\n'
- + this.jsonStr( this.elementInfoOrNull( hdaSelector ) ) );
- whenInStateFn.call( this );
- finallyFn();
-
- }, function timeout(){
- this.debug( 'timed out:\n'
- + this.jsonStr( this.elementInfoOrNull( hdaSelector ) ) );
- timeoutFn.call( this );
- finallyFn();
- }
- );
- });
- });
-};
-
// =================================================================== MISCELAIN
/** Send message to stderr
*/
@@ -958,9 +661,10 @@
history : 'galaxy_history'
},
messages : {
- all : '[class*="message"]',
+ all : '[class*="message"]',
error : '.errormessage',
- done : '.donemessage'
+ done : '.donemessage',
+ donelarge : '.donemessagelarge'
},
loginPage : {
form : 'form#login',
@@ -970,6 +674,15 @@
registrationPage : {
form : 'form#registration',
submit_xpath : "//input[@value='Submit']"
+ },
+ tools : {
+ general : {
+ form : 'form#tool_form',
+ executeButton_xpath : '//input[@value="Execute"]'
+ },
+ upload : {
+ fileInput : 'files_0|file_data' // is this general?
+ }
}
};
@@ -983,17 +696,11 @@
login : 'Login',
logout : 'Logout'
}
- }
-};
-
-SpaceGhost.prototype.tools = {
- general : {
- form : 'form#tool_form',
- executeButton_xpath : '//input[@value="Execute"]'
},
- upload : {
- panelLabel : 'Upload File',
- fileInput : 'files_0|file_data' // is this general?
+ tools : {
+ upload : {
+ panelLabel : 'Upload File'
+ }
}
};
@@ -1007,6 +714,12 @@
}
};
+SpaceGhost.prototype.loadJSONFile = function loadJSONFile( filepath ){
+ //precondition: filepath is relative to script dir
+ filepath = this.options.scriptDir + filepath;
+ return JSON.parse( require( 'fs' ).read( filepath ) );
+};
+
// =================================================================== EXPORTS
/**
*/
@@ -1021,10 +734,3 @@
return new SpaceGhost(options);
};
-// ------------------------------------------------------------------- included libs
-//??: can we require underscore, etc. from the ../../static/scripts/lib?
-// yep!
-//var _ = require( '../../static/scripts/libs/underscore' );
-//var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
-//console.debug( JSON.stringify( _.pluck(stooges, 'name') ) );
-//exports._ = _;
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/upload-tests.js
--- a/test/casperjs/upload-tests.js
+++ b/test/casperjs/upload-tests.js
@@ -32,7 +32,7 @@
general tool execution
*/
// =================================================================== globals and helpers
-var email = spaceghost.getRandomEmail(),
+var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
email = spaceghost.fixtureData.testUser.email;
@@ -42,44 +42,22 @@
// =================================================================== TESTS
// ------------------------------------------------------------------- start a new user
-spaceghost.loginOrRegisterUser( email, password );
+spaceghost.user.loginOrRegisterUser( email, password );
//??: why is a reload needed here? If we don't, loggedInAs === '' ...
spaceghost.thenOpen( spaceghost.baseUrl, function(){
- var loggedInAs = spaceghost.loggedInAs();
+ var loggedInAs = spaceghost.user.loggedInAs();
this.test.assert( loggedInAs === email, 'loggedInAs() matches email: "' + loggedInAs + '"' );
});
-// ------------------------------------------------------------------- get avail. tools
-// list available tools
-//spaceghost.then( function(){
-// spaceghost.withFrame( 'galaxy_tools', function(){
-// //var availableTools = this.fetchText( 'a.tool-link' );
-//
-// var availableTools = this.evaluate( function(){
-// //var toolTitles = __utils__.findAll( 'div.toolTitle' );
-// //return Array.prototype.map.call( toolTitles, function( e ){
-// // //return e.innerHtml;
-// // return e.textContent || e.innerText;
-// //}).join( '\n' );
-//
-// var toolLinks = __utils__.findAll( 'a.tool-link' );
-// return Array.prototype.map.call( toolLinks, function( e ){
-// //return e.innerHtml;
-// return e.textContent || e.innerText;
-// }).join( '\n' );
-// });
-// this.debug( 'availableTools: ' + availableTools );
-// });
-//});
-// ------------------------------------------------------------------- upload from fs
-// test uploading from the filesystem
+// ------------------------------------------------------------------- long form
+// upload a file from the filesystem
var uploadInfo = {};
spaceghost.then( function(){
// strangely, this works with a non-existant file --> empty txt file
var filename = '1.sam';
var filepath = this.options.scriptDir + '/../../test-data/' + filename;
- this._uploadFile( filepath );
+ this.tools._uploadFile( filepath );
// when an upload begins successfully...
// 1. main should reload with a donemessagelarge
@@ -90,7 +68,7 @@
this.test.assert( doneElementInfo !== null,
"Found donemessagelarge after uploading file" );
- uploadInfo = this.parseDoneMessageForTool( doneElementInfo.text );
+ uploadInfo = this.tools._parseDoneMessageForTool( doneElementInfo.text );
this.test.assert( uploadInfo.hid >= 0,
'Found sensible hid from upload donemessagelarge: ' + uploadInfo.hid );
this.test.assert( uploadInfo.name === filename,
@@ -99,12 +77,12 @@
});
-// wait for upload to finish
+// move to the history panel and wait for upload to finish
spaceghost.then( function(){
var hdaInfo = null;
this.withFrame( 'galaxy_history', function(){
- hdaInfo = this.hdaElementInfoByTitle( uploadInfo.name, uploadInfo.hid );
+ hdaInfo = this.historypanel.hdaElementInfoByTitle( uploadInfo.name, uploadInfo.hid );
this.debug( 'hda:\n' + this.jsonStr( hdaInfo ) );
});
@@ -113,7 +91,7 @@
//precondition: needs class
var hdaStateClass = hdaInfo.attributes[ 'class' ].match( /historyItem\-(\w+)/ )[0];
if( hdaStateClass !== 'historyItem-ok' ){
- this.waitForHdaState( '#' + hdaInfo.attributes.id, 'ok',
+ this.historypanel.waitForHdaState( '#' + hdaInfo.attributes.id, 'ok',
function whenInStateFn(){
this.test.assert( true, 'Upload completed successfully for: ' + uploadInfo.name );
@@ -126,6 +104,34 @@
});
});
+spaceghost.then( function(){
+ this.test.comment( 'testing convenience function' );
+ spaceghost.tools.uploadFile( '../../test-data/1.sam', function( uploadInfo ){
+ this.test.assert( uploadInfo.hdaElement !== null, "Convenience function produced hda in ok state" );
+ });
+});
+
+/*
+//??: this error's AND waitFor()s THREE times - something to do with assertStepsRaise + waitFor
+spaceghost.then( function(){
+ this.test.comment( 'testing convenience function timeout error' );
+ this.assertStepsRaise( 'GalaxyError: Upload Error: timeout waiting', function(){
+ spaceghost.then( function(){
+ spaceghost.tools.uploadFile( '../../test-data/1.sam', function( uploadInfo ){
+ this.test.fail( "Convenience function did not timeout!" );
+ }, 250 );
+ });
+ });
+});
+
+// this correctly errors
+spaceghost.then( function(){
+ spaceghost.tools.uploadFile( '../../test-data/1.sam', function( uploadInfo ){
+ this.test.fail( "Convenience function did not timeout!" );
+ }, 250 );
+});
+*/
+
// ===================================================================
spaceghost.run( function(){
this.test.done();
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d5896e8a60fa/
changeset: d5896e8a60fa
branch: stable
user: inithello
date: 2013-02-19 18:29:29
summary: Fix for installing a repository that only contains a workflow, then importing that workflow to Galaxy.
affected #: 1 file
diff -r 8da37d3985ab9c489760e64d4e3eb707dfbeb4b8 -r d5896e8a60fa948f1713d4b5e30126a12a958679 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -740,8 +740,8 @@
repository = suc.get_tool_shed_repository_by_id( trans, repository_id )
changeset_revision = repository.changeset_revision
metadata = repository.metadata
- workflows = metadata[ 'workflows' ]
- tools_metadata = metadata[ 'tools' ]
+ workflows = metadata.get( 'workflows', [] )
+ tools_metadata = metadata.get( 'tools', [] )
workflow_dict = None
for workflow_data_tuple in workflows:
# The value of workflow_data_tuple is ( relative_path_to_workflow_file, exported_workflow_dict ).
https://bitbucket.org/galaxy/galaxy-central/commits/e45b9ade65b1/
changeset: e45b9ade65b1
user: inithello
date: 2013-02-19 18:29:29
summary: Fix for installing a repository that only contains a workflow, then importing that workflow to Galaxy.
affected #: 1 file
diff -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee -r e45b9ade65b1a27ded8d55a3003b153035551148 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -745,8 +745,8 @@
repository = suc.get_tool_shed_repository_by_id( trans, repository_id )
changeset_revision = repository.changeset_revision
metadata = repository.metadata
- workflows = metadata[ 'workflows' ]
- tools_metadata = metadata[ 'tools' ]
+ workflows = metadata.get( 'workflows', [] )
+ tools_metadata = metadata.get( 'tools', [] )
workflow_dict = None
for workflow_data_tuple in workflows:
# The value of workflow_data_tuple is ( relative_path_to_workflow_file, exported_workflow_dict ).
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/445b212b1c6d/
changeset: 445b212b1c6d
user: natefoo
date: 2013-02-19 17:30:29
summary: Fix the manage jobs admin interface broken by the removal of the manager. This necessitated removing the job lock feature, although it should return in a future release when we have handler communication outside the database.
affected #: 4 files
diff -r 9852dd712f5c628d1f635fe643f036eb2b930863 -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -1690,7 +1690,7 @@
"""
Implements the JobQueue / JobStopQueue interface but does nothing
"""
- def put( self, *args ):
+ def put( self, *args, **kwargs ):
return
def put_stop( self, *args ):
return
diff -r 9852dd712f5c628d1f635fe643f036eb2b930863 -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -493,7 +493,7 @@
.filter( ( model.Job.state == model.Job.states.DELETED_NEW ) \
& ( model.Job.handler == self.app.config.server_name ) ).all()
for job in newly_deleted_jobs:
- jobs_to_check.append( ( job, None ) )
+ jobs_to_check.append( ( job, job.stderr ) )
# Also pull from the queue (in the case of Administrative stopped jobs)
try:
while 1:
diff -r 9852dd712f5c628d1f635fe643f036eb2b930863 -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -1016,8 +1016,6 @@
deleted = []
msg = None
status = None
- if self.app.config.job_manager != self.app.config.server_name:
- return trans.show_error_message( 'This Galaxy instance (%s) is not the job manager (%s). If using multiple servers, please directly access the job manager instance to manage jobs.' % (self.app.config.server_name, self.app.config.job_manager) )
job_ids = util.listify( stop )
if job_ids and stop_msg in [ None, '' ]:
msg = 'Please enter an error message to display to the user describing why the job was terminated'
@@ -1026,7 +1024,15 @@
if stop_msg[-1] not in PUNCTUATION:
stop_msg += '.'
for job_id in job_ids:
- trans.app.job_manager.job_stop_queue.put( job_id, error_msg="This job was stopped by an administrator: %s For more information or help" % stop_msg )
+ error_msg = "This job was stopped by an administrator: %s <a href='%s' target='_blank'>Contact support</a> for additional help." \
+ % ( stop_msg, self.app.config.get("support_url", "http://wiki.galaxyproject.org/Support" ) )
+ if trans.app.config.track_jobs_in_database:
+ job = trans.app.model.Job.get( job_id )
+ job.stderr = error_msg
+ job.state = trans.app.model.Job.states.DELETED_NEW
+ trans.sa_session.add( job )
+ else:
+ trans.app.job_manager.job_stop_queue.put( job_id, error_msg=error_msg )
deleted.append( str( job_id ) )
if deleted:
msg = 'Queued job'
@@ -1035,11 +1041,7 @@
msg += ' for deletion: '
msg += ', '.join( deleted )
status = 'done'
- if ajl_submit:
- if job_lock == 'on':
- trans.app.job_manager.job_queue.job_lock = True
- else:
- trans.app.job_manager.job_queue.job_lock = False
+ trans.sa_session.flush()
cutoff_time = datetime.utcnow() - timedelta( seconds=int( cutoff ) )
jobs = trans.sa_session.query( trans.app.model.Job ) \
.filter( and_( trans.app.model.Job.table.c.update_time < cutoff_time,
@@ -1060,8 +1062,7 @@
last_updated = last_updated,
cutoff = cutoff,
msg = msg,
- status = status,
- job_lock = trans.app.job_manager.job_queue.job_lock )
+ status = status )
## ---- Utility methods -------------------------------------------------------
diff -r 9852dd712f5c628d1f635fe643f036eb2b930863 -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee templates/admin/jobs.mako
--- a/templates/admin/jobs.mako
+++ b/templates/admin/jobs.mako
@@ -46,6 +46,7 @@
<td>Last Update</td><td>Tool</td><td>State</td>
+ <td>Inputs</td><td>Command Line</td><td>Job Runner</td><td>PID/Cluster ID</td>
@@ -67,6 +68,13 @@
<td>${last_updated[job.id]} ago</td><td>${job.tool_id}</td><td>${job.state}</td>
+ <%
+ try:
+ inputs = ", ".join( [ '%s %s' % ( da.dataset.id, da.dataset.state ) for da in job.input_datasets ] )
+ except:
+ inputs = 'Unable to determine inputs'
+ %>
+ <td>${inputs}</td><td>${job.command_line}</td><td>${job.job_runner_name}</td><td>${job.job_runner_external_id}</td>
@@ -125,32 +133,3 @@
</div></div></form>
-<form name="jobs" action="${h.url_for(controller='admin', action='jobs')}" method="POST">
- <p/>
- <div class="toolForm">
- <div class="toolFormTitle">
- Administrative Job Lock
- </div>
- <div class="toolFormBody">
- <div class="form-row">
- <input type="hidden" name="ajl_submit" value="True"/>
- %if job_lock==True:
- <p>Job dispatching is currently <strong>locked</strong>.</p>
- <label>
- <input type='checkbox' name='job_lock' checked='checked' />
- Prevent jobs from dispatching.
- </label>
- %else:
- <p>Job dispatching is currently <strong>unlocked</strong>.</p>
- <label>
- <input type='checkbox' name='job_lock' />
- Prevent jobs from dispatching.
- </label>
- %endif
- </div>
- <div class="form-row">
- <input type="submit" class="primary-button" name="submit" value="Update">
- </div>
- </div>
- </div>
-</form>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Trackster: prevent data requests for very small regions by using a (configurable) minimum region size. This improves performance when zoomed in on small regions. Pack scripts.
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9852dd712f5c/
changeset: 9852dd712f5c
user: jgoecks
date: 2013-02-19 16:16:21
summary: Trackster: prevent data requests for very small regions by using a (configurable) minimum region size. This improves performance when zoomed in on small regions. Pack scripts.
affected #: 4 files
diff -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 -r 9852dd712f5c628d1f635fe643f036eb2b930863 static/scripts/packed/viz/trackster/tracks.js
--- a/static/scripts/packed/viz/trackster/tracks.js
+++ b/static/scripts/packed/viz/trackster/tracks.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","mvc/data","viz/trackster/filters"],function(ab,x,l,u,L,Y,i){var q=ab.extend;var V=function(ac){return("isResolved" in ac)};var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();if(ap.offsetY<aq){$(this).insertBefore(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var aa=16,G=9,D=20,A=100,I=12000,S=400,K=5000,w=100,o="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",v="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20;function W(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.name=af.name;this.view=ad;this.container=ac;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.content_visible=true;this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var af=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(){ad.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(ag){if((ag.keyCode||ag.which)===27){af()}else{if((ag.keyCode||ag.which)===13){ac()}}};$(window).bind("keypress.check_enter_esc",ae);show_modal("Configure",ad.config.build_form(),{Cancel:af,OK:ac})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.remove()}}];q(r.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(){},to_dict:function(){},set_name:function(ac){this.old_name=this.name;this.name=ac;this.name_div.text(this.name)},revert_name:function(){if(this.old_name){this.name=this.old_name;this.name_div.text(this.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("href","javascript:void(0);").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(z.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw()}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,z.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw(true)}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof c){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ag=[];for(var ad=0;ad<this.drawables.length;ad++){ag.push(this.drawables[ad].name)}var ae="Composite Track of "+this.drawables.length+" tracks ("+ag.join(", ")+")";var af=new f(this.view,this.view,{name:ae,drawables:this.drawables});var ac=this.container.replace_drawable(this,af,true);af.request_draw()},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){z.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac,ae){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].request_draw(ac,ae)}}});var Z=Backbone.View.extend({initialize:function(ac){q(ac,{obj_type:"View"});z.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new x.CanvasManager(this.container.get(0).ownerDocument);this.reset()},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){x.select_datasets(select_datasets_url,add_track_async_url,{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("href","javascript:void(0);").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_drawables(),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new X(this,{content_div:this.top_labeltrack}));this.add_label_track(new X(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")}});q(Z.prototype,z.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=w;var ac=this,ad=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new B(ac))}ac.chrom_data=ag.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,af=ac.chrom_data.length;ai<af;ai++){var ah=ac.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(ag.prev_chroms){aj+='<option value="previous">Previous '+w+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+w+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-w});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+w});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();ae.request_redraw(true);for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad!==undefined&&aj!==undefined){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/ |,/g,"");var ak=this,ac,af,ad=ag.split(":"),ai=ad[0],aj=ad[1];if(aj!==undefined){try{var ah=aj.split("-");ac=parseInt(ah[0],10);af=parseInt(ah[1],10)}catch(ae){return false}}ak.change_chrom(ai,ac,af)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw();var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){z.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ak,ac,aj,al){var ai=this,ah=(al?[al]:ai.drawables),ae;var ad;for(var ag=0;ag<ah.length;ag++){ad=ah[ag];ae=-1;for(var af=0;af<ai.tracks_to_be_redrawn.length;af++){if(ai.tracks_to_be_redrawn[af][0]===ad){ae=af;break}}if(ae<0){ai.tracks_to_be_redrawn.push([ad,ac,aj])}else{ai.tracks_to_be_redrawn[ag][1]=ac;ai.tracks_to_be_redrawn[ag][2]=aj}}if(!this.requested_redraw){requestAnimationFrame(function(){ai._redraw(ak)});this.requested_redraw=true}},_redraw:function(am){this.requested_redraw=false;var aj=this.low,af=this.high;if(aj<this.max_low){aj=this.max_low}if(af>this.max_high){af=this.max_high}var al=this.high-this.low;if(this.high!==0&&al<this.min_separation){af=aj+this.min_separation}this.low=Math.floor(aj);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ac=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ai=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var an=13;this.overview_box.css({left:ac,width:Math.max(an,ai)}).show();if(ai<an){this.overview_box.css("left",ac-(an-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ac,width:ai})}if(!am){var ae,ad,ak;for(var ag=0,ah=this.tracks_to_be_redrawn.length;ag<ah;ag++){ae=this.tracks_to_be_redrawn[ag][0];ad=this.tracks_to_be_redrawn[ag][1];ak=this.tracks_to_be_redrawn[ag][2];if(ae){ae._draw(ad,ak)}}this.tracks_to_be_redrawn=[];for(ag=0,ah=this.label_tracks.length;ag<ah;ag++){this.label_tracks[ag]._draw()}}},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ae.dataset_id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=function(ae,aj,af){this.track=ae;this.name=aj.name;this.params=[];var aq=aj.params;for(var ag=0;ag<aq.length;ag++){var al=aq[ag],ad=al.name,ap=al.label,ah=unescape(al.html),ar=al.value,an=al.type;if(an==="number"){this.params.push(new e(ad,ap,ah,(ad in af?af[ad]:ar),al.min,al.max))}else{if(an==="select"){this.params.push(new N(ad,ap,ah,(ad in af?af[ad]:ar)))}else{console.log("WARNING: unrecognized tool parameter type:",ad,an)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(au){au.stopPropagation()}).click(function(au){au.stopPropagation()}).bind("dblclick",function(au){au.stopPropagation()});var ao=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var am=this.params;var ak=this;$.each(this.params,function(av,ay){var ax=$("<div>").addClass("param-row").appendTo(ak.parent_div);var au=$("<div>").addClass("param-label").text(ay.label).appendTo(ax);var aw=$("<div/>").addClass("param-input").html(ay.html).appendTo(ax);aw.find(":input").val(ay.value);$("<div style='clear: both;'/>").appendTo(ax)});this.parent_div.find("input").click(function(){$(this).select()});var at=$("<div>").addClass("param-row").appendTo(this.parent_div);var ai=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(at);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(at);ac.click(function(){ak.run_on_region()});ai.click(function(){ak.run_on_dataset()});if("visible" in af&&af.visible){this.parent_div.show()}};q(s.prototype,{update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},state_dict:function(){var ad={};for(var ac=0;ac<this.params.length;ac++){ad[this.params[ac].name]=this.params[ac].value}ad.visible=this.parent_div.is(":visible");return ad},get_param_values_dict:function(){var ac={};this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();ac[ad]=ae});return ac},get_param_values:function(){var ac=[];this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();if(ad){ac[ac.length]=ae}});return ac},run_on_dataset:function(){var ac=this;ac.run({target_dataset_id:this.track.original_dataset_id,tool_id:ac.name},null,function(ad){show_modal(ac.name+" is Running",ac.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ai=new x.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new P(view,view,{name:this.name});var af=ah.container.replace_drawable(ah,ag,false);ag.container_div.insertBefore(ah.view.content_div.children()[af]);ag.add_drawable(ah);ah.container_div.appendTo(ag.content_div);ac=ag}else{ac=ah.container}var aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new Y.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(y+ag.message)}else{af(ag)}}})}});var N=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};q(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){N.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};q(e.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};C.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ac){this.track=ac.track;this.params=ac.params;this.values={};this.restore_values((ac.saved_values?ac.saved_values:{}));this.onchange=ac.onchange};q(F.prototype,{restore_values:function(ac){var ad=this;$.each(this.params,function(ae,af){if(ac[af.key]!==undefined){ad.values[af.key]=ac[af.key]}else{ad.values[af.key]=af.default_value}})},build_form:function(){var af=this;var ac=$("<div />");var ae;function ad(ak,ag){for(var ao=0;ao<ak.length;ao++){ae=ak[ao];if(ae.hidden){continue}var ai="param_"+ao;var at=af.values[ae.key];var av=$("<div class='form-row' />").appendTo(ag);av.append($("<label />").attr("for",ai).text(ae.label+":"));if(ae.type==="bool"){av.append($('<input type="checkbox" />').attr("id",ai).attr("name",ai).attr("checked",at))}else{if(ae.type==="text"){av.append($('<input type="text"/>').attr("id",ai).val(at).click(function(){$(this).select()}))}else{if(ae.type==="select"){var aq=$("<select />").attr("id",ai);for(var am=0;am<ae.options.length;am++){$("<option/>").text(ae.options[am].label).attr("value",ae.options[am].value).appendTo(aq)}aq.val(at);av.append(aq)}else{if(ae.type==="color"){var au=$("<div/>").appendTo(av),ap=$("<input />").attr("id",ai).attr("name",ai).val(at).css("float","left").appendTo(au).click(function(ax){$(".bs-tooltip").removeClass("in");var aw=$(this).siblings(".bs-tooltip").addClass("in");aw.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(aw).height()/2)+($(this).height()/2)}).show();aw.click(function(ay){ay.stopPropagation()});$(document).bind("click.color-picker",function(){aw.hide();$(document).unbind("click.color-picker")});ax.stopPropagation()}),an=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(au).attr("title","Set new random color").tooltip(),ar=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(au).hide(),aj=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ar),ah=$("<div class='tooltip-arrow'></div>").appendTo(ar),al=$.farbtastic(aj,{width:100,height:100,callback:ap,color:at});au.append($("<div/>").css("clear","both"));(function(aw){an.click(function(){aw.setColor(l.get_random_color())})})(al)}else{av.append($("<input />").attr("id",ai).attr("name",ai).val(at))}}}}if(ae.help){av.append($("<div class='help'/>").text(ae.help))}}}ad(this.params,ac);return ac},update_from_form:function(ac){var ae=this;var ad=false;$.each(this.params,function(af,ah){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="float"){ag=parseFloat(ag)}else{if(ah.type==="int"){ag=parseInt(ag)}else{if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}}}if(ag!==ae.values[ah.key]){ae.values[ah.key]=ag;ad=true}}});if(ad){this.onchange();this.track.changed()}}});var b=function(ac,ag,ae,ad,af){this.track=ac;this.region=ag;this.low=ag.get("start");this.high=ag.get("end");this.resolution=ae;this.html_elt=$("<div class='track-tile'/>").append(ad).height($(ad).attr("height"));this.data=af;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(ac,ah,ae,ad,af,ag){b.call(this,ac,ah,ae,ad,af);this.max_val=ag};q(j.prototype,b.prototype);var O=function(af,an,ag,ae,ai,ap,aj,aq,ad,am){b.call(this,af,an,ag,ae,ai);this.mode=aj;this.all_slotted=ad;this.feature_mapper=am;this.has_icons=false;if(aq){this.has_icons=true;var ak=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ae.width}).prependTo(this.html_elt);var al=new x.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),ao=ai.length,ah=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ah.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()});ac.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()})}};q(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ak=at[0],ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}var af=$("<div/>").attr("id",ak).addClass("feature-popup"),au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?W(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"))-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"))+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=new Y.Dataset({id:ae.dataset_id,hda_ldda:ae.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new x.GenomeDataManager({dataset:this.dataset,data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=0;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.dynamic_tool_div.toggle();if(ac.dynamic_tool_div.is(":visible")){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new x.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new x.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ac.dataset_id,hda_ldda:ac.hda_ldda,regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ae,{No:ah,Yes:ad})}},r.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&r.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},on_resize:function(){},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.values.height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.values.mode?this.config.values.mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof X){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof R){return"VcfTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset_id){return}var ac=$.Deferred(),af={hda_ldda:ad.hda_ldda,data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(v);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when(ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in af&&af.tool?new s(this,af.tool,af.tool_state):null);this.tile_cache=new x.Cache(Q);if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};q(M.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw(true)},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;ac.tile_cache.clear();ac.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ad,ac){this.view.request_redraw(false,ad,ac,this)},before_draw:function(){},_draw:function(ad,ao){if(!this.can_draw()){return}var al=this.view.low,ah=this.view.high,aj=ah-al,ae=this.view.container.width(),aq=this.view.resolution_px_b,ag=this.view.resolution_b_px;if(this.is_overview){al=this.view.max_low;ah=this.view.max_high;ag=(view.max_high-view.max_low)/ae;aq=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(ag*S)),ak=true,ap=[],ai=function(ar){return(ar&&"track" in ar)};while((ac*S*ag)<ah){var am=this._get_tile_bounds(ac,ag),an=this.draw_helper(ad,am,ag,this.tiles_div,aq);if(ai(an)){ap.push(an)}else{ak=false}ac+=1}if(!ao){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;if(ak){this.tiles_div.children(".remove").remove();af.postdraw_actions(ap,ae,aq,ao)}},postdraw_actions:function(ad,ae,ag,ac){var af=ab.find(ad,function(ah){return ah.has_icons});if(af){ab.each(ad,function(ah){if(!ah.has_icons){ah.html_elt.css("padding-top",D)}})}},draw_helper:function(ac,af,ar,ah,ai,ao){var an=this,aw=this._gen_tile_cache_key(ai,af);if(!ao){ao={}}var av=(ac?undefined:an.tile_cache.get_elt(aw));if(av){an.show_tile(av,ah,ai);return av}var al=true;var at=an.data_manager.get_data(af,an.mode,ar,an.data_url_extra_params);if(V(at)){al=false}var aj;if(view.reference_track&&ai>view.canvas_manager.char_width_px){aj=view.reference_track.data_manager.get_data(af,an.mode,ar,view.reference_track.data_url_extra_params);if(V(aj)){al=false}}if(al){q(at,ao.more_tile_data);var ak=an.mode;if(ak==="Auto"){ak=an.get_mode(at);an.update_auto_mode(ak)}var ae=an.view.canvas_manager.new_canvas(),au=af.get("start"),ad=af.get("end"),ap=Math.ceil((ad-au)*ai)+an.left_offset,am=an.get_canvas_height(at,ak,ai,ap);ae.width=ap;ae.height=am;var aq=ae.getContext("2d");aq.translate(this.left_offset,0);var av=an.draw_tile(at,aq,ak,ar,af,ai,aj);if(av!==undefined){an.tile_cache.set_elt(aw,av);an.show_tile(av,ah,ai)}return av}var ag=$.Deferred();$.when(at,aj).then(function(){view.request_redraw(false,false,false,an);ag.resolve()});return ag},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah,ai){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{ah.append(ac)}ae.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ae.html_elt.height());ae.html_elt.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*S*ad),ag=Math.ceil(S*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new x.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){return true},can_subset:function(ac){return false},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ae,af,ah,ac){var ad=this;ad.normal_postdraw_actions(ae,af,ah,ac);ad.dataset_check_type="converted_datasets_state";ad.data_query_wait=K;var ag=new l.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset_id,hda_ldda:ad.hda_ldda},interval:ad.data_query_wait,success_fn:function(ai){return ai!=="pending"}});$.when(ag.go()).then(function(){ad.data_manager.set("data_type","data")});ad.postdraw_actions=ad.normal_postdraw_actions}}});var X=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(X.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ae=this.view,af=ae.high-ae.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/ai)*ai,ag=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ah=(ac-ae.low)/af*ag;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ah-1}));ac+=ai}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){M.call(this,ad,ac,ag);this.drawables=[];this.left_offset=0;if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ac){M.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,draw_helper:function(ad,ah,av,aj,al,at){var aq=this,aB=this._gen_tile_cache_key(al,ah);if(!at){at={}}var aA=(ad?undefined:aq.tile_cache.get_elt(aB));if(aA){aq.show_tile(aA,aj,al);return aA}var ak=[],aq,ao=true,aw,am;for(var ax=0;ax<this.drawables.length;ax++){aq=this.drawables[ax];aw=aq.data_manager.get_data(ah,aq.mode,av,aq.data_url_extra_params);if(V(aw)){ao=false}ak.push(aw);am=null;if(view.reference_track&&al>view.canvas_manager.char_width_px){am=view.reference_track.data_manager.get_data(ah,aq.mode,av,view.reference_track.data_url_extra_params);if(V(am)){ao=false}}ak.push(am)}if(ao){q(aw,at.more_tile_data);this.tile_predraw_init();var ag=aq.view.canvas_manager.new_canvas(),ay=ah.get("start"),ae=ah.get("end"),az=0,ar=Math.ceil((ae-ay)*al)+this.left_offset,ap=0,af=[],ax;var ac=0;for(ax=0;ax<this.drawables.length;ax++,az+=2){aq=this.drawables[ax];aw=ak[az];var an=aq.mode;if(an==="Auto"){an=aq.get_mode(aw);aq.update_auto_mode(an)}af.push(an);ac=aq.get_canvas_height(aw,an,al,ar);if(ac>ap){ap=ac}}ag.width=ar;ag.height=(at.height?at.height:ap);az=0;var au=ag.getContext("2d");au.translate(this.left_offset,0);au.globalAlpha=0.5;au.globalCompositeOperation="source-over";for(ax=0;ax<this.drawables.length;ax++,az+=2){aq=this.drawables[ax];aw=ak[az];am=ak[az+1];aA=aq.draw_tile(aw,au,af[ax],av,ah,al,am)}this.tile_cache.set_elt(aB,aA);this.show_tile(aA,aj,al);return aA}var ai=$.Deferred(),aq=this;$.when.apply($,ak).then(function(){view.request_redraw(false,false,false,aq);ai.resolve()});return ai},show_group:function(){var af=new P(this.view,this.container,{name:this.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw()},tile_predraw_init:function(){var af=Number.MAX_VALUE,ac=-af,ad;for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];if(ad instanceof h){if(ad.prefs.min_value<af){af=ad.prefs.min_value}if(ad.prefs.max_value>ac){ac=ad.prefs.max_value}}}for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];ad.prefs.min_value=af;ad.prefs.max_value=ac}},postdraw_actions:function(ae,ah,aj,ad){M.prototype.postdraw_actions.call(this,ae,ah,aj,ad);var ag=-1;for(var af=0;af<ae.length;af++){var ac=ae[af].html_elt.find("canvas").height();if(ac>ag){ag=ac}}for(var af=0;af<ae.length;af++){var ai=ae[af];if(ai.html_elt.find("canvas").height()!==ag){this.draw_helper(true,ai.index,ai.resolution,ai.html_elt.parent(),aj,{height:ag});ai.html_elt.remove()}}}});var B=function(ac){M.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});ac.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new x.ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};q(B.prototype,r.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:r.prototype.can_draw,draw_helper:function(ae,af,ac,ag,ah,ad){if(ah>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ae,af,ac,ag,ah,ad)}else{this.hide_contents();return null}},draw_tile:function(ak,al,ag,af,ai,am){var ae=this;if(am>this.view.canvas_manager.char_width_px){if(ak.data===null){this.hide_contents();return}var ad=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";ak=ak.data;for(var ah=0,aj=ak.length;ah<aj;ah++){var ac=Math.floor(ah*am);al.fillText(ak[ah],ac,10)}this.show_contents();return new b(ae,ai,af,ad,ak)}this.hide_contents()}});var h=function(ae,ad,af){var ac=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:l.get_random_color()},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(h.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ac=this;ac.vertical_range=undefined;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.hda_ldda},function(ad){ac.container_div.addClass("line-track");var ag=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=ag.min,ai=ag.max;ae=Math.floor(Math.min(0,Math.max(ae,ag.mean-2*ag.sd)));ai=Math.ceil(Math.max(0,Math.min(ai,ag.mean+2*ag.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ai;$("#track_"+ac.dataset_id+"_minval").val(ac.prefs.min_value);$("#track_"+ac.dataset_id+"_maxval").val(ac.prefs.max_value)}ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.total_frequency=ag.total_frequency;ac.container_div.find(".yaxislabel").remove();var ah=$("<div/>").text(W(ac.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_min_value(aj)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ac.dataset_id+"_minval").prependTo(ac.container_div),af=$("<div/>").text(W(ac.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_max_value(aj)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ac.dataset_id+"_maxval").prependTo(ac.container_div)})},draw_tile:function(al,aj,ae,ad,ag,ak){var ac=aj.canvas,af=ag.get("start"),ai=ag.get("end"),ah=new L.LinePainter(al.data,af,ai,this.prefs,ae);ah.draw(aj,ac.width,ac.height,ak);return new b(this,ag,ad,ac,al.data)},can_subset:function(ac){return false}});var t=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(t.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;this.tile_cache.clear();this.request_draw()},draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,af,ae,ah);var ag=l.get_random_color(),ac=l.get_random_color([ag,"#FFFFFF"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.tile_cache.clear();ad.set_painter_from_config();ad.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=ah.dataset_id;this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(c.prototype,r.prototype,M.prototype,{set_dataset:function(ac){this.dataset_id=ac.get("id");this.hda_ldda=ac.get("hda_ldda");this.dataset=ac;this.data_manager.set("dataset",ac)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ar,am,ah,ag){M.prototype.postdraw_actions.call(this,ar,ag);var al=this,ao;if(al.mode==="Coverage"){var ad=-1;for(ao=0;ao<ar.length;ao++){var an=ar[ao].max_val;if(an>ad){ad=an}}for(ao=0;ao<ar.length;ao++){var au=ar[ao];if(au.max_val!==ad){au.html_elt.remove();al.draw_helper(true,au.index,au.resolution,au.html_elt.parent(),ah,{more_tile_data:{max:ad}})}}}if(al.filters_manager){var ai=al.filters_manager.filters;for(var aq=0;aq<ai.length;aq++){ai[aq].update_ui_elt()}var at=false,ac,aj;for(ao=0;ao<ar.length;ao++){if(ar[ao].data.length){ac=ar[ao].data[0];for(var aq=0;aq<ai.length;aq++){aj=ai[aq];if(aj.applies_to(ac)&&aj.min!==aj.max){at=true;break}}}}if(al.filters_available!==at){al.filters_available=at;if(!al.filters_available){al.filters_manager.hide()}al.update_icons()}}this.container_div.find(".yaxislabel").remove();var af=ar[0];if(af instanceof j){var ak=(this.prefs.histogram_max?this.prefs.histogram_max:af.max_val),ae=$("<div/>").text(ak).make_text_editable({num_cols:12,on_finish:function(av){$(".bs-tooltip").remove();var av=parseFloat(av);al.prefs.histogram_max=(!isNaN(av)?av:null);al.tile_cache.clear();al.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ae)}if(af instanceof O){var ap=true;for(ao=0;ao<ar.length;ao++){if(!ar[ao].all_slotted){ap=false;break}}if(!ap){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){var ac;if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}else{if(ac==="summary_tree"){ac="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,A,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="summary_tree"||ag==="Coverage"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(aa,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,ar,af,aj,ae){var ap=this,ad=aq.canvas,ay=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(ao==="summary_tree"||ao==="Coverage"){var aA=new L.SummaryTreePainter(am,ay,ac,this.prefs);aA.draw(aq,ad.width,ad.height,aj);return new j(ap,af,ar,ad,am.data,am.max)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var at=0,av=am.data.length;at<av;at++){var ah=am.data[at];var au=false;var al;for(var ax=0,aC=ak.length;ax<aC;ax++){al=ak[ax];al.update_attrs(ah);if(!al.keep(ah)){au=true;break}}if(!au){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aB=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae);var aw=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){aw=aA.draw(aq,ad.width,ad.height,aj,an);aw.translation=-ag}return new O(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="summary_tree"}else{if(ac.extra_info==="no_detail"||ac.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="summary_tree"||ac.message||ac.extra_info==="no_detail"){return false}return true}});var R=function(ad,ac,ae){c.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:l.get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};q(R.prototype,r.prototype,M.prototype,c.prototype);var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=l.get_random_color(),ac=l.get_random_color([af,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block and sense strand color",type:"color",default_value:af},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};q(T.prototype,r.prototype,M.prototype,c.prototype);var d={LineTrack:h,FeatureTrack:c,VcfTrack:R,ReadTrack:T,DiagonalHeatmapTrack:t,CompositeTrack:f,DrawableGroup:P};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new d[af](ad,ac,ae)}};return{TracksterView:Z,DrawableGroup:P,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:t,ReadTrack:T,VcfTrack:R,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","mvc/data","viz/trackster/filters"],function(ab,x,l,u,L,Y,i){var q=ab.extend;var V=function(ac){return("isResolved" in ac)};var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();if(ap.offsetY<aq){$(this).insertBefore(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var aa=16,G=9,D=20,A=100,I=12000,S=400,K=5000,w=100,o="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",v="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20;function W(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.name=af.name;this.view=ad;this.container=ac;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.content_visible=true;this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var af=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(){ad.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(ag){if((ag.keyCode||ag.which)===27){af()}else{if((ag.keyCode||ag.which)===13){ac()}}};$(window).bind("keypress.check_enter_esc",ae);show_modal("Configure",ad.config.build_form(),{Cancel:af,OK:ac})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.remove()}}];q(r.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(){},to_dict:function(){},set_name:function(ac){this.old_name=this.name;this.name=ac;this.name_div.text(this.name)},revert_name:function(){if(this.old_name){this.name=this.old_name;this.name_div.text(this.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("href","javascript:void(0);").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(z.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw()}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,z.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw(true)}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof c){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ag=[];for(var ad=0;ad<this.drawables.length;ad++){ag.push(this.drawables[ad].name)}var ae="Composite Track of "+this.drawables.length+" tracks ("+ag.join(", ")+")";var af=new f(this.view,this.view,{name:ae,drawables:this.drawables});var ac=this.container.replace_drawable(this,af,true);af.request_draw()},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){z.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac,ae){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].request_draw(ac,ae)}}});var Z=Backbone.View.extend({initialize:function(ac){q(ac,{obj_type:"View"});z.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new x.CanvasManager(this.container.get(0).ownerDocument);this.reset()},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){x.select_datasets(select_datasets_url,add_track_async_url,{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("href","javascript:void(0);").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_drawables(),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new X(this,{content_div:this.top_labeltrack}));this.add_label_track(new X(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")}});q(Z.prototype,z.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=w;var ac=this,ad=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new B(ac))}ac.chrom_data=ag.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,af=ac.chrom_data.length;ai<af;ai++){var ah=ac.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(ag.prev_chroms){aj+='<option value="previous">Previous '+w+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+w+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-w});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+w});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();ae.request_redraw(true);for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad!==undefined&&aj!==undefined){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/ |,/g,"");var ak=this,ac,af,ad=ag.split(":"),ai=ad[0],aj=ad[1];if(aj!==undefined){try{var ah=aj.split("-");ac=parseInt(ah[0],10);af=parseInt(ah[1],10)}catch(ae){return false}}ak.change_chrom(ai,ac,af)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw();var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){z.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ak,ac,aj,al){var ai=this,ah=(al?[al]:ai.drawables),ae;var ad;for(var ag=0;ag<ah.length;ag++){ad=ah[ag];ae=-1;for(var af=0;af<ai.tracks_to_be_redrawn.length;af++){if(ai.tracks_to_be_redrawn[af][0]===ad){ae=af;break}}if(ae<0){ai.tracks_to_be_redrawn.push([ad,ac,aj])}else{ai.tracks_to_be_redrawn[ag][1]=ac;ai.tracks_to_be_redrawn[ag][2]=aj}}if(!this.requested_redraw){requestAnimationFrame(function(){ai._redraw(ak)});this.requested_redraw=true}},_redraw:function(am){this.requested_redraw=false;var aj=this.low,af=this.high;if(aj<this.max_low){aj=this.max_low}if(af>this.max_high){af=this.max_high}var al=this.high-this.low;if(this.high!==0&&al<this.min_separation){af=aj+this.min_separation}this.low=Math.floor(aj);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=1/this.resolution_b_px;var ac=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ai=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var an=13;this.overview_box.css({left:ac,width:Math.max(an,ai)}).show();if(ai<an){this.overview_box.css("left",ac-(an-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ac,width:ai})}if(!am){var ae,ad,ak;for(var ag=0,ah=this.tracks_to_be_redrawn.length;ag<ah;ag++){ae=this.tracks_to_be_redrawn[ag][0];ad=this.tracks_to_be_redrawn[ag][1];ak=this.tracks_to_be_redrawn[ag][2];if(ae){ae._draw(ad,ak)}}this.tracks_to_be_redrawn=[];for(ag=0,ah=this.label_tracks.length;ag<ah;ag++){this.label_tracks[ag]._draw()}}},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ae.dataset_id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=function(ae,aj,af){this.track=ae;this.name=aj.name;this.params=[];var aq=aj.params;for(var ag=0;ag<aq.length;ag++){var al=aq[ag],ad=al.name,ap=al.label,ah=unescape(al.html),ar=al.value,an=al.type;if(an==="number"){this.params.push(new e(ad,ap,ah,(ad in af?af[ad]:ar),al.min,al.max))}else{if(an==="select"){this.params.push(new N(ad,ap,ah,(ad in af?af[ad]:ar)))}else{console.log("WARNING: unrecognized tool parameter type:",ad,an)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(au){au.stopPropagation()}).click(function(au){au.stopPropagation()}).bind("dblclick",function(au){au.stopPropagation()});var ao=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var am=this.params;var ak=this;$.each(this.params,function(av,ay){var ax=$("<div>").addClass("param-row").appendTo(ak.parent_div);var au=$("<div>").addClass("param-label").text(ay.label).appendTo(ax);var aw=$("<div/>").addClass("param-input").html(ay.html).appendTo(ax);aw.find(":input").val(ay.value);$("<div style='clear: both;'/>").appendTo(ax)});this.parent_div.find("input").click(function(){$(this).select()});var at=$("<div>").addClass("param-row").appendTo(this.parent_div);var ai=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(at);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(at);ac.click(function(){ak.run_on_region()});ai.click(function(){ak.run_on_dataset()});if("visible" in af&&af.visible){this.parent_div.show()}};q(s.prototype,{update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},state_dict:function(){var ad={};for(var ac=0;ac<this.params.length;ac++){ad[this.params[ac].name]=this.params[ac].value}ad.visible=this.parent_div.is(":visible");return ad},get_param_values_dict:function(){var ac={};this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();ac[ad]=ae});return ac},get_param_values:function(){var ac=[];this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();if(ad){ac[ac.length]=ae}});return ac},run_on_dataset:function(){var ac=this;ac.run({target_dataset_id:this.track.original_dataset_id,tool_id:ac.name},null,function(ad){show_modal(ac.name+" is Running",ac.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ai=new x.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new P(view,view,{name:this.name});var af=ah.container.replace_drawable(ah,ag,false);ag.container_div.insertBefore(ah.view.content_div.children()[af]);ag.add_drawable(ah);ah.container_div.appendTo(ag.content_div);ac=ag}else{ac=ah.container}var aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new Y.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(y+ag.message)}else{af(ag)}}})}});var N=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};q(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){N.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};q(e.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};C.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ac){this.track=ac.track;this.params=ac.params;this.values={};this.restore_values((ac.saved_values?ac.saved_values:{}));this.onchange=ac.onchange};q(F.prototype,{restore_values:function(ac){var ad=this;$.each(this.params,function(ae,af){if(ac[af.key]!==undefined){ad.values[af.key]=ac[af.key]}else{ad.values[af.key]=af.default_value}})},build_form:function(){var af=this;var ac=$("<div />");var ae;function ad(ak,ag){for(var ao=0;ao<ak.length;ao++){ae=ak[ao];if(ae.hidden){continue}var ai="param_"+ao;var at=af.values[ae.key];var av=$("<div class='form-row' />").appendTo(ag);av.append($("<label />").attr("for",ai).text(ae.label+":"));if(ae.type==="bool"){av.append($('<input type="checkbox" />').attr("id",ai).attr("name",ai).attr("checked",at))}else{if(ae.type==="text"){av.append($('<input type="text"/>').attr("id",ai).val(at).click(function(){$(this).select()}))}else{if(ae.type==="select"){var aq=$("<select />").attr("id",ai);for(var am=0;am<ae.options.length;am++){$("<option/>").text(ae.options[am].label).attr("value",ae.options[am].value).appendTo(aq)}aq.val(at);av.append(aq)}else{if(ae.type==="color"){var au=$("<div/>").appendTo(av),ap=$("<input />").attr("id",ai).attr("name",ai).val(at).css("float","left").appendTo(au).click(function(ax){$(".bs-tooltip").removeClass("in");var aw=$(this).siblings(".bs-tooltip").addClass("in");aw.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(aw).height()/2)+($(this).height()/2)}).show();aw.click(function(ay){ay.stopPropagation()});$(document).bind("click.color-picker",function(){aw.hide();$(document).unbind("click.color-picker")});ax.stopPropagation()}),an=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(au).attr("title","Set new random color").tooltip(),ar=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(au).hide(),aj=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ar),ah=$("<div class='tooltip-arrow'></div>").appendTo(ar),al=$.farbtastic(aj,{width:100,height:100,callback:ap,color:at});au.append($("<div/>").css("clear","both"));(function(aw){an.click(function(){aw.setColor(l.get_random_color())})})(al)}else{av.append($("<input />").attr("id",ai).attr("name",ai).val(at))}}}}if(ae.help){av.append($("<div class='help'/>").text(ae.help))}}}ad(this.params,ac);return ac},update_from_form:function(ac){var ae=this;var ad=false;$.each(this.params,function(af,ah){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="float"){ag=parseFloat(ag)}else{if(ah.type==="int"){ag=parseInt(ag)}else{if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}}}if(ag!==ae.values[ah.key]){ae.values[ah.key]=ag;ad=true}}});if(ad){this.onchange();this.track.changed()}}});var b=function(ac,ag,ae,ad,af){this.track=ac;this.region=ag;this.low=ag.get("start");this.high=ag.get("end");this.resolution=ae;this.html_elt=$("<div class='track-tile'/>").append(ad).height($(ad).attr("height"));this.data=af;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(ac,ah,ae,ad,af,ag){b.call(this,ac,ah,ae,ad,af);this.max_val=ag};q(j.prototype,b.prototype);var O=function(af,an,ag,ae,ai,ap,aj,aq,ad,am){b.call(this,af,an,ag,ae,ai);this.mode=aj;this.all_slotted=ad;this.feature_mapper=am;this.has_icons=false;if(aq){this.has_icons=true;var ak=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ae.width}).prependTo(this.html_elt);var al=new x.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),ao=ai.length,ah=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ah.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()});ac.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()})}};q(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ak=at[0],ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}var af=$("<div/>").attr("id",ak).addClass("feature-popup"),au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?W(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"))-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"))+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=new Y.Dataset({id:ae.dataset_id,hda_ldda:ae.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new x.GenomeDataManager({dataset:this.dataset,genome:new x.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=0;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.dynamic_tool_div.toggle();if(ac.dynamic_tool_div.is(":visible")){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new x.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new x.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ac.dataset_id,hda_ldda:ac.hda_ldda,regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ae,{No:ah,Yes:ad})}},r.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&r.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},on_resize:function(){},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.values.height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.values.mode?this.config.values.mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof X){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof R){return"VcfTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset_id){return}var ac=$.Deferred(),af={hda_ldda:ad.hda_ldda,data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(v);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when(ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in af&&af.tool?new s(this,af.tool,af.tool_state):null);this.tile_cache=new x.Cache(Q);if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};q(M.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw(true)},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;ac.tile_cache.clear();ac.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ad,ac){this.view.request_redraw(false,ad,ac,this)},before_draw:function(){},_draw:function(ad,ao){if(!this.can_draw()){return}var al=this.view.low,ah=this.view.high,aj=ah-al,ae=this.view.container.width(),aq=this.view.resolution_px_b,ag=this.view.resolution_b_px;if(this.is_overview){al=this.view.max_low;ah=this.view.max_high;ag=(view.max_high-view.max_low)/ae;aq=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(ag*S)),ak=true,ap=[],ai=function(ar){return(ar&&"track" in ar)};while((ac*S*ag)<ah){var am=this._get_tile_bounds(ac,ag),an=this.draw_helper(ad,am,ag,this.tiles_div,aq);if(ai(an)){ap.push(an)}else{ak=false}ac+=1}if(!ao){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;if(ak){this.tiles_div.children(".remove").remove();af.postdraw_actions(ap,ae,aq,ao)}},postdraw_actions:function(ad,ae,ag,ac){var af=ab.find(ad,function(ah){return ah.has_icons});if(af){ab.each(ad,function(ah){if(!ah.has_icons){ah.html_elt.css("padding-top",D)}})}},draw_helper:function(ac,af,ar,ah,ai,ao){var an=this,aw=this._gen_tile_cache_key(ai,af);if(!ao){ao={}}var av=(ac?undefined:an.tile_cache.get_elt(aw));if(av){an.show_tile(av,ah,ai);return av}var al=true;var at=an.data_manager.get_data(af,an.mode,ar,an.data_url_extra_params);if(V(at)){al=false}var aj;if(view.reference_track&&ai>view.canvas_manager.char_width_px){aj=view.reference_track.data_manager.get_data(af,an.mode,ar,view.reference_track.data_url_extra_params);if(V(aj)){al=false}}if(al){q(at,ao.more_tile_data);var ak=an.mode;if(ak==="Auto"){ak=an.get_mode(at);an.update_auto_mode(ak)}var ae=an.view.canvas_manager.new_canvas(),au=af.get("start"),ad=af.get("end"),ap=Math.ceil((ad-au)*ai)+an.left_offset,am=an.get_canvas_height(at,ak,ai,ap);ae.width=ap;ae.height=am;var aq=ae.getContext("2d");aq.translate(this.left_offset,0);var av=an.draw_tile(at,aq,ak,ar,af,ai,aj);if(av!==undefined){an.tile_cache.set_elt(aw,av);an.show_tile(av,ah,ai)}return av}var ag=$.Deferred();$.when(at,aj).then(function(){view.request_redraw(false,false,false,an);ag.resolve()});return ag},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah,ai){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{ah.append(ac)}ae.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ae.html_elt.height());ae.html_elt.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*S*ad),ag=Math.ceil(S*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new x.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){return true},can_subset:function(ac){return false},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ae,af,ah,ac){var ad=this;ad.normal_postdraw_actions(ae,af,ah,ac);ad.dataset_check_type="converted_datasets_state";ad.data_query_wait=K;var ag=new l.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset_id,hda_ldda:ad.hda_ldda},interval:ad.data_query_wait,success_fn:function(ai){return ai!=="pending"}});$.when(ag.go()).then(function(){ad.data_manager.set("data_type","data")});ad.postdraw_actions=ad.normal_postdraw_actions}}});var X=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(X.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ae=this.view,af=ae.high-ae.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/ai)*ai,ag=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ah=(ac-ae.low)/af*ag;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ah-1}));ac+=ai}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){M.call(this,ad,ac,ag);this.drawables=[];this.left_offset=0;if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ac){M.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,draw_helper:function(ad,ah,av,aj,al,at){var aq=this,aB=this._gen_tile_cache_key(al,ah);if(!at){at={}}var aA=(ad?undefined:aq.tile_cache.get_elt(aB));if(aA){aq.show_tile(aA,aj,al);return aA}var ak=[],aq,ao=true,aw,am;for(var ax=0;ax<this.drawables.length;ax++){aq=this.drawables[ax];aw=aq.data_manager.get_data(ah,aq.mode,av,aq.data_url_extra_params);if(V(aw)){ao=false}ak.push(aw);am=null;if(view.reference_track&&al>view.canvas_manager.char_width_px){am=view.reference_track.data_manager.get_data(ah,aq.mode,av,view.reference_track.data_url_extra_params);if(V(am)){ao=false}}ak.push(am)}if(ao){q(aw,at.more_tile_data);this.tile_predraw_init();var ag=aq.view.canvas_manager.new_canvas(),ay=ah.get("start"),ae=ah.get("end"),az=0,ar=Math.ceil((ae-ay)*al)+this.left_offset,ap=0,af=[],ax;var ac=0;for(ax=0;ax<this.drawables.length;ax++,az+=2){aq=this.drawables[ax];aw=ak[az];var an=aq.mode;if(an==="Auto"){an=aq.get_mode(aw);aq.update_auto_mode(an)}af.push(an);ac=aq.get_canvas_height(aw,an,al,ar);if(ac>ap){ap=ac}}ag.width=ar;ag.height=(at.height?at.height:ap);az=0;var au=ag.getContext("2d");au.translate(this.left_offset,0);au.globalAlpha=0.5;au.globalCompositeOperation="source-over";for(ax=0;ax<this.drawables.length;ax++,az+=2){aq=this.drawables[ax];aw=ak[az];am=ak[az+1];aA=aq.draw_tile(aw,au,af[ax],av,ah,al,am)}this.tile_cache.set_elt(aB,aA);this.show_tile(aA,aj,al);return aA}var ai=$.Deferred(),aq=this;$.when.apply($,ak).then(function(){view.request_redraw(false,false,false,aq);ai.resolve()});return ai},show_group:function(){var af=new P(this.view,this.container,{name:this.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw()},tile_predraw_init:function(){var af=Number.MAX_VALUE,ac=-af,ad;for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];if(ad instanceof h){if(ad.prefs.min_value<af){af=ad.prefs.min_value}if(ad.prefs.max_value>ac){ac=ad.prefs.max_value}}}for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];ad.prefs.min_value=af;ad.prefs.max_value=ac}},postdraw_actions:function(ae,ah,aj,ad){M.prototype.postdraw_actions.call(this,ae,ah,aj,ad);var ag=-1;for(var af=0;af<ae.length;af++){var ac=ae[af].html_elt.find("canvas").height();if(ac>ag){ag=ac}}for(var af=0;af<ae.length;af++){var ai=ae[af];if(ai.html_elt.find("canvas").height()!==ag){this.draw_helper(true,ai.index,ai.resolution,ai.html_elt.parent(),aj,{height:ag});ai.html_elt.remove()}}}});var B=function(ac){M.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});ac.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new x.ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};q(B.prototype,r.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:r.prototype.can_draw,draw_helper:function(ae,af,ac,ag,ah,ad){if(ah>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ae,af,ac,ag,ah,ad)}else{this.hide_contents();return null}},draw_tile:function(ak,al,ag,af,ai,am){var ae=this;if(am>this.view.canvas_manager.char_width_px){if(ak.data===null){this.hide_contents();return}var ad=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";ak=ak.data;for(var ah=0,aj=ak.length;ah<aj;ah++){var ac=Math.floor(ah*am);al.fillText(ak[ah],ac,10)}this.show_contents();return new b(ae,ai,af,ad,ak)}this.hide_contents()}});var h=function(ae,ad,af){var ac=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:l.get_random_color()},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(h.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ac=this;ac.vertical_range=undefined;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.hda_ldda},function(ad){ac.container_div.addClass("line-track");var ag=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=ag.min,ai=ag.max;ae=Math.floor(Math.min(0,Math.max(ae,ag.mean-2*ag.sd)));ai=Math.ceil(Math.max(0,Math.min(ai,ag.mean+2*ag.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ai;$("#track_"+ac.dataset_id+"_minval").val(ac.prefs.min_value);$("#track_"+ac.dataset_id+"_maxval").val(ac.prefs.max_value)}ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.total_frequency=ag.total_frequency;ac.container_div.find(".yaxislabel").remove();var ah=$("<div/>").text(W(ac.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_min_value(aj)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ac.dataset_id+"_minval").prependTo(ac.container_div),af=$("<div/>").text(W(ac.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_max_value(aj)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ac.dataset_id+"_maxval").prependTo(ac.container_div)})},draw_tile:function(al,aj,ae,ad,ag,ak){var ac=aj.canvas,af=ag.get("start"),ai=ag.get("end"),ah=new L.LinePainter(al.data,af,ai,this.prefs,ae);ah.draw(aj,ac.width,ac.height,ak);return new b(this,ag,ad,ac,al.data)},can_subset:function(ac){return false}});var t=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(t.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;this.tile_cache.clear();this.request_draw()},draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,af,ae,ah);var ag=l.get_random_color(),ac=l.get_random_color([ag,"#FFFFFF"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.tile_cache.clear();ad.set_painter_from_config();ad.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=ah.dataset_id;this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(c.prototype,r.prototype,M.prototype,{set_dataset:function(ac){this.dataset_id=ac.get("id");this.hda_ldda=ac.get("hda_ldda");this.dataset=ac;this.data_manager.set("dataset",ac)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ar,am,ah,ag){M.prototype.postdraw_actions.call(this,ar,ag);var al=this,ao;if(al.mode==="Coverage"){var ad=-1;for(ao=0;ao<ar.length;ao++){var an=ar[ao].max_val;if(an>ad){ad=an}}for(ao=0;ao<ar.length;ao++){var au=ar[ao];if(au.max_val!==ad){au.html_elt.remove();al.draw_helper(true,au.index,au.resolution,au.html_elt.parent(),ah,{more_tile_data:{max:ad}})}}}if(al.filters_manager){var ai=al.filters_manager.filters;for(var aq=0;aq<ai.length;aq++){ai[aq].update_ui_elt()}var at=false,ac,aj;for(ao=0;ao<ar.length;ao++){if(ar[ao].data.length){ac=ar[ao].data[0];for(var aq=0;aq<ai.length;aq++){aj=ai[aq];if(aj.applies_to(ac)&&aj.min!==aj.max){at=true;break}}}}if(al.filters_available!==at){al.filters_available=at;if(!al.filters_available){al.filters_manager.hide()}al.update_icons()}}this.container_div.find(".yaxislabel").remove();var af=ar[0];if(af instanceof j){var ak=(this.prefs.histogram_max?this.prefs.histogram_max:af.max_val),ae=$("<div/>").text(ak).make_text_editable({num_cols:12,on_finish:function(av){$(".bs-tooltip").remove();var av=parseFloat(av);al.prefs.histogram_max=(!isNaN(av)?av:null);al.tile_cache.clear();al.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ae)}if(af instanceof O){var ap=true;for(ao=0;ao<ar.length;ao++){if(!ar[ao].all_slotted){ap=false;break}}if(!ap){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){var ac;if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}else{if(ac==="summary_tree"){ac="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,A,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="summary_tree"||ag==="Coverage"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(aa,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,ar,af,aj,ae){var ap=this,ad=aq.canvas,ay=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(ao==="summary_tree"||ao==="Coverage"){var aA=new L.SummaryTreePainter(am,ay,ac,this.prefs);aA.draw(aq,ad.width,ad.height,aj);return new j(ap,af,ar,ad,am.data,am.max)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var at=0,av=am.data.length;at<av;at++){var ah=am.data[at];var au=false;var al;for(var ax=0,aC=ak.length;ax<aC;ax++){al=ak[ax];al.update_attrs(ah);if(!al.keep(ah)){au=true;break}}if(!au){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aB=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae);var aw=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){aw=aA.draw(aq,ad.width,ad.height,aj,an);aw.translation=-ag}return new O(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="summary_tree"}else{if(ac.extra_info==="no_detail"||ac.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="summary_tree"||ac.message||ac.extra_info==="no_detail"){return false}return true}});var R=function(ad,ac,ae){c.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:l.get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};q(R.prototype,r.prototype,M.prototype,c.prototype);var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=l.get_random_color(),ac=l.get_random_color([af,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block and sense strand color",type:"color",default_value:af},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};q(T.prototype,r.prototype,M.prototype,c.prototype);var d={LineTrack:h,FeatureTrack:c,VcfTrack:R,ReadTrack:T,DiagonalHeatmapTrack:t,CompositeTrack:f,DrawableGroup:P};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new d[af](ad,ac,ae)}};return{TracksterView:Z,DrawableGroup:P,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:t,ReadTrack:T,VcfTrack:R,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
diff -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 -r 9852dd712f5c628d1f635fe643f036eb2b930863 static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,p){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,init_data:null,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(A,z,w,y){var B=this.get_elt(A);if(B&&(j(B)||this.get("data_mode_compatible")(B,z))){return B}var C=this.get("key_ary"),v=this.get("obj_cache"),D,u;for(var x=0;x<C.length;x++){D=C[x];u=new g({from_str:D});if(u.contains(A)){B=v[D];if(j(B)||(this.get("data_mode_compatible")(B,z)&&this.get("can_subset")(B))){this.move_key_to_end(D,x);return B}}}return this.load_data(A,z,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}else{if(u.dataset_type==="summary_tree"){w.level=Math.min(u.level-1,2)}}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var n=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<=w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}return u},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("config",p.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var o=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:s.extend({},o.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,ReferenceTrackDataManager:n,TrackBrowserRouter:h,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,p){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:500,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(A,z,w,y){var B=this.get_elt(A);if(B&&(j(B)||this.get("data_mode_compatible")(B,z))){return B}var C=this.get("key_ary"),v=this.get("obj_cache"),D,u;for(var x=0;x<C.length;x++){D=C[x];u=new g({from_str:D});if(u.contains(A)){B=v[D];if(j(B)||(this.get("data_mode_compatible")(B,z)&&this.get("can_subset")(B))){this.move_key_to_end(D,x);return B}}}if(A.length()<this.attributes.min_region_size){var E=new g({from_str:this.most_recently_added()});if(!E||(A.get("start")>E.get("start"))){A.set("end",A.get("start")+this.attributes.min_region_size)}else{A.set("start",A.get("end")-this.attributes.min_region_size)}A.set("genome",this.attributes.genome);A.trim()}return this.load_data(A,z,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}else{if(u.dataset_type==="summary_tree"){w.level=Math.min(u.level-1,2)}}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var n=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})},get_chrom_len:function(u){return s.find(this.get_chroms_info(),function(v){return v.chrom===u}).len}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,genome:null},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>x){if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}else{u=(y>=w?g.overlap_results.CONTAINS:g.overlap_results.CONTAINED_BY)}}return u},trim:function(u){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var v=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>v){this.attributes.end=v-1}}return this},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("config",p.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var o=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:s.extend({},o.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,ReferenceTrackDataManager:n,TrackBrowserRouter:h,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
diff -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 -r 9852dd712f5c628d1f635fe643f036eb2b930863 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -2222,6 +2222,14 @@
obj_dict.data_manager :
new visualization.GenomeDataManager({
dataset: this.dataset,
+ // HACK: simulate 'genome' attributes from view for now.
+ // View should eventually use Genome object.
+ genome: new visualization.Genome({
+ key: view.dbkey,
+ chroms_info: {
+ chrom_info: view.chrom_data
+ }
+ }),
data_mode_compatible: this.data_and_mode_compatible,
can_subset: this.can_subset
}));
diff -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 -r 9852dd712f5c628d1f635fe643f036eb2b930863 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -166,21 +166,33 @@
return value;
},
- // Move key to end of cache. Keys are removed from the front, so moving a key to the end
- // delays the key's removal.
+ /**
+ * Move key to end of cache. Keys are removed from the front, so moving a key to the end
+ * delays the key's removal.
+ */
move_key_to_end: function(key, index) {
this.attributes.key_ary.splice(index, 1);
this.attributes.key_ary.push(key);
},
+ /**
+ * Clear all elements from the cache.
+ */
clear: function() {
this.attributes.obj_cache = {};
this.attributes.key_ary = [];
},
- // Returns the number of elements in the cache.
+ /** Returns the number of elements in the cache. */
size: function() {
return this.attributes.key_ary.length;
+ },
+
+ /** Returns key most recently added to cache. */
+ most_recently_added: function() {
+ return this.size() === 0 ? null :
+ // Most recent key is at the end of key array.
+ this.attributes.key_ary[this.attributes.key_ary.length - 1];
}
});
@@ -190,7 +202,9 @@
var GenomeDataManager = Cache.extend({
defaults: _.extend({}, Cache.prototype.defaults, {
dataset: null,
+ genome: null,
init_data: null,
+ min_region_size: 200,
filters_manager: null,
data_type: "data",
data_mode_compatible: function(entry, mode) { return true; },
@@ -356,6 +370,28 @@
}
}
+ // If needed, extend region to make it minimum size.
+ if (region.length() < this.attributes.min_region_size) {
+ // IDEA: alternative heuristic is to find adjacent cache entry to region and use that to extend.
+ // This would prevent bad extensions when zooming in/out while still preserving the behavior
+ // below.
+
+ // Use heuristic to extend region: extend relative to last data request.
+ var last_request = new GenomeRegion({from_str: this.most_recently_added()});
+ if (!last_request || (region.get('start') > last_request.get('start'))) {
+ // This request is after the last request, so extend right.
+ region.set('end', region.get('start') + this.attributes.min_region_size);
+ }
+ else {
+ // This request is after the last request, so extend left.
+ region.set('start', region.get('end') - this.attributes.min_region_size);
+ }
+
+ // Trim region to avoid invalid coordinates.
+ region.set('genome', this.attributes.genome);
+ region.trim();
+ }
+
return this.load_data(region, mode, resolution, extra_params);
},
@@ -574,6 +610,7 @@
* Returns a GenomeRegion object denoting a complete chromosome.
*/
get_chrom_region: function(chr_name) {
+ // FIXME: use findWhere in underscore 1.4
var chrom_info = _.find(this.get_chroms_info(), function(chrom_info) {
return chrom_info.chrom === chr_name;
});
@@ -581,6 +618,14 @@
chrom: chrom_info.chrom,
end: chrom_info.len
});
+ },
+
+ /** Returns the length of a chromosome. */
+ get_chrom_len: function(chr_name) {
+ // FIXME: use findWhere in underscore 1.4
+ return _.find(this.get_chroms_info(), function(chrom_info) {
+ return chrom_info.chrom === chr_name;
+ }).len;
}
});
@@ -591,7 +636,8 @@
defaults: {
chrom: null,
start: 0,
- end: 0
+ end: 0,
+ genome: null
},
/**
@@ -645,24 +691,24 @@
first_end = this.get('end'), second_end = a_region.get('end'),
overlap;
- // Look at chroms.
+ // Compare chroms.
if (first_chrom && second_chrom && first_chrom !== second_chrom) {
return GenomeRegion.overlap_results.DIF_CHROMS;
}
- // Look at regions.
+ // Compare regions.
if (first_start < second_start) {
if (first_end < second_start) {
overlap = GenomeRegion.overlap_results.BEFORE;
}
- else if (first_end <= second_end) {
+ else if (first_end < second_end) {
overlap = GenomeRegion.overlap_results.OVERLAP_START;
}
- else { // first_end > second_end
+ else { // first_end >= second_end
overlap = GenomeRegion.overlap_results.CONTAINS;
}
}
- else { // first_start >= second_start
+ else if (first_start > second_start) {
if (first_start > second_end) {
overlap = GenomeRegion.overlap_results.AFTER;
}
@@ -673,9 +719,34 @@
overlap = GenomeRegion.overlap_results.OVERLAP_END;
}
}
+ else { // first_start === second_start
+ overlap = (first_end >= second_end ?
+ GenomeRegion.overlap_results.CONTAINS :
+ GenomeRegion.overlap_results.CONTAINED_BY);
+ }
return overlap;
},
+
+ /**
+ * Trim a region to match genome's constraints.
+ */
+ trim: function(genome) {
+ // Assume that all chromosome/contigs start at 0.
+ if (this.attributes.start < 0) {
+ this.attributes.start = 0;
+ }
+
+ // Only try to trim the end if genome is set.
+ if (this.attributes.genome) {
+ var chrom_len = this.attributes.genome.get_chrom_len(this.attributes.chrom);
+ if (this.attributes.end > chrom_len) {
+ this.attributes.end = chrom_len - 1;
+ }
+ }
+
+ return this;
+ },
/**
* Returns true if this region contains a given region.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Properly handle subdirectory collection in a job output's extra_files_path.
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ddb55ff5fd1c/
changeset: ddb55ff5fd1c
user: natefoo
date: 2013-02-19 16:07:14
summary: Properly handle subdirectory collection in a job output's extra_files_path.
affected #: 1 file
diff -r 90f3b97fba53d68f955ddce9de97d12e10763b45 -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -2635,19 +2635,26 @@
"""
for name, hda in output.items():
temp_file_path = os.path.join( job_working_directory, "dataset_%s_files" % ( hda.dataset.id ) )
+ extra_dir = None
try:
- a_files = os.listdir( temp_file_path )
- if len( a_files ) > 0:
- for f in a_files:
+ # This skips creation of directories - object store
+ # automatically creates them. However, empty directories will
+ # not be created in the object store at all, which might be a
+ # problem.
+ for root, dirs, files in os.walk( temp_file_path ):
+ extra_dir = root.replace(job_working_directory, '', 1).lstrip(os.path.sep)
+ for f in files:
self.app.object_store.update_from_file(hda.dataset,
- extra_dir="dataset_%d_files" % hda.dataset.id,
+ extra_dir=extra_dir,
alt_name = f,
- file_name = os.path.join(temp_file_path, f),
+ file_name = os.path.join(root, f),
create = True,
preserve_symlinks = True )
- # Clean up after being handled by object store.
- # FIXME: If the object (e.g., S3) becomes async, this will
- # cause issues so add it to the object store functionality?
+ # Clean up after being handled by object store.
+ # FIXME: If the object (e.g., S3) becomes async, this will
+ # cause issues so add it to the object store functionality?
+ if extra_dir is not None:
+ # there was an extra_files_path dir, attempt to remove it
shutil.rmtree(temp_file_path)
except Exception, e:
log.debug( "Error in collect_associated_files: %s" % ( e ) )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Small fixes for trackster resolution calculation.
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/90f3b97fba53/
changeset: 90f3b97fba53
user: jgoecks
date: 2013-02-19 14:56:32
summary: Small fixes for trackster resolution calculation.
affected #: 1 file
diff -r 1f073bb32539ea9d978c04a892a36d995561cb30 -r 90f3b97fba53d68f955ddce9de97d12e10763b45 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -1427,11 +1427,12 @@
// -- Drawing code --
- // Calculate resolution in both pixels/base and bases/pixel; round bases/pixels for tile calculations.
- // TODO: require minimum difference in new resolution to update?
+ // Calculate resolution in both pixels/base and bases/pixel.
+ // TODO: require minimum difference in new resolution to update? This
+ // would help alleviate issues when window is being resized.
this.resolution_b_px = (this.high - this.low) / this.viewport_container.width();
- this.resolution_px_b = this.viewport_container.width() / (this.high - this.low);
-
+ this.resolution_px_b = 1 / this.resolution_b_px;
+
// Overview
var left_px = ( this.low / (this.max_high - this.max_low) * this.overview_viewport.width() ) || 0;
var width_px = ( (this.high - this.low)/(this.max_high - this.max_low) * this.overview_viewport.width() ) || 0;
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a0f1ae0dc3ff/
changeset: a0f1ae0dc3ff
user: sfk
date: 2013-02-18 00:46:39
summary: Fixed a small bug when jobwrapper was referenced but it didnt exist
affected #: 1 file
diff -r 09c81e81952d4768d63fde4840f31958d8e23041 -r a0f1ae0dc3ff4474e46b8e54aea4b999d8e0d0e0 lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -607,7 +607,7 @@
try:
self.job_runners[runner_name].stop_job( job )
except KeyError:
- log.error( 'stop(): (%s) Invalid job runner: %s' % ( job_wrapper.job_id, runner_name ) )
+ log.error( 'stop(): (%s) Invalid job runner: %s' % ( job.get_id(), runner_name ) )
# Job and output dataset states have already been updated, so nothing is done here.
def recover( self, job, job_wrapper ):
https://bitbucket.org/galaxy/galaxy-central/commits/1f073bb32539/
changeset: 1f073bb32539
user: natefoo
date: 2013-02-19 14:53:25
summary: Merged in sfk/galaxy-central-random-bug-fix (pull request #126)
Fixed a small bug when jobwrapper was referenced but it didnt exist
affected #: 1 file
diff -r 31aca8c9901ecf4ad852f7114d6550d997374888 -r 1f073bb32539ea9d978c04a892a36d995561cb30 lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -607,7 +607,7 @@
try:
self.job_runners[runner_name].stop_job( job )
except KeyError:
- log.error( 'stop(): (%s) Invalid job runner: %s' % ( job_wrapper.job_id, runner_name ) )
+ log.error( 'stop(): (%s) Invalid job runner: %s' % ( job.get_id(), runner_name ) )
# Job and output dataset states have already been updated, so nothing is done here.
def recover( self, job, job_wrapper ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Fix for installing a repository from the tool shed that includes a repository dependency defintion where the required repository is owned by a user other than the dependent repository.
by Bitbucket 18 Feb '13
by Bitbucket 18 Feb '13
18 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8da37d3985ab/
changeset: 8da37d3985ab
branch: stable
user: greg
date: 2013-02-18 21:28:06
summary: Fix for installing a repository from the tool shed that includes a repository dependency defintion where the required repository is owned by a user other than the dependent repository.
affected #: 3 files
diff -r 337e5b6bd7dc5696087c436e54192149c1bc8bc3 -r 8da37d3985ab9c489760e64d4e3eb707dfbeb4b8 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -714,7 +714,11 @@
for rd_tup in rd_tups:
tool_shed, name, owner, changeset_revision = rd_tup
# Updates to installed repository revisions may have occurred, so make sure to locate the appropriate repository revision if one exists.
- repository, current_changeset_revision = repository_was_previously_installed( trans, tool_shed, name, repo_info_tuple )
+ # We need to create a temporary repo_info_tuple that includes the correct repository owner which we get from the current rd_tup. The current
+ # tuple looks like: ( description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td )
+ tmp_clone_url = suc.generate_clone_url_from_repo_info_tup( rd_tup )
+ tmp_repo_info_tuple = ( None, tmp_clone_url, changeset_revision, None, owner, None, None )
+ repository, current_changeset_revision = repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple )
if repository:
new_rd_tup = [ tool_shed, name, owner, changeset_revision, repository.id, repository.status ]
if repository.status == trans.model.ToolShedRepository.installation_status.INSTALLED:
diff -r 337e5b6bd7dc5696087c436e54192149c1bc8bc3 -r 8da37d3985ab9c489760e64d4e3eb707dfbeb4b8 lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -953,6 +953,12 @@
return '%s://%s%s/repos/%s/%s' % ( protocol, username, base, repository.user.username, repository.name )
else:
return '%s/repos/%s/%s' % ( base_url, repository.user.username, repository.name )
+def generate_clone_url_from_repo_info_tup( repo_info_tup ):
+ """Generate teh URL for cloning a repositoyr given a tuple of toolshed, name, owner, changeset_revision."""
+ # Example tuple: ['http://localhost:9009', 'blast_datatypes', 'test', '461a4216e8ab']
+ toolshed, name, owner, changeset_revision = repo_info_tup
+ # Don't include the changeset_revision in clone urls.
+ return url_join( toolshed, 'repos', owner, name )
def generate_datatypes_metadata( datatypes_config, metadata_dict ):
"""Update the received metadata_dict with information from the parsed datatypes_config."""
tree = ElementTree.parse( datatypes_config )
diff -r 337e5b6bd7dc5696087c436e54192149c1bc8bc3 -r 8da37d3985ab9c489760e64d4e3eb707dfbeb4b8 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1461,12 +1461,15 @@
repository_clone_url = suc.generate_clone_url_for_repository_in_tool_shed( trans, repository )
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
metadata = repository_metadata.metadata
- if not includes_tools and 'tools' in metadata:
- includes_tools = True
- if not has_repository_dependencies and 'repository_dependencies' in metadata:
- has_repository_dependencies = True
- if not includes_tool_dependencies and 'tool_dependencies' in metadata:
- includes_tool_dependencies = True
+ if not includes_tools:
+ if 'tools' in metadata:
+ includes_tools = True
+ if not has_repository_dependencies:
+ if 'repository_dependencies' in metadata:
+ has_repository_dependencies = True
+ if not includes_tool_dependencies:
+ if 'tool_dependencies' in metadata:
+ includes_tool_dependencies = True
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
ctx = suc.get_changectx_for_changeset( repo, changeset_revision )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0