galaxy-commits
Threads by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d270d3cf7627/
Changeset: d270d3cf7627
Branch: stable
User: greg
Date: 2014-02-19 19:05:25
Summary: Make managing an in-memory registry of bi-directional installed repository dependency relationships a configurable option for Galaxy instances.
Affected #: 6 files
diff -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 -r d270d3cf7627a42b6fac2aa69701deadb89c8ffc lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -95,6 +95,7 @@
self.tool_data_table_config_path = resolve_path( kwargs.get( 'tool_data_table_config_path', 'tool_data_table_conf.xml' ), self.root )
self.shed_tool_data_table_config = resolve_path( kwargs.get( 'shed_tool_data_table_config', 'shed_tool_data_table_conf.xml' ), self.root )
self.enable_tool_shed_check = string_as_bool( kwargs.get( 'enable_tool_shed_check', False ) )
+ self.manage_dependency_relationships = string_as_bool( kwargs.get( 'manage_dependency_relationships', True ) )
self.running_functional_tests = string_as_bool( kwargs.get( 'running_functional_tests', False ) )
self.hours_between_check = kwargs.get( 'hours_between_check', 12 )
try:
diff -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 -r d270d3cf7627a42b6fac2aa69701deadb89c8ffc 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
@@ -271,9 +271,10 @@
if remove_from_disk_checked:
tool_shed_repository.status = trans.install_model.ToolShedRepository.installation_status.UNINSTALLED
tool_shed_repository.error_message = None
- # Remove the uninstalled repository and any tool dependencies from the in-memory dictionaries in the
- # installed_repository_manager.
- trans.app.installed_repository_manager.handle_repository_uninstall( tool_shed_repository )
+ if trans.app.config.manage_dependency_relationships:
+ # Remove the uninstalled repository and any tool dependencies from the in-memory dictionaries in the
+ # installed_repository_manager.
+ trans.app.installed_repository_manager.handle_repository_uninstall( tool_shed_repository )
else:
tool_shed_repository.status = trans.install_model.ToolShedRepository.installation_status.DEACTIVATED
trans.install_model.context.add( tool_shed_repository )
diff -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 -r d270d3cf7627a42b6fac2aa69701deadb89c8ffc lib/tool_shed/galaxy_install/installed_repository_manager.py
--- a/lib/tool_shed/galaxy_install/installed_repository_manager.py
+++ b/lib/tool_shed/galaxy_install/installed_repository_manager.py
@@ -62,8 +62,9 @@
# whose values are a list of tuples defining tool_dependency objects (whose status is 'Installed') that require the key
# at runtime. The value defines the entire tool dependency tree.
self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies = {}
- # Load defined dependency relationships for installed tool shed repositories and their contents.
- self.load_dependency_relationships()
+ if app.config.manage_dependency_relationships:
+ # Load defined dependency relationships for installed tool shed repositories and their contents.
+ self.load_dependency_relationships()
def add_entry_to_installed_repository_dependencies_of_installed_repositories( self, repository ):
"""
diff -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 -r d270d3cf7627a42b6fac2aa69701deadb89c8ffc lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -602,8 +602,9 @@
suc.update_tool_shed_repository_status( trans.app,
tool_shed_repository,
trans.install_model.ToolShedRepository.installation_status.INSTALLED )
- # Add the installed repository and any tool dependencies to the in-memory dictionaries in the installed_repository_manager.
- trans.app.installed_repository_manager.handle_repository_install( tool_shed_repository )
+ if trans.app.config.manage_dependency_relationships:
+ # Add the installed repository and any tool dependencies to the in-memory dictionaries in the installed_repository_manager.
+ trans.app.installed_repository_manager.handle_repository_install( tool_shed_repository )
else:
# An error occurred while cloning the repository, so reset everything necessary to enable another attempt.
set_repository_attributes( trans,
diff -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 -r d270d3cf7627a42b6fac2aa69701deadb89c8ffc lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -507,8 +507,9 @@
if tool_dependency and tool_dependency.status in [ app.install_model.ToolDependency.installation_status.INSTALLED,
app.install_model.ToolDependency.installation_status.ERROR ]:
installed_tool_dependencies.append( tool_dependency )
- # Add the tool_dependency to the in-memory dictionaries in the installed_repository_manager.
- app.installed_repository_manager.handle_tool_dependency_install( tool_shed_repository, tool_dependency )
+ if app.config.manage_dependency_relationships:
+ # Add the tool_dependency to the in-memory dictionaries in the installed_repository_manager.
+ app.installed_repository_manager.handle_tool_dependency_install( tool_shed_repository, tool_dependency )
elif elem.tag == 'set_environment':
# <set_environment version="1.0">
# <environment_variable name="R_SCRIPT_PATH"action="set_to">$REPOSITORY_INSTALL_DIR</environment_variable>
diff -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 -r d270d3cf7627a42b6fac2aa69701deadb89c8ffc universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -152,6 +152,11 @@
#enable_tool_shed_check = False
#hours_between_check = 12
+# Enable use of an in-memory registry with bi-directional relationships
+# between repositories (i.e., in addition to lists of dependencies for a
+# repository, keep an in-memory registry of dependent items for each repository.
+#manage_dependency_relationships = True
+
# XML config file that contains data table entries for the ToolDataTableManager. This file is manually
# maintained by the Galaxy administrator.
#tool_data_table_config_path = tool_data_table_conf.xml
https://bitbucket.org/galaxy/galaxy-central/commits/ef0654f99261/
Changeset: ef0654f99261
User: inithello
Date: 2014-02-19 19:09:03
Summary: Merge bugfix from stable.
Affected #: 1 file
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: Make managing an in-memory registry of bi-directional installed repository dependency relationships a configurable option for Galaxy instances.
by commits-noreply@bitbucket.org 19 Feb '14
by commits-noreply@bitbucket.org 19 Feb '14
19 Feb '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4df1be355e4f/
Changeset: 4df1be355e4f
User: greg
Date: 2014-02-19 19:05:25
Summary: Make managing an in-memory registry of bi-directional installed repository dependency relationships a configurable option for Galaxy instances.
Affected #: 6 files
diff -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 -r 4df1be355e4f7cdbbc927027ce60b81cf222956f lib/galaxy/config.py
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -95,6 +95,7 @@
self.tool_data_table_config_path = resolve_path( kwargs.get( 'tool_data_table_config_path', 'tool_data_table_conf.xml' ), self.root )
self.shed_tool_data_table_config = resolve_path( kwargs.get( 'shed_tool_data_table_config', 'shed_tool_data_table_conf.xml' ), self.root )
self.enable_tool_shed_check = string_as_bool( kwargs.get( 'enable_tool_shed_check', False ) )
+ self.manage_dependency_relationships = string_as_bool( kwargs.get( 'manage_dependency_relationships', True ) )
self.running_functional_tests = string_as_bool( kwargs.get( 'running_functional_tests', False ) )
self.hours_between_check = kwargs.get( 'hours_between_check', 12 )
try:
diff -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 -r 4df1be355e4f7cdbbc927027ce60b81cf222956f 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
@@ -271,9 +271,10 @@
if remove_from_disk_checked:
tool_shed_repository.status = trans.install_model.ToolShedRepository.installation_status.UNINSTALLED
tool_shed_repository.error_message = None
- # Remove the uninstalled repository and any tool dependencies from the in-memory dictionaries in the
- # installed_repository_manager.
- trans.app.installed_repository_manager.handle_repository_uninstall( tool_shed_repository )
+ if trans.app.config.manage_dependency_relationships:
+ # Remove the uninstalled repository and any tool dependencies from the in-memory dictionaries in the
+ # installed_repository_manager.
+ trans.app.installed_repository_manager.handle_repository_uninstall( tool_shed_repository )
else:
tool_shed_repository.status = trans.install_model.ToolShedRepository.installation_status.DEACTIVATED
trans.install_model.context.add( tool_shed_repository )
diff -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 -r 4df1be355e4f7cdbbc927027ce60b81cf222956f lib/tool_shed/galaxy_install/installed_repository_manager.py
--- a/lib/tool_shed/galaxy_install/installed_repository_manager.py
+++ b/lib/tool_shed/galaxy_install/installed_repository_manager.py
@@ -62,8 +62,9 @@
# whose values are a list of tuples defining tool_dependency objects (whose status is 'Installed') that require the key
# at runtime. The value defines the entire tool dependency tree.
self.installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies = {}
- # Load defined dependency relationships for installed tool shed repositories and their contents.
- self.load_dependency_relationships()
+ if app.config.manage_dependency_relationships:
+ # Load defined dependency relationships for installed tool shed repositories and their contents.
+ self.load_dependency_relationships()
def add_entry_to_installed_repository_dependencies_of_installed_repositories( self, repository ):
"""
diff -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 -r 4df1be355e4f7cdbbc927027ce60b81cf222956f lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -602,8 +602,9 @@
suc.update_tool_shed_repository_status( trans.app,
tool_shed_repository,
trans.install_model.ToolShedRepository.installation_status.INSTALLED )
- # Add the installed repository and any tool dependencies to the in-memory dictionaries in the installed_repository_manager.
- trans.app.installed_repository_manager.handle_repository_install( tool_shed_repository )
+ if trans.app.config.manage_dependency_relationships:
+ # Add the installed repository and any tool dependencies to the in-memory dictionaries in the installed_repository_manager.
+ trans.app.installed_repository_manager.handle_repository_install( tool_shed_repository )
else:
# An error occurred while cloning the repository, so reset everything necessary to enable another attempt.
set_repository_attributes( trans,
diff -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 -r 4df1be355e4f7cdbbc927027ce60b81cf222956f lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -507,8 +507,9 @@
if tool_dependency and tool_dependency.status in [ app.install_model.ToolDependency.installation_status.INSTALLED,
app.install_model.ToolDependency.installation_status.ERROR ]:
installed_tool_dependencies.append( tool_dependency )
- # Add the tool_dependency to the in-memory dictionaries in the installed_repository_manager.
- app.installed_repository_manager.handle_tool_dependency_install( tool_shed_repository, tool_dependency )
+ if app.config.manage_dependency_relationships:
+ # Add the tool_dependency to the in-memory dictionaries in the installed_repository_manager.
+ app.installed_repository_manager.handle_tool_dependency_install( tool_shed_repository, tool_dependency )
elif elem.tag == 'set_environment':
# <set_environment version="1.0">
# <environment_variable name="R_SCRIPT_PATH"action="set_to">$REPOSITORY_INSTALL_DIR</environment_variable>
diff -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 -r 4df1be355e4f7cdbbc927027ce60b81cf222956f universe_wsgi.ini.sample
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -152,6 +152,11 @@
#enable_tool_shed_check = False
#hours_between_check = 12
+# Enable use of an in-memory registry with bi-directional relationships
+# between repositories (i.e., in addition to lists of dependencies for a
+# repository, keep an in-memory registry of dependent items for each repository.
+#manage_dependency_relationships = True
+
# XML config file that contains data table entries for the ToolDataTableManager. This file is manually
# maintained by the Galaxy administrator.
#tool_data_table_config_path = tool_data_table_conf.xml
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
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1298d3f6aca5/
Changeset: 1298d3f6aca5
Branch: stable
User: natefoo
Date: 2014-02-19 19:00:33
Summary: Stop jobs when all output datasets are deleted via the API.
Affected #: 3 files
diff -r 44968207ddd283d0023c72e3d25fd39b1c71eb99 -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -849,6 +849,18 @@
break
return job
+ def stop_hda_creating_job( self, hda ):
+ """
+ Stops an HDA's creating job if all the job's other outputs are deleted.
+ """
+ if hda.parent_id is None and len( hda.creating_job_associations ) > 0:
+ # Mark associated job for deletion
+ job = hda.creating_job_associations[0].job
+ if job.state in [ self.app.model.Job.states.QUEUED, self.app.model.Job.states.RUNNING, self.app.model.Job.states.NEW ]:
+ # Are *all* of the job's other output datasets deleted?
+ if job.check_if_output_datasets_deleted():
+ job.mark_deleted( self.app.config.track_jobs_in_database )
+ self.app.job_manager.job_stop_queue.put( job.id )
class UsesLibraryMixin:
diff -r 44968207ddd283d0023c72e3d25fd39b1c71eb99 -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -278,6 +278,8 @@
# get_dataset can return a string during an error
if hda and isinstance( hda, trans.model.HistoryDatasetAssociation ):
changed = self.set_hda_from_dict( trans, hda, payload )
+ if payload.get( 'deleted', False ):
+ self.stop_hda_creating_job( hda )
except Exception, exception:
log.error( 'Update of history (%s), HDA (%s) failed: %s',
history_id, id, str( exception ), exc_info=True )
@@ -347,6 +349,8 @@
trans.sa_session.flush()
rval[ 'purged' ] = True
+ self.stop_hda_creating_job( hda )
+
trans.sa_session.flush()
rval[ 'deleted' ] = True
diff -r 44968207ddd283d0023c72e3d25fd39b1c71eb99 -r 1298d3f6aca59825d0eb3d32afd5686c4b1b9294 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -839,14 +839,7 @@
hda.mark_deleted()
hda.clear_associated_files()
trans.log_event( "Dataset id %s marked as deleted" % str(id) )
- if hda.parent_id is None and len( hda.creating_job_associations ) > 0:
- # Mark associated job for deletion
- job = hda.creating_job_associations[0].job
- if job.state in [ self.app.model.Job.states.QUEUED, self.app.model.Job.states.RUNNING, self.app.model.Job.states.NEW ]:
- # Are *all* of the job's other output datasets deleted?
- if job.check_if_output_datasets_deleted():
- job.mark_deleted( self.app.config.track_jobs_in_database )
- self.app.job_manager.job_stop_queue.put( job.id )
+ self.stop_hda_creating_job( hda )
trans.sa_session.flush()
except Exception, e:
msg = 'HDA deletion failed (encoded: %s, decoded: %s)' % ( dataset_id, id )
https://bitbucket.org/galaxy/galaxy-central/commits/0db8172d6d36/
Changeset: 0db8172d6d36
User: natefoo
Date: 2014-02-19 19:01:03
Summary: merge.
Affected #: 3 files
diff -r c85f8fb5d63e667b63e10cdce518254f56002f55 -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -892,6 +892,18 @@
break
return job
+ def stop_hda_creating_job( self, hda ):
+ """
+ Stops an HDA's creating job if all the job's other outputs are deleted.
+ """
+ if hda.parent_id is None and len( hda.creating_job_associations ) > 0:
+ # Mark associated job for deletion
+ job = hda.creating_job_associations[0].job
+ if job.state in [ self.app.model.Job.states.QUEUED, self.app.model.Job.states.RUNNING, self.app.model.Job.states.NEW ]:
+ # Are *all* of the job's other output datasets deleted?
+ if job.check_if_output_datasets_deleted():
+ job.mark_deleted( self.app.config.track_jobs_in_database )
+ self.app.job_manager.job_stop_queue.put( job.id )
class UsesLibraryMixin:
diff -r c85f8fb5d63e667b63e10cdce518254f56002f55 -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 lib/galaxy/webapps/galaxy/api/history_contents.py
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -280,6 +280,8 @@
# get_dataset can return a string during an error
if hda and isinstance( hda, trans.model.HistoryDatasetAssociation ):
changed = self.set_hda_from_dict( trans, hda, payload )
+ if payload.get( 'deleted', False ):
+ self.stop_hda_creating_job( hda )
except Exception, exception:
log.error( 'Update of history (%s), HDA (%s) failed: %s',
history_id, id, str( exception ), exc_info=True )
@@ -349,6 +351,8 @@
trans.sa_session.flush()
rval[ 'purged' ] = True
+ self.stop_hda_creating_job( hda )
+
trans.sa_session.flush()
rval[ 'deleted' ] = True
diff -r c85f8fb5d63e667b63e10cdce518254f56002f55 -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 lib/galaxy/webapps/galaxy/controllers/dataset.py
--- a/lib/galaxy/webapps/galaxy/controllers/dataset.py
+++ b/lib/galaxy/webapps/galaxy/controllers/dataset.py
@@ -839,14 +839,7 @@
hda.mark_deleted()
hda.clear_associated_files()
trans.log_event( "Dataset id %s marked as deleted" % str(id) )
- if hda.parent_id is None and len( hda.creating_job_associations ) > 0:
- # Mark associated job for deletion
- job = hda.creating_job_associations[0].job
- if job.state in [ self.app.model.Job.states.QUEUED, self.app.model.Job.states.RUNNING, self.app.model.Job.states.NEW ]:
- # Are *all* of the job's other output datasets deleted?
- if job.check_if_output_datasets_deleted():
- job.mark_deleted( self.app.config.track_jobs_in_database )
- self.app.job_manager.job_stop_queue.put( job.id )
+ self.stop_hda_creating_job( hda )
trans.sa_session.flush()
except Exception, e:
msg = 'HDA deletion failed (encoded: %s, decoded: %s)' % ( dataset_id, id )
https://bitbucket.org/galaxy/galaxy-central/commits/e51429649b44/
Changeset: e51429649b44
User: natefoo
Date: 2014-02-19 19:02:12
Summary: merge.
Affected #: 6 files
diff -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -843,35 +843,6 @@
history. <br>You can <a href="%s">continue and import this history</a> or %s.
""" % ( web.url_for(controller='history', action='imp', id=id, confirm=True, referer=trans.request.referer ), referer_message ), use_panels=True )
- # Replaced with view (below) but kept (available via manual URL editing) for now
- @web.expose
- def original_view( self, trans, id=None, show_deleted=False, use_panels=True ):
- """View a history. If a history is importable, then it is viewable by any user."""
- # Get history to view.
- if not id:
- return trans.show_error_message( "You must specify a history you want to view." )
- history_to_view = self.get_history( trans, id, False)
- # Integrity checks.
- if not history_to_view:
- return trans.show_error_message( "The specified history does not exist." )
- # Admin users can view any history
- if( ( history_to_view.user != trans.user )
- and ( not trans.user_is_admin() )
- and ( not history_to_view.importable ) ):
- error( "Either you are not allowed to view this history or the owner of this history has not made it accessible." )
- # View history.
- show_deleted = galaxy.util.string_as_bool( show_deleted )
- datasets = self.get_history_datasets( trans, history_to_view, show_deleted=show_deleted )
- try:
- use_panels = galaxy.util.string_as_bool( use_panels )
- except:
- pass # already a bool
- return trans.stream_template_mako( "history/original_view.mako",
- history = history_to_view,
- datasets = datasets,
- show_deleted = show_deleted,
- use_panels = use_panels )
-
@web.expose
def view( self, trans, id=None, show_deleted=False, show_hidden=False, use_panels=True ):
"""
diff -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 static/scripts/mvc/ui.js
--- a/static/scripts/mvc/ui.js
+++ b/static/scripts/mvc/ui.js
@@ -783,77 +783,110 @@
* });
* $( '.myElement' ).modeButton( 'callModeFn', 'bler' );
*/
+ /** constructor */
function ModeButton( element, options ){
this.currModeIndex = 0;
- return this.init( element, options );
+ return this._init( element, options );
}
+ /** html5 data key to store this object inside an element */
ModeButton.prototype.DATA_KEY = 'mode-button';
+ /** default options */
ModeButton.prototype.defaults = {
- modes : [
- { mode: 'default' }
- ]
+ switchModesOnClick : true
};
- ModeButton.prototype.init = function _init( element, options ){
+ // ---- private interface
+ /** set up options, intial mode, and the click handler */
+ ModeButton.prototype._init = function _init( element, options ){
+ //console.debug( 'ModeButton._init:', element, options );
options = options || {};
this.$element = $( element );
this.options = jQuery.extend( true, {}, this.defaults, options );
+ if( !options.modes ){
+ throw new Error( 'ModeButton requires a "modes" array' );
+ }
var modeButton = this;
this.$element.click( function _ModeButtonClick( event ){
-
// call the curr mode fn
modeButton.callModeFn();
// inc the curr mode index
- modeButton._incModeIndex();
+ if( modeButton.options.switchModesOnClick ){ modeButton._incModeIndex(); }
// set the element html
$( this ).html( modeButton.options.modes[ modeButton.currModeIndex ].html );
});
-
- this.currModeIndex = 0;
- if( this.options.initialMode ){
- this.currModeIndex = this._getModeIndex( this.options.initialMode );
- }
- return this;
+ return this.reset();
};
-
-
- ModeButton.prototype._getModeIndex = function __getModeIndex( modeKey ){
- for( var i=0; i<this.options.modes.length; i+=1 ){
- if( this.options.modes[ i ].mode === modeKey ){ return i; }
- }
- throw new Error( 'mode not found: ' + modeKey );
- };
- ModeButton.prototype.getCurrMode = function _getCurrMode(){
- return this.options.modes[ this.currModeIndex ];
- };
- ModeButton.prototype.getMode = function _getMode( modeKey ){
- if( !modeKey ){ return this.getCurrMode(); }
- return this.options.modes[( this._getModeIndex( modeKey ) )];
- };
- ModeButton.prototype.hasMode = function _hasMode( modeKey ){
- return !!this.getMode( modeKey );
- };
- ModeButton.prototype.currentMode = function _currentMode(){
- return this.options.modes[ this.currModeIndex ];
- };
- ModeButton.prototype.setMode = function _setMode( newModeKey ){
- var newMode = this.getMode( newModeKey );
- this.$element.html( newMode.html || null );
- return this;
- };
- ModeButton.prototype._incModeIndex = function __incModeIndex(){
+ /** increment the mode index to the next in the array, looping back to zero if at the last */
+ ModeButton.prototype._incModeIndex = function _incModeIndex(){
this.currModeIndex += 1;
if( this.currModeIndex >= this.options.modes.length ){
this.currModeIndex = 0;
}
return this;
};
- ModeButton.prototype.callModeFn = function _callModeFn( modeKey ){
+ /** get the mode index in the modes array for the given key (mode name) */
+ ModeButton.prototype._getModeIndex = function _getModeIndex( modeKey ){
+ for( var i=0; i<this.options.modes.length; i+=1 ){
+ if( this.options.modes[ i ].mode === modeKey ){ return i; }
+ }
+ throw new Error( 'mode not found: ' + modeKey );
+ };
+ /** set the current mode to the one with the given index and set button html */
+ ModeButton.prototype._setModeByIndex = function _setModeByIndex( index ){
+ var newMode = this.options.modes[ index ];
+ if( !newMode ){
+ throw new Error( 'mode index not found: ' + index );
+ }
+ this.currModeIndex = index;
+ if( newMode.html ){
+ this.$element.html( newMode.html );
+ }
+ return this;
+ };
+
+ // ---- public interface
+ /** get the current mode object (not just the mode name) */
+ ModeButton.prototype.currentMode = function currentMode(){
+ return this.options.modes[ this.currModeIndex ];
+ };
+ /** return the mode key of the current mode */
+ ModeButton.prototype.current = function current(){
+ // sugar for returning mode name
+ return this.currentMode().mode;
+ };
+ /** get the mode with the given modeKey or the current mode if modeKey is undefined */
+ ModeButton.prototype.getMode = function getMode( modeKey ){
+ if( !modeKey ){ return this.currentMode(); }
+ return this.options.modes[( this._getModeIndex( modeKey ) )];
+ };
+ /** T/F if the button has the given mode */
+ ModeButton.prototype.hasMode = function hasMode( modeKey ){
+ try {
+ return !!this.getMode( modeKey );
+ } catch( err ){}
+ return false;
+ };
+ /** set the current mode to the mode with the given name */
+ ModeButton.prototype.setMode = function setMode( modeKey ){
+ return this._setModeByIndex( this._getModeIndex( modeKey ) );
+ };
+ /** reset to the initial mode */
+ ModeButton.prototype.reset = function reset(){
+ this.currModeIndex = 0;
+ if( this.options.initialMode ){
+ this.currModeIndex = this._getModeIndex( this.options.initialMode );
+ }
+ return this._setModeByIndex( this.currModeIndex );
+ };
+ /** manually call the click handler of the given mode */
+ ModeButton.prototype.callModeFn = function callModeFn( modeKey ){
var modeFn = this.getMode( modeKey ).onclick;
if( modeFn && jQuery.type( modeFn === 'function' ) ){
- return modeFn.call( this );
+ // call with the element as context (std jquery pattern)
+ modeFn.call( this.$element.get(0) );
+ return this;
}
return undefined;
};
@@ -861,26 +894,32 @@
// as jq plugin
jQuery.fn.extend({
modeButton : function $modeButton( options ){
- var nonOptionsArgs = jQuery.makeArray( arguments ).slice( 1 );
+ if( !this.size() ){ return this; }
+
//TODO: does map still work with jq multi selection (i.e. $( '.class-for-many-btns' ).modeButton)?
- return this.map( function(){
- var $this = $( this ),
- data = $this.data( 'mode-button' );
+ if( jQuery.type( options ) === 'object' ){
+ return this.map( function(){
+ var $this = $( this );
+ $this.data( 'mode-button', new ModeButton( $this, options ) );
+ return this;
+ });
+ }
- if( jQuery.type( options ) === 'object' ){
- data = new ModeButton( $this, options );
- $this.data( 'mode-button', data );
+ var $first = $( this[0] ),
+ button = $first.data( 'mode-button' );
+ console.debug( 'first, button', $first, button );
- } else if( data && jQuery.type( options ) === 'string' ){
- var fn = data[ options ];
- if( jQuery.type( fn ) === 'function' ){
- return fn.apply( data, nonOptionsArgs );
- }
- } else if ( data ){
- return data;
+ if( !button ){
+ throw new Error( 'modeButton needs an options object or string name of a function' );
+ }
+
+ if( button && jQuery.type( options ) === 'string' ){
+ var fnName = options;
+ if( button && jQuery.type( button[ fnName ] ) === 'function' ){
+ return button[ fnName ].apply( button, jQuery.makeArray( arguments ).slice( 1 ) );
}
- return this;
- });
+ }
+ return button;
}
});
}());
diff -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 static/scripts/packed/mvc/ui.js
--- a/static/scripts/packed/mvc/ui.js
+++ b/static/scripts/packed/mvc/ui.js
@@ -1,1 +1,1 @@
-var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.create=function _create(b,a){return new PopupMenu(b,a)};PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b}(function(){function a(j,p){var d=27,m=13,c=$(j),e=true,g={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(q){},minSearchLen:0,escWillClear:true,oninit:function(){}};function i(q){var r=$(this).parent().children("input");r.val("");r.trigger("clear:searchInput");p.onclear()}function o(r,q){$(this).trigger("search:searchInput",q);if(typeof p.onfirstsearch==="function"&&e){e=false;p.onfirstsearch(q)}else{p.onsearch(q)}}function f(){return['<input type="text" name="',p.name,'" placeholder="',p.placeholder,'" ','class="search-query ',p.classes,'" ',"/>"].join("")}function l(){return $(f()).focus(function(q){$(this).select()}).keyup(function(r){if(r.which===d&&p.escWillClear){i.call(this,r)}else{var q=$(this).val();if((r.which===m)||(p.minSearchLen&&q.length>=p.minSearchLen)){o.call(this,r,q)}else{if(!q.length){i.call(this,r)}}}}).val(p.initialVal)}function k(){return $(['<span class="search-clear fa fa-times-circle" ','title="',_l("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(q){i.call(this,q)})}function n(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',_l("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function h(){c.find(".search-loading").toggle();c.find(".search-clear").toggle()}if(jQuery.type(p)==="string"){if(p==="toggle-loading"){h()}return c}if(jQuery.type(p)==="object"){p=jQuery.extend(true,{},g,p)}return c.addClass("search-input").prepend([l(),k(),n()])}jQuery.fn.extend({searchInput:function b(c){return this.each(function(){return a(this,c)})}})}());(function(){function b(m,l){this.currModeIndex=0;return this.init(m,l)}b.prototype.DATA_KEY="mode-button";b.prototype.defaults={modes:[{mode:"default"}]};b.prototype.init=function f(m,l){l=l||{};this.$element=$(m);this.options=jQuery.extend(true,{},this.defaults,l);var o=this;this.$element.click(function n(p){o.callModeFn();o._incModeIndex();$(this).html(o.options.modes[o.currModeIndex].html)});this.currModeIndex=0;if(this.options.initialMode){this.currModeIndex=this._getModeIndex(this.options.initialMode)}return this};b.prototype._getModeIndex=function j(l){for(var m=0;m<this.options.modes.length;m+=1){if(this.options.modes[m].mode===l){return m}}throw new Error("mode not found: "+l)};b.prototype.getCurrMode=function a(){return this.options.modes[this.currModeIndex]};b.prototype.getMode=function g(l){if(!l){return this.getCurrMode()}return this.options.modes[(this._getModeIndex(l))]};b.prototype.hasMode=function k(l){return !!this.getMode(l)};b.prototype.currentMode=function e(){return this.options.modes[this.currModeIndex]};b.prototype.setMode=function c(m){var l=this.getMode(m);this.$element.html(l.html||null);return this};b.prototype._incModeIndex=function d(){this.currModeIndex+=1;if(this.currModeIndex>=this.options.modes.length){this.currModeIndex=0}return this};b.prototype.callModeFn=function h(l){var m=this.getMode(l).onclick;if(m&&jQuery.type(m==="function")){return m.call(this)}return undefined};jQuery.fn.extend({modeButton:function i(m){var l=jQuery.makeArray(arguments).slice(1);return this.map(function(){var p=$(this),o=p.data("mode-button");if(jQuery.type(m)==="object"){o=new b(p,m);p.data("mode-button",o)}else{if(o&&jQuery.type(m)==="string"){var n=o[m];if(jQuery.type(n)==="function"){return n.apply(o,l)}}else{if(o){return o}}}return this})}})}());function dropDownSelect(b,c){c=c||((!_.isEmpty(b))?(b[0]):(""));var a=$(['<div class="dropdown-select btn-group">','<button type="button" class="btn btn-default">','<span class="dropdown-select-selected">'+c+"</span>","</button>","</div>"].join("\n"));if(b&&b.length>1){a.find("button").addClass("dropdown-toggle").attr("data-toggle","dropdown").append(' <span class="caret"></span>');a.append(['<ul class="dropdown-menu" role="menu">',_.map(b,function(e){return['<li><a href="javascript:void(0)">',e,"</a></li>"].join("")}).join("\n"),"</ul>"].join("\n"))}function d(g){var h=$(this),f=h.parents(".dropdown-select"),e=h.text();f.find(".dropdown-select-selected").text(e);f.trigger("change.dropdown-select",e)}a.find("a").click(d);return a}(function(){function e(k,j){return this.init(k,j)}e.prototype.DATA_KEY="filter-control";e.prototype.init=function g(k,j){j=j||{filters:[]};this.$element=$(k).addClass("filter-control btn-group");this.options=jQuery.extend(true,{},this.defaults,j);this.currFilter=this.options.filters[0];return this.render()};e.prototype.render=function d(){this.$element.empty().append([this._renderKeySelect(),this._renderOpSelect(),this._renderValueInput()]);return this};e.prototype._renderKeySelect=function a(){var j=this;var k=this.options.filters.map(function(l){return l.key});this.$keySelect=dropDownSelect(k,this.currFilter.key).addClass("filter-control-key").on("change.dropdown-select",function(m,l){j.currFilter=_.findWhere(j.options.filters,{key:l});j.render()._triggerChange()});return this.$keySelect};e.prototype._renderOpSelect=function i(){var j=this,k=this.currFilter.ops;this.$opSelect=dropDownSelect(k,k[0]).addClass("filter-control-op").on("change.dropdown-select",function(m,l){j._triggerChange()});return this.$opSelect};e.prototype._renderValueInput=function c(){var j=this;if(this.currFilter.values){this.$valueSelect=dropDownSelect(this.currFilter.values,this.currFilter.values[0]).on("change.dropdown-select",function(l,k){j._triggerChange()})}else{this.$valueSelect=$("<input/>").addClass("form-control").on("change",function(k,l){j._triggerChange()})}this.$valueSelect.addClass("filter-control-value");return this.$valueSelect};e.prototype.val=function b(){var k=this.$element.find(".filter-control-key .dropdown-select-selected").text(),m=this.$element.find(".filter-control-op .dropdown-select-selected").text(),j=this.$element.find(".filter-control-value"),l=(j.hasClass("dropdown-select"))?(j.find(".dropdown-select-selected").text()):(j.val());return{key:k,op:m,value:l}};e.prototype._triggerChange=function h(){this.$element.trigger("change.filter-control",this.val())};jQuery.fn.extend({filterControl:function f(k){var j=jQuery.makeArray(arguments).slice(1);return this.map(function(){var n=$(this),m=n.data(e.prototype.DATA_KEY);if(jQuery.type(k)==="object"){m=new e(n,k);n.data(e.prototype.DATA_KEY,m)}if(m&&jQuery.type(k)==="string"){var l=m[k];if(jQuery.type(l)==="function"){return l.apply(m,j)}}return this})}})}());(function(){function i(o,n){this.numPages=null;this.currPage=0;return this.init(o,n)}i.prototype.DATA_KEY="pagination";i.prototype.defaults={startingPage:0,perPage:20,totalDataSize:null,currDataSize:null};i.prototype.init=function g(n,o){o=o||{};this.$element=n;this.options=jQuery.extend(true,{},this.defaults,o);this.currPage=this.options.startingPage;if(this.options.totalDataSize!==null){this.numPages=Math.ceil(this.options.totalDataSize/this.options.perPage);if(this.currPage>=this.numPages){this.currPage=this.numPages-1}}this.$element.data(i.prototype.DATA_KEY,this);this._render();return this};function m(n){return $(['<li><a href="javascript:void(0);">',n,"</a></li>"].join(""))}i.prototype._render=function e(){if(this.options.totalDataSize===0){return this}if(this.numPages===1){return this}if(this.numPages>0){this._renderPages();this._scrollToActivePage()}else{this._renderPrevNext()}return this};i.prototype._renderPrevNext=function b(){var o=this,p=m("Prev"),n=m("Next"),q=$("<ul/>").addClass("pagination pagination-prev-next");if(this.currPage===0){p.addClass("disabled")}else{p.click(function(){o.prevPage()})}if((this.numPages&&this.currPage===(this.numPages-1))||(this.options.currDataSize&&this.options.currDataSize<this.options.perPage)){n.addClass("disabled")}else{n.click(function(){o.nextPage()})}this.$element.html(q.append([p,n]));return this.$element};i.prototype._renderPages=function a(){var n=this,q=$("<div>").addClass("pagination-scroll-container"),s=$("<ul/>").addClass("pagination pagination-page-list"),r=function(t){n.goToPage($(this).data("page"))};for(var o=0;o<this.numPages;o+=1){var p=m(o+1).attr("data-page",o).click(r);if(o===this.currPage){p.addClass("active")}s.append(p)}return this.$element.html(q.html(s))};i.prototype._scrollToActivePage=function l(){var p=this.$element.find(".pagination-scroll-container");if(!p.size()){return this}var o=this.$element.find("li.active"),n=p.width()/2;p.scrollLeft(p.scrollLeft()+o.position().left-n);return this};i.prototype.goToPage=function j(n){if(n<=0){n=0}if(this.numPages&&n>=this.numPages){n=this.numPages-1}if(n===this.currPage){return this}this.currPage=n;this.$element.trigger("pagination.page-change",this.currPage);this._render();return this};i.prototype.prevPage=function c(){return this.goToPage(this.currPage-1)};i.prototype.nextPage=function h(){return this.goToPage(this.currPage+1)};i.prototype.page=function f(){return this.currPage};i.create=function k(n,o){return new i(n,o)};jQuery.fn.extend({pagination:function d(o){var n=jQuery.makeArray(arguments).slice(1);if(jQuery.type(o)==="object"){return this.map(function(){i.create($(this),o);return this})}var q=$(this[0]),r=q.data(i.prototype.DATA_KEY);if(r){if(jQuery.type(o)==="string"){var p=r[o];if(jQuery.type(p)==="function"){return p.apply(r,n)}}else{return r}}return undefined}})}());(function(){var g={renameColumns:false,columnNames:[],commentChar:"#",hideCommentRows:false,includePrompts:true,topLeftContent:"Columns:"},s="peek-control.change",t="peek-control.rename",l="peek-control",v="control",f="control-prompt",c="selected",n="disabled",u="button",q="renamable-header",p="column-index",a="column-name";function i(w){if(w.disabled&&jQuery.type(w.disabled)!=="array"){throw new Error('"disabled" must be defined as an array of indeces: '+JSON.stringify(w))}if(w.multiselect&&w.selected&&jQuery.type(w.selected)!=="array"){throw new Error('Mulitselect rows need an array for "selected": '+JSON.stringify(w))}if(!w.label||!w.id){throw new Error("Peek controls need a label and id for each control row: "+JSON.stringify(w))}if(w.disabled&&w.disabled.indexOf(w.selected)!==-1){throw new Error("Selected column is in the list of disabled columns: "+JSON.stringify(w))}return w}function o(x,w){return $("<div/>").addClass(u).text(x.label)}function k(x,w){var y=$("<td/>").html(o(x,w)).attr("data-"+p,w);if(x.disabled&&x.disabled.indexOf(w)!==-1){y.addClass(n)}return y}function e(y,z,w){var x=y.children("."+u);if(y.hasClass(c)){x.html((z.selectedText!==undefined)?(z.selectedText):(z.label))}else{x.html((z.unselectedText!==undefined)?(z.unselectedText):(z.label))}}function h(z,x){var y=k(z,x);if(z.selected===x){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);if(!E.hasClass(c)){var A=E.parent().children("."+c).removeClass(c);A.each(function(){e($(this),z,x)});E.addClass(c);e(E,z,x);var C={},B=E.parent().attr("id"),F=E.data(p);C[B]=F;E.parents(".peek").trigger(s,C)}})}return y}function m(z,x){var y=k(z,x);if(z.selected&&z.selected.indexOf(x)!==-1){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);E.toggleClass(c);e(E,z,x);var C=E.parent().find("."+c).map(function(G,H){return $(H).data(p)});var B={},A=E.parent().attr("id"),F=jQuery.makeArray(C);B[A]=F;E.parents(".peek").trigger(s,B)})}return y}function j(y,z){var w=[];for(var x=0;x<y;x+=1){w.push(z.multiselect?m(z,x):h(z,x))}return w}function r(y,z,x){var A=$("<tr/>").attr("id",z.id).addClass(v);if(x){var w=$("<td/>").addClass(f).text(z.label+":");A.append(w)}A.append(j(y,z));return A}function b(E){E=jQuery.extend(true,{},g,E);var D=$(this).addClass(l),A=D.find("table"),z=A.find("th").size(),C=A.find("tr").size(),w=A.find("td[colspan]").map(function(H,F){var G=$(this);if(G.text()&&G.text().match(new RegExp("^"+E.commentChar))){return $(this).css("color","grey").parent().get(0)}return null});if(E.hideCommentRows){w.hide();C-=w.size()}if(E.includePrompts){var y=$("<th/>").addClass("top-left").text(E.topLeftContent).attr("rowspan",C);A.find("tr").first().prepend(y)}var B=A.find("th:not(.top-left)").each(function(G,I){var H=$(this),J=H.text().replace(/^\d+\.*/,""),F=E.columnNames[G]||J;H.attr("data-"+a,F).text((G+1)+((F)?("."+F):("")))});if(E.renameColumns){B.addClass(q).click(function x(){var G=$(this),F=G.index()+(E.includePrompts?0:1),I=G.data(a),H=prompt("New column name:",I);if(H!==null&&H!==I){G.text(F+(H?("."+H):"")).data(a,H).attr("data-",a,H);var J=jQuery.makeArray(G.parent().children("th:not(.top-left)").map(function(){return $(this).data(a)}));G.parents(".peek").trigger(t,J)}})}E.controls.forEach(function(G,F){i(G);var H=r(z,G,E.includePrompts);A.find("tbody").append(H)});return this}jQuery.fn.extend({peekControl:function d(w){return this.map(function(){return b.call(this,w)})}})}());
\ No newline at end of file
+var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.create=function _create(b,a){return new PopupMenu(b,a)};PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b}(function(){function a(j,p){var d=27,m=13,c=$(j),e=true,g={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(q){},minSearchLen:0,escWillClear:true,oninit:function(){}};function i(q){var r=$(this).parent().children("input");r.val("");r.trigger("clear:searchInput");p.onclear()}function o(r,q){$(this).trigger("search:searchInput",q);if(typeof p.onfirstsearch==="function"&&e){e=false;p.onfirstsearch(q)}else{p.onsearch(q)}}function f(){return['<input type="text" name="',p.name,'" placeholder="',p.placeholder,'" ','class="search-query ',p.classes,'" ',"/>"].join("")}function l(){return $(f()).focus(function(q){$(this).select()}).keyup(function(r){if(r.which===d&&p.escWillClear){i.call(this,r)}else{var q=$(this).val();if((r.which===m)||(p.minSearchLen&&q.length>=p.minSearchLen)){o.call(this,r,q)}else{if(!q.length){i.call(this,r)}}}}).val(p.initialVal)}function k(){return $(['<span class="search-clear fa fa-times-circle" ','title="',_l("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(q){i.call(this,q)})}function n(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',_l("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function h(){c.find(".search-loading").toggle();c.find(".search-clear").toggle()}if(jQuery.type(p)==="string"){if(p==="toggle-loading"){h()}return c}if(jQuery.type(p)==="object"){p=jQuery.extend(true,{},g,p)}return c.addClass("search-input").prepend([l(),k(),n()])}jQuery.fn.extend({searchInput:function b(c){return this.each(function(){return a(this,c)})}})}());(function(){function c(o,n){this.currModeIndex=0;return this._init(o,n)}c.prototype.DATA_KEY="mode-button";c.prototype.defaults={switchModesOnClick:true};c.prototype._init=function j(o,n){n=n||{};this.$element=$(o);this.options=jQuery.extend(true,{},this.defaults,n);if(!n.modes){throw new Error('ModeButton requires a "modes" array')}var q=this;this.$element.click(function p(r){q.callModeFn();if(q.options.switchModesOnClick){q._incModeIndex()}$(this).html(q.options.modes[q.currModeIndex].html)});return this.reset()};c.prototype._incModeIndex=function l(){this.currModeIndex+=1;if(this.currModeIndex>=this.options.modes.length){this.currModeIndex=0}return this};c.prototype._getModeIndex=function f(n){for(var o=0;o<this.options.modes.length;o+=1){if(this.options.modes[o].mode===n){return o}}throw new Error("mode not found: "+n)};c.prototype._setModeByIndex=function m(n){var o=this.options.modes[n];if(!o){throw new Error("mode index not found: "+n)}this.currModeIndex=n;if(o.html){this.$element.html(o.html)}return this};c.prototype.currentMode=function d(){return this.options.modes[this.currModeIndex]};c.prototype.current=function i(){return this.currentMode().mode};c.prototype.getMode=function g(n){if(!n){return this.currentMode()}return this.options.modes[(this._getModeIndex(n))]};c.prototype.hasMode=function b(n){try{return !!this.getMode(n)}catch(o){}return false};c.prototype.setMode=function a(n){return this._setModeByIndex(this._getModeIndex(n))};c.prototype.reset=function h(){this.currModeIndex=0;if(this.options.initialMode){this.currModeIndex=this._getModeIndex(this.options.initialMode)}return this._setModeByIndex(this.currModeIndex)};c.prototype.callModeFn=function e(n){var o=this.getMode(n).onclick;if(o&&jQuery.type(o==="function")){o.call(this.$element.get(0));return this}return undefined};jQuery.fn.extend({modeButton:function k(n){if(!this.size()){return this}if(jQuery.type(n)==="object"){return this.map(function(){var r=$(this);r.data("mode-button",new c(r,n));return this})}var p=$(this[0]),o=p.data("mode-button");console.debug("first, button",p,o);if(!o){throw new Error("modeButton needs an options object or string name of a function")}if(o&&jQuery.type(n)==="string"){var q=n;if(o&&jQuery.type(o[q])==="function"){return o[q].apply(o,jQuery.makeArray(arguments).slice(1))}}return o}})}());function dropDownSelect(b,c){c=c||((!_.isEmpty(b))?(b[0]):(""));var a=$(['<div class="dropdown-select btn-group">','<button type="button" class="btn btn-default">','<span class="dropdown-select-selected">'+c+"</span>","</button>","</div>"].join("\n"));if(b&&b.length>1){a.find("button").addClass("dropdown-toggle").attr("data-toggle","dropdown").append(' <span class="caret"></span>');a.append(['<ul class="dropdown-menu" role="menu">',_.map(b,function(e){return['<li><a href="javascript:void(0)">',e,"</a></li>"].join("")}).join("\n"),"</ul>"].join("\n"))}function d(g){var h=$(this),f=h.parents(".dropdown-select"),e=h.text();f.find(".dropdown-select-selected").text(e);f.trigger("change.dropdown-select",e)}a.find("a").click(d);return a}(function(){function e(k,j){return this.init(k,j)}e.prototype.DATA_KEY="filter-control";e.prototype.init=function g(k,j){j=j||{filters:[]};this.$element=$(k).addClass("filter-control btn-group");this.options=jQuery.extend(true,{},this.defaults,j);this.currFilter=this.options.filters[0];return this.render()};e.prototype.render=function d(){this.$element.empty().append([this._renderKeySelect(),this._renderOpSelect(),this._renderValueInput()]);return this};e.prototype._renderKeySelect=function a(){var j=this;var k=this.options.filters.map(function(l){return l.key});this.$keySelect=dropDownSelect(k,this.currFilter.key).addClass("filter-control-key").on("change.dropdown-select",function(m,l){j.currFilter=_.findWhere(j.options.filters,{key:l});j.render()._triggerChange()});return this.$keySelect};e.prototype._renderOpSelect=function i(){var j=this,k=this.currFilter.ops;this.$opSelect=dropDownSelect(k,k[0]).addClass("filter-control-op").on("change.dropdown-select",function(m,l){j._triggerChange()});return this.$opSelect};e.prototype._renderValueInput=function c(){var j=this;if(this.currFilter.values){this.$valueSelect=dropDownSelect(this.currFilter.values,this.currFilter.values[0]).on("change.dropdown-select",function(l,k){j._triggerChange()})}else{this.$valueSelect=$("<input/>").addClass("form-control").on("change",function(k,l){j._triggerChange()})}this.$valueSelect.addClass("filter-control-value");return this.$valueSelect};e.prototype.val=function b(){var k=this.$element.find(".filter-control-key .dropdown-select-selected").text(),m=this.$element.find(".filter-control-op .dropdown-select-selected").text(),j=this.$element.find(".filter-control-value"),l=(j.hasClass("dropdown-select"))?(j.find(".dropdown-select-selected").text()):(j.val());return{key:k,op:m,value:l}};e.prototype._triggerChange=function h(){this.$element.trigger("change.filter-control",this.val())};jQuery.fn.extend({filterControl:function f(k){var j=jQuery.makeArray(arguments).slice(1);return this.map(function(){var n=$(this),m=n.data(e.prototype.DATA_KEY);if(jQuery.type(k)==="object"){m=new e(n,k);n.data(e.prototype.DATA_KEY,m)}if(m&&jQuery.type(k)==="string"){var l=m[k];if(jQuery.type(l)==="function"){return l.apply(m,j)}}return this})}})}());(function(){function i(o,n){this.numPages=null;this.currPage=0;return this.init(o,n)}i.prototype.DATA_KEY="pagination";i.prototype.defaults={startingPage:0,perPage:20,totalDataSize:null,currDataSize:null};i.prototype.init=function g(n,o){o=o||{};this.$element=n;this.options=jQuery.extend(true,{},this.defaults,o);this.currPage=this.options.startingPage;if(this.options.totalDataSize!==null){this.numPages=Math.ceil(this.options.totalDataSize/this.options.perPage);if(this.currPage>=this.numPages){this.currPage=this.numPages-1}}this.$element.data(i.prototype.DATA_KEY,this);this._render();return this};function m(n){return $(['<li><a href="javascript:void(0);">',n,"</a></li>"].join(""))}i.prototype._render=function e(){if(this.options.totalDataSize===0){return this}if(this.numPages===1){return this}if(this.numPages>0){this._renderPages();this._scrollToActivePage()}else{this._renderPrevNext()}return this};i.prototype._renderPrevNext=function b(){var o=this,p=m("Prev"),n=m("Next"),q=$("<ul/>").addClass("pagination pagination-prev-next");if(this.currPage===0){p.addClass("disabled")}else{p.click(function(){o.prevPage()})}if((this.numPages&&this.currPage===(this.numPages-1))||(this.options.currDataSize&&this.options.currDataSize<this.options.perPage)){n.addClass("disabled")}else{n.click(function(){o.nextPage()})}this.$element.html(q.append([p,n]));return this.$element};i.prototype._renderPages=function a(){var n=this,q=$("<div>").addClass("pagination-scroll-container"),s=$("<ul/>").addClass("pagination pagination-page-list"),r=function(t){n.goToPage($(this).data("page"))};for(var o=0;o<this.numPages;o+=1){var p=m(o+1).attr("data-page",o).click(r);if(o===this.currPage){p.addClass("active")}s.append(p)}return this.$element.html(q.html(s))};i.prototype._scrollToActivePage=function l(){var p=this.$element.find(".pagination-scroll-container");if(!p.size()){return this}var o=this.$element.find("li.active"),n=p.width()/2;p.scrollLeft(p.scrollLeft()+o.position().left-n);return this};i.prototype.goToPage=function j(n){if(n<=0){n=0}if(this.numPages&&n>=this.numPages){n=this.numPages-1}if(n===this.currPage){return this}this.currPage=n;this.$element.trigger("pagination.page-change",this.currPage);this._render();return this};i.prototype.prevPage=function c(){return this.goToPage(this.currPage-1)};i.prototype.nextPage=function h(){return this.goToPage(this.currPage+1)};i.prototype.page=function f(){return this.currPage};i.create=function k(n,o){return new i(n,o)};jQuery.fn.extend({pagination:function d(o){var n=jQuery.makeArray(arguments).slice(1);if(jQuery.type(o)==="object"){return this.map(function(){i.create($(this),o);return this})}var q=$(this[0]),r=q.data(i.prototype.DATA_KEY);if(r){if(jQuery.type(o)==="string"){var p=r[o];if(jQuery.type(p)==="function"){return p.apply(r,n)}}else{return r}}return undefined}})}());(function(){var g={renameColumns:false,columnNames:[],commentChar:"#",hideCommentRows:false,includePrompts:true,topLeftContent:"Columns:"},s="peek-control.change",t="peek-control.rename",l="peek-control",v="control",f="control-prompt",c="selected",n="disabled",u="button",q="renamable-header",p="column-index",a="column-name";function i(w){if(w.disabled&&jQuery.type(w.disabled)!=="array"){throw new Error('"disabled" must be defined as an array of indeces: '+JSON.stringify(w))}if(w.multiselect&&w.selected&&jQuery.type(w.selected)!=="array"){throw new Error('Mulitselect rows need an array for "selected": '+JSON.stringify(w))}if(!w.label||!w.id){throw new Error("Peek controls need a label and id for each control row: "+JSON.stringify(w))}if(w.disabled&&w.disabled.indexOf(w.selected)!==-1){throw new Error("Selected column is in the list of disabled columns: "+JSON.stringify(w))}return w}function o(x,w){return $("<div/>").addClass(u).text(x.label)}function k(x,w){var y=$("<td/>").html(o(x,w)).attr("data-"+p,w);if(x.disabled&&x.disabled.indexOf(w)!==-1){y.addClass(n)}return y}function e(y,z,w){var x=y.children("."+u);if(y.hasClass(c)){x.html((z.selectedText!==undefined)?(z.selectedText):(z.label))}else{x.html((z.unselectedText!==undefined)?(z.unselectedText):(z.label))}}function h(z,x){var y=k(z,x);if(z.selected===x){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);if(!E.hasClass(c)){var A=E.parent().children("."+c).removeClass(c);A.each(function(){e($(this),z,x)});E.addClass(c);e(E,z,x);var C={},B=E.parent().attr("id"),F=E.data(p);C[B]=F;E.parents(".peek").trigger(s,C)}})}return y}function m(z,x){var y=k(z,x);if(z.selected&&z.selected.indexOf(x)!==-1){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);E.toggleClass(c);e(E,z,x);var C=E.parent().find("."+c).map(function(G,H){return $(H).data(p)});var B={},A=E.parent().attr("id"),F=jQuery.makeArray(C);B[A]=F;E.parents(".peek").trigger(s,B)})}return y}function j(y,z){var w=[];for(var x=0;x<y;x+=1){w.push(z.multiselect?m(z,x):h(z,x))}return w}function r(y,z,x){var A=$("<tr/>").attr("id",z.id).addClass(v);if(x){var w=$("<td/>").addClass(f).text(z.label+":");A.append(w)}A.append(j(y,z));return A}function b(E){E=jQuery.extend(true,{},g,E);var D=$(this).addClass(l),A=D.find("table"),z=A.find("th").size(),C=A.find("tr").size(),w=A.find("td[colspan]").map(function(H,F){var G=$(this);if(G.text()&&G.text().match(new RegExp("^"+E.commentChar))){return $(this).css("color","grey").parent().get(0)}return null});if(E.hideCommentRows){w.hide();C-=w.size()}if(E.includePrompts){var y=$("<th/>").addClass("top-left").text(E.topLeftContent).attr("rowspan",C);A.find("tr").first().prepend(y)}var B=A.find("th:not(.top-left)").each(function(G,I){var H=$(this),J=H.text().replace(/^\d+\.*/,""),F=E.columnNames[G]||J;H.attr("data-"+a,F).text((G+1)+((F)?("."+F):("")))});if(E.renameColumns){B.addClass(q).click(function x(){var G=$(this),F=G.index()+(E.includePrompts?0:1),I=G.data(a),H=prompt("New column name:",I);if(H!==null&&H!==I){G.text(F+(H?("."+H):"")).data(a,H).attr("data-",a,H);var J=jQuery.makeArray(G.parent().children("th:not(.top-left)").map(function(){return $(this).data(a)}));G.parents(".peek").trigger(t,J)}})}E.controls.forEach(function(G,F){i(G);var H=r(z,G,E.includePrompts);A.find("tbody").append(H)});return this}jQuery.fn.extend({peekControl:function d(w){return this.map(function(){return b.call(this,w)})}})}());
\ No newline at end of file
diff -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 templates/webapps/galaxy/history/original_view.mako
--- a/templates/webapps/galaxy/history/original_view.mako
+++ /dev/null
@@ -1,173 +0,0 @@
-<%namespace file="/display_common.mako" import="get_history_link, get_controller_name" />
-<%namespace file="/root/history_common.mako" import="render_dataset" />
-<%namespace file="/tagging_common.mako" import="render_individual_tagging_element, render_community_tagging_element" />
-
-<%!
- def inherit(context):
- if context.get('use_panels'):
- return '/webapps/galaxy/base_panels.mako'
- else:
- return '/base.mako'
-%>
-<%inherit file="${inherit(context)}"/>
-
-<%def name="javascripts()">
- ${parent.javascripts()}
- ${h.js( "libs/jquery/jstorage" )}
- <script type="text/javascript">
- $(function() {
- init_history_items( $("div.historyItemWrapper"), false, "nochanges" );
- $( '#switch-to-link' ).click( function( event ){
- var galaxy = window.Galaxy || window.parent.Galaxy;
- if( galaxy ){
- galaxy.currHistoryPanel.switchToHistory( '${ trans.security.encode_id( history.id ) }' );
- }
- });
- $( '#refresh' ).click( function( event ){ window.location.reload( true ); })
- });
- </script>
-</%def>
-
-<%def name="stylesheets()">
- ${parent.stylesheets()}
- ${h.css( "history", "autocomplete_tagging" )}
-
- <style type="text/css">
-
- /* these don't appear to be used? */
- .page-body
- {
- padding: 10px;
- float: left;
- width: 65%;
- }
- .page-meta
- {
- float: right;
- width: 27%;
- padding: 0.5em;
- margin: 0.25em;
- vertical-align: text-top;
- border: 2px solid #DDDDDD;
- border-top: 4px solid #DDDDDD;
- }
-
-
- body {
- padding: 0px;
- margin: 0px;
- }
-
- div.unified-panel-body {
- position: absolute;
- top: 0px;
- width: 100%;
- }
-
- #history-name-area {
- margin: 12px 0px 0px 16px;
- font-size: 120%;
- }
- #top-links {
- margin: 4px 0px 8px 16px;
- }
-
- .historyItemContainer {
- /*padding-right: 3px;*/
- }
- .historyItemBody {
- display: none;
- }
- div.historyItemWrapper {
- margin: 0px 4px 0px 4px ;
- border-left: 1px solid #999999;
- border-right: 1px solid #999999;
- }
- /* TODO: unify with other history css and into .less */
- </style>
-
- <noscript>
- <style>
- .historyItemBody {
- display: block;
- }
- </style>
- </noscript>
-</%def>
-
-<%def name="init()">
-<%
- self.has_left_panel=False
- self.has_right_panel=False
- self.message_box_visible=False
-%>
-</%def>
-
-<%def name="body()">
- ${center_panel()}
-</%def>
-
-<%def name="center_panel()">
- ## Get URL to other histories owned by user that owns this history.
- <%
- ##TODO: is there a better way to create this URL? Can't use 'f-username' as a key b/c it's not a valid identifier.
- href_to_published_histories = h.url_for( controller='/history', action='list_published')
- if history.user is not None:
- href_to_user_histories = h.url_for( controller='/history', action='list_published', xxx=history.user.username).replace( 'xxx', 'f-username')
- else:
- href_to_user_histories = h.url_for( controller='/history', action='list_published' )##should this instead be be None or empty string?
- %>
-
- <div class="unified-panel-body">
- <div style="overflow: auto; height: 100%;">
- ## Render view of history.
- <div id="history-name-area" class="historyLinks" style="color: gray; font-weight: bold; padding: 0px 0px 5px 0px">
- <div id="history-name">${history.get_display_name()}</div>
- </div>
-
- <div id="top-links" class="historyLinks" style="padding: 0px 0px 5px 0px">
- %if not history.purged and history.user != trans.user:
- ##TODO: need to remove _top
- <a href="${h.url_for(controller='history', action='imp', id=trans.security.encode_id(history.id) )}"
- >import and start using history</a> |
- <a id="refresh" href="javascript:void(0)" >${_('refresh')}</a> |
- %endif
- %if not history.purged and history.user == trans.user:
- <a id="switch-to-link" href="javascript:void(0)">${_('switch to this history')}</a> |
- <a id="refresh" href="javascript:void(0)" >${_('refresh')}</a> |
- %endif
- %if show_deleted:
- <a href="${h.url_for(controller='history', action='view', id=trans.security.encode_id(history.id), show_deleted=False, use_panels=use_panels )}">${_('hide deleted')}</a> |
- %else:
- <a href="${h.url_for(controller='history', action='view', id=trans.security.encode_id(history.id), show_deleted=True, use_panels=use_panels )}">${_('show deleted')}</a> |
- %endif
- <a href="#" class="toggle">collapse all</a>
- </div>
-
- %if history.deleted:
- <div class="warningmessagesmall">
- ${_('You are currently viewing a deleted history!')}
- </div>
- <p></p>
- %endif
-
- %if not datasets:
- <div class="infomessagesmall" id="emptyHistoryMessage">
-
- %else:
- ## Render requested datasets, ordered from newest to oldest
- %for data in datasets:
- %if data.visible:
- <div class="historyItemContainer visible-right-border" id="historyItemContainer-${data.id}">
- ${render_dataset( data, data.hid, show_deleted_on_refresh = show_deleted, for_editing=False )}
- </div>
- %endif
- %endfor
-
- <div class="infomessagesmall" id="emptyHistoryMessage" style="display:none;">
- %endif
- ${_("Your history is empty. Click 'Get Data' on the left pane to start")}
- </div>
- </div>
- </div>
-</%def>
diff -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 templates/webapps/galaxy/history/view.mako
--- a/templates/webapps/galaxy/history/view.mako
+++ b/templates/webapps/galaxy/history/view.mako
@@ -77,6 +77,7 @@
%endif
<script type="text/javascript">
+ ##TODO: remove when Galaxy is either ensured or removed from the history panel
var using_panels = ${ 'false' if not use_panels else 'true' };
%if not use_panels:
window.Galaxy = {};
@@ -87,113 +88,107 @@
## ----------------------------------------------------------------------------
<%def name="center_panel()">
+<%
+ show_deleted = context.get( 'show_deleted', None )
+ show_hidden = context.get( 'show_hidden', None )
+
+ user_is_owner_json = 'true' if user_is_owner else 'false'
+ show_deleted_json = h.to_json_string( show_deleted )
+ show_hidden_json = h.to_json_string( show_hidden )
+
+ imp_with_deleted_url = h.url_for( controller='history', action='imp', id=history['id'], all_datasets=True )
+ imp_without_deleted_url = h.url_for( controller='history', action='imp', id=history['id'] )
+%>
+
<div id="header" class="clear"><div id="history-view-controls" class="pull-right">
- <%
- show_deleted = context.get( 'show_deleted', None )
- show_hidden = context.get( 'show_hidden', None )
-
- show_deleted_js = 'true' if show_deleted == True else ( 'null' if show_deleted == None else 'false' )
- show_hidden_js = 'true' if show_hidden == True else ( 'null' if show_hidden == None else 'false' )
- print 'user_is_owner:', user_is_owner
- %>
%if not user_is_owner and not history[ 'purged' ]:
- <a id="import" class="btn btn-default" style="display: none;"
- href="${h.url_for( controller='history', action='imp', id=history['id'], all_datasets=show_deleted )}">
- ${_('Import and start using history')}
- </a>
+ <button id="import" class="btn btn-default"></button>
%endif
- <button id="toggle-deleted" class="btn btn-default">
- ${_('Exclude deleted') if show_deleted else _('Include deleted')}
- </button>
- <button id="toggle-hidden" class="btn btn-default">
- ${_('Exclude hidden') if show_hidden else _('Include hidden')}
- </button>
+ <button id="toggle-deleted" class="btn btn-default"></button>
+ <button id="toggle-hidden" class="btn btn-default"></button></div></div><div id="history-${ history[ 'id' ] }" class="history-panel unified-panel-body" style="overflow: auto;"></div><script type="text/javascript">
+ $(function(){
+ $( '#toggle-deleted' ).modeButton({
+ initialMode : "${ 'showing_deleted' if show_deleted else 'not_showing_deleted' }",
+ modes: [
+ { mode: 'showing_deleted', html: _l( 'Exclude deleted' ) },
+ { mode: 'not_showing_deleted', html: _l( 'Include deleted' ) }
+ ]
+ }).click( function(){
+ // allow the 'include/exclude deleted' button to control whether the 'import' button includes deleted
+ // datasets when importing or not; when deleted datasets are shown, they'll be imported
+ $( '#import' ).modeButton( 'setMode',
+ $( this ).modeButton( 'current' ) === 'showing_deleted'? 'with_deleted': 'without_deleted' )
+ });
+
+ $( '#toggle-hidden' ).modeButton({
+ initialMode : "${ 'showing_hidden' if show_hidden else 'not_showing_hidden' }",
+ modes: [
+ { mode: 'showing_hidden', html: _l( 'Exclude hidden' ) },
+ { mode: 'not_showing_hidden', html: _l( 'Include hidden' ) }
+ ]
+ });
+
+ $( '#import' ).modeButton({
+ switchModesOnClick : false,
+ initialMode : "${ 'with_deleted' if show_deleted else 'without_deleted' }",
+ modes: [
+ { mode: 'with_deleted', html: _l( 'Import with deleted datasets and start using history' ),
+ onclick: function importWithDeleted(){
+ window.location = '${imp_with_deleted_url}';
+ }
+ },
+ { mode: 'without_deleted', html: _l( 'Import and start using history' ),
+ onclick: function importWithoutDeleted(){
+ window.location = '${imp_without_deleted_url}';
+ }
+ },
+ ]
+ });
+ });
+
var debugging = JSON.parse( sessionStorage.getItem( 'debugging' ) ) || false,
userIsOwner = ${'true' if user_is_owner else 'false'},
historyJSON = ${h.to_json_string( history )},
hdaJSON = ${h.to_json_string( hdas )};
- window.hdaJSON = hdaJSON;
-
- $( '#toggle-deleted' ).modeButton({
- initialMode : (${ show_deleted_js })?( 'exclude' ):( 'include' ),
- modes: [
- { mode: 'exclude', html: _l( 'Exclude deleted' ) },
- { mode: 'include', html: _l( 'Include deleted' ) }
- ]
- }).click( function(){
- // allow the 'include/exclude deleted' button to control whether the 'import' button includes deleted datasets
- // when importing or not; when deleted datasets are shown, they'll be imported
- var $importBtn = $( '#import' );
- if( $importBtn.size() ){
- // a bit hacky
- var href = $importBtn.attr( 'href' ),
- includeDeleted = $( this ).modeButton()[0].getMode().mode === 'exclude';
- href = href.replace( /all_datasets=True|False/, ( includeDeleted )?( 'True' ):( 'False' ) );
- $importBtn.attr( 'href', href );
- $importBtn.text( includeDeleted ? _l( 'Import with deleted datasets and start using history' )
- : _l( 'Import and start using history' ) );
- }
- });
-
- $( '#toggle-hidden' ).modeButton({
- initialMode : (${ show_hidden_js })?( 'exclude' ):( 'include' ),
- modes: [
- { mode: 'exclude', html: _l( 'Exclude hidden' ) },
- { mode: 'include', html: _l( 'Include hidden' ) }
- ]
- });
-
- ##TODO: move to mako
- if( Galaxy.currUser.id !== historyJSON.user_id ){
- $( '#import' ).show();
- }
+ panelToUse = ( userIsOwner )?
+ ({ location: 'mvc/history/history-panel', className: 'HistoryPanel' }):
+ ({ location: 'mvc/history/readonly-history-panel', className: 'ReadOnlyHistoryPanel' });
require.config({
baseUrl : "${h.url_for( '/static/scripts' )}"
- })([
- %if user_is_owner:
- 'mvc/history/history-panel'
- %else:
- 'mvc/history/readonly-history-panel'
- %endif
- ${ }
- ], function( panelMod ){
- //require([ "mvc/history/history-panel" ], function( historyPanel ){
- // history module is already in the dpn chain from the panel. We can re-scope it here.
- var historyModel = require( 'mvc/history/history-model' ),
- hdaBaseView = require( 'mvc/dataset/hda-base' ),
- history = new historyModel.History( historyJSON, hdaJSON, {
- logger: ( debugging )?( console ):( null )
+ })([ panelToUse.location ], function( panelMod ){
+ $(function(){
+ var panelClass = panelMod[ panelToUse.className ],
+ // history module is already in the dpn chain from the panel. We can re-scope it here.
+ historyModel = require( 'mvc/history/history-model' ),
+ hdaBaseView = require( 'mvc/dataset/hda-base' ),
+ history = new historyModel.History( historyJSON, hdaJSON, {
+ logger: ( debugging )?( console ):( null )
+ });
+
+ window.historyPanel = new panelClass({
+ show_deleted : ${show_deleted_json},
+ show_hidden : ${show_hidden_json},
+ el : $( "#history-" + historyJSON.id ),
+ model : history,
+ onready : function(){
+ var panel = this;
+ $( '#toggle-deleted' ).on( 'click', function(){
+ panel.toggleShowDeleted();
+ });
+ $( '#toggle-hidden' ).on( 'click', function(){
+ panel.toggleShowHidden();
+ });
+ this.render();
+ }
});
-
- window.panelMod = panelMod;
- %if user_is_owner:
- window.panelClass = panelMod.HistoryPanel;
- %else:
- window.panelClass = panelMod.ReadOnlyHistoryPanel;
- %endif
- window.historyPanel = new panelClass({
- show_deleted : ${show_deleted_js},
- show_hidden : ${show_hidden_js},
- el : $( "#history-" + historyJSON.id ),
- model : history,
- onready : function(){
- var panel = this;
- $( '#toggle-deleted' ).on( 'click', function(){
- panel.toggleShowDeleted();
- });
- $( '#toggle-hidden' ).on( 'click', function(){
- panel.toggleShowHidden();
- });
- this.render();
- }
});
});
</script>
diff -r 0db8172d6d363ba1010df08a79f6db435f4f0ee7 -r e51429649b44d5b434a6b6f4e10daa1dbf390c20 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -1,7 +1,6 @@
<?xml version="1.0"?><tool name="Upload File" id="upload1" version="1.1.4" workflow_compatible="false">
- <hidden>True</hidden><description>
from your computer
</description>
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: guerler: Add get data back to to tool panel (will be replaced by a placeholder soon)
by commits-noreply@bitbucket.org 19 Feb '14
by commits-noreply@bitbucket.org 19 Feb '14
19 Feb '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/742b4ffd3b99/
Changeset: 742b4ffd3b99
User: guerler
Date: 2014-02-19 18:51:52
Summary: Add get data back to to tool panel (will be replaced by a placeholder soon)
Affected #: 1 file
diff -r 7ebec9da47844efbf37942faab3809cb0169e5c2 -r 742b4ffd3b99160cae864049f09defe710dd7ee4 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -1,7 +1,6 @@
<?xml version="1.0"?><tool name="Upload File" id="upload1" version="1.1.4" workflow_compatible="false">
- <hidden>True</hidden><description>
from your computer
</description>
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: history/view: clean up, replace import link with window.location; UI mode button: several fixes, clean up, docs; Remove original_view from controllers/history (and templates)
by commits-noreply@bitbucket.org 19 Feb '14
by commits-noreply@bitbucket.org 19 Feb '14
19 Feb '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7ebec9da4784/
Changeset: 7ebec9da4784
User: carlfeberhard
Date: 2014-02-19 18:32:06
Summary: history/view: clean up, replace import link with window.location; UI mode button: several fixes, clean up, docs; Remove original_view from controllers/history (and templates)
Affected #: 5 files
diff -r c85f8fb5d63e667b63e10cdce518254f56002f55 -r 7ebec9da47844efbf37942faab3809cb0169e5c2 lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -843,35 +843,6 @@
history. <br>You can <a href="%s">continue and import this history</a> or %s.
""" % ( web.url_for(controller='history', action='imp', id=id, confirm=True, referer=trans.request.referer ), referer_message ), use_panels=True )
- # Replaced with view (below) but kept (available via manual URL editing) for now
- @web.expose
- def original_view( self, trans, id=None, show_deleted=False, use_panels=True ):
- """View a history. If a history is importable, then it is viewable by any user."""
- # Get history to view.
- if not id:
- return trans.show_error_message( "You must specify a history you want to view." )
- history_to_view = self.get_history( trans, id, False)
- # Integrity checks.
- if not history_to_view:
- return trans.show_error_message( "The specified history does not exist." )
- # Admin users can view any history
- if( ( history_to_view.user != trans.user )
- and ( not trans.user_is_admin() )
- and ( not history_to_view.importable ) ):
- error( "Either you are not allowed to view this history or the owner of this history has not made it accessible." )
- # View history.
- show_deleted = galaxy.util.string_as_bool( show_deleted )
- datasets = self.get_history_datasets( trans, history_to_view, show_deleted=show_deleted )
- try:
- use_panels = galaxy.util.string_as_bool( use_panels )
- except:
- pass # already a bool
- return trans.stream_template_mako( "history/original_view.mako",
- history = history_to_view,
- datasets = datasets,
- show_deleted = show_deleted,
- use_panels = use_panels )
-
@web.expose
def view( self, trans, id=None, show_deleted=False, show_hidden=False, use_panels=True ):
"""
diff -r c85f8fb5d63e667b63e10cdce518254f56002f55 -r 7ebec9da47844efbf37942faab3809cb0169e5c2 static/scripts/mvc/ui.js
--- a/static/scripts/mvc/ui.js
+++ b/static/scripts/mvc/ui.js
@@ -783,77 +783,110 @@
* });
* $( '.myElement' ).modeButton( 'callModeFn', 'bler' );
*/
+ /** constructor */
function ModeButton( element, options ){
this.currModeIndex = 0;
- return this.init( element, options );
+ return this._init( element, options );
}
+ /** html5 data key to store this object inside an element */
ModeButton.prototype.DATA_KEY = 'mode-button';
+ /** default options */
ModeButton.prototype.defaults = {
- modes : [
- { mode: 'default' }
- ]
+ switchModesOnClick : true
};
- ModeButton.prototype.init = function _init( element, options ){
+ // ---- private interface
+ /** set up options, intial mode, and the click handler */
+ ModeButton.prototype._init = function _init( element, options ){
+ //console.debug( 'ModeButton._init:', element, options );
options = options || {};
this.$element = $( element );
this.options = jQuery.extend( true, {}, this.defaults, options );
+ if( !options.modes ){
+ throw new Error( 'ModeButton requires a "modes" array' );
+ }
var modeButton = this;
this.$element.click( function _ModeButtonClick( event ){
-
// call the curr mode fn
modeButton.callModeFn();
// inc the curr mode index
- modeButton._incModeIndex();
+ if( modeButton.options.switchModesOnClick ){ modeButton._incModeIndex(); }
// set the element html
$( this ).html( modeButton.options.modes[ modeButton.currModeIndex ].html );
});
-
- this.currModeIndex = 0;
- if( this.options.initialMode ){
- this.currModeIndex = this._getModeIndex( this.options.initialMode );
- }
- return this;
+ return this.reset();
};
-
-
- ModeButton.prototype._getModeIndex = function __getModeIndex( modeKey ){
- for( var i=0; i<this.options.modes.length; i+=1 ){
- if( this.options.modes[ i ].mode === modeKey ){ return i; }
- }
- throw new Error( 'mode not found: ' + modeKey );
- };
- ModeButton.prototype.getCurrMode = function _getCurrMode(){
- return this.options.modes[ this.currModeIndex ];
- };
- ModeButton.prototype.getMode = function _getMode( modeKey ){
- if( !modeKey ){ return this.getCurrMode(); }
- return this.options.modes[( this._getModeIndex( modeKey ) )];
- };
- ModeButton.prototype.hasMode = function _hasMode( modeKey ){
- return !!this.getMode( modeKey );
- };
- ModeButton.prototype.currentMode = function _currentMode(){
- return this.options.modes[ this.currModeIndex ];
- };
- ModeButton.prototype.setMode = function _setMode( newModeKey ){
- var newMode = this.getMode( newModeKey );
- this.$element.html( newMode.html || null );
- return this;
- };
- ModeButton.prototype._incModeIndex = function __incModeIndex(){
+ /** increment the mode index to the next in the array, looping back to zero if at the last */
+ ModeButton.prototype._incModeIndex = function _incModeIndex(){
this.currModeIndex += 1;
if( this.currModeIndex >= this.options.modes.length ){
this.currModeIndex = 0;
}
return this;
};
- ModeButton.prototype.callModeFn = function _callModeFn( modeKey ){
+ /** get the mode index in the modes array for the given key (mode name) */
+ ModeButton.prototype._getModeIndex = function _getModeIndex( modeKey ){
+ for( var i=0; i<this.options.modes.length; i+=1 ){
+ if( this.options.modes[ i ].mode === modeKey ){ return i; }
+ }
+ throw new Error( 'mode not found: ' + modeKey );
+ };
+ /** set the current mode to the one with the given index and set button html */
+ ModeButton.prototype._setModeByIndex = function _setModeByIndex( index ){
+ var newMode = this.options.modes[ index ];
+ if( !newMode ){
+ throw new Error( 'mode index not found: ' + index );
+ }
+ this.currModeIndex = index;
+ if( newMode.html ){
+ this.$element.html( newMode.html );
+ }
+ return this;
+ };
+
+ // ---- public interface
+ /** get the current mode object (not just the mode name) */
+ ModeButton.prototype.currentMode = function currentMode(){
+ return this.options.modes[ this.currModeIndex ];
+ };
+ /** return the mode key of the current mode */
+ ModeButton.prototype.current = function current(){
+ // sugar for returning mode name
+ return this.currentMode().mode;
+ };
+ /** get the mode with the given modeKey or the current mode if modeKey is undefined */
+ ModeButton.prototype.getMode = function getMode( modeKey ){
+ if( !modeKey ){ return this.currentMode(); }
+ return this.options.modes[( this._getModeIndex( modeKey ) )];
+ };
+ /** T/F if the button has the given mode */
+ ModeButton.prototype.hasMode = function hasMode( modeKey ){
+ try {
+ return !!this.getMode( modeKey );
+ } catch( err ){}
+ return false;
+ };
+ /** set the current mode to the mode with the given name */
+ ModeButton.prototype.setMode = function setMode( modeKey ){
+ return this._setModeByIndex( this._getModeIndex( modeKey ) );
+ };
+ /** reset to the initial mode */
+ ModeButton.prototype.reset = function reset(){
+ this.currModeIndex = 0;
+ if( this.options.initialMode ){
+ this.currModeIndex = this._getModeIndex( this.options.initialMode );
+ }
+ return this._setModeByIndex( this.currModeIndex );
+ };
+ /** manually call the click handler of the given mode */
+ ModeButton.prototype.callModeFn = function callModeFn( modeKey ){
var modeFn = this.getMode( modeKey ).onclick;
if( modeFn && jQuery.type( modeFn === 'function' ) ){
- return modeFn.call( this );
+ // call with the element as context (std jquery pattern)
+ modeFn.call( this.$element.get(0) );
+ return this;
}
return undefined;
};
@@ -861,26 +894,32 @@
// as jq plugin
jQuery.fn.extend({
modeButton : function $modeButton( options ){
- var nonOptionsArgs = jQuery.makeArray( arguments ).slice( 1 );
+ if( !this.size() ){ return this; }
+
//TODO: does map still work with jq multi selection (i.e. $( '.class-for-many-btns' ).modeButton)?
- return this.map( function(){
- var $this = $( this ),
- data = $this.data( 'mode-button' );
+ if( jQuery.type( options ) === 'object' ){
+ return this.map( function(){
+ var $this = $( this );
+ $this.data( 'mode-button', new ModeButton( $this, options ) );
+ return this;
+ });
+ }
- if( jQuery.type( options ) === 'object' ){
- data = new ModeButton( $this, options );
- $this.data( 'mode-button', data );
+ var $first = $( this[0] ),
+ button = $first.data( 'mode-button' );
+ console.debug( 'first, button', $first, button );
- } else if( data && jQuery.type( options ) === 'string' ){
- var fn = data[ options ];
- if( jQuery.type( fn ) === 'function' ){
- return fn.apply( data, nonOptionsArgs );
- }
- } else if ( data ){
- return data;
+ if( !button ){
+ throw new Error( 'modeButton needs an options object or string name of a function' );
+ }
+
+ if( button && jQuery.type( options ) === 'string' ){
+ var fnName = options;
+ if( button && jQuery.type( button[ fnName ] ) === 'function' ){
+ return button[ fnName ].apply( button, jQuery.makeArray( arguments ).slice( 1 ) );
}
- return this;
- });
+ }
+ return button;
}
});
}());
diff -r c85f8fb5d63e667b63e10cdce518254f56002f55 -r 7ebec9da47844efbf37942faab3809cb0169e5c2 static/scripts/packed/mvc/ui.js
--- a/static/scripts/packed/mvc/ui.js
+++ b/static/scripts/packed/mvc/ui.js
@@ -1,1 +1,1 @@
-var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.create=function _create(b,a){return new PopupMenu(b,a)};PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b}(function(){function a(j,p){var d=27,m=13,c=$(j),e=true,g={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(q){},minSearchLen:0,escWillClear:true,oninit:function(){}};function i(q){var r=$(this).parent().children("input");r.val("");r.trigger("clear:searchInput");p.onclear()}function o(r,q){$(this).trigger("search:searchInput",q);if(typeof p.onfirstsearch==="function"&&e){e=false;p.onfirstsearch(q)}else{p.onsearch(q)}}function f(){return['<input type="text" name="',p.name,'" placeholder="',p.placeholder,'" ','class="search-query ',p.classes,'" ',"/>"].join("")}function l(){return $(f()).focus(function(q){$(this).select()}).keyup(function(r){if(r.which===d&&p.escWillClear){i.call(this,r)}else{var q=$(this).val();if((r.which===m)||(p.minSearchLen&&q.length>=p.minSearchLen)){o.call(this,r,q)}else{if(!q.length){i.call(this,r)}}}}).val(p.initialVal)}function k(){return $(['<span class="search-clear fa fa-times-circle" ','title="',_l("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(q){i.call(this,q)})}function n(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',_l("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function h(){c.find(".search-loading").toggle();c.find(".search-clear").toggle()}if(jQuery.type(p)==="string"){if(p==="toggle-loading"){h()}return c}if(jQuery.type(p)==="object"){p=jQuery.extend(true,{},g,p)}return c.addClass("search-input").prepend([l(),k(),n()])}jQuery.fn.extend({searchInput:function b(c){return this.each(function(){return a(this,c)})}})}());(function(){function b(m,l){this.currModeIndex=0;return this.init(m,l)}b.prototype.DATA_KEY="mode-button";b.prototype.defaults={modes:[{mode:"default"}]};b.prototype.init=function f(m,l){l=l||{};this.$element=$(m);this.options=jQuery.extend(true,{},this.defaults,l);var o=this;this.$element.click(function n(p){o.callModeFn();o._incModeIndex();$(this).html(o.options.modes[o.currModeIndex].html)});this.currModeIndex=0;if(this.options.initialMode){this.currModeIndex=this._getModeIndex(this.options.initialMode)}return this};b.prototype._getModeIndex=function j(l){for(var m=0;m<this.options.modes.length;m+=1){if(this.options.modes[m].mode===l){return m}}throw new Error("mode not found: "+l)};b.prototype.getCurrMode=function a(){return this.options.modes[this.currModeIndex]};b.prototype.getMode=function g(l){if(!l){return this.getCurrMode()}return this.options.modes[(this._getModeIndex(l))]};b.prototype.hasMode=function k(l){return !!this.getMode(l)};b.prototype.currentMode=function e(){return this.options.modes[this.currModeIndex]};b.prototype.setMode=function c(m){var l=this.getMode(m);this.$element.html(l.html||null);return this};b.prototype._incModeIndex=function d(){this.currModeIndex+=1;if(this.currModeIndex>=this.options.modes.length){this.currModeIndex=0}return this};b.prototype.callModeFn=function h(l){var m=this.getMode(l).onclick;if(m&&jQuery.type(m==="function")){return m.call(this)}return undefined};jQuery.fn.extend({modeButton:function i(m){var l=jQuery.makeArray(arguments).slice(1);return this.map(function(){var p=$(this),o=p.data("mode-button");if(jQuery.type(m)==="object"){o=new b(p,m);p.data("mode-button",o)}else{if(o&&jQuery.type(m)==="string"){var n=o[m];if(jQuery.type(n)==="function"){return n.apply(o,l)}}else{if(o){return o}}}return this})}})}());function dropDownSelect(b,c){c=c||((!_.isEmpty(b))?(b[0]):(""));var a=$(['<div class="dropdown-select btn-group">','<button type="button" class="btn btn-default">','<span class="dropdown-select-selected">'+c+"</span>","</button>","</div>"].join("\n"));if(b&&b.length>1){a.find("button").addClass("dropdown-toggle").attr("data-toggle","dropdown").append(' <span class="caret"></span>');a.append(['<ul class="dropdown-menu" role="menu">',_.map(b,function(e){return['<li><a href="javascript:void(0)">',e,"</a></li>"].join("")}).join("\n"),"</ul>"].join("\n"))}function d(g){var h=$(this),f=h.parents(".dropdown-select"),e=h.text();f.find(".dropdown-select-selected").text(e);f.trigger("change.dropdown-select",e)}a.find("a").click(d);return a}(function(){function e(k,j){return this.init(k,j)}e.prototype.DATA_KEY="filter-control";e.prototype.init=function g(k,j){j=j||{filters:[]};this.$element=$(k).addClass("filter-control btn-group");this.options=jQuery.extend(true,{},this.defaults,j);this.currFilter=this.options.filters[0];return this.render()};e.prototype.render=function d(){this.$element.empty().append([this._renderKeySelect(),this._renderOpSelect(),this._renderValueInput()]);return this};e.prototype._renderKeySelect=function a(){var j=this;var k=this.options.filters.map(function(l){return l.key});this.$keySelect=dropDownSelect(k,this.currFilter.key).addClass("filter-control-key").on("change.dropdown-select",function(m,l){j.currFilter=_.findWhere(j.options.filters,{key:l});j.render()._triggerChange()});return this.$keySelect};e.prototype._renderOpSelect=function i(){var j=this,k=this.currFilter.ops;this.$opSelect=dropDownSelect(k,k[0]).addClass("filter-control-op").on("change.dropdown-select",function(m,l){j._triggerChange()});return this.$opSelect};e.prototype._renderValueInput=function c(){var j=this;if(this.currFilter.values){this.$valueSelect=dropDownSelect(this.currFilter.values,this.currFilter.values[0]).on("change.dropdown-select",function(l,k){j._triggerChange()})}else{this.$valueSelect=$("<input/>").addClass("form-control").on("change",function(k,l){j._triggerChange()})}this.$valueSelect.addClass("filter-control-value");return this.$valueSelect};e.prototype.val=function b(){var k=this.$element.find(".filter-control-key .dropdown-select-selected").text(),m=this.$element.find(".filter-control-op .dropdown-select-selected").text(),j=this.$element.find(".filter-control-value"),l=(j.hasClass("dropdown-select"))?(j.find(".dropdown-select-selected").text()):(j.val());return{key:k,op:m,value:l}};e.prototype._triggerChange=function h(){this.$element.trigger("change.filter-control",this.val())};jQuery.fn.extend({filterControl:function f(k){var j=jQuery.makeArray(arguments).slice(1);return this.map(function(){var n=$(this),m=n.data(e.prototype.DATA_KEY);if(jQuery.type(k)==="object"){m=new e(n,k);n.data(e.prototype.DATA_KEY,m)}if(m&&jQuery.type(k)==="string"){var l=m[k];if(jQuery.type(l)==="function"){return l.apply(m,j)}}return this})}})}());(function(){function i(o,n){this.numPages=null;this.currPage=0;return this.init(o,n)}i.prototype.DATA_KEY="pagination";i.prototype.defaults={startingPage:0,perPage:20,totalDataSize:null,currDataSize:null};i.prototype.init=function g(n,o){o=o||{};this.$element=n;this.options=jQuery.extend(true,{},this.defaults,o);this.currPage=this.options.startingPage;if(this.options.totalDataSize!==null){this.numPages=Math.ceil(this.options.totalDataSize/this.options.perPage);if(this.currPage>=this.numPages){this.currPage=this.numPages-1}}this.$element.data(i.prototype.DATA_KEY,this);this._render();return this};function m(n){return $(['<li><a href="javascript:void(0);">',n,"</a></li>"].join(""))}i.prototype._render=function e(){if(this.options.totalDataSize===0){return this}if(this.numPages===1){return this}if(this.numPages>0){this._renderPages();this._scrollToActivePage()}else{this._renderPrevNext()}return this};i.prototype._renderPrevNext=function b(){var o=this,p=m("Prev"),n=m("Next"),q=$("<ul/>").addClass("pagination pagination-prev-next");if(this.currPage===0){p.addClass("disabled")}else{p.click(function(){o.prevPage()})}if((this.numPages&&this.currPage===(this.numPages-1))||(this.options.currDataSize&&this.options.currDataSize<this.options.perPage)){n.addClass("disabled")}else{n.click(function(){o.nextPage()})}this.$element.html(q.append([p,n]));return this.$element};i.prototype._renderPages=function a(){var n=this,q=$("<div>").addClass("pagination-scroll-container"),s=$("<ul/>").addClass("pagination pagination-page-list"),r=function(t){n.goToPage($(this).data("page"))};for(var o=0;o<this.numPages;o+=1){var p=m(o+1).attr("data-page",o).click(r);if(o===this.currPage){p.addClass("active")}s.append(p)}return this.$element.html(q.html(s))};i.prototype._scrollToActivePage=function l(){var p=this.$element.find(".pagination-scroll-container");if(!p.size()){return this}var o=this.$element.find("li.active"),n=p.width()/2;p.scrollLeft(p.scrollLeft()+o.position().left-n);return this};i.prototype.goToPage=function j(n){if(n<=0){n=0}if(this.numPages&&n>=this.numPages){n=this.numPages-1}if(n===this.currPage){return this}this.currPage=n;this.$element.trigger("pagination.page-change",this.currPage);this._render();return this};i.prototype.prevPage=function c(){return this.goToPage(this.currPage-1)};i.prototype.nextPage=function h(){return this.goToPage(this.currPage+1)};i.prototype.page=function f(){return this.currPage};i.create=function k(n,o){return new i(n,o)};jQuery.fn.extend({pagination:function d(o){var n=jQuery.makeArray(arguments).slice(1);if(jQuery.type(o)==="object"){return this.map(function(){i.create($(this),o);return this})}var q=$(this[0]),r=q.data(i.prototype.DATA_KEY);if(r){if(jQuery.type(o)==="string"){var p=r[o];if(jQuery.type(p)==="function"){return p.apply(r,n)}}else{return r}}return undefined}})}());(function(){var g={renameColumns:false,columnNames:[],commentChar:"#",hideCommentRows:false,includePrompts:true,topLeftContent:"Columns:"},s="peek-control.change",t="peek-control.rename",l="peek-control",v="control",f="control-prompt",c="selected",n="disabled",u="button",q="renamable-header",p="column-index",a="column-name";function i(w){if(w.disabled&&jQuery.type(w.disabled)!=="array"){throw new Error('"disabled" must be defined as an array of indeces: '+JSON.stringify(w))}if(w.multiselect&&w.selected&&jQuery.type(w.selected)!=="array"){throw new Error('Mulitselect rows need an array for "selected": '+JSON.stringify(w))}if(!w.label||!w.id){throw new Error("Peek controls need a label and id for each control row: "+JSON.stringify(w))}if(w.disabled&&w.disabled.indexOf(w.selected)!==-1){throw new Error("Selected column is in the list of disabled columns: "+JSON.stringify(w))}return w}function o(x,w){return $("<div/>").addClass(u).text(x.label)}function k(x,w){var y=$("<td/>").html(o(x,w)).attr("data-"+p,w);if(x.disabled&&x.disabled.indexOf(w)!==-1){y.addClass(n)}return y}function e(y,z,w){var x=y.children("."+u);if(y.hasClass(c)){x.html((z.selectedText!==undefined)?(z.selectedText):(z.label))}else{x.html((z.unselectedText!==undefined)?(z.unselectedText):(z.label))}}function h(z,x){var y=k(z,x);if(z.selected===x){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);if(!E.hasClass(c)){var A=E.parent().children("."+c).removeClass(c);A.each(function(){e($(this),z,x)});E.addClass(c);e(E,z,x);var C={},B=E.parent().attr("id"),F=E.data(p);C[B]=F;E.parents(".peek").trigger(s,C)}})}return y}function m(z,x){var y=k(z,x);if(z.selected&&z.selected.indexOf(x)!==-1){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);E.toggleClass(c);e(E,z,x);var C=E.parent().find("."+c).map(function(G,H){return $(H).data(p)});var B={},A=E.parent().attr("id"),F=jQuery.makeArray(C);B[A]=F;E.parents(".peek").trigger(s,B)})}return y}function j(y,z){var w=[];for(var x=0;x<y;x+=1){w.push(z.multiselect?m(z,x):h(z,x))}return w}function r(y,z,x){var A=$("<tr/>").attr("id",z.id).addClass(v);if(x){var w=$("<td/>").addClass(f).text(z.label+":");A.append(w)}A.append(j(y,z));return A}function b(E){E=jQuery.extend(true,{},g,E);var D=$(this).addClass(l),A=D.find("table"),z=A.find("th").size(),C=A.find("tr").size(),w=A.find("td[colspan]").map(function(H,F){var G=$(this);if(G.text()&&G.text().match(new RegExp("^"+E.commentChar))){return $(this).css("color","grey").parent().get(0)}return null});if(E.hideCommentRows){w.hide();C-=w.size()}if(E.includePrompts){var y=$("<th/>").addClass("top-left").text(E.topLeftContent).attr("rowspan",C);A.find("tr").first().prepend(y)}var B=A.find("th:not(.top-left)").each(function(G,I){var H=$(this),J=H.text().replace(/^\d+\.*/,""),F=E.columnNames[G]||J;H.attr("data-"+a,F).text((G+1)+((F)?("."+F):("")))});if(E.renameColumns){B.addClass(q).click(function x(){var G=$(this),F=G.index()+(E.includePrompts?0:1),I=G.data(a),H=prompt("New column name:",I);if(H!==null&&H!==I){G.text(F+(H?("."+H):"")).data(a,H).attr("data-",a,H);var J=jQuery.makeArray(G.parent().children("th:not(.top-left)").map(function(){return $(this).data(a)}));G.parents(".peek").trigger(t,J)}})}E.controls.forEach(function(G,F){i(G);var H=r(z,G,E.includePrompts);A.find("tbody").append(H)});return this}jQuery.fn.extend({peekControl:function d(w){return this.map(function(){return b.call(this,w)})}})}());
\ No newline at end of file
+var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.create=function _create(b,a){return new PopupMenu(b,a)};PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b}(function(){function a(j,p){var d=27,m=13,c=$(j),e=true,g={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(q){},minSearchLen:0,escWillClear:true,oninit:function(){}};function i(q){var r=$(this).parent().children("input");r.val("");r.trigger("clear:searchInput");p.onclear()}function o(r,q){$(this).trigger("search:searchInput",q);if(typeof p.onfirstsearch==="function"&&e){e=false;p.onfirstsearch(q)}else{p.onsearch(q)}}function f(){return['<input type="text" name="',p.name,'" placeholder="',p.placeholder,'" ','class="search-query ',p.classes,'" ',"/>"].join("")}function l(){return $(f()).focus(function(q){$(this).select()}).keyup(function(r){if(r.which===d&&p.escWillClear){i.call(this,r)}else{var q=$(this).val();if((r.which===m)||(p.minSearchLen&&q.length>=p.minSearchLen)){o.call(this,r,q)}else{if(!q.length){i.call(this,r)}}}}).val(p.initialVal)}function k(){return $(['<span class="search-clear fa fa-times-circle" ','title="',_l("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(q){i.call(this,q)})}function n(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',_l("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function h(){c.find(".search-loading").toggle();c.find(".search-clear").toggle()}if(jQuery.type(p)==="string"){if(p==="toggle-loading"){h()}return c}if(jQuery.type(p)==="object"){p=jQuery.extend(true,{},g,p)}return c.addClass("search-input").prepend([l(),k(),n()])}jQuery.fn.extend({searchInput:function b(c){return this.each(function(){return a(this,c)})}})}());(function(){function c(o,n){this.currModeIndex=0;return this._init(o,n)}c.prototype.DATA_KEY="mode-button";c.prototype.defaults={switchModesOnClick:true};c.prototype._init=function j(o,n){n=n||{};this.$element=$(o);this.options=jQuery.extend(true,{},this.defaults,n);if(!n.modes){throw new Error('ModeButton requires a "modes" array')}var q=this;this.$element.click(function p(r){q.callModeFn();if(q.options.switchModesOnClick){q._incModeIndex()}$(this).html(q.options.modes[q.currModeIndex].html)});return this.reset()};c.prototype._incModeIndex=function l(){this.currModeIndex+=1;if(this.currModeIndex>=this.options.modes.length){this.currModeIndex=0}return this};c.prototype._getModeIndex=function f(n){for(var o=0;o<this.options.modes.length;o+=1){if(this.options.modes[o].mode===n){return o}}throw new Error("mode not found: "+n)};c.prototype._setModeByIndex=function m(n){var o=this.options.modes[n];if(!o){throw new Error("mode index not found: "+n)}this.currModeIndex=n;if(o.html){this.$element.html(o.html)}return this};c.prototype.currentMode=function d(){return this.options.modes[this.currModeIndex]};c.prototype.current=function i(){return this.currentMode().mode};c.prototype.getMode=function g(n){if(!n){return this.currentMode()}return this.options.modes[(this._getModeIndex(n))]};c.prototype.hasMode=function b(n){try{return !!this.getMode(n)}catch(o){}return false};c.prototype.setMode=function a(n){return this._setModeByIndex(this._getModeIndex(n))};c.prototype.reset=function h(){this.currModeIndex=0;if(this.options.initialMode){this.currModeIndex=this._getModeIndex(this.options.initialMode)}return this._setModeByIndex(this.currModeIndex)};c.prototype.callModeFn=function e(n){var o=this.getMode(n).onclick;if(o&&jQuery.type(o==="function")){o.call(this.$element.get(0));return this}return undefined};jQuery.fn.extend({modeButton:function k(n){if(!this.size()){return this}if(jQuery.type(n)==="object"){return this.map(function(){var r=$(this);r.data("mode-button",new c(r,n));return this})}var p=$(this[0]),o=p.data("mode-button");console.debug("first, button",p,o);if(!o){throw new Error("modeButton needs an options object or string name of a function")}if(o&&jQuery.type(n)==="string"){var q=n;if(o&&jQuery.type(o[q])==="function"){return o[q].apply(o,jQuery.makeArray(arguments).slice(1))}}return o}})}());function dropDownSelect(b,c){c=c||((!_.isEmpty(b))?(b[0]):(""));var a=$(['<div class="dropdown-select btn-group">','<button type="button" class="btn btn-default">','<span class="dropdown-select-selected">'+c+"</span>","</button>","</div>"].join("\n"));if(b&&b.length>1){a.find("button").addClass("dropdown-toggle").attr("data-toggle","dropdown").append(' <span class="caret"></span>');a.append(['<ul class="dropdown-menu" role="menu">',_.map(b,function(e){return['<li><a href="javascript:void(0)">',e,"</a></li>"].join("")}).join("\n"),"</ul>"].join("\n"))}function d(g){var h=$(this),f=h.parents(".dropdown-select"),e=h.text();f.find(".dropdown-select-selected").text(e);f.trigger("change.dropdown-select",e)}a.find("a").click(d);return a}(function(){function e(k,j){return this.init(k,j)}e.prototype.DATA_KEY="filter-control";e.prototype.init=function g(k,j){j=j||{filters:[]};this.$element=$(k).addClass("filter-control btn-group");this.options=jQuery.extend(true,{},this.defaults,j);this.currFilter=this.options.filters[0];return this.render()};e.prototype.render=function d(){this.$element.empty().append([this._renderKeySelect(),this._renderOpSelect(),this._renderValueInput()]);return this};e.prototype._renderKeySelect=function a(){var j=this;var k=this.options.filters.map(function(l){return l.key});this.$keySelect=dropDownSelect(k,this.currFilter.key).addClass("filter-control-key").on("change.dropdown-select",function(m,l){j.currFilter=_.findWhere(j.options.filters,{key:l});j.render()._triggerChange()});return this.$keySelect};e.prototype._renderOpSelect=function i(){var j=this,k=this.currFilter.ops;this.$opSelect=dropDownSelect(k,k[0]).addClass("filter-control-op").on("change.dropdown-select",function(m,l){j._triggerChange()});return this.$opSelect};e.prototype._renderValueInput=function c(){var j=this;if(this.currFilter.values){this.$valueSelect=dropDownSelect(this.currFilter.values,this.currFilter.values[0]).on("change.dropdown-select",function(l,k){j._triggerChange()})}else{this.$valueSelect=$("<input/>").addClass("form-control").on("change",function(k,l){j._triggerChange()})}this.$valueSelect.addClass("filter-control-value");return this.$valueSelect};e.prototype.val=function b(){var k=this.$element.find(".filter-control-key .dropdown-select-selected").text(),m=this.$element.find(".filter-control-op .dropdown-select-selected").text(),j=this.$element.find(".filter-control-value"),l=(j.hasClass("dropdown-select"))?(j.find(".dropdown-select-selected").text()):(j.val());return{key:k,op:m,value:l}};e.prototype._triggerChange=function h(){this.$element.trigger("change.filter-control",this.val())};jQuery.fn.extend({filterControl:function f(k){var j=jQuery.makeArray(arguments).slice(1);return this.map(function(){var n=$(this),m=n.data(e.prototype.DATA_KEY);if(jQuery.type(k)==="object"){m=new e(n,k);n.data(e.prototype.DATA_KEY,m)}if(m&&jQuery.type(k)==="string"){var l=m[k];if(jQuery.type(l)==="function"){return l.apply(m,j)}}return this})}})}());(function(){function i(o,n){this.numPages=null;this.currPage=0;return this.init(o,n)}i.prototype.DATA_KEY="pagination";i.prototype.defaults={startingPage:0,perPage:20,totalDataSize:null,currDataSize:null};i.prototype.init=function g(n,o){o=o||{};this.$element=n;this.options=jQuery.extend(true,{},this.defaults,o);this.currPage=this.options.startingPage;if(this.options.totalDataSize!==null){this.numPages=Math.ceil(this.options.totalDataSize/this.options.perPage);if(this.currPage>=this.numPages){this.currPage=this.numPages-1}}this.$element.data(i.prototype.DATA_KEY,this);this._render();return this};function m(n){return $(['<li><a href="javascript:void(0);">',n,"</a></li>"].join(""))}i.prototype._render=function e(){if(this.options.totalDataSize===0){return this}if(this.numPages===1){return this}if(this.numPages>0){this._renderPages();this._scrollToActivePage()}else{this._renderPrevNext()}return this};i.prototype._renderPrevNext=function b(){var o=this,p=m("Prev"),n=m("Next"),q=$("<ul/>").addClass("pagination pagination-prev-next");if(this.currPage===0){p.addClass("disabled")}else{p.click(function(){o.prevPage()})}if((this.numPages&&this.currPage===(this.numPages-1))||(this.options.currDataSize&&this.options.currDataSize<this.options.perPage)){n.addClass("disabled")}else{n.click(function(){o.nextPage()})}this.$element.html(q.append([p,n]));return this.$element};i.prototype._renderPages=function a(){var n=this,q=$("<div>").addClass("pagination-scroll-container"),s=$("<ul/>").addClass("pagination pagination-page-list"),r=function(t){n.goToPage($(this).data("page"))};for(var o=0;o<this.numPages;o+=1){var p=m(o+1).attr("data-page",o).click(r);if(o===this.currPage){p.addClass("active")}s.append(p)}return this.$element.html(q.html(s))};i.prototype._scrollToActivePage=function l(){var p=this.$element.find(".pagination-scroll-container");if(!p.size()){return this}var o=this.$element.find("li.active"),n=p.width()/2;p.scrollLeft(p.scrollLeft()+o.position().left-n);return this};i.prototype.goToPage=function j(n){if(n<=0){n=0}if(this.numPages&&n>=this.numPages){n=this.numPages-1}if(n===this.currPage){return this}this.currPage=n;this.$element.trigger("pagination.page-change",this.currPage);this._render();return this};i.prototype.prevPage=function c(){return this.goToPage(this.currPage-1)};i.prototype.nextPage=function h(){return this.goToPage(this.currPage+1)};i.prototype.page=function f(){return this.currPage};i.create=function k(n,o){return new i(n,o)};jQuery.fn.extend({pagination:function d(o){var n=jQuery.makeArray(arguments).slice(1);if(jQuery.type(o)==="object"){return this.map(function(){i.create($(this),o);return this})}var q=$(this[0]),r=q.data(i.prototype.DATA_KEY);if(r){if(jQuery.type(o)==="string"){var p=r[o];if(jQuery.type(p)==="function"){return p.apply(r,n)}}else{return r}}return undefined}})}());(function(){var g={renameColumns:false,columnNames:[],commentChar:"#",hideCommentRows:false,includePrompts:true,topLeftContent:"Columns:"},s="peek-control.change",t="peek-control.rename",l="peek-control",v="control",f="control-prompt",c="selected",n="disabled",u="button",q="renamable-header",p="column-index",a="column-name";function i(w){if(w.disabled&&jQuery.type(w.disabled)!=="array"){throw new Error('"disabled" must be defined as an array of indeces: '+JSON.stringify(w))}if(w.multiselect&&w.selected&&jQuery.type(w.selected)!=="array"){throw new Error('Mulitselect rows need an array for "selected": '+JSON.stringify(w))}if(!w.label||!w.id){throw new Error("Peek controls need a label and id for each control row: "+JSON.stringify(w))}if(w.disabled&&w.disabled.indexOf(w.selected)!==-1){throw new Error("Selected column is in the list of disabled columns: "+JSON.stringify(w))}return w}function o(x,w){return $("<div/>").addClass(u).text(x.label)}function k(x,w){var y=$("<td/>").html(o(x,w)).attr("data-"+p,w);if(x.disabled&&x.disabled.indexOf(w)!==-1){y.addClass(n)}return y}function e(y,z,w){var x=y.children("."+u);if(y.hasClass(c)){x.html((z.selectedText!==undefined)?(z.selectedText):(z.label))}else{x.html((z.unselectedText!==undefined)?(z.unselectedText):(z.label))}}function h(z,x){var y=k(z,x);if(z.selected===x){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);if(!E.hasClass(c)){var A=E.parent().children("."+c).removeClass(c);A.each(function(){e($(this),z,x)});E.addClass(c);e(E,z,x);var C={},B=E.parent().attr("id"),F=E.data(p);C[B]=F;E.parents(".peek").trigger(s,C)}})}return y}function m(z,x){var y=k(z,x);if(z.selected&&z.selected.indexOf(x)!==-1){y.addClass(c)}e(y,z,x);if(!y.hasClass(n)){y.click(function w(D){var E=$(this);E.toggleClass(c);e(E,z,x);var C=E.parent().find("."+c).map(function(G,H){return $(H).data(p)});var B={},A=E.parent().attr("id"),F=jQuery.makeArray(C);B[A]=F;E.parents(".peek").trigger(s,B)})}return y}function j(y,z){var w=[];for(var x=0;x<y;x+=1){w.push(z.multiselect?m(z,x):h(z,x))}return w}function r(y,z,x){var A=$("<tr/>").attr("id",z.id).addClass(v);if(x){var w=$("<td/>").addClass(f).text(z.label+":");A.append(w)}A.append(j(y,z));return A}function b(E){E=jQuery.extend(true,{},g,E);var D=$(this).addClass(l),A=D.find("table"),z=A.find("th").size(),C=A.find("tr").size(),w=A.find("td[colspan]").map(function(H,F){var G=$(this);if(G.text()&&G.text().match(new RegExp("^"+E.commentChar))){return $(this).css("color","grey").parent().get(0)}return null});if(E.hideCommentRows){w.hide();C-=w.size()}if(E.includePrompts){var y=$("<th/>").addClass("top-left").text(E.topLeftContent).attr("rowspan",C);A.find("tr").first().prepend(y)}var B=A.find("th:not(.top-left)").each(function(G,I){var H=$(this),J=H.text().replace(/^\d+\.*/,""),F=E.columnNames[G]||J;H.attr("data-"+a,F).text((G+1)+((F)?("."+F):("")))});if(E.renameColumns){B.addClass(q).click(function x(){var G=$(this),F=G.index()+(E.includePrompts?0:1),I=G.data(a),H=prompt("New column name:",I);if(H!==null&&H!==I){G.text(F+(H?("."+H):"")).data(a,H).attr("data-",a,H);var J=jQuery.makeArray(G.parent().children("th:not(.top-left)").map(function(){return $(this).data(a)}));G.parents(".peek").trigger(t,J)}})}E.controls.forEach(function(G,F){i(G);var H=r(z,G,E.includePrompts);A.find("tbody").append(H)});return this}jQuery.fn.extend({peekControl:function d(w){return this.map(function(){return b.call(this,w)})}})}());
\ No newline at end of file
diff -r c85f8fb5d63e667b63e10cdce518254f56002f55 -r 7ebec9da47844efbf37942faab3809cb0169e5c2 templates/webapps/galaxy/history/original_view.mako
--- a/templates/webapps/galaxy/history/original_view.mako
+++ /dev/null
@@ -1,173 +0,0 @@
-<%namespace file="/display_common.mako" import="get_history_link, get_controller_name" />
-<%namespace file="/root/history_common.mako" import="render_dataset" />
-<%namespace file="/tagging_common.mako" import="render_individual_tagging_element, render_community_tagging_element" />
-
-<%!
- def inherit(context):
- if context.get('use_panels'):
- return '/webapps/galaxy/base_panels.mako'
- else:
- return '/base.mako'
-%>
-<%inherit file="${inherit(context)}"/>
-
-<%def name="javascripts()">
- ${parent.javascripts()}
- ${h.js( "libs/jquery/jstorage" )}
- <script type="text/javascript">
- $(function() {
- init_history_items( $("div.historyItemWrapper"), false, "nochanges" );
- $( '#switch-to-link' ).click( function( event ){
- var galaxy = window.Galaxy || window.parent.Galaxy;
- if( galaxy ){
- galaxy.currHistoryPanel.switchToHistory( '${ trans.security.encode_id( history.id ) }' );
- }
- });
- $( '#refresh' ).click( function( event ){ window.location.reload( true ); })
- });
- </script>
-</%def>
-
-<%def name="stylesheets()">
- ${parent.stylesheets()}
- ${h.css( "history", "autocomplete_tagging" )}
-
- <style type="text/css">
-
- /* these don't appear to be used? */
- .page-body
- {
- padding: 10px;
- float: left;
- width: 65%;
- }
- .page-meta
- {
- float: right;
- width: 27%;
- padding: 0.5em;
- margin: 0.25em;
- vertical-align: text-top;
- border: 2px solid #DDDDDD;
- border-top: 4px solid #DDDDDD;
- }
-
-
- body {
- padding: 0px;
- margin: 0px;
- }
-
- div.unified-panel-body {
- position: absolute;
- top: 0px;
- width: 100%;
- }
-
- #history-name-area {
- margin: 12px 0px 0px 16px;
- font-size: 120%;
- }
- #top-links {
- margin: 4px 0px 8px 16px;
- }
-
- .historyItemContainer {
- /*padding-right: 3px;*/
- }
- .historyItemBody {
- display: none;
- }
- div.historyItemWrapper {
- margin: 0px 4px 0px 4px ;
- border-left: 1px solid #999999;
- border-right: 1px solid #999999;
- }
- /* TODO: unify with other history css and into .less */
- </style>
-
- <noscript>
- <style>
- .historyItemBody {
- display: block;
- }
- </style>
- </noscript>
-</%def>
-
-<%def name="init()">
-<%
- self.has_left_panel=False
- self.has_right_panel=False
- self.message_box_visible=False
-%>
-</%def>
-
-<%def name="body()">
- ${center_panel()}
-</%def>
-
-<%def name="center_panel()">
- ## Get URL to other histories owned by user that owns this history.
- <%
- ##TODO: is there a better way to create this URL? Can't use 'f-username' as a key b/c it's not a valid identifier.
- href_to_published_histories = h.url_for( controller='/history', action='list_published')
- if history.user is not None:
- href_to_user_histories = h.url_for( controller='/history', action='list_published', xxx=history.user.username).replace( 'xxx', 'f-username')
- else:
- href_to_user_histories = h.url_for( controller='/history', action='list_published' )##should this instead be be None or empty string?
- %>
-
- <div class="unified-panel-body">
- <div style="overflow: auto; height: 100%;">
- ## Render view of history.
- <div id="history-name-area" class="historyLinks" style="color: gray; font-weight: bold; padding: 0px 0px 5px 0px">
- <div id="history-name">${history.get_display_name()}</div>
- </div>
-
- <div id="top-links" class="historyLinks" style="padding: 0px 0px 5px 0px">
- %if not history.purged and history.user != trans.user:
- ##TODO: need to remove _top
- <a href="${h.url_for(controller='history', action='imp', id=trans.security.encode_id(history.id) )}"
- >import and start using history</a> |
- <a id="refresh" href="javascript:void(0)" >${_('refresh')}</a> |
- %endif
- %if not history.purged and history.user == trans.user:
- <a id="switch-to-link" href="javascript:void(0)">${_('switch to this history')}</a> |
- <a id="refresh" href="javascript:void(0)" >${_('refresh')}</a> |
- %endif
- %if show_deleted:
- <a href="${h.url_for(controller='history', action='view', id=trans.security.encode_id(history.id), show_deleted=False, use_panels=use_panels )}">${_('hide deleted')}</a> |
- %else:
- <a href="${h.url_for(controller='history', action='view', id=trans.security.encode_id(history.id), show_deleted=True, use_panels=use_panels )}">${_('show deleted')}</a> |
- %endif
- <a href="#" class="toggle">collapse all</a>
- </div>
-
- %if history.deleted:
- <div class="warningmessagesmall">
- ${_('You are currently viewing a deleted history!')}
- </div>
- <p></p>
- %endif
-
- %if not datasets:
- <div class="infomessagesmall" id="emptyHistoryMessage">
-
- %else:
- ## Render requested datasets, ordered from newest to oldest
- %for data in datasets:
- %if data.visible:
- <div class="historyItemContainer visible-right-border" id="historyItemContainer-${data.id}">
- ${render_dataset( data, data.hid, show_deleted_on_refresh = show_deleted, for_editing=False )}
- </div>
- %endif
- %endfor
-
- <div class="infomessagesmall" id="emptyHistoryMessage" style="display:none;">
- %endif
- ${_("Your history is empty. Click 'Get Data' on the left pane to start")}
- </div>
- </div>
- </div>
-</%def>
diff -r c85f8fb5d63e667b63e10cdce518254f56002f55 -r 7ebec9da47844efbf37942faab3809cb0169e5c2 templates/webapps/galaxy/history/view.mako
--- a/templates/webapps/galaxy/history/view.mako
+++ b/templates/webapps/galaxy/history/view.mako
@@ -77,6 +77,7 @@
%endif
<script type="text/javascript">
+ ##TODO: remove when Galaxy is either ensured or removed from the history panel
var using_panels = ${ 'false' if not use_panels else 'true' };
%if not use_panels:
window.Galaxy = {};
@@ -87,113 +88,107 @@
## ----------------------------------------------------------------------------
<%def name="center_panel()">
+<%
+ show_deleted = context.get( 'show_deleted', None )
+ show_hidden = context.get( 'show_hidden', None )
+
+ user_is_owner_json = 'true' if user_is_owner else 'false'
+ show_deleted_json = h.to_json_string( show_deleted )
+ show_hidden_json = h.to_json_string( show_hidden )
+
+ imp_with_deleted_url = h.url_for( controller='history', action='imp', id=history['id'], all_datasets=True )
+ imp_without_deleted_url = h.url_for( controller='history', action='imp', id=history['id'] )
+%>
+
<div id="header" class="clear"><div id="history-view-controls" class="pull-right">
- <%
- show_deleted = context.get( 'show_deleted', None )
- show_hidden = context.get( 'show_hidden', None )
-
- show_deleted_js = 'true' if show_deleted == True else ( 'null' if show_deleted == None else 'false' )
- show_hidden_js = 'true' if show_hidden == True else ( 'null' if show_hidden == None else 'false' )
- print 'user_is_owner:', user_is_owner
- %>
%if not user_is_owner and not history[ 'purged' ]:
- <a id="import" class="btn btn-default" style="display: none;"
- href="${h.url_for( controller='history', action='imp', id=history['id'], all_datasets=show_deleted )}">
- ${_('Import and start using history')}
- </a>
+ <button id="import" class="btn btn-default"></button>
%endif
- <button id="toggle-deleted" class="btn btn-default">
- ${_('Exclude deleted') if show_deleted else _('Include deleted')}
- </button>
- <button id="toggle-hidden" class="btn btn-default">
- ${_('Exclude hidden') if show_hidden else _('Include hidden')}
- </button>
+ <button id="toggle-deleted" class="btn btn-default"></button>
+ <button id="toggle-hidden" class="btn btn-default"></button></div></div><div id="history-${ history[ 'id' ] }" class="history-panel unified-panel-body" style="overflow: auto;"></div><script type="text/javascript">
+ $(function(){
+ $( '#toggle-deleted' ).modeButton({
+ initialMode : "${ 'showing_deleted' if show_deleted else 'not_showing_deleted' }",
+ modes: [
+ { mode: 'showing_deleted', html: _l( 'Exclude deleted' ) },
+ { mode: 'not_showing_deleted', html: _l( 'Include deleted' ) }
+ ]
+ }).click( function(){
+ // allow the 'include/exclude deleted' button to control whether the 'import' button includes deleted
+ // datasets when importing or not; when deleted datasets are shown, they'll be imported
+ $( '#import' ).modeButton( 'setMode',
+ $( this ).modeButton( 'current' ) === 'showing_deleted'? 'with_deleted': 'without_deleted' )
+ });
+
+ $( '#toggle-hidden' ).modeButton({
+ initialMode : "${ 'showing_hidden' if show_hidden else 'not_showing_hidden' }",
+ modes: [
+ { mode: 'showing_hidden', html: _l( 'Exclude hidden' ) },
+ { mode: 'not_showing_hidden', html: _l( 'Include hidden' ) }
+ ]
+ });
+
+ $( '#import' ).modeButton({
+ switchModesOnClick : false,
+ initialMode : "${ 'with_deleted' if show_deleted else 'without_deleted' }",
+ modes: [
+ { mode: 'with_deleted', html: _l( 'Import with deleted datasets and start using history' ),
+ onclick: function importWithDeleted(){
+ window.location = '${imp_with_deleted_url}';
+ }
+ },
+ { mode: 'without_deleted', html: _l( 'Import and start using history' ),
+ onclick: function importWithoutDeleted(){
+ window.location = '${imp_without_deleted_url}';
+ }
+ },
+ ]
+ });
+ });
+
var debugging = JSON.parse( sessionStorage.getItem( 'debugging' ) ) || false,
userIsOwner = ${'true' if user_is_owner else 'false'},
historyJSON = ${h.to_json_string( history )},
hdaJSON = ${h.to_json_string( hdas )};
- window.hdaJSON = hdaJSON;
-
- $( '#toggle-deleted' ).modeButton({
- initialMode : (${ show_deleted_js })?( 'exclude' ):( 'include' ),
- modes: [
- { mode: 'exclude', html: _l( 'Exclude deleted' ) },
- { mode: 'include', html: _l( 'Include deleted' ) }
- ]
- }).click( function(){
- // allow the 'include/exclude deleted' button to control whether the 'import' button includes deleted datasets
- // when importing or not; when deleted datasets are shown, they'll be imported
- var $importBtn = $( '#import' );
- if( $importBtn.size() ){
- // a bit hacky
- var href = $importBtn.attr( 'href' ),
- includeDeleted = $( this ).modeButton()[0].getMode().mode === 'exclude';
- href = href.replace( /all_datasets=True|False/, ( includeDeleted )?( 'True' ):( 'False' ) );
- $importBtn.attr( 'href', href );
- $importBtn.text( includeDeleted ? _l( 'Import with deleted datasets and start using history' )
- : _l( 'Import and start using history' ) );
- }
- });
-
- $( '#toggle-hidden' ).modeButton({
- initialMode : (${ show_hidden_js })?( 'exclude' ):( 'include' ),
- modes: [
- { mode: 'exclude', html: _l( 'Exclude hidden' ) },
- { mode: 'include', html: _l( 'Include hidden' ) }
- ]
- });
-
- ##TODO: move to mako
- if( Galaxy.currUser.id !== historyJSON.user_id ){
- $( '#import' ).show();
- }
+ panelToUse = ( userIsOwner )?
+ ({ location: 'mvc/history/history-panel', className: 'HistoryPanel' }):
+ ({ location: 'mvc/history/readonly-history-panel', className: 'ReadOnlyHistoryPanel' });
require.config({
baseUrl : "${h.url_for( '/static/scripts' )}"
- })([
- %if user_is_owner:
- 'mvc/history/history-panel'
- %else:
- 'mvc/history/readonly-history-panel'
- %endif
- ${ }
- ], function( panelMod ){
- //require([ "mvc/history/history-panel" ], function( historyPanel ){
- // history module is already in the dpn chain from the panel. We can re-scope it here.
- var historyModel = require( 'mvc/history/history-model' ),
- hdaBaseView = require( 'mvc/dataset/hda-base' ),
- history = new historyModel.History( historyJSON, hdaJSON, {
- logger: ( debugging )?( console ):( null )
+ })([ panelToUse.location ], function( panelMod ){
+ $(function(){
+ var panelClass = panelMod[ panelToUse.className ],
+ // history module is already in the dpn chain from the panel. We can re-scope it here.
+ historyModel = require( 'mvc/history/history-model' ),
+ hdaBaseView = require( 'mvc/dataset/hda-base' ),
+ history = new historyModel.History( historyJSON, hdaJSON, {
+ logger: ( debugging )?( console ):( null )
+ });
+
+ window.historyPanel = new panelClass({
+ show_deleted : ${show_deleted_json},
+ show_hidden : ${show_hidden_json},
+ el : $( "#history-" + historyJSON.id ),
+ model : history,
+ onready : function(){
+ var panel = this;
+ $( '#toggle-deleted' ).on( 'click', function(){
+ panel.toggleShowDeleted();
+ });
+ $( '#toggle-hidden' ).on( 'click', function(){
+ panel.toggleShowHidden();
+ });
+ this.render();
+ }
});
-
- window.panelMod = panelMod;
- %if user_is_owner:
- window.panelClass = panelMod.HistoryPanel;
- %else:
- window.panelClass = panelMod.ReadOnlyHistoryPanel;
- %endif
- window.historyPanel = new panelClass({
- show_deleted : ${show_deleted_js},
- show_hidden : ${show_hidden_js},
- el : $( "#history-" + historyJSON.id ),
- model : history,
- onready : function(){
- var panel = this;
- $( '#toggle-deleted' ).on( 'click', function(){
- panel.toggleShowDeleted();
- });
- $( '#toggle-hidden' ).on( 'click', function(){
- panel.toggleShowHidden();
- });
- this.render();
- }
});
});
</script>
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: Fix TypeDef error in history panel by adding sanity check for tags/annotations being open (Thanks, Aysam)
by commits-noreply@bitbucket.org 18 Feb '14
by commits-noreply@bitbucket.org 18 Feb '14
18 Feb '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c85f8fb5d63e/
Changeset: c85f8fb5d63e
User: carlfeberhard
Date: 2014-02-18 22:40:23
Summary: Fix TypeDef error in history panel by adding sanity check for tags/annotations being open (Thanks, Aysam)
Affected #: 2 files
diff -r 82d6ee82d5d4714eefdbce041f6c983a806a58d7 -r c85f8fb5d63e667b63e10cdce518254f56002f55 static/scripts/mvc/history/history-panel.js
--- a/static/scripts/mvc/history/history-panel.js
+++ b/static/scripts/mvc/history/history-panel.js
@@ -44,6 +44,11 @@
/** selected hda ids */
this.selectedHdaIds = [];
+ /** editor for tags - sub-view */
+ this.tagsEditor = null;
+ /** editor for annotations - sub-view */
+ this.annotationEditor = null;
+
// states/modes the panel can be in
/** is the panel currently showing the dataset selection controls? */
this.selecting = attributes.selecting || false;
@@ -250,8 +255,8 @@
selectable : this.selecting,
hasUser : this.model.ownedByCurrUser(),
logger : this.logger,
- tagsEditorShown : !this.tagsEditor.isHidden(),
- annotationEditorShown : !this.annotationEditor.isHidden()
+ tagsEditorShown : ( this.tagsEditor && !this.tagsEditor.isHidden() ),
+ annotationEditorShown : ( this.annotationEditor && !this.annotationEditor.isHidden() )
});
this._setUpHdaListeners( hdaView );
return hdaView;
diff -r 82d6ee82d5d4714eefdbce041f6c983a806a58d7 -r c85f8fb5d63e667b63e10cdce518254f56002f55 static/scripts/packed/mvc/history/history-panel.js
--- a/static/scripts/packed/mvc/history/history-panel.js
+++ b/static/scripts/packed/mvc/history/history-panel.js
@@ -1,1 +1,1 @@
-define(["mvc/dataset/hda-model","mvc/dataset/hda-edit","mvc/history/readonly-history-panel"],function(c,a,b){var d=b.ReadOnlyHistoryPanel.extend({HDAViewClass:a.HDAEditView,initialize:function(e){e=e||{};this.selectedHdaIds=[];this.selecting=e.selecting||false;this.annotationEditorShown=e.annotationEditorShown||false;this.tagsEditorShown=e.tagsEditorShown||false;b.ReadOnlyHistoryPanel.prototype.initialize.call(this,e)},_setUpModelEventHandlers:function(){b.ReadOnlyHistoryPanel.prototype._setUpModelEventHandlers.call(this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);this.model.hdas.on("change:deleted",this.handleHdaDeletionChange,this);this.model.hdas.on("change:visible",this.handleHdaVisibleChange,this);this.model.hdas.on("change:purged",function(e){this.model.fetch()},this)},renderModel:function(){var e=$("<div/>");e.append(d.templates.historyPanel(this.model.toJSON()));if(Galaxy.currUser.id&&Galaxy.currUser.id===this.model.get("user_id")){this._renderTags(e);this._renderAnnotation(e)}e.find(".history-secondary-actions").prepend(this._renderSelectButton());e.find(".history-dataset-actions").toggle(this.selecting);e.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(e);this.renderHdas(e);return e},_renderTags:function(e){var f=this;this.tagsEditor=new TagsEditor({model:this.model,el:e.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},onshow:function(){f.toggleHDATagEditors(true,f.fxSpeed)},onhide:function(){f.toggleHDATagEditors(false,f.fxSpeed)},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(e.find(".history-secondary-actions"))})},_renderAnnotation:function(e){var f=this;this.annotationEditor=new AnnotationEditor({model:this.model,el:e.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},onshow:function(){f.toggleHDAAnnotationEditors(true,f.fxSpeed)},onhide:function(){f.toggleHDAAnnotationEditors(false,f.fxSpeed)},$activator:faIconButton({title:_l("Edit history Annotation"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(e.find(".history-secondary-actions"))})},_renderSelectButton:function(e){return faIconButton({title:_l("Operations on multiple datasets"),classes:"history-select-btn",faIcon:"fa-check-square-o"})},_setUpBehaviours:function(e){e=e||this.$el;e.find("[title]").tooltip({placement:"bottom"});if(!this.model){return}this._setUpDatasetActionsPopup(e);if((!Galaxy.currUser||Galaxy.currUser.isAnonymous())||(Galaxy.currUser.id!==this.model.get("user_id"))){return}var f=this;e.find(".history-name").attr("title",_l("Click to rename history")).tooltip({placement:"bottom"}).make_text_editable({on_finish:function(g){var h=f.model.get("name");if(g&&g!==h){f.$el.find(".history-name").text(g);f.model.save({name:g}).fail(function(){f.$el.find(".history-name").text(f.model.previous("name"))})}else{f.$el.find(".history-name").text(h)}}})},_setUpDatasetActionsPopup:function(e){var f=this;(new PopupMenu(e.find(".history-dataset-action-popup-btn"),[{html:_l("Hide datasets"),func:function(){var g=c.HistoryDatasetAssociation.prototype.hide;f.getSelectedHdaCollection().ajaxQueue(g)}},{html:_l("Unhide datasets"),func:function(){var g=c.HistoryDatasetAssociation.prototype.unhide;f.getSelectedHdaCollection().ajaxQueue(g)}},{html:_l("Delete datasets"),func:function(){var g=c.HistoryDatasetAssociation.prototype["delete"];f.getSelectedHdaCollection().ajaxQueue(g)}},{html:_l("Undelete datasets"),func:function(){var g=c.HistoryDatasetAssociation.prototype.undelete;f.getSelectedHdaCollection().ajaxQueue(g)}},{html:_l("Permanently delete datasets"),func:function(){if(confirm(_l("This will permanently remove the data in your datasets. Are you sure?"))){var g=c.HistoryDatasetAssociation.prototype.purge;f.getSelectedHdaCollection().ajaxQueue(g)}}}]))},handleHdaDeletionChange:function(e){if(e.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[e.id])}},handleHdaVisibleChange:function(e){if(e.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[e.id])}},createHdaView:function(f){var e=f.get("id"),g=new this.HDAViewClass({model:f,linkTarget:this.linkTarget,expanded:this.storage.get("expandedHdas")[e],selectable:this.selecting,hasUser:this.model.ownedByCurrUser(),logger:this.logger,tagsEditorShown:!this.tagsEditor.isHidden(),annotationEditorShown:!this.annotationEditor.isHidden()});this._setUpHdaListeners(g);return g},_setUpHdaListeners:function(f){var e=this;b.ReadOnlyHistoryPanel.prototype._setUpHdaListeners.call(this,f);f.on("selected",function(g){var h=g.model.get("id");e.selectedHdaIds=_.union(e.selectedHdaIds,[h])});f.on("de-selected",function(g){var h=g.model.get("id");e.selectedHdaIds=_.without(e.selectedHdaIds,h)})},toggleHDATagEditors:function(e){var f=arguments;_.each(this.hdaViews,function(g){if(g.tagsEditor){g.tagsEditor.toggle.apply(g.tagsEditor,f)}})},toggleHDAAnnotationEditors:function(e){var f=arguments;_.each(this.hdaViews,function(g){if(g.annotationEditor){g.annotationEditor.toggle.apply(g.annotationEditor,f)}})},removeHdaView:function(f){if(!f){return}var e=this;f.$el.fadeOut(e.fxSpeed,function(){f.off();f.remove();delete e.hdaViews[f.model.id];if(_.isEmpty(e.hdaViews)){e.$el.find(e.emptyMsgSelector).fadeIn(e.fxSpeed,function(){e.trigger("empty-history",e)})}})},events:_.extend(_.clone(b.ReadOnlyHistoryPanel.prototype.events),{"click .history-select-btn":function(f){this.toggleSelectors(this.fxSpeed)},"click .history-select-all-datasets-btn":"selectAllDatasets","click .history-deselect-all-datasets-btn":"deselectAllDatasets"}),updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},showSelectors:function(e){this.selecting=true;this.$el.find(".history-dataset-actions").slideDown(e);_.each(this.hdaViews,function(f){f.showSelector(e)});this.selectedHdaIds=[]},hideSelectors:function(e){this.selecting=false;this.$el.find(".history-dataset-actions").slideUp(e);_.each(this.hdaViews,function(f){f.hideSelector(e)});this.selectedHdaIds=[]},toggleSelectors:function(e){if(!this.selecting){this.showSelectors(e)}else{this.hideSelectors(e)}},selectAllDatasets:function(e){_.each(this.hdaViews,function(f){f.select(e)})},deselectAllDatasets:function(e){_.each(this.hdaViews,function(f){f.deselect(e)})},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(e){return e.selected})},getSelectedHdaCollection:function(){return new c.HDACollection(_.map(this.getSelectedHdaViews(),function(e){return e.model}),{historyId:this.model.id})},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});d.templates={historyPanel:Handlebars.templates["template-history-historyPanel"],anonHistoryPanel:Handlebars.templates["template-history-historyPanel-anon"]};return{HistoryPanel:d}});
\ No newline at end of file
+define(["mvc/dataset/hda-model","mvc/dataset/hda-edit","mvc/history/readonly-history-panel"],function(c,a,b){var d=b.ReadOnlyHistoryPanel.extend({HDAViewClass:a.HDAEditView,initialize:function(e){e=e||{};this.selectedHdaIds=[];this.tagsEditor=null;this.annotationEditor=null;this.selecting=e.selecting||false;this.annotationEditorShown=e.annotationEditorShown||false;this.tagsEditorShown=e.tagsEditorShown||false;b.ReadOnlyHistoryPanel.prototype.initialize.call(this,e)},_setUpModelEventHandlers:function(){b.ReadOnlyHistoryPanel.prototype._setUpModelEventHandlers.call(this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);this.model.hdas.on("change:deleted",this.handleHdaDeletionChange,this);this.model.hdas.on("change:visible",this.handleHdaVisibleChange,this);this.model.hdas.on("change:purged",function(e){this.model.fetch()},this)},renderModel:function(){var e=$("<div/>");e.append(d.templates.historyPanel(this.model.toJSON()));if(Galaxy.currUser.id&&Galaxy.currUser.id===this.model.get("user_id")){this._renderTags(e);this._renderAnnotation(e)}e.find(".history-secondary-actions").prepend(this._renderSelectButton());e.find(".history-dataset-actions").toggle(this.selecting);e.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(e);this.renderHdas(e);return e},_renderTags:function(e){var f=this;this.tagsEditor=new TagsEditor({model:this.model,el:e.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},onshow:function(){f.toggleHDATagEditors(true,f.fxSpeed)},onhide:function(){f.toggleHDATagEditors(false,f.fxSpeed)},$activator:faIconButton({title:_l("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(e.find(".history-secondary-actions"))})},_renderAnnotation:function(e){var f=this;this.annotationEditor=new AnnotationEditor({model:this.model,el:e.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},onshow:function(){f.toggleHDAAnnotationEditors(true,f.fxSpeed)},onhide:function(){f.toggleHDAAnnotationEditors(false,f.fxSpeed)},$activator:faIconButton({title:_l("Edit history Annotation"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(e.find(".history-secondary-actions"))})},_renderSelectButton:function(e){return faIconButton({title:_l("Operations on multiple datasets"),classes:"history-select-btn",faIcon:"fa-check-square-o"})},_setUpBehaviours:function(e){e=e||this.$el;e.find("[title]").tooltip({placement:"bottom"});if(!this.model){return}this._setUpDatasetActionsPopup(e);if((!Galaxy.currUser||Galaxy.currUser.isAnonymous())||(Galaxy.currUser.id!==this.model.get("user_id"))){return}var f=this;e.find(".history-name").attr("title",_l("Click to rename history")).tooltip({placement:"bottom"}).make_text_editable({on_finish:function(g){var h=f.model.get("name");if(g&&g!==h){f.$el.find(".history-name").text(g);f.model.save({name:g}).fail(function(){f.$el.find(".history-name").text(f.model.previous("name"))})}else{f.$el.find(".history-name").text(h)}}})},_setUpDatasetActionsPopup:function(e){var f=this;(new PopupMenu(e.find(".history-dataset-action-popup-btn"),[{html:_l("Hide datasets"),func:function(){var g=c.HistoryDatasetAssociation.prototype.hide;f.getSelectedHdaCollection().ajaxQueue(g)}},{html:_l("Unhide datasets"),func:function(){var g=c.HistoryDatasetAssociation.prototype.unhide;f.getSelectedHdaCollection().ajaxQueue(g)}},{html:_l("Delete datasets"),func:function(){var g=c.HistoryDatasetAssociation.prototype["delete"];f.getSelectedHdaCollection().ajaxQueue(g)}},{html:_l("Undelete datasets"),func:function(){var g=c.HistoryDatasetAssociation.prototype.undelete;f.getSelectedHdaCollection().ajaxQueue(g)}},{html:_l("Permanently delete datasets"),func:function(){if(confirm(_l("This will permanently remove the data in your datasets. Are you sure?"))){var g=c.HistoryDatasetAssociation.prototype.purge;f.getSelectedHdaCollection().ajaxQueue(g)}}}]))},handleHdaDeletionChange:function(e){if(e.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[e.id])}},handleHdaVisibleChange:function(e){if(e.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[e.id])}},createHdaView:function(f){var e=f.get("id"),g=new this.HDAViewClass({model:f,linkTarget:this.linkTarget,expanded:this.storage.get("expandedHdas")[e],selectable:this.selecting,hasUser:this.model.ownedByCurrUser(),logger:this.logger,tagsEditorShown:(this.tagsEditor&&!this.tagsEditor.isHidden()),annotationEditorShown:(this.annotationEditor&&!this.annotationEditor.isHidden())});this._setUpHdaListeners(g);return g},_setUpHdaListeners:function(f){var e=this;b.ReadOnlyHistoryPanel.prototype._setUpHdaListeners.call(this,f);f.on("selected",function(g){var h=g.model.get("id");e.selectedHdaIds=_.union(e.selectedHdaIds,[h])});f.on("de-selected",function(g){var h=g.model.get("id");e.selectedHdaIds=_.without(e.selectedHdaIds,h)})},toggleHDATagEditors:function(e){var f=arguments;_.each(this.hdaViews,function(g){if(g.tagsEditor){g.tagsEditor.toggle.apply(g.tagsEditor,f)}})},toggleHDAAnnotationEditors:function(e){var f=arguments;_.each(this.hdaViews,function(g){if(g.annotationEditor){g.annotationEditor.toggle.apply(g.annotationEditor,f)}})},removeHdaView:function(f){if(!f){return}var e=this;f.$el.fadeOut(e.fxSpeed,function(){f.off();f.remove();delete e.hdaViews[f.model.id];if(_.isEmpty(e.hdaViews)){e.$el.find(e.emptyMsgSelector).fadeIn(e.fxSpeed,function(){e.trigger("empty-history",e)})}})},events:_.extend(_.clone(b.ReadOnlyHistoryPanel.prototype.events),{"click .history-select-btn":function(f){this.toggleSelectors(this.fxSpeed)},"click .history-select-all-datasets-btn":"selectAllDatasets","click .history-deselect-all-datasets-btn":"deselectAllDatasets"}),updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},showSelectors:function(e){this.selecting=true;this.$el.find(".history-dataset-actions").slideDown(e);_.each(this.hdaViews,function(f){f.showSelector(e)});this.selectedHdaIds=[]},hideSelectors:function(e){this.selecting=false;this.$el.find(".history-dataset-actions").slideUp(e);_.each(this.hdaViews,function(f){f.hideSelector(e)});this.selectedHdaIds=[]},toggleSelectors:function(e){if(!this.selecting){this.showSelectors(e)}else{this.hideSelectors(e)}},selectAllDatasets:function(e){_.each(this.hdaViews,function(f){f.select(e)})},deselectAllDatasets:function(e){_.each(this.hdaViews,function(f){f.deselect(e)})},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(e){return e.selected})},getSelectedHdaCollection:function(){return new c.HDACollection(_.map(this.getSelectedHdaViews(),function(e){return e.model}),{historyId:this.model.id})},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});d.templates={historyPanel:Handlebars.templates["template-history-historyPanel"],anonHistoryPanel:Handlebars.templates["template-history-historyPanel-anon"]};return{HistoryPanel:d}});
\ No newline at end of file
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/33812bcdc523/
Changeset: 33812bcdc523
User: carlfeberhard
Date: 2014-02-18 21:11:48
Summary: History panel: begin process of breaking up panel into more focused prototypes
Affected #: 11 files
diff -r 26e37f6af3a8a090d9d6e923fa3e90acb0e64572 -r 33812bcdc52393bf179dd501b4334be4ec4e97a7 lib/galaxy/webapps/galaxy/controllers/history.py
--- a/lib/galaxy/webapps/galaxy/controllers/history.py
+++ b/lib/galaxy/webapps/galaxy/controllers/history.py
@@ -887,10 +887,13 @@
history_dictionary = {}
hda_dictionaries = []
+ user_is_owner = False
try:
history_to_view = self.get_history( trans, id, False )
if not history_to_view:
return trans.show_error_message( "The specified history does not exist." )
+ if history_to_view.user == trans.user:
+ user_is_owner = True
# Admin users can view any history
if( ( history_to_view.user != trans.user )
@@ -925,7 +928,7 @@
+ 'Please contact a Galaxy administrator if the problem persists.' )
return trans.fill_template_mako( "history/view.mako",
- history=history_dictionary, hdas=hda_dictionaries,
+ history=history_dictionary, hdas=hda_dictionaries, user_is_owner=user_is_owner,
show_deleted=show_deleted, show_hidden=show_hidden, use_panels=use_panels )
@web.expose
@@ -941,9 +944,8 @@
# Security check raises error if user cannot access history.
self.security_check( trans, history, False, True)
- # Get datasets.
+ # Get datasets and annotations
datasets = self.get_history_datasets( trans, history )
- # Get annotations.
history.annotation = self.get_item_annotation_str( trans.sa_session, history.user, history )
for dataset in datasets:
dataset.annotation = self.get_item_annotation_str( trans.sa_session, history.user, dataset )
@@ -957,8 +959,9 @@
else:
user_item_rating = 0
ave_item_rating, num_ratings = self.get_ave_item_rating_data( trans.sa_session, history )
- return trans.stream_template_mako( "history/display.mako", item = history, item_data = datasets,
- user_item_rating = user_item_rating, ave_item_rating=ave_item_rating, num_ratings=num_ratings )
+
+ return trans.stream_template_mako( "history/display.mako", item=history, item_data=datasets,
+ user_item_rating = user_item_rating, ave_item_rating=ave_item_rating, num_ratings=num_ratings )
@web.expose
@web.require_login( "share Galaxy histories" )
diff -r 26e37f6af3a8a090d9d6e923fa3e90acb0e64572 -r 33812bcdc52393bf179dd501b4334be4ec4e97a7 static/scripts/mvc/history/current-history-panel.js
--- /dev/null
+++ b/static/scripts/mvc/history/current-history-panel.js
@@ -0,0 +1,285 @@
+define([
+ "mvc/dataset/hda-edit",
+ "mvc/history/history-panel"
+], function( hdaEdit, hpanel ){
+// ============================================================================
+/** session storage for history panel preferences (and to maintain state)
+ */
+var HistoryPanelPrefs = SessionStorageModel.extend({
+ defaults : {
+ /** is the panel currently showing the search/filter controls? */
+ searching : false,
+ /** should the tags editor be shown or hidden initially? */
+ tagsEditorShown : false,
+ /** should the annotation editor be shown or hidden initially? */
+ annotationEditorShown : false
+ },
+ toString : function(){
+ return 'HistoryPanelPrefs(' + JSON.stringify( this.toJSON() ) + ')';
+ }
+});
+
+/** key string to store panel prefs (made accessible on class so you can access sessionStorage directly) */
+HistoryPanelPrefs.storageKey = function storageKey(){
+ return ( 'history-panel' );
+};
+
+/* =============================================================================
+TODO:
+
+============================================================================= */
+/** @class View/Controller for the user's current history model as used in the history
+ * panel (current right hand panel).
+ * @name HistoryPanel
+ *
+ * @augments Backbone.View
+ * @borrows LoggableMixin#logger as #logger
+ * @borrows LoggableMixin#log as #log
+ * @constructs
+ */
+var CurrentHistoryPanel = hpanel.HistoryPanel.extend(
+/** @lends HistoryPanel.prototype */{
+
+ ///** logger used to record this.log messages, commonly set to console */
+ //// comment this out to suppress log output
+ //logger : console,
+
+ /** class to use for constructing the HDA views */
+ HDAViewClass : hdaEdit.HDAEditView,
+
+ emptyMsg : _l( "This history is empty. Click 'Get Data' on the left pane to start" ),
+ noneFoundMsg : _l( "No matching datasets found" ),
+
+ // ......................................................................... SET UP
+ /** Set up the view, set up storage, bind listeners to HDACollection events
+ * @param {Object} attributes
+ * @config {Object} urlTemplates.hda nested object containing url templates for HDAViews
+ * @throws 'needs urlTemplates' if urlTemplates.history or urlTemplates.hda aren't present
+ * @see PersistentStorage
+ * @see Backbone.View#initialize
+ */
+ initialize : function( attributes ){
+ attributes = attributes || {};
+
+ // ---- persistent preferences
+ /** maintain state / preferences over page loads */
+ this.preferences = new HistoryPanelPrefs( _.extend({
+ id : HistoryPanelPrefs.storageKey()
+ }, _.pick( attributes, _.keys( HistoryPanelPrefs.prototype.defaults ) )));
+
+ hpanel.HistoryPanel.prototype.initialize.call( this, attributes );
+ if( this.model ){
+ console.debug( this.model );
+ this.model.checkForUpdates();
+ }
+ },
+
+ // ------------------------------------------------------------------------ loading history/hda models
+ /** (re-)loads the user's current history & hdas w/ details */
+ loadCurrentHistory : function( attributes ){
+ // implemented as a 'fresh start' or for when there is no model (intial panel render)
+ var panel = this;
+ return this.loadHistoryWithHDADetails( 'current', attributes )
+ .then(function( historyData, hdaData ){
+ panel.trigger( 'current-history', panel );
+ });
+ },
+
+ /** loads a history & hdas w/ details and makes them the current history */
+ switchToHistory : function( historyId, attributes ){
+ //console.info( 'switchToHistory:', historyId, attributes );
+ var panel = this,
+ historyFn = function(){
+ // make this current and get history data with one call
+ return jQuery.post( galaxy_config.root + 'api/histories/' + historyId + '/set_as_current' );
+ };
+ return this.loadHistoryWithHDADetails( historyId, attributes, historyFn )
+ .then(function( historyData, hdaData ){
+ panel.trigger( 'switched-history', panel );
+ });
+ },
+
+ /** creates a new history on the server and sets it as the user's current history */
+ createNewHistory : function( attributes ){
+ if( !Galaxy || !Galaxy.currUser || Galaxy.currUser.isAnonymous() ){
+ this.displayMessage( 'error', _l( 'You must be logged in to create histories' ) );
+ return $.when();
+ }
+ var panel = this,
+ historyFn = function(){
+ // get history data from posting a new history (and setting it to current)
+ return jQuery.post( galaxy_config.root + 'api/histories', { current: true });
+ };
+ // id undefined bc there is no historyId yet - the server will provide
+ // (no need for details - nothing expanded in new history)
+ return this.loadHistory( undefined, attributes, historyFn )
+ .then(function( historyData, hdaData ){
+ panel.trigger( 'new-history', panel );
+ });
+ },
+
+ /** release/free/shutdown old models and set up panel for new models */
+ setModel : function( newHistoryJSON, newHdaJSON, attributes ){
+ attributes = attributes || {};
+ hpanel.HistoryPanel.prototype.setModel.call( this, newHistoryJSON, newHdaJSON, attributes );
+ this.model.checkForUpdates();
+ return this;
+ },
+
+ // ------------------------------------------------------------------------ history/hda event listening
+ /** listening for history and HDA events */
+ _setUpModelEventHandlers : function(){
+ hpanel.HistoryPanel.prototype._setUpModelEventHandlers.call( this );
+ // ---- history
+ // update the quota meter when current history changes size
+ if( Galaxy && Galaxy.quotaMeter ){
+ this.listenTo( this.model, 'change:nice_size', function(){
+ //console.info( '!! model size changed:', this.model.get( 'nice_size' ) )
+//TODO: global
+ Galaxy.quotaMeter.update();
+ });
+ }
+
+ // if an a hidden hda is created (gen. by a workflow), moves thru the updater to the ready state,
+ // then: remove it from the collection if the panel is set to NOT show hidden datasets
+ this.model.hdas.on( 'state:ready', function( hda, newState, oldState ){
+ if( ( !hda.get( 'visible' ) )
+ && ( !this.storage.get( 'show_hidden' ) ) ){
+ this.removeHdaView( this.hdaViews[ hda.id ] );
+ }
+ }, this );
+
+ },
+
+ // ------------------------------------------------------------------------ panel rendering
+ /** Render urls, historyPanel body, and hdas (if any are shown)
+ * @fires: rendered when the panel is attached and fully visible
+ * @see Backbone.View#render
+ */
+ render : function( speed, callback ){
+ // send a speed of 0 to have no fade in/out performed
+ speed = ( speed === undefined )?( this.fxSpeed ):( speed );
+ var panel = this,
+ $newRender;
+
+ // handle the possibility of no model (can occur if fetching the model returns an error)
+ if( this.model ){
+ $newRender = this.renderModel();
+ } else {
+ $newRender = this.renderWithoutModel();
+ }
+
+ // fade out existing, swap with the new, fade in, set up behaviours
+ $( panel ).queue( 'fx', [
+ function( next ){
+ //panel.$el.fadeTo( panel.fxSpeed, 0.0001, next );
+ if( speed && panel.$el.is( ':visible' ) ){
+ panel.$el.fadeOut( speed, next );
+ } else {
+ next();
+ }
+ },
+ function( next ){
+ // swap over from temp div newRender
+ panel.$el.empty();
+ if( $newRender ){
+ panel.$el.append( $newRender.children() );
+ panel.renderBasedOnPrefs();
+ }
+ next();
+ },
+ function( next ){
+ if( speed && !panel.$el.is( ':visible' ) ){
+ panel.$el.fadeIn( speed, next );
+ } else {
+ next();
+ }
+ },
+ function( next ){
+ //TODO: ideally, these would be set up before the fade in (can't because of async save text)
+ if( callback ){ callback.call( this ); }
+ panel.trigger( 'rendered', this );
+ next();
+ }
+ ]);
+ return this;
+ },
+
+ renderBasedOnPrefs : function(){
+ if( this.preferences.get( 'searching' ) ){
+ this.showSearchControls( 0 );
+ }
+ },
+
+ // ........................................................................ external objects/MVC
+ //TODO: remove quota meter from panel and remove this
+ /** add listeners to an external quota meter (mvc/user/user-quotameter.js) */
+ connectToQuotaMeter : function( quotaMeter ){
+ if( !quotaMeter ){
+ return this;
+ }
+ // show/hide the 'over quota message' in the history when the meter tells it to
+ this.listenTo( quotaMeter, 'quota:over', this.showQuotaMessage );
+ this.listenTo( quotaMeter, 'quota:under', this.hideQuotaMessage );
+
+ // having to add this to handle re-render of hview while overquota (the above do not fire)
+ this.on( 'rendered rendered:initial', function(){
+ if( quotaMeter && quotaMeter.isOverQuota() ){
+ this.showQuotaMessage();
+ }
+ });
+ return this;
+ },
+
+//TODO: this seems more like a per user message than a history message; IOW, this doesn't belong here
+ /** Show the over quota message (which happens to be in the history panel).
+ */
+ showQuotaMessage : function(){
+ var msg = this.$el.find( '.quota-message' );
+ //this.log( this + ' showing quota message:', msg, userData );
+ if( msg.is( ':hidden' ) ){ msg.slideDown( this.fxSpeed ); }
+ },
+
+//TODO: this seems more like a per user message than a history message
+ /** Hide the over quota message (which happens to be in the history panel).
+ */
+ hideQuotaMessage : function(){
+ var msg = this.$el.find( '.quota-message' );
+ //this.log( this + ' hiding quota message:', msg, userData );
+ if( !msg.is( ':hidden' ) ){ msg.slideUp( this.fxSpeed ); }
+ },
+
+//TODO: move show_deleted/hidden into panel from opt menu and remove this
+ /** add listeners to an external options menu (templates/webapps/galaxy/root/index.mako) */
+ connectToOptionsMenu : function( optionsMenu ){
+ if( !optionsMenu ){
+ return this;
+ }
+ // set a visible indication in the popupmenu for show_hidden/deleted based on the currHistoryPanel's settings
+ this.on( 'new-storage', function( storage, panel ){
+ if( optionsMenu && storage ){
+ optionsMenu.findItemByHtml( _l( 'Include Deleted Datasets' ) ).checked = storage.get( 'show_deleted' );
+ optionsMenu.findItemByHtml( _l( 'Include Hidden Datasets' ) ).checked = storage.get( 'show_hidden' );
+ }
+ });
+ return this;
+ },
+
+ /** Return a string rep of the history
+ */
+ toString : function(){
+ return 'CurrentHistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
+ }
+});
+
+//------------------------------------------------------------------------------ TEMPLATES
+CurrentHistoryPanel.templates = {
+ historyPanel : Handlebars.templates[ 'template-history-historyPanel' ],
+ anonHistoryPanel : Handlebars.templates[ 'template-history-historyPanel-anon' ]
+};
+
+//==============================================================================
+ return {
+ CurrentHistoryPanel : CurrentHistoryPanel
+ };
+});
diff -r 26e37f6af3a8a090d9d6e923fa3e90acb0e64572 -r 33812bcdc52393bf179dd501b4334be4ec4e97a7 static/scripts/mvc/history/history-model.js
--- a/static/scripts/mvc/history/history-model.js
+++ b/static/scripts/mvc/history/history-model.js
@@ -75,7 +75,7 @@
/** cached timeout id for the HDA updater */
this.updateTimeoutId = null;
// set up update timeout if needed
- this.checkForUpdates();
+ //this.checkForUpdates();
},
/** set up any event listeners for this history including those to the contained HDAs
diff -r 26e37f6af3a8a090d9d6e923fa3e90acb0e64572 -r 33812bcdc52393bf179dd501b4334be4ec4e97a7 static/scripts/mvc/history/history-panel.js
--- a/static/scripts/mvc/history/history-panel.js
+++ b/static/scripts/mvc/history/history-panel.js
@@ -1,157 +1,46 @@
define([
- "mvc/history/history-model",
"mvc/dataset/hda-model",
- "mvc/dataset/hda-base",
- "mvc/dataset/hda-edit"
-], function( historyModel, hdaModel, hdaBase, hdaEdit ){
+ "mvc/dataset/hda-edit",
+ "mvc/history/readonly-history-panel"
+], function( hdaModel, hdaEdit, readonlyPanel ){
+/* =============================================================================
+TODO:
-
-// ============================================================================
-/** session storage for history panel preferences (and to maintain state)
- */
-var HistoryPanelPrefs = SessionStorageModel.extend({
- defaults : {
- /** is the panel currently showing the search/filter controls? */
- searching : false,
- /** should the tags editor be shown or hidden initially? */
- tagsEditorShown : false,
- /** should the annotation editor be shown or hidden initially? */
- annotationEditorShown : false
- },
- toString : function(){
- return 'HistoryPanelPrefs(' + JSON.stringify( this.toJSON() ) + ')';
- }
-});
-
-/** key string to store panel prefs (made accessible on class so you can access sessionStorage directly) */
-HistoryPanelPrefs.storageKey = function storageKey(){
- return ( 'history-panel' );
-};
-
-
-// ============================================================================
-/** session storage for individual history preferences
- */
-var HistoryPrefs = SessionStorageModel.extend({
- defaults : {
- //TODO:?? expandedHdas to array?
- expandedHdas : {},
- //TODO:?? move to user?
- show_deleted : false,
- show_hidden : false
- //TODO: add scroll position?
- },
- /** add an hda id to the hash of expanded hdas */
- addExpandedHda : function( id ){
- this.save( 'expandedHdas', _.extend( this.get( 'expandedHdas' ), _.object([ id ], [ true ]) ) );
- },
- /** remove an hda id from the hash of expanded hdas */
- removeExpandedHda : function( id ){
- this.save( 'expandedHdas', _.omit( this.get( 'expandedHdas' ), id ) );
- },
- toString : function(){
- return 'HistoryPrefs(' + this.id + ')';
- }
-});
-
-/** key string to store each histories settings under */
-HistoryPrefs.historyStorageKey = function historyStorageKey( historyId ){
- // class lvl for access w/o instantiation
- if( !historyId ){
- throw new Error( 'HistoryPrefs.historyStorageKey needs valid id: ' + historyId );
- }
- // single point of change
- return ( 'history:' + historyId );
-};
-
-
-/* =============================================================================
-Backbone.js implementation of history panel
-
-r.js optimizer cline:
-r.js -o baseUrl=. name=./mvc/history/history-panel.js out=history-panel.min.js
-
-TODO:
- tags & annotations -> out
- use model.save instead of urls
-
- feature creep:
- lineage
- hide button
- show permissions in info
- show shared/sharing status on ds, history
- selection, multi-select (and actions common to selected (ugh))
- searching
- sorting, re-shuffling
-
============================================================================= */
-/** @class View/Controller for the history model as used in the history
- * panel (current right hand panel).
+/** @class View/Controller for the history model.
* @name HistoryPanel
*
+ * Allows:
+ * (everything ReadOnlyHistoryPanel allows)
+ * changing the name
+ * displaying and editing tags and annotations
+ * multi-selection and operations on mulitple hdas
+ * Does not allow:
+ * changing the name
+ *
* @augments Backbone.View
* @borrows LoggableMixin#logger as #logger
* @borrows LoggableMixin#log as #log
* @constructs
*/
-var HistoryPanel = Backbone.View.extend( LoggableMixin ).extend(
+var HistoryPanel = readonlyPanel.ReadOnlyHistoryPanel.extend(
/** @lends HistoryPanel.prototype */{
-
+
///** logger used to record this.log messages, commonly set to console */
//// comment this out to suppress log output
//logger : console,
- /** which class to use for constructing the HDA views */
- //defaultHDAViewClass : hdaBase.HDABaseView,
- defaultHDAViewClass : hdaEdit.HDAEditView,
+ /** class to use for constructing the HDA views */
+ HDAViewClass : hdaEdit.HDAEditView,
- tagName : 'div',
- className : 'history-panel',
-
- /** (in ms) that jquery effects will use */
- fxSpeed : 'fast',
-
- datasetsSelector : '.datasets-list',
- emptyMsgSelector : '.empty-history-message',
- msgsSelector : '.message-container',
-
// ......................................................................... SET UP
/** Set up the view, set up storage, bind listeners to HDACollection events
* @param {Object} attributes
- * @config {Object} urlTemplates.hda nested object containing url templates for HDAViews
- * @throws 'needs urlTemplates' if urlTemplates.history or urlTemplates.hda aren't present
- * @see PersistentStorage
- * @see Backbone.View#initialize
*/
initialize : function( attributes ){
attributes = attributes || {};
- // set the logger if requested
- if( attributes.logger ){
- this.logger = attributes.logger;
- }
- this.log( this + '.initialize:', attributes );
// ---- set up instance vars
- // control contents/behavior based on where (and in what context) the panel is being used
- /** which backbone view class to use when displaying the hda list */
- this.HDAViewClass = attributes.HDAViewClass || this.defaultHDAViewClass;
- /** where should pages from links be displayed? (default to new tab/window) */
- this.linkTarget = attributes.linkTarget || '_blank';
-
- // ---- sub views and saved elements
- /** map of hda model ids to hda views */
- this.hdaViews = {};
- /** loading indicator */
- this.indicator = new LoadingIndicator( this.$el );
-
- // ---- persistent state and preferences
- /** maintain state / preferences over page loads */
- this.preferences = new HistoryPanelPrefs( _.extend({
- id : HistoryPanelPrefs.storageKey()
- }, _.pick( attributes, _.keys( HistoryPanelPrefs.prototype.defaults ) )));
-
- /** filters for displaying hdas */
- this.filters = [];
/** selected hda ids */
this.selectedHdaIds = [];
@@ -161,443 +50,33 @@
this.annotationEditorShown = attributes.annotationEditorShown || false;
this.tagsEditorShown = attributes.tagsEditorShown || false;
- this._setUpListeners();
-
- // ---- handle models passed on init
- if( this.model ){
- this._setUpWebStorage( attributes.initiallyExpanded, attributes.show_deleted, attributes.show_hidden );
- this._setUpModelEventHandlers();
- }
-//TODO: remove?
- // ---- and any run functions
- if( attributes.onready ){
- attributes.onready.call( this );
- }
+ readonlyPanel.ReadOnlyHistoryPanel.prototype.initialize.call( this, attributes );
},
- /** create any event listeners for the panel
- * @fires: rendered:initial on the first render
- * @fires: empty-history when switching to a history with no HDAs or creating a new history
- */
- _setUpListeners : function(){
- // ---- event handlers for self
- this.on( 'error', function( model, xhr, options, msg, details ){
- this.errorHandler( model, xhr, options, msg, details );
- });
-
- this.on( 'loading-history', function(){
- // show the loading indicator when loading a new history starts...
- this.showLoadingIndicator( 'loading history...', 40 );
- });
- this.on( 'loading-done', function(){
- // ...hiding it again when loading is done (or there's been an error)
- this.hideLoadingIndicator( 40 );
- });
-
- // throw the first render up as a diff namespace using once
- // (for outside consumption)
- this.once( 'rendered', function(){
- this.trigger( 'rendered:initial', this );
- return false;
- });
-
- // trigger an event when there are no visible hdas
- // (for outside consumption)
- this.on( 'switched-history current-history new-history', function(){
- if( _.isEmpty( this.hdaViews ) ){
- this.trigger( 'empty-history', this );
- }
- });
-
- // debugging
- if( this.logger ){
- this.on( 'all', function( event ){
- this.log( this + '', arguments );
- }, this );
- }
- },
-
- //TODO: see base-mvc
- //onFree : function(){
- // _.each( this.hdaViews, function( view, modelId ){
- // view.free();
- // });
- // this.hdaViews = null;
- //},
-
- // ........................................................................ error handling
- /** Event listener to handle errors (from the panel, the history, or the history's HDAs)
- * @param {Model or View} model the (Backbone) source of the error
- * @param {XMLHTTPRequest} xhr any ajax obj. assoc. with the error
- * @param {Object} options the options map commonly used with bbone ajax
- * @param {String} msg optional message passed to ease error location
- * @param {Object} msg optional object containing error details
- */
- errorHandler : function( model, xhr, options, msg, details ){
- var parsed = this._parseErrorMessage( model, xhr, options, msg, details );
-
- // interrupted ajax
- if( xhr && xhr.status === 0 && xhr.readyState === 0 ){
-
- // bad gateway
- } else if( xhr && xhr.status === 502 ){
-//TODO: gmail style 'reconnecting in Ns'
-
- // otherwise, show an error message inside the panel
- } else {
- // it's possible to have a triggered error before the message container is rendered - wait for it to show
- if( !this.$el.find( this.msgsSelector ).is( ':visible' ) ){
- this.once( 'rendered', function(){
- this.displayMessage( 'error', parsed.message, parsed.details );
- });
- } else {
- this.displayMessage( 'error', parsed.message, parsed.details );
- }
- }
- },
-
- /** Parse an error event into an Object usable by displayMessage based on the parameters
- * note: see errorHandler for more info on params
- */
- _parseErrorMessage : function( model, xhr, options, msg, details ){
- var user = Galaxy.currUser,
- // add the args (w/ some extra info) into an obj
- parsed = {
- message : this._bePolite( msg ),
- details : {
- user : ( user instanceof User )?( user.toJSON() ):( user + '' ),
- source : ( model instanceof Backbone.Model )?( model.toJSON() ):( model + '' ),
- xhr : xhr,
- options : ( xhr )?( _.omit( options, 'xhr' ) ):( options )
- }
- };
- // add any extra details passed in
- _.extend( parsed.details, details || {} );
- // fancy xhr.header parsing (--> obj)
- if( xhr && _.isFunction( xhr.getAllResponseHeaders ) ){
- var responseHeaders = xhr.getAllResponseHeaders();
- responseHeaders = _.compact( responseHeaders.split( '\n' ) );
- responseHeaders = _.map( responseHeaders, function( header ){
- return header.split( ': ' );
- });
- parsed.details.xhr.responseHeaders = _.object( responseHeaders );
- }
- return parsed;
- },
-
- /** Modify an error message to be fancy and wear a monocle. */
- _bePolite : function( msg ){
- msg = msg || _l( 'An error occurred while getting updates from the server' );
- return msg + '. ' + _l( 'Please contact a Galaxy administrator if the problem persists.' );
- },
-
- // ------------------------------------------------------------------------ loading history/hda models
-
- //NOTE: all the following fns replace the existing history model with a new model
- // (in the following 'details' refers to the full set of hda api data (urls, display_apps, misc_info, etc.)
- // - hdas w/o details will have summary data only (name, hid, deleted, visible, state, etc.))
-
- /** (re-)loads the user's current history & hdas w/ details */
- loadCurrentHistory : function( attributes ){
- // implemented as a 'fresh start' or for when there is no model (intial panel render)
- var panel = this;
- return this.loadHistoryWithHDADetails( 'current', attributes )
- .then(function( historyData, hdaData ){
- panel.trigger( 'current-history', panel );
- });
- },
-
- /** loads a history & hdas w/ details and makes them the current history */
- switchToHistory : function( historyId, attributes ){
- //console.info( 'switchToHistory:', historyId, attributes );
- var panel = this,
- historyFn = function(){
- // make this current and get history data with one call
- return jQuery.post( galaxy_config.root + 'api/histories/' + historyId + '/set_as_current' );
- };
- return this.loadHistoryWithHDADetails( historyId, attributes, historyFn )
- .then(function( historyData, hdaData ){
- panel.trigger( 'switched-history', panel );
- });
- },
-
- /** creates a new history on the server and sets it as the user's current history */
- createNewHistory : function( attributes ){
- if( !Galaxy || !Galaxy.currUser || Galaxy.currUser.isAnonymous() ){
- this.displayMessage( 'error', _l( 'You must be logged in to create histories' ) );
- return $.when();
- }
- var panel = this,
- historyFn = function(){
- // get history data from posting a new history (and setting it to current)
- return jQuery.post( galaxy_config.root + 'api/histories', { current: true });
- };
- // id undefined bc there is no historyId yet - the server will provide
- // (no need for details - nothing expanded in new history)
- return this.loadHistory( undefined, attributes, historyFn )
- .then(function( historyData, hdaData ){
- panel.trigger( 'new-history', panel );
- });
- },
-
- /** loads a history & hdas w/ details (but does not make them the current history) */
- loadHistoryWithHDADetails : function( historyId, attributes, historyFn, hdaFn ){
- //console.info( 'loadHistoryWithHDADetails:', historyId, attributes, historyFn, hdaFn );
- var panel = this,
- // will be called to get hda ids that need details from the api
- hdaDetailIds = function( historyData ){
-//TODO: non-visible HDAs are getting details loaded... either stop loading them at all or filter ids thru isVisible
- return panel.getExpandedHdaIds( historyData.id );
- };
- return this.loadHistory( historyId, attributes, historyFn, hdaFn, hdaDetailIds );
- },
-
- /** loads a history & hdas w/ NO details (but does not make them the current history) */
- loadHistory : function( historyId, attributes, historyFn, hdaFn, hdaDetailIds ){
- this.trigger( 'loading-history', this );
- attributes = attributes || {};
- var panel = this;
- //console.info( 'loadHistory:', historyId, attributes, historyFn, hdaFn, hdaDetailIds );
- var xhr = historyModel.History.getHistoryData( historyId, {
- historyFn : historyFn,
- hdaFn : hdaFn,
- hdaDetailIds : attributes.initiallyExpanded || hdaDetailIds
- });
- return this._loadHistoryFromXHR( xhr, attributes )
- .fail( function( xhr, where, history ){
- // throw an error up for the error handler
- panel.trigger( 'error', panel, xhr, attributes, _l( 'An error was encountered while ' + where ),
- { historyId: historyId, history: history || {} });
- })
- .always( function(){
- // bc hideLoadingIndicator relies on this firing
- panel.trigger( 'loading-done', panel );
- });
- },
-
- /** given an xhr that will provide both history and hda data, pass data to set model or handle xhr errors */
- _loadHistoryFromXHR : function( xhr, attributes ){
- var panel = this;
- xhr.then( function( historyJSON, hdaJSON ){
- panel.setModel( historyJSON, hdaJSON, attributes );
- });
- xhr.fail( function( xhr, where ){
- // always render - whether we get a model or not
- panel.render();
- });
- return xhr;
- },
-
- /** release/free/shutdown old models and set up panel for new models */
- setModel : function( newHistoryJSON, newHdaJSON, attributes ){
- attributes = attributes || {};
- //console.info( 'setModel:', newHistoryJSON, newHdaJSON.length, attributes );
-
- // stop/release the previous model, and clear cache to hda sub-views
- if( this.model ){
- this.model.clearUpdateTimeout();
- this.stopListening( this.model );
- this.stopListening( this.model.hdas );
- //TODO: see base-mvc
- //this.model.free();
- }
- this.hdaViews = {};
-
- // set up the new model and render
- if( Galaxy && Galaxy.currUser ){
-//TODO: global
- newHistoryJSON.user = Galaxy.currUser.toJSON();
- }
- this.model = new historyModel.History( newHistoryJSON, newHdaJSON, attributes );
- this._setUpWebStorage( attributes.initiallyExpanded, attributes.show_deleted, attributes.show_hidden );
- this._setUpModelEventHandlers();
- this.selectedHdaIds = [];
- this.trigger( 'new-model', this );
- this.render();
- return this;
- },
-
- // ------------------------------------------------------------------------ browser stored prefs
- /** Set up client side storage. Currently PersistanStorage keyed under 'HistoryPanel.<id>'
- * @param {Object} initiallyExpanded
- * @param {Boolean} show_deleted whether to show deleted HDAs (overrides stored)
- * @param {Boolean} show_hidden
- * @see PersistentStorage
- */
- _setUpWebStorage : function( initiallyExpanded, show_deleted, show_hidden ){
- //console.debug( '_setUpWebStorage', initiallyExpanded, show_deleted, show_hidden );
- this.storage = new HistoryPrefs({
- id: HistoryPrefs.historyStorageKey( this.model.get( 'id' ) )
- });
-
- // expanded Hdas is a map of hda.ids -> a boolean repr'ing whether this hda's body is already expanded
- // store any pre-expanded ids passed in
- if( _.isObject( initiallyExpanded ) ){
- this.storage.set( 'exandedHdas', initiallyExpanded );
- }
-
- // get the show_deleted/hidden settings giving priority to values passed in, using web storage otherwise
- // if the page has specifically requested show_deleted/hidden, these will be either true or false
- // (as opposed to undefined, null) - and we give priority to that setting
- if( _.isBoolean( show_deleted ) ){
- this.storage.set( 'show_deleted', show_deleted );
- }
- if( _.isBoolean( show_hidden ) ){
- this.storage.set( 'show_hidden', show_hidden );
- }
-
- this.trigger( 'new-storage', this.storage, this );
- this.log( this + ' (init\'d) storage:', this.storage.get() );
- },
-
- /** clear all stored history panel data */
- clearWebStorage : function(){
- for( var key in sessionStorage ){
- if( key.indexOf( 'history:' ) === 0 ){
- sessionStorage.removeItem( key );
- }
- }
- },
-
- /** get all stored data as an Object for a history with the given id */
- getStoredOptions : function( historyId ){
- if( !historyId || historyId === 'current' ){
- return ( this.storage )?( this.storage.get() ):( {} );
- }
- //TODO: make storage engine generic
- var item = sessionStorage.getItem( HistoryPrefs.historyStorageKey( historyId ) );
- return ( item === null )?( {} ):( JSON.parse( item ) );
- },
-
- /** get an array of expanded hda ids for the given history id */
- getExpandedHdaIds : function( historyId ){
- var expandedHdas = this.getStoredOptions( historyId ).expandedHdas;
- return (( _.isEmpty( expandedHdas ) )?( [] ):( _.keys( expandedHdas ) ));
- },
-
- // ------------------------------------------------------------------------ history/hda event listening
+ // ------------------------------------------------------------------------ panel rendering
/** listening for history and HDA events */
_setUpModelEventHandlers : function(){
- // ---- history
- // on a model error - bounce it up to the panel and remove it from the model
- this.model.on( 'error error:hdas', function( model, xhr, options, msg ){
- this.errorHandler( model, xhr, options, msg );
- }, this );
+ readonlyPanel.ReadOnlyHistoryPanel.prototype._setUpModelEventHandlers.call( this );
- // don't need to re-render entire model on all changes, just render disk size when it changes
this.model.on( 'change:nice_size', this.updateHistoryDiskSize, this );
- // update the quota meter when current history changes size
- if( Galaxy && Galaxy.quotaMeter ){
- this.listenTo( this.model, 'change:nice_size', function(){
- //console.info( '!! model size changed:', this.model.get( 'nice_size' ) )
-//TODO: global
- Galaxy.quotaMeter.update();
- });
- }
-
- // ---- hdas
- // bind events from the model's hda collection
- // note: don't listen to the hdas for errors, history will pass that to us
- //this.model.hdas.on( 'reset', this.addAll, this );
- this.model.hdas.on( 'add', this.addHdaView, this );
-
this.model.hdas.on( 'change:deleted', this.handleHdaDeletionChange, this );
this.model.hdas.on( 'change:visible', this.handleHdaVisibleChange, this );
- // when an hda is purged the disk size changes
this.model.hdas.on( 'change:purged', function( hda ){
// hafta get the new nice-size w/o the purged hda
this.model.fetch();
}, this );
-
- // if an a hidden hda is created (gen. by a workflow), moves thru the updater to the ready state,
- // then: remove it from the collection if the panel is set to NOT show hidden datasets
- this.model.hdas.on( 'state:ready', function( hda, newState, oldState ){
- if( ( !hda.get( 'visible' ) )
- && ( !this.storage.get( 'show_hidden' ) ) ){
- this.removeHdaView( this.hdaViews[ hda.id ] );
- }
- }, this );
-
},
// ------------------------------------------------------------------------ panel rendering
- /** Render urls, historyPanel body, and hdas (if any are shown)
- * @fires: rendered when the panel is attached and fully visible
- * @see Backbone.View#render
- */
- render : function( speed, callback ){
- // send a speed of 0 to have no fade in/out performed
- speed = ( speed === undefined )?( this.fxSpeed ):( speed );
- var panel = this,
- $newRender;
-
- // handle the possibility of no model (can occur if fetching the model returns an error)
- if( this.model ){
- $newRender = this.renderModel();
- } else {
- $newRender = this.renderWithoutModel();
- }
-
- // fade out existing, swap with the new, fade in, set up behaviours
- $( panel ).queue( 'fx', [
- function( next ){
- //panel.$el.fadeTo( panel.fxSpeed, 0.0001, next );
- if( speed && panel.$el.is( ':visible' ) ){
- panel.$el.fadeOut( speed, next );
- } else {
- next();
- }
- },
- function( next ){
- // swap over from temp div newRender
- panel.$el.empty();
- if( $newRender ){
- panel.$el.append( $newRender.children() );
- panel.renderBasedOnPrefs();
- }
- next();
- },
- function( next ){
- if( speed && !panel.$el.is( ':visible' ) ){
- panel.$el.fadeIn( speed, next );
- } else {
- next();
- }
- },
- function( next ){
- //TODO: ideally, these would be set up before the fade in (can't because of async save text)
- if( callback ){ callback.call( this ); }
- panel.trigger( 'rendered', this );
- next();
- }
- ]);
- return this;
- },
-
- /** render with no history data */
- renderWithoutModel : function( ){
- // we'll always need the message container
- var $newRender = $( '<div/>' ),
- $msgContainer = $( '<div/>' ).addClass( 'message-container' )
- .css({ 'margin-left': '4px', 'margin-right': '4px' });
- return $newRender.append( $msgContainer );
- },
-
/** render with history data */
renderModel : function( ){
var $newRender = $( '<div/>' );
- // render based on anonymity, set up behaviors
- if( !Galaxy || !Galaxy.currUser || Galaxy.currUser.isAnonymous() ){
- $newRender.append( HistoryPanel.templates.anonHistoryPanel( this.model.toJSON() ) );
-
- } else {
- $newRender.append( HistoryPanel.templates.historyPanel( this.model.toJSON() ) );
- if( Galaxy.currUser.id && Galaxy.currUser.id === this.model.get( 'user_id' ) ){
- this._renderTags( $newRender );
- this._renderAnnotation( $newRender );
- }
+ $newRender.append( HistoryPanel.templates.historyPanel( this.model.toJSON() ) );
+ if( Galaxy.currUser.id && Galaxy.currUser.id === this.model.get( 'user_id' ) ){
+ this._renderTags( $newRender );
+ this._renderAnnotation( $newRender );
}
// search and select available to both anon/logged-in users
$newRender.find( '.history-secondary-actions' ).prepend( this._renderSelectButton() );
@@ -611,12 +90,6 @@
return $newRender;
},
- renderBasedOnPrefs : function(){
- if( this.preferences.get( 'searching' ) ){
- this.showSearchControls( 0 );
- }
- },
-
_renderTags : function( $where ){
var panel = this;
this.tagsEditor = new TagsEditor({
@@ -625,11 +98,9 @@
onshowFirstTime : function(){ this.render(); },
// show hide hda view tag editors when this is shown/hidden
onshow : function(){
- panel.preferences.set( 'tagsEditorShown', true );
panel.toggleHDATagEditors( true, panel.fxSpeed );
},
onhide : function(){
- panel.preferences.set( 'tagsEditorShown', false );
panel.toggleHDATagEditors( false, panel.fxSpeed );
},
$activator : faIconButton({
@@ -638,9 +109,6 @@
faIcon : 'fa-tags'
}).appendTo( $where.find( '.history-secondary-actions' ) )
});
- if( this.preferences.get( 'tagsEditorShown' ) ){
- this.tagsEditor.toggle( true );
- }
},
_renderAnnotation : function( $where ){
var panel = this;
@@ -650,11 +118,9 @@
onshowFirstTime : function(){ this.render(); },
// show hide hda view annotation editors when this is shown/hidden
onshow : function(){
- panel.preferences.set( 'annotationEditorShown', true );
panel.toggleHDAAnnotationEditors( true, panel.fxSpeed );
},
onhide : function(){
- panel.preferences.set( 'annotationEditorShown', false );
panel.toggleHDAAnnotationEditors( false, panel.fxSpeed );
},
$activator : faIconButton({
@@ -663,18 +129,8 @@
faIcon : 'fa-comment'
}).appendTo( $where.find( '.history-secondary-actions' ) )
});
- if( this.preferences.get( 'annotationEditorShown' ) ){
- this.annotationEditor.toggle( true );
- }
},
- /** button for opening search */
- _renderSearchButton : function( $where ){
- return faIconButton({
- title : _l( 'Search datasets' ),
- classes : 'history-search-btn',
- faIcon : 'fa-search'
- });
- },
+
/** button for starting select mode */
_renderSelectButton : function( $where ){
return faIconButton({
@@ -762,45 +218,23 @@
},
// ------------------------------------------------------------------------ hda sub-views
- /** alias to the model. Updates the hda list only (not the history) */
- refreshHdas : function( detailIds, options ){
- if( this.model ){
- return this.model.refresh( detailIds, options );
- }
- // may have callbacks - so return an empty promise
- return $.when();
+ /** If this hda is deleted and we're not showing deleted hdas, remove the view
+ * @param {HistoryDataAssociation} the hda to check
+ */
+ handleHdaDeletionChange : function( hda ){
+ if( hda.get( 'deleted' ) && !this.storage.get( 'show_deleted' ) ){
+ this.removeHdaView( this.hdaViews[ hda.id ] );
+ } // otherwise, the hdaView rendering should handle it
},
- /** Add an hda view to the panel for the given hda
- * @param {HistoryDatasetAssociation} hda
+
+ /** If this hda is hidden and we're not showing hidden hdas, remove the view
+ * @param {HistoryDataAssociation} the hda to check
*/
- addHdaView : function( hda ){
- this.log( 'add.' + this, hda );
- var panel = this;
-
- // don't add the view if it wouldn't be visible accrd. to current settings
- if( !hda.isVisible( this.storage.get( 'show_deleted' ), this.storage.get( 'show_hidden' ) ) ){
- return;
- }
-
- // create and prepend to current el, if it was empty fadeout the emptyMsg first
- $({}).queue([
- function fadeOutEmptyMsg( next ){
- var $emptyMsg = panel.$el.find( panel.emptyMsgSelector );
- if( $emptyMsg.is( ':visible' ) ){
- $emptyMsg.fadeOut( panel.fxSpeed, next );
- } else {
- next();
- }
- },
- function createAndPrepend( next ){
- panel.scrollToTop();
- var $whereTo = panel.$el.find( panel.datasetsSelector ),
- hdaView = panel.createHdaView( hda );
- panel.hdaViews[ hda.id ] = hdaView;
- hdaView.render().$el.hide().prependTo( $whereTo ).slideDown( panel.fxSpeed );
- }
- ]);
+ handleHdaVisibleChange : function( hda ){
+ if( hda.hidden() && !this.storage.get( 'show_hidden' ) ){
+ this.removeHdaView( this.hdaViews[ hda.id ] );
+ } // otherwise, the hdaView rendering should handle it
},
/** Create an HDA view for the given HDA (but leave attachment for addHdaView above)
@@ -816,8 +250,8 @@
selectable : this.selecting,
hasUser : this.model.ownedByCurrUser(),
logger : this.logger,
- tagsEditorShown : this.preferences.get( 'tagsEditorShown' ),
- annotationEditorShown : this.preferences.get( 'annotationEditorShown' )
+ tagsEditorShown : !this.tagsEditor.isHidden(),
+ annotationEditorShown : !this.annotationEditor.isHidden()
});
this._setUpHdaListeners( hdaView );
return hdaView;
@@ -829,13 +263,8 @@
*/
_setUpHdaListeners : function( hdaView ){
var historyView = this;
- // maintain a list of hdas whose bodies are expanded
- hdaView.on( 'body-expanded', function( id ){
- historyView.storage.addExpandedHda( id );
- });
- hdaView.on( 'body-collapsed', function( id ){
- historyView.storage.removeExpandedHda( id );
- });
+ readonlyPanel.ReadOnlyHistoryPanel.prototype._setUpHdaListeners.call( this, hdaView );
+
// maintain a list of hdas that are selected
hdaView.on( 'selected', function( hdaView ){
var id = hdaView.model.get( 'id' );
@@ -847,88 +276,6 @@
historyView.selectedHdaIds = _.without( historyView.selectedHdaIds, id );
//console.debug( 'de-selected', historyView.selectedHdaIds );
});
-//TODO: remove?
- hdaView.on( 'error', function( model, xhr, options, msg ){
- historyView.errorHandler( model, xhr, options, msg );
- });
- },
-
- /** If this hda is deleted and we're not showing deleted hdas, remove the view
- * @param {HistoryDataAssociation} the hda to check
- */
- handleHdaDeletionChange : function( hda ){
- if( hda.get( 'deleted' ) && !this.storage.get( 'show_deleted' ) ){
- this.removeHdaView( this.hdaViews[ hda.id ] );
- } // otherwise, the hdaView rendering should handle it
- },
-
- /** If this hda is hidden and we're not showing hidden hdas, remove the view
- * @param {HistoryDataAssociation} the hda to check
- */
- handleHdaVisibleChange : function( hda ){
- if( hda.hidden() && !this.storage.get( 'show_hidden' ) ){
- this.removeHdaView( this.hdaViews[ hda.id ] );
- } // otherwise, the hdaView rendering should handle it
- },
-
- /** Remove a view from the panel and if the panel is now empty, re-render
- * @param {Int} the id of the hdaView to remove
- */
- removeHdaView : function( hdaView ){
- if( !hdaView ){ return; }
-
- var panel = this;
- hdaView.$el.fadeOut( panel.fxSpeed, function(){
- hdaView.off();
- hdaView.remove();
- delete panel.hdaViews[ hdaView.model.id ];
- if( _.isEmpty( panel.hdaViews ) ){
- panel.$el.find( panel.emptyMsgSelector ).fadeIn( panel.fxSpeed, function(){
- panel.trigger( 'empty-history', panel );
- });
- }
- });
- },
-
- /** Set up/render a view for each HDA to be shown, init with model and listeners.
- * HDA views are cached to the map this.hdaViews (using the model.id as key).
- * @param {jQuery} $whereTo what dom element to prepend the HDA views to
- * @returns the number of visible hda views
- */
- renderHdas : function( $whereTo ){
- $whereTo = $whereTo || this.$el;
- var historyView = this,
- newHdaViews = {},
- $datasetsList = $whereTo.find( this.datasetsSelector ),
- // only render the shown hdas
- //TODO: switch to more general filtered pattern
- visibleHdas = this.model.hdas.getVisible(
- this.storage.get( 'show_deleted' ),
- this.storage.get( 'show_hidden' ),
- this.filters
- );
- //console.debug( 'renderHdas, visibleHdas:', visibleHdas, $whereTo );
- $datasetsList.empty();
-
- if( visibleHdas.length ){
- visibleHdas.each( function( hda ){
- // render it (NOTE: reverse order, newest on top (prepend))
- var hdaId = hda.get( 'id' ),
- hdaView = historyView.createHdaView( hda );
- newHdaViews[ hdaId ] = hdaView;
- if( _.contains( historyView.selectedHdaIds, hdaId ) ){
- hdaView.selected = true;
- }
- $datasetsList.prepend( hdaView.render().$el );
- });
- $whereTo.find( this.emptyMsgSelector ).hide();
-
- } else {
- //console.debug( 'emptyMsg:', $whereTo.find( this.emptyMsgSelector ) )
- $whereTo.find( this.emptyMsgSelector ).show();
- }
- this.hdaViews = newHdaViews;
- return this.hdaViews;
},
/** toggle the visibility of each hdaView's tagsEditor applying all the args sent to this function */
@@ -951,149 +298,41 @@
});
},
+ /** Remove a view from the panel and if the panel is now empty, re-render
+ * @param {Int} the id of the hdaView to remove
+ */
+ removeHdaView : function( hdaView ){
+ if( !hdaView ){ return; }
+
+ var panel = this;
+ hdaView.$el.fadeOut( panel.fxSpeed, function(){
+ hdaView.off();
+ hdaView.remove();
+ delete panel.hdaViews[ hdaView.model.id ];
+ if( _.isEmpty( panel.hdaViews ) ){
+ panel.$el.find( panel.emptyMsgSelector ).fadeIn( panel.fxSpeed, function(){
+ panel.trigger( 'empty-history', panel );
+ });
+ }
+ });
+ },
+
// ------------------------------------------------------------------------ panel events
/** event map */
- events : {
- // allow (error) messages to be clicked away
- //TODO: switch to common close (X) idiom
- 'click .message-container' : 'clearMessages',
-
- 'click .history-search-btn' : 'toggleSearchControls',
+ events : _.extend( _.clone( readonlyPanel.ReadOnlyHistoryPanel.prototype.events ), {
'click .history-select-btn' : function( e ){ this.toggleSelectors( this.fxSpeed ); },
-
'click .history-select-all-datasets-btn' : 'selectAllDatasets',
'click .history-deselect-all-datasets-btn' : 'deselectAllDatasets'
- },
+ }),
/** Update the history size display (curr. upper right of panel).
*/
updateHistoryDiskSize : function(){
this.$el.find( '.history-size' ).text( this.model.get( 'nice_size' ) );
},
-
- /** Collapse all hda bodies and clear expandedHdas in the storage
- */
- collapseAllHdaBodies : function(){
- _.each( this.hdaViews, function( item ){
- item.toggleBodyVisibility( null, false );
- });
- this.storage.set( 'expandedHdas', {} );
- },
-
- /** Handle the user toggling the deleted visibility by:
- * (1) storing the new value in the persistent storage
- * (2) re-rendering the history
- * @returns {Boolean} new show_deleted setting
- */
- toggleShowDeleted : function(){
- this.storage.set( 'show_deleted', !this.storage.get( 'show_deleted' ) );
- this.renderHdas();
- return this.storage.get( 'show_deleted' );
- },
-
- /** Handle the user toggling the deleted visibility by:
- * (1) storing the new value in the persistent storage
- * (2) re-rendering the history
- * @returns {Boolean} new show_hidden setting
- */
- toggleShowHidden : function(){
- this.storage.set( 'show_hidden', !this.storage.get( 'show_hidden' ) );
- this.renderHdas();
- return this.storage.get( 'show_hidden' );
- },
-
- // ........................................................................ filters
- /** render a search input for filtering datasets shown
- * (see the search section in the HDA model for implementation of the actual searching)
- * return will start the search
- * esc will clear the search
- * clicking the clear button will clear the search
- * uses searchInput in ui.js
- */
- setUpSearchInput : function( $where ){
- var panel = this,
- inputSelector = '.history-search-input';
-
- function onSearch( searchFor ){
- //console.debug( 'onSearch', searchFor, panel );
- panel.searchFor = searchFor;
- panel.filters = [ function( hda ){ return hda.matchesAll( panel.searchFor ); } ];
- panel.trigger( 'search:searching', searchFor, panel );
- panel.renderHdas();
- }
- function onFirstSearch( searchFor ){
- //console.debug( 'onSearch', searchFor, panel );
- if( panel.model.hdas.haveDetails() ){
- onSearch( searchFor );
- return;
- }
- panel.$el.find( inputSelector ).searchInput( 'toggle-loading' );
- panel.model.hdas.fetchAllDetails({ silent: true })
- .always( function(){
- panel.$el.find( inputSelector ).searchInput( 'toggle-loading' );
- })
- .done( function(){
- onSearch( searchFor );
- });
- }
- function onSearchClear(){
- //console.debug( 'onSearchClear', panel );
- panel.searchFor = '';
- panel.filters = [];
- panel.trigger( 'search:clear', panel );
- panel.renderHdas();
- }
- $where.searchInput({
- initialVal : panel.searchFor,
- name : 'history-search',
- placeholder : 'search datasets',
- classes : 'history-search',
- onfirstsearch : onFirstSearch,
- onsearch : onSearch,
- onclear : onSearchClear
- });
- return $where;
- },
-//TODO: to hidden/shown plugin
- showSearchControls : function( speed ){
- speed = ( speed === undefined )?( this.fxSpeed ):( speed );
- var panel = this,
- $searchControls = this.$el.find( '.history-search-controls' ),
- $input = $searchControls.find( '.history-search-input' );
- // if it hasn't been rendered - do it now
- if( !$input.children().size() ){
- this.setUpSearchInput( $input );
- //$searchControls.append( faIconButton({
- // title : _l( 'More search options' ),
- // classes : 'history-search-advanced',
- // faIcon : 'fa-ellipsis-horizontal'
- //}) );
- }
- // then slide open, focusing on the input, and persisting the setting when it's done
- $searchControls.slideDown( speed, function(){
- $( this ).find( 'input' ).focus();
- panel.preferences.set( 'searching', true );
- });
- },
- hideSearchControls : function(){
- speed = ( speed === undefined )?( this.fxSpeed ):( speed );
- var panel = this;
- this.$el.find( '.history-search-controls' ).slideUp( speed, function(){
- panel.preferences.set( 'searching', false );
- });
- },
-
- /** toggle showing/hiding the search controls (rendering first on the initial show) */
- toggleSearchControls : function( eventOrSpeed ){
- speed = ( jQuery.type( eventOrSpeed ) === 'number' )?( eventOrSpeed ):( this.fxSpeed );
- if( this.$el.find( '.history-search-controls' ).is( ':visible' ) ){
- this.hideSearchControls( speed );
- } else {
- this.showSearchControls( speed );
- }
- },
// ........................................................................ multi-select of hdas
+ /** show selectors on all visible hdas and associated controls */
showSelectors : function( speed ){
this.selecting = true;
this.$el.find( '.history-dataset-actions' ).slideDown( speed );
@@ -1103,6 +342,7 @@
this.selectedHdaIds = [];
},
+ /** hide selectors on all visible hdas and associated controls */
hideSelectors : function( speed ){
this.selecting = false;
this.$el.find( '.history-dataset-actions' ).slideUp( speed );
@@ -1112,6 +352,7 @@
this.selectedHdaIds = [];
},
+ /** show or hide selectors on all visible hdas and associated controls */
toggleSelectors : function( speed ){
if( !this.selecting ){
this.showSelectors( speed );
@@ -1120,245 +361,36 @@
}
},
+ /** select all visible hdas */
selectAllDatasets : function( event ){
_.each( this.hdaViews, function( view ){
view.select( event );
});
},
+ /** deselect all visible hdas */
deselectAllDatasets : function( event ){
_.each( this.hdaViews, function( view ){
view.deselect( event );
});
},
+ /** return an array of all currently selected hdas */
getSelectedHdaViews : function(){
return _.filter( this.hdaViews, function( v ){
return v.selected;
});
},
+ /** return an HdaCollection of the models of all currenly selected hdas */
getSelectedHdaCollection : function(){
return new hdaModel.HDACollection( _.map( this.getSelectedHdaViews(), function( hdaView ){
return hdaView.model;
}), { historyId: this.model.id });
},
- // ........................................................................ loading indicator
- /** hide the panel and display a loading indicator (in the panel's parent) when history model's are switched */
- showLoadingIndicator : function( msg, speed, callback ){
- speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
- if( !this.indicator ){
- this.indicator = new LoadingIndicator( this.$el, this.$el.parent() );
- }
- if( !this.$el.is( ':visible' ) ){
- this.indicator.show( 0, callback );
- } else {
- this.$el.fadeOut( speed );
- this.indicator.show( msg, speed, callback );
- }
- },
-
- /** hide the loading indicator */
- hideLoadingIndicator : function( speed, callback ){
- speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
- if( this.indicator ){
- this.indicator.hide( speed, callback );
- }
- },
-
- // ........................................................................ (error) messages
- /** Display a message in the top of the panel.
- * @param {String} type type of message ('done', 'error', 'warning')
- * @param {String} msg the message to display
- */
- displayMessage : function( type, msg, details ){
- //precondition: msgContainer must have been rendered even if there's no model
- var panel = this;
- //console.debug( 'displayMessage', type, msg, details );
-
- this.scrollToTop();
- var $msgContainer = this.$el.find( this.msgsSelector ),
- $msg = $( '<div/>' ).addClass( type + 'message' ).html( msg );
- //console.debug( ' ', $msgContainer );
-
- if( !_.isEmpty( details ) ){
- var $detailsLink = $( '<a href="javascript:void(0)">Details</a>' )
- .click( function(){
- Galaxy.modal.show( panel.messageToModalOptions( type, msg, details ) );
- return false;
- });
- $msg.append( ' ', $detailsLink );
- }
- return $msgContainer.html( $msg );
- },
-
- /** convert msg and details into modal options usable by Galaxy.modal */
- messageToModalOptions : function( type, msg, details ){
- // only error is fleshed out here
- var panel = this,
- $modalBody = $( '<div/>' ),
- options = { title: 'Details' };
-
- //TODO: to some util library
- function objToTable( obj ){
- obj = _.omit( obj, _.functions( obj ) );
- return [
- '<table>',
- _.map( obj, function( val, key ){
- val = ( _.isObject( val ) )?( objToTable( val ) ):( val );
- return '<tr><td style="vertical-align: top; color: grey">' + key + '</td>'
- + '<td style="padding-left: 8px">' + val + '</td></tr>';
- }).join( '' ),
- '</table>'
- ].join( '' );
- }
-
- if( _.isObject( details ) ){
- options.body = $modalBody.append( objToTable( details ) );
-
- } else {
- options.body = $modalBody.html( details );
- }
- options.buttons = {
- 'Ok': function(){
- Galaxy.modal.hide();
- panel.clearMessages();
- }
- //TODO: if( type === 'error' ){ options.buttons[ 'Report this error' ] = function(){} }
- };
- return options;
- },
-
- /** Remove all messages from the panel.
- */
- clearMessages : function(){
- var $msgContainer = this.$el.find( this.msgsSelector );
- $msgContainer.empty();
- },
-
- // ........................................................................ scrolling
- /** get the current scroll position of the panel in its parent */
- scrollPosition : function(){
- return this.$el.parent().scrollTop();
- },
-
- /** set the current scroll position of the panel in its parent */
- scrollTo : function( pos ){
- this.$el.parent().scrollTop( pos );
- },
-
- /** Scrolls the panel to the top.
- * @returns {HistoryPanel} the panel
- */
- scrollToTop : function(){
- this.$el.parent().scrollTop( 0 );
- return this;
- },
-
- /** Scrolls the panel (the enclosing container - in gen., the page) so that some object
- * is displayed in the vertical middle.
- * NOTE: if no size is given the panel will scroll to objTop (putting it at the top).
- * @param {Number} objTop the top offset of the object to view
- * @param {Number} objSize the size of the object to view
- * @returns {HistoryPanel} the panel
- */
- scrollIntoView : function( where, size ){
- if( !size ){
- this.$el.parent().parent().scrollTop( where );
- return this;
- }
- // otherwise, place the object in the vertical middle
- var viewport = window,
- panelContainer = this.$el.parent().parent(),
- containerHeight = $( viewport ).innerHeight(),
- middleOffset = ( containerHeight / 2 ) - ( size / 2 );
-
- $( panelContainer ).scrollTop( where - middleOffset );
- return this;
- },
-
- /** Scrolls the panel to show the HDA with the given id.
- * @param {String} id the id of HDA to scroll into view
- * @returns {HistoryPanel} the panel
- */
- scrollToId : function( id ){
- // do nothing if id not found
- if( ( !id ) || ( !this.hdaViews[ id ] ) ){
- return this;
- }
- var $viewEl = this.hdaViews[ id ].$el;
- this.scrollIntoView( $viewEl.offset().top, $viewEl.outerHeight() );
- return this;
- },
-
- /** Scrolls the panel to show the HDA with the given hid.
- * @param {Integer} hid the hid of HDA to scroll into view
- * @returns {HistoryPanel} the panel
- */
- scrollToHid : function( hid ){
- var hda = this.model.hdas.getByHid( hid );
- // do nothing if hid not found
- if( !hda ){ return this; }
- return this.scrollToId( hda.id );
- },
-
- // ........................................................................ external objects/MVC
- //TODO: remove quota meter from panel and remove this
- /** add listeners to an external quota meter (mvc/user/user-quotameter.js) */
- connectToQuotaMeter : function( quotaMeter ){
- if( !quotaMeter ){
- return this;
- }
- // show/hide the 'over quota message' in the history when the meter tells it to
- this.listenTo( quotaMeter, 'quota:over', this.showQuotaMessage );
- this.listenTo( quotaMeter, 'quota:under', this.hideQuotaMessage );
-
- // having to add this to handle re-render of hview while overquota (the above do not fire)
- this.on( 'rendered rendered:initial', function(){
- if( quotaMeter && quotaMeter.isOverQuota() ){
- this.showQuotaMessage();
- }
- });
- return this;
- },
-
-//TODO: this seems more like a per user message than a history message; IOW, this doesn't belong here
- /** Show the over quota message (which happens to be in the history panel).
- */
- showQuotaMessage : function(){
- var msg = this.$el.find( '.quota-message' );
- //this.log( this + ' showing quota message:', msg, userData );
- if( msg.is( ':hidden' ) ){ msg.slideDown( this.fxSpeed ); }
- },
-
-//TODO: this seems more like a per user message than a history message
- /** Hide the over quota message (which happens to be in the history panel).
- */
- hideQuotaMessage : function(){
- var msg = this.$el.find( '.quota-message' );
- //this.log( this + ' hiding quota message:', msg, userData );
- if( !msg.is( ':hidden' ) ){ msg.slideUp( this.fxSpeed ); }
- },
-
-//TODO: move show_deleted/hidden into panel from opt menu and remove this
- /** add listeners to an external options menu (templates/webapps/galaxy/root/index.mako) */
- connectToOptionsMenu : function( optionsMenu ){
- if( !optionsMenu ){
- return this;
- }
- // set a visible indication in the popupmenu for show_hidden/deleted based on the currHistoryPanel's settings
- this.on( 'new-storage', function( storage, panel ){
- if( optionsMenu && storage ){
- optionsMenu.findItemByHtml( _l( 'Include Deleted Datasets' ) ).checked = storage.get( 'show_deleted' );
- optionsMenu.findItemByHtml( _l( 'Include Hidden Datasets' ) ).checked = storage.get( 'show_hidden' );
- }
- });
- return this;
- },
-
- /** Return a string rep of the history
- */
+ // ........................................................................ misc
+ /** Return a string rep of the history */
toString : function(){
return 'HistoryPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')';
}
@@ -1372,6 +404,6 @@
//==============================================================================
return {
- HistoryPanel : HistoryPanel
+ HistoryPanel : HistoryPanel
};
});
This diff is so big that we needed to truncate the remainder.
https://bitbucket.org/galaxy/galaxy-central/commits/82d6ee82d5d4/
Changeset: 82d6ee82d5d4
User: carlfeberhard
Date: 2014-02-18 21:12:31
Summary: merge
Affected #: 1 file
diff -r 33812bcdc52393bf179dd501b4334be4ec4e97a7 -r 82d6ee82d5d4714eefdbce041f6c983a806a58d7 templates/webapps/galaxy/mobile/history/detail.mako
--- a/templates/webapps/galaxy/mobile/history/detail.mako
+++ b/templates/webapps/galaxy/mobile/history/detail.mako
@@ -12,7 +12,7 @@
if data.state in ['no state','',None]:
data_state = "queued"
else:
- data_state = data.state
+ data_state = str( data.state )
%><li id="historyItemContainer-${data.id}">
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: dan: Fix for server error caused by unicode substitution in url_for.
by commits-noreply@bitbucket.org 18 Feb '14
by commits-noreply@bitbucket.org 18 Feb '14
18 Feb '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e9d3248c6fc3/
Changeset: e9d3248c6fc3
User: dan
Date: 2014-02-18 21:09:46
Summary: Fix for server error caused by unicode substitution in url_for.
Affected #: 1 file
diff -r 26e37f6af3a8a090d9d6e923fa3e90acb0e64572 -r e9d3248c6fc312f8c7671a8e1233265c4ff0a0b1 templates/webapps/galaxy/mobile/history/detail.mako
--- a/templates/webapps/galaxy/mobile/history/detail.mako
+++ b/templates/webapps/galaxy/mobile/history/detail.mako
@@ -12,7 +12,7 @@
if data.state in ['no state','',None]:
data_state = "queued"
else:
- data_state = data.state
+ data_state = str( data.state )
%><li id="historyItemContainer-${data.id}">
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: guerler: Upload: Hide former upload tool
by commits-noreply@bitbucket.org 18 Feb '14
by commits-noreply@bitbucket.org 18 Feb '14
18 Feb '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/26e37f6af3a8/
Changeset: 26e37f6af3a8
User: guerler
Date: 2014-02-18 20:57:08
Summary: Upload: Hide former upload tool
Affected #: 3 files
diff -r c755326c2018efa988daebe96c355a32b6482018 -r 26e37f6af3a8a090d9d6e923fa3e90acb0e64572 static/scripts/mvc/upload/upload-view.js
--- a/static/scripts/mvc/upload/upload-view.js
+++ b/static/scripts/mvc/upload/upload-view.js
@@ -183,7 +183,7 @@
buttons : {
'Choose local file' : function() {self.uploadbox.select()},
'Choose FTP file' : function() {self._eventFtp()},
- 'Create new file' : function() {self._eventCreate()},
+ 'Paste/Fetch data' : function() {self._eventCreate()},
'Start' : function() {self._eventStart()},
'Pause' : function() {self._eventStop()},
'Reset' : function() {self._eventReset()},
@@ -577,11 +577,11 @@
{
this.modal.enableButton('Choose local file');
this.modal.enableButton('Choose FTP file');
- this.modal.enableButton('Create new file');
+ this.modal.enableButton('Paste/Fetch data');
} else {
this.modal.disableButton('Choose local file');
this.modal.disableButton('Choose FTP file');
- this.modal.disableButton('Create new file');
+ this.modal.disableButton('Paste/Fetch data');
}
// ftp button
diff -r c755326c2018efa988daebe96c355a32b6482018 -r 26e37f6af3a8a090d9d6e923fa3e90acb0e64572 static/scripts/packed/mvc/upload/upload-view.js
--- a/static/scripts/packed/mvc/upload/upload-view.js
+++ b/static/scripts/packed/mvc/upload/upload-view.js
@@ -1,1 +1,1 @@
-define(["galaxy.modal","utils/utils","mvc/upload/upload-button","mvc/upload/upload-model","mvc/upload/upload-row","mvc/upload/upload-ftp","mvc/ui/ui-popover","mvc/ui","utils/uploadbox"],function(a,f,e,c,b,g,d){return Backbone.View.extend({options:{nginx_upload_path:""},modal:null,ui_button:null,uploadbox:null,current_history:null,upload_size:0,list_extensions:[],list_genomes:[],auto:{id:"auto",text:"Auto-detect",description:"This system will try to detect the file type automatically. If your file is not detected properly as one of the known formats, it most likely means that it has some format problems (e.g., different number of columns on different rows). You can still coerce the system to set your data to the format you think it should be. You can also upload compressed files, which will automatically be decompressed."},collection:new c.Collection(),ftp:null,counter:{announce:0,success:0,error:0,running:0,reset:function(){this.announce=this.success=this.error=this.running=0}},initialize:function(i){var h=this;if(i){this.options=_.defaults(i,this.options)}if(!Galaxy.currHistoryPanel||!Galaxy.currHistoryPanel.model){window.setTimeout(function(){h.initialize()},500);return}this.ui_button=new e.Model({icon:"fa-upload",tooltip:"Download from URL or upload files from disk",label:"Load Data",onclick:function(j){if(j){h._eventShow(j)}},onunload:function(){if(h.counter.running>0){return"Several uploads are still processing."}}});$("#left .unified-panel-header-inner").append((new e.View(this.ui_button)).$el);var h=this;f.jsonFromUrl(galaxy_config.root+"api/datatypes?extension_only=False",function(j){for(key in j){h.list_extensions.push({id:j[key].extension,text:j[key].extension,description:j[key].description,description_url:j[key].description_url})}h.list_extensions.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0});if(!h.options.datatypes_disable_auto){h.list_extensions.unshift(h.auto)}});f.jsonFromUrl(galaxy_config.root+"api/genomes",function(j){for(key in j){h.list_genomes.push({id:j[key][1],text:j[key][0]})}h.list_genomes.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0})});this.collection.on("remove",function(j){h._eventRemove(j)});this.collection.on("change:genome",function(k){var j=k.get("genome");h.collection.each(function(l){if(l.get("status")=="init"&&l.get("genome")=="?"){l.set("genome",j)}})})},_eventShow:function(j){j.preventDefault();if(!this.modal){var h=this;this.modal=new a.GalaxyModal({title:"Download data directly from web or upload files from your disk",body:this._template("upload-box","upload-info"),buttons:{"Choose local file":function(){h.uploadbox.select()},"Choose FTP file":function(){h._eventFtp()},"Create new file":function(){h._eventCreate()},Start:function(){h._eventStart()},Pause:function(){h._eventStop()},Reset:function(){h._eventReset()},Close:function(){h.modal.hide()},},height:"400",width:"900",closing_events:true});this.setElement("#upload-box");var h=this;this.uploadbox=this.$el.uploadbox({announce:function(k,l,m){h._eventAnnounce(k,l,m)},initialize:function(k,l,m){return h._eventInitialize(k,l,m)},progress:function(k,l,m){h._eventProgress(k,l,m)},success:function(k,l,m){h._eventSuccess(k,l,m)},error:function(k,l,m){h._eventError(k,l,m)},complete:function(){h._eventComplete()}});var i=this.modal.getButton("Choose FTP file");this.ftp=new d.View({title:"FTP files",container:i})}this.modal.show();this._updateUser();this._updateScreen()},_eventRemove:function(i){var h=i.get("status");if(h=="success"){this.counter.success--}else{if(h=="error"){this.counter.error--}else{this.counter.announce--}}this._updateScreen();this.uploadbox.remove(i.id)},_eventAnnounce:function(h,i,k){this.counter.announce++;this._updateScreen();var j=new b(this,{id:h,file_name:i.name,file_size:i.size,file_mode:i.mode,file_path:i.path});this.collection.add(j.model);$(this.el).find("tbody:first").append(j.$el);j.render()},_eventInitialize:function(m,j,s){var k=this.collection.get(m);k.set("status","running");var o=k.get("file_name");var n=k.get("file_path");var h=k.get("file_mode");var p=k.get("extension");var r=k.get("genome");var q=k.get("url_paste");var l=k.get("space_to_tabs");var i=k.get("to_posix_lines");if(!q&&!(j.size>0)){return null}this.uploadbox.configure({url:this.options.nginx_upload_path});if(h=="local"){this.uploadbox.configure({paramname:"files_0|file_data"})}else{this.uploadbox.configure({paramname:null})}tool_input={};if(h=="new"){tool_input["files_0|url_paste"]=q}if(h=="ftp"){tool_input["files_0|ftp_files"]=n}tool_input.dbkey=r;tool_input.file_type=p;tool_input["files_0|type"]="upload_dataset";tool_input.space_to_tabs=l;tool_input.to_posix_lines=i;data={};data.history_id=this.current_history;data.tool_id="upload1";data.inputs=JSON.stringify(tool_input);return data},_eventProgress:function(i,j,h){var k=this.collection.get(i);k.set("percentage",h);this.ui_button.set("percentage",this._upload_percentage(h,j.size))},_eventSuccess:function(i,j,l){var k=this.collection.get(i);k.set("percentage",100);k.set("status","success");var h=k.get("file_size");this.ui_button.set("percentage",this._upload_percentage(100,h));this.upload_completed+=h*100;this.counter.announce--;this.counter.success++;this._updateScreen();Galaxy.currHistoryPanel.refreshHdas()},_eventError:function(h,i,k){var j=this.collection.get(h);j.set("percentage",100);j.set("status","error");j.set("info",k);this.ui_button.set("percentage",this._upload_percentage(100,i.size));this.ui_button.set("status","danger");this.upload_completed+=i.size*100;this.counter.announce--;this.counter.error++;this._updateScreen()},_eventComplete:function(){this.collection.each(function(h){if(h.get("status")=="queued"){h.set("status","init")}});this.counter.running=0;this._updateScreen()},_eventFtp:function(){if(!this.ftp.visible){this.ftp.empty();this.ftp.append((new g(this)).$el);this.ftp.show()}else{this.ftp.hide()}},_eventCreate:function(){this.uploadbox.add([{name:"New File",size:0,mode:"new"}])},_eventStart:function(){if(this.counter.announce==0||this.counter.running>0){return}var h=this;this.upload_size=0;this.upload_completed=0;this.collection.each(function(i){if(i.get("status")=="init"){i.set("status","queued");h.upload_size+=i.get("file_size")}});this.ui_button.set("percentage",0);this.ui_button.set("status","success");this.counter.running=this.counter.announce;this._updateScreen();this.uploadbox.start()},_eventStop:function(){if(this.counter.running==0){return}this.ui_button.set("status","info");this.uploadbox.stop();$("#upload-info").html("Queue will pause after completing the current file...")},_eventReset:function(){if(this.counter.running==0){this.collection.reset();this.counter.reset();this._updateScreen();this.uploadbox.reset();this.ui_button.set("percentage",0)}},_updateUser:function(){this.current_user=Galaxy.currUser.get("id");this.current_history=null;if(this.current_user){this.current_history=Galaxy.currHistoryPanel.model.get("id")}},_updateScreen:function(){if(this.counter.announce==0){if(this.uploadbox.compatible()){message="You can Drag & Drop files into this box."}else{message="Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Some supported browsers are: Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."}}else{if(this.counter.running==0){message="You added "+this.counter.announce+" file(s) to the queue. Add more files or click 'Start' to proceed."}else{message="Please wait..."+this.counter.announce+" out of "+this.counter.running+" remaining."}}$("#upload-info").html(message);if(this.counter.running==0&&this.counter.announce+this.counter.success+this.counter.error>0){this.modal.enableButton("Reset")}else{this.modal.disableButton("Reset")}if(this.counter.running==0&&this.counter.announce>0){this.modal.enableButton("Start")}else{this.modal.disableButton("Start")}if(this.counter.running>0){this.modal.enableButton("Pause")}else{this.modal.disableButton("Pause")}if(this.counter.running==0){this.modal.enableButton("Choose local file");this.modal.enableButton("Choose FTP file");this.modal.enableButton("Create new file")}else{this.modal.disableButton("Choose local file");this.modal.disableButton("Choose FTP file");this.modal.disableButton("Create new file")}if(this.current_user&&this.options.ftp_upload_dir&&this.options.ftp_upload_site){this.modal.showButton("Choose FTP file")}else{this.modal.hideButton("Choose FTP file")}if(this.counter.announce+this.counter.success+this.counter.error>0){$(this.el).find("#upload-table").show()}else{$(this.el).find("#upload-table").hide()}},_upload_percentage:function(h,i){return(this.upload_completed+(h*i))/this.upload_size},_template:function(i,h){return'<div id="'+i+'" class="upload-box"><table id="upload-table" class="table table-striped" style="display: none;"><thead><tr><th>Name</th><th>Size</th><th>Type</th><th>Genome</th><th>Settings</th><th>Status</th><th></th></tr></thead><tbody></tbody></table></div><h6 id="'+h+'" class="upload-info"></h6>'}})});
\ No newline at end of file
+define(["galaxy.modal","utils/utils","mvc/upload/upload-button","mvc/upload/upload-model","mvc/upload/upload-row","mvc/upload/upload-ftp","mvc/ui/ui-popover","mvc/ui","utils/uploadbox"],function(a,f,e,c,b,g,d){return Backbone.View.extend({options:{nginx_upload_path:""},modal:null,ui_button:null,uploadbox:null,current_history:null,upload_size:0,list_extensions:[],list_genomes:[],auto:{id:"auto",text:"Auto-detect",description:"This system will try to detect the file type automatically. If your file is not detected properly as one of the known formats, it most likely means that it has some format problems (e.g., different number of columns on different rows). You can still coerce the system to set your data to the format you think it should be. You can also upload compressed files, which will automatically be decompressed."},collection:new c.Collection(),ftp:null,counter:{announce:0,success:0,error:0,running:0,reset:function(){this.announce=this.success=this.error=this.running=0}},initialize:function(i){var h=this;if(i){this.options=_.defaults(i,this.options)}if(!Galaxy.currHistoryPanel||!Galaxy.currHistoryPanel.model){window.setTimeout(function(){h.initialize()},500);return}this.ui_button=new e.Model({icon:"fa-upload",tooltip:"Download from URL or upload files from disk",label:"Load Data",onclick:function(j){if(j){h._eventShow(j)}},onunload:function(){if(h.counter.running>0){return"Several uploads are still processing."}}});$("#left .unified-panel-header-inner").append((new e.View(this.ui_button)).$el);var h=this;f.jsonFromUrl(galaxy_config.root+"api/datatypes?extension_only=False",function(j){for(key in j){h.list_extensions.push({id:j[key].extension,text:j[key].extension,description:j[key].description,description_url:j[key].description_url})}h.list_extensions.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0});if(!h.options.datatypes_disable_auto){h.list_extensions.unshift(h.auto)}});f.jsonFromUrl(galaxy_config.root+"api/genomes",function(j){for(key in j){h.list_genomes.push({id:j[key][1],text:j[key][0]})}h.list_genomes.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0})});this.collection.on("remove",function(j){h._eventRemove(j)});this.collection.on("change:genome",function(k){var j=k.get("genome");h.collection.each(function(l){if(l.get("status")=="init"&&l.get("genome")=="?"){l.set("genome",j)}})})},_eventShow:function(j){j.preventDefault();if(!this.modal){var h=this;this.modal=new a.GalaxyModal({title:"Download data directly from web or upload files from your disk",body:this._template("upload-box","upload-info"),buttons:{"Choose local file":function(){h.uploadbox.select()},"Choose FTP file":function(){h._eventFtp()},"Paste/Fetch data":function(){h._eventCreate()},Start:function(){h._eventStart()},Pause:function(){h._eventStop()},Reset:function(){h._eventReset()},Close:function(){h.modal.hide()},},height:"400",width:"900",closing_events:true});this.setElement("#upload-box");var h=this;this.uploadbox=this.$el.uploadbox({announce:function(k,l,m){h._eventAnnounce(k,l,m)},initialize:function(k,l,m){return h._eventInitialize(k,l,m)},progress:function(k,l,m){h._eventProgress(k,l,m)},success:function(k,l,m){h._eventSuccess(k,l,m)},error:function(k,l,m){h._eventError(k,l,m)},complete:function(){h._eventComplete()}});var i=this.modal.getButton("Choose FTP file");this.ftp=new d.View({title:"FTP files",container:i})}this.modal.show();this._updateUser();this._updateScreen()},_eventRemove:function(i){var h=i.get("status");if(h=="success"){this.counter.success--}else{if(h=="error"){this.counter.error--}else{this.counter.announce--}}this._updateScreen();this.uploadbox.remove(i.id)},_eventAnnounce:function(h,i,k){this.counter.announce++;this._updateScreen();var j=new b(this,{id:h,file_name:i.name,file_size:i.size,file_mode:i.mode,file_path:i.path});this.collection.add(j.model);$(this.el).find("tbody:first").append(j.$el);j.render()},_eventInitialize:function(m,j,s){var k=this.collection.get(m);k.set("status","running");var o=k.get("file_name");var n=k.get("file_path");var h=k.get("file_mode");var p=k.get("extension");var r=k.get("genome");var q=k.get("url_paste");var l=k.get("space_to_tabs");var i=k.get("to_posix_lines");if(!q&&!(j.size>0)){return null}this.uploadbox.configure({url:this.options.nginx_upload_path});if(h=="local"){this.uploadbox.configure({paramname:"files_0|file_data"})}else{this.uploadbox.configure({paramname:null})}tool_input={};if(h=="new"){tool_input["files_0|url_paste"]=q}if(h=="ftp"){tool_input["files_0|ftp_files"]=n}tool_input.dbkey=r;tool_input.file_type=p;tool_input["files_0|type"]="upload_dataset";tool_input.space_to_tabs=l;tool_input.to_posix_lines=i;data={};data.history_id=this.current_history;data.tool_id="upload1";data.inputs=JSON.stringify(tool_input);return data},_eventProgress:function(i,j,h){var k=this.collection.get(i);k.set("percentage",h);this.ui_button.set("percentage",this._upload_percentage(h,j.size))},_eventSuccess:function(i,j,l){var k=this.collection.get(i);k.set("percentage",100);k.set("status","success");var h=k.get("file_size");this.ui_button.set("percentage",this._upload_percentage(100,h));this.upload_completed+=h*100;this.counter.announce--;this.counter.success++;this._updateScreen();Galaxy.currHistoryPanel.refreshHdas()},_eventError:function(h,i,k){var j=this.collection.get(h);j.set("percentage",100);j.set("status","error");j.set("info",k);this.ui_button.set("percentage",this._upload_percentage(100,i.size));this.ui_button.set("status","danger");this.upload_completed+=i.size*100;this.counter.announce--;this.counter.error++;this._updateScreen()},_eventComplete:function(){this.collection.each(function(h){if(h.get("status")=="queued"){h.set("status","init")}});this.counter.running=0;this._updateScreen()},_eventFtp:function(){if(!this.ftp.visible){this.ftp.empty();this.ftp.append((new g(this)).$el);this.ftp.show()}else{this.ftp.hide()}},_eventCreate:function(){this.uploadbox.add([{name:"New File",size:0,mode:"new"}])},_eventStart:function(){if(this.counter.announce==0||this.counter.running>0){return}var h=this;this.upload_size=0;this.upload_completed=0;this.collection.each(function(i){if(i.get("status")=="init"){i.set("status","queued");h.upload_size+=i.get("file_size")}});this.ui_button.set("percentage",0);this.ui_button.set("status","success");this.counter.running=this.counter.announce;this._updateScreen();this.uploadbox.start()},_eventStop:function(){if(this.counter.running==0){return}this.ui_button.set("status","info");this.uploadbox.stop();$("#upload-info").html("Queue will pause after completing the current file...")},_eventReset:function(){if(this.counter.running==0){this.collection.reset();this.counter.reset();this._updateScreen();this.uploadbox.reset();this.ui_button.set("percentage",0)}},_updateUser:function(){this.current_user=Galaxy.currUser.get("id");this.current_history=null;if(this.current_user){this.current_history=Galaxy.currHistoryPanel.model.get("id")}},_updateScreen:function(){if(this.counter.announce==0){if(this.uploadbox.compatible()){message="You can Drag & Drop files into this box."}else{message="Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Some supported browsers are: Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."}}else{if(this.counter.running==0){message="You added "+this.counter.announce+" file(s) to the queue. Add more files or click 'Start' to proceed."}else{message="Please wait..."+this.counter.announce+" out of "+this.counter.running+" remaining."}}$("#upload-info").html(message);if(this.counter.running==0&&this.counter.announce+this.counter.success+this.counter.error>0){this.modal.enableButton("Reset")}else{this.modal.disableButton("Reset")}if(this.counter.running==0&&this.counter.announce>0){this.modal.enableButton("Start")}else{this.modal.disableButton("Start")}if(this.counter.running>0){this.modal.enableButton("Pause")}else{this.modal.disableButton("Pause")}if(this.counter.running==0){this.modal.enableButton("Choose local file");this.modal.enableButton("Choose FTP file");this.modal.enableButton("Paste/Fetch data")}else{this.modal.disableButton("Choose local file");this.modal.disableButton("Choose FTP file");this.modal.disableButton("Paste/Fetch data")}if(this.current_user&&this.options.ftp_upload_dir&&this.options.ftp_upload_site){this.modal.showButton("Choose FTP file")}else{this.modal.hideButton("Choose FTP file")}if(this.counter.announce+this.counter.success+this.counter.error>0){$(this.el).find("#upload-table").show()}else{$(this.el).find("#upload-table").hide()}},_upload_percentage:function(h,i){return(this.upload_completed+(h*i))/this.upload_size},_template:function(i,h){return'<div id="'+i+'" class="upload-box"><table id="upload-table" class="table table-striped" style="display: none;"><thead><tr><th>Name</th><th>Size</th><th>Type</th><th>Genome</th><th>Settings</th><th>Status</th><th></th></tr></thead><tbody></tbody></table></div><h6 id="'+h+'" class="upload-info"></h6>'}})});
\ No newline at end of file
diff -r c755326c2018efa988daebe96c355a32b6482018 -r 26e37f6af3a8a090d9d6e923fa3e90acb0e64572 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -1,6 +1,7 @@
<?xml version="1.0"?><tool name="Upload File" id="upload1" version="1.1.4" workflow_compatible="false">
+ <hidden>True</hidden><description>
from your computer
</description>
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: guerler: Upload: Load user details on show
by commits-noreply@bitbucket.org 18 Feb '14
by commits-noreply@bitbucket.org 18 Feb '14
18 Feb '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c755326c2018/
Changeset: c755326c2018
User: guerler
Date: 2014-02-18 19:21:03
Summary: Upload: Load user details on show
Affected #: 2 files
diff -r 5ea343bbc97bc1ebb8fa1bcd3e0df2889ef232ca -r c755326c2018efa988daebe96c355a32b6482018 static/scripts/mvc/upload/upload-view.js
--- a/static/scripts/mvc/upload/upload-view.js
+++ b/static/scripts/mvc/upload/upload-view.js
@@ -214,13 +214,16 @@
title : 'FTP files',
container : button
});
-
- // setup info
- this._updateScreen();
}
// show modal
this.modal.show();
+
+ // refresh
+ this._updateUser();
+
+ // setup info
+ this._updateScreen();
},
//
@@ -526,9 +529,6 @@
// set screen
_updateScreen: function () {
- // refresh
- this._updateUser();
-
/*
update on screen info
*/
diff -r 5ea343bbc97bc1ebb8fa1bcd3e0df2889ef232ca -r c755326c2018efa988daebe96c355a32b6482018 static/scripts/packed/mvc/upload/upload-view.js
--- a/static/scripts/packed/mvc/upload/upload-view.js
+++ b/static/scripts/packed/mvc/upload/upload-view.js
@@ -1,1 +1,1 @@
-define(["galaxy.modal","utils/utils","mvc/upload/upload-button","mvc/upload/upload-model","mvc/upload/upload-row","mvc/upload/upload-ftp","mvc/ui/ui-popover","mvc/ui","utils/uploadbox"],function(a,f,e,c,b,g,d){return Backbone.View.extend({options:{nginx_upload_path:""},modal:null,ui_button:null,uploadbox:null,current_history:null,upload_size:0,list_extensions:[],list_genomes:[],auto:{id:"auto",text:"Auto-detect",description:"This system will try to detect the file type automatically. If your file is not detected properly as one of the known formats, it most likely means that it has some format problems (e.g., different number of columns on different rows). You can still coerce the system to set your data to the format you think it should be. You can also upload compressed files, which will automatically be decompressed."},collection:new c.Collection(),ftp:null,counter:{announce:0,success:0,error:0,running:0,reset:function(){this.announce=this.success=this.error=this.running=0}},initialize:function(i){var h=this;if(i){this.options=_.defaults(i,this.options)}if(!Galaxy.currHistoryPanel||!Galaxy.currHistoryPanel.model){window.setTimeout(function(){h.initialize()},500);return}this.ui_button=new e.Model({icon:"fa-upload",tooltip:"Download from URL or upload files from disk",label:"Load Data",onclick:function(j){if(j){h._eventShow(j)}},onunload:function(){if(h.counter.running>0){return"Several uploads are still processing."}}});$("#left .unified-panel-header-inner").append((new e.View(this.ui_button)).$el);var h=this;f.jsonFromUrl(galaxy_config.root+"api/datatypes?extension_only=False",function(j){for(key in j){h.list_extensions.push({id:j[key].extension,text:j[key].extension,description:j[key].description,description_url:j[key].description_url})}h.list_extensions.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0});if(!h.options.datatypes_disable_auto){h.list_extensions.unshift(h.auto)}});f.jsonFromUrl(galaxy_config.root+"api/genomes",function(j){for(key in j){h.list_genomes.push({id:j[key][1],text:j[key][0]})}h.list_genomes.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0})});this.collection.on("remove",function(j){h._eventRemove(j)});this.collection.on("change:genome",function(k){var j=k.get("genome");h.collection.each(function(l){if(l.get("status")=="init"&&l.get("genome")=="?"){l.set("genome",j)}})})},_eventShow:function(j){j.preventDefault();if(!this.modal){var h=this;this.modal=new a.GalaxyModal({title:"Download data directly from web or upload files from your disk",body:this._template("upload-box","upload-info"),buttons:{"Choose local file":function(){h.uploadbox.select()},"Choose FTP file":function(){h._eventFtp()},"Create new file":function(){h._eventCreate()},Start:function(){h._eventStart()},Pause:function(){h._eventStop()},Reset:function(){h._eventReset()},Close:function(){h.modal.hide()},},height:"400",width:"900",closing_events:true});this.setElement("#upload-box");var h=this;this.uploadbox=this.$el.uploadbox({announce:function(k,l,m){h._eventAnnounce(k,l,m)},initialize:function(k,l,m){return h._eventInitialize(k,l,m)},progress:function(k,l,m){h._eventProgress(k,l,m)},success:function(k,l,m){h._eventSuccess(k,l,m)},error:function(k,l,m){h._eventError(k,l,m)},complete:function(){h._eventComplete()}});var i=this.modal.getButton("Choose FTP file");this.ftp=new d.View({title:"FTP files",container:i});this._updateScreen()}this.modal.show()},_eventRemove:function(i){var h=i.get("status");if(h=="success"){this.counter.success--}else{if(h=="error"){this.counter.error--}else{this.counter.announce--}}this._updateScreen();this.uploadbox.remove(i.id)},_eventAnnounce:function(h,i,k){this.counter.announce++;this._updateScreen();var j=new b(this,{id:h,file_name:i.name,file_size:i.size,file_mode:i.mode,file_path:i.path});this.collection.add(j.model);$(this.el).find("tbody:first").append(j.$el);j.render()},_eventInitialize:function(m,j,s){var k=this.collection.get(m);k.set("status","running");var o=k.get("file_name");var n=k.get("file_path");var h=k.get("file_mode");var p=k.get("extension");var r=k.get("genome");var q=k.get("url_paste");var l=k.get("space_to_tabs");var i=k.get("to_posix_lines");if(!q&&!(j.size>0)){return null}this.uploadbox.configure({url:this.options.nginx_upload_path});if(h=="local"){this.uploadbox.configure({paramname:"files_0|file_data"})}else{this.uploadbox.configure({paramname:null})}tool_input={};if(h=="new"){tool_input["files_0|url_paste"]=q}if(h=="ftp"){tool_input["files_0|ftp_files"]=n}tool_input.dbkey=r;tool_input.file_type=p;tool_input["files_0|type"]="upload_dataset";tool_input.space_to_tabs=l;tool_input.to_posix_lines=i;data={};data.history_id=this.current_history;data.tool_id="upload1";data.inputs=JSON.stringify(tool_input);return data},_eventProgress:function(i,j,h){var k=this.collection.get(i);k.set("percentage",h);this.ui_button.set("percentage",this._upload_percentage(h,j.size))},_eventSuccess:function(i,j,l){var k=this.collection.get(i);k.set("percentage",100);k.set("status","success");var h=k.get("file_size");this.ui_button.set("percentage",this._upload_percentage(100,h));this.upload_completed+=h*100;this.counter.announce--;this.counter.success++;this._updateScreen();Galaxy.currHistoryPanel.refreshHdas()},_eventError:function(h,i,k){var j=this.collection.get(h);j.set("percentage",100);j.set("status","error");j.set("info",k);this.ui_button.set("percentage",this._upload_percentage(100,i.size));this.ui_button.set("status","danger");this.upload_completed+=i.size*100;this.counter.announce--;this.counter.error++;this._updateScreen()},_eventComplete:function(){this.collection.each(function(h){if(h.get("status")=="queued"){h.set("status","init")}});this.counter.running=0;this._updateScreen()},_eventFtp:function(){if(!this.ftp.visible){this.ftp.empty();this.ftp.append((new g(this)).$el);this.ftp.show()}else{this.ftp.hide()}},_eventCreate:function(){this.uploadbox.add([{name:"New File",size:0,mode:"new"}])},_eventStart:function(){if(this.counter.announce==0||this.counter.running>0){return}var h=this;this.upload_size=0;this.upload_completed=0;this.collection.each(function(i){if(i.get("status")=="init"){i.set("status","queued");h.upload_size+=i.get("file_size")}});this.ui_button.set("percentage",0);this.ui_button.set("status","success");this.counter.running=this.counter.announce;this._updateScreen();this.uploadbox.start()},_eventStop:function(){if(this.counter.running==0){return}this.ui_button.set("status","info");this.uploadbox.stop();$("#upload-info").html("Queue will pause after completing the current file...")},_eventReset:function(){if(this.counter.running==0){this.collection.reset();this.counter.reset();this._updateScreen();this.uploadbox.reset();this.ui_button.set("percentage",0)}},_updateUser:function(){this.current_user=Galaxy.currUser.get("id");this.current_history=null;if(this.current_user){this.current_history=Galaxy.currHistoryPanel.model.get("id")}},_updateScreen:function(){this._updateUser();if(this.counter.announce==0){if(this.uploadbox.compatible()){message="You can Drag & Drop files into this box."}else{message="Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Some supported browsers are: Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."}}else{if(this.counter.running==0){message="You added "+this.counter.announce+" file(s) to the queue. Add more files or click 'Start' to proceed."}else{message="Please wait..."+this.counter.announce+" out of "+this.counter.running+" remaining."}}$("#upload-info").html(message);if(this.counter.running==0&&this.counter.announce+this.counter.success+this.counter.error>0){this.modal.enableButton("Reset")}else{this.modal.disableButton("Reset")}if(this.counter.running==0&&this.counter.announce>0){this.modal.enableButton("Start")}else{this.modal.disableButton("Start")}if(this.counter.running>0){this.modal.enableButton("Pause")}else{this.modal.disableButton("Pause")}if(this.counter.running==0){this.modal.enableButton("Choose local file");this.modal.enableButton("Choose FTP file");this.modal.enableButton("Create new file")}else{this.modal.disableButton("Choose local file");this.modal.disableButton("Choose FTP file");this.modal.disableButton("Create new file")}if(this.current_user&&this.options.ftp_upload_dir&&this.options.ftp_upload_site){this.modal.showButton("Choose FTP file")}else{this.modal.hideButton("Choose FTP file")}if(this.counter.announce+this.counter.success+this.counter.error>0){$(this.el).find("#upload-table").show()}else{$(this.el).find("#upload-table").hide()}},_upload_percentage:function(h,i){return(this.upload_completed+(h*i))/this.upload_size},_template:function(i,h){return'<div id="'+i+'" class="upload-box"><table id="upload-table" class="table table-striped" style="display: none;"><thead><tr><th>Name</th><th>Size</th><th>Type</th><th>Genome</th><th>Settings</th><th>Status</th><th></th></tr></thead><tbody></tbody></table></div><h6 id="'+h+'" class="upload-info"></h6>'}})});
\ No newline at end of file
+define(["galaxy.modal","utils/utils","mvc/upload/upload-button","mvc/upload/upload-model","mvc/upload/upload-row","mvc/upload/upload-ftp","mvc/ui/ui-popover","mvc/ui","utils/uploadbox"],function(a,f,e,c,b,g,d){return Backbone.View.extend({options:{nginx_upload_path:""},modal:null,ui_button:null,uploadbox:null,current_history:null,upload_size:0,list_extensions:[],list_genomes:[],auto:{id:"auto",text:"Auto-detect",description:"This system will try to detect the file type automatically. If your file is not detected properly as one of the known formats, it most likely means that it has some format problems (e.g., different number of columns on different rows). You can still coerce the system to set your data to the format you think it should be. You can also upload compressed files, which will automatically be decompressed."},collection:new c.Collection(),ftp:null,counter:{announce:0,success:0,error:0,running:0,reset:function(){this.announce=this.success=this.error=this.running=0}},initialize:function(i){var h=this;if(i){this.options=_.defaults(i,this.options)}if(!Galaxy.currHistoryPanel||!Galaxy.currHistoryPanel.model){window.setTimeout(function(){h.initialize()},500);return}this.ui_button=new e.Model({icon:"fa-upload",tooltip:"Download from URL or upload files from disk",label:"Load Data",onclick:function(j){if(j){h._eventShow(j)}},onunload:function(){if(h.counter.running>0){return"Several uploads are still processing."}}});$("#left .unified-panel-header-inner").append((new e.View(this.ui_button)).$el);var h=this;f.jsonFromUrl(galaxy_config.root+"api/datatypes?extension_only=False",function(j){for(key in j){h.list_extensions.push({id:j[key].extension,text:j[key].extension,description:j[key].description,description_url:j[key].description_url})}h.list_extensions.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0});if(!h.options.datatypes_disable_auto){h.list_extensions.unshift(h.auto)}});f.jsonFromUrl(galaxy_config.root+"api/genomes",function(j){for(key in j){h.list_genomes.push({id:j[key][1],text:j[key][0]})}h.list_genomes.sort(function(l,k){return l.id>k.id?1:l.id<k.id?-1:0})});this.collection.on("remove",function(j){h._eventRemove(j)});this.collection.on("change:genome",function(k){var j=k.get("genome");h.collection.each(function(l){if(l.get("status")=="init"&&l.get("genome")=="?"){l.set("genome",j)}})})},_eventShow:function(j){j.preventDefault();if(!this.modal){var h=this;this.modal=new a.GalaxyModal({title:"Download data directly from web or upload files from your disk",body:this._template("upload-box","upload-info"),buttons:{"Choose local file":function(){h.uploadbox.select()},"Choose FTP file":function(){h._eventFtp()},"Create new file":function(){h._eventCreate()},Start:function(){h._eventStart()},Pause:function(){h._eventStop()},Reset:function(){h._eventReset()},Close:function(){h.modal.hide()},},height:"400",width:"900",closing_events:true});this.setElement("#upload-box");var h=this;this.uploadbox=this.$el.uploadbox({announce:function(k,l,m){h._eventAnnounce(k,l,m)},initialize:function(k,l,m){return h._eventInitialize(k,l,m)},progress:function(k,l,m){h._eventProgress(k,l,m)},success:function(k,l,m){h._eventSuccess(k,l,m)},error:function(k,l,m){h._eventError(k,l,m)},complete:function(){h._eventComplete()}});var i=this.modal.getButton("Choose FTP file");this.ftp=new d.View({title:"FTP files",container:i})}this.modal.show();this._updateUser();this._updateScreen()},_eventRemove:function(i){var h=i.get("status");if(h=="success"){this.counter.success--}else{if(h=="error"){this.counter.error--}else{this.counter.announce--}}this._updateScreen();this.uploadbox.remove(i.id)},_eventAnnounce:function(h,i,k){this.counter.announce++;this._updateScreen();var j=new b(this,{id:h,file_name:i.name,file_size:i.size,file_mode:i.mode,file_path:i.path});this.collection.add(j.model);$(this.el).find("tbody:first").append(j.$el);j.render()},_eventInitialize:function(m,j,s){var k=this.collection.get(m);k.set("status","running");var o=k.get("file_name");var n=k.get("file_path");var h=k.get("file_mode");var p=k.get("extension");var r=k.get("genome");var q=k.get("url_paste");var l=k.get("space_to_tabs");var i=k.get("to_posix_lines");if(!q&&!(j.size>0)){return null}this.uploadbox.configure({url:this.options.nginx_upload_path});if(h=="local"){this.uploadbox.configure({paramname:"files_0|file_data"})}else{this.uploadbox.configure({paramname:null})}tool_input={};if(h=="new"){tool_input["files_0|url_paste"]=q}if(h=="ftp"){tool_input["files_0|ftp_files"]=n}tool_input.dbkey=r;tool_input.file_type=p;tool_input["files_0|type"]="upload_dataset";tool_input.space_to_tabs=l;tool_input.to_posix_lines=i;data={};data.history_id=this.current_history;data.tool_id="upload1";data.inputs=JSON.stringify(tool_input);return data},_eventProgress:function(i,j,h){var k=this.collection.get(i);k.set("percentage",h);this.ui_button.set("percentage",this._upload_percentage(h,j.size))},_eventSuccess:function(i,j,l){var k=this.collection.get(i);k.set("percentage",100);k.set("status","success");var h=k.get("file_size");this.ui_button.set("percentage",this._upload_percentage(100,h));this.upload_completed+=h*100;this.counter.announce--;this.counter.success++;this._updateScreen();Galaxy.currHistoryPanel.refreshHdas()},_eventError:function(h,i,k){var j=this.collection.get(h);j.set("percentage",100);j.set("status","error");j.set("info",k);this.ui_button.set("percentage",this._upload_percentage(100,i.size));this.ui_button.set("status","danger");this.upload_completed+=i.size*100;this.counter.announce--;this.counter.error++;this._updateScreen()},_eventComplete:function(){this.collection.each(function(h){if(h.get("status")=="queued"){h.set("status","init")}});this.counter.running=0;this._updateScreen()},_eventFtp:function(){if(!this.ftp.visible){this.ftp.empty();this.ftp.append((new g(this)).$el);this.ftp.show()}else{this.ftp.hide()}},_eventCreate:function(){this.uploadbox.add([{name:"New File",size:0,mode:"new"}])},_eventStart:function(){if(this.counter.announce==0||this.counter.running>0){return}var h=this;this.upload_size=0;this.upload_completed=0;this.collection.each(function(i){if(i.get("status")=="init"){i.set("status","queued");h.upload_size+=i.get("file_size")}});this.ui_button.set("percentage",0);this.ui_button.set("status","success");this.counter.running=this.counter.announce;this._updateScreen();this.uploadbox.start()},_eventStop:function(){if(this.counter.running==0){return}this.ui_button.set("status","info");this.uploadbox.stop();$("#upload-info").html("Queue will pause after completing the current file...")},_eventReset:function(){if(this.counter.running==0){this.collection.reset();this.counter.reset();this._updateScreen();this.uploadbox.reset();this.ui_button.set("percentage",0)}},_updateUser:function(){this.current_user=Galaxy.currUser.get("id");this.current_history=null;if(this.current_user){this.current_history=Galaxy.currHistoryPanel.model.get("id")}},_updateScreen:function(){if(this.counter.announce==0){if(this.uploadbox.compatible()){message="You can Drag & Drop files into this box."}else{message="Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Some supported browsers are: Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+."}}else{if(this.counter.running==0){message="You added "+this.counter.announce+" file(s) to the queue. Add more files or click 'Start' to proceed."}else{message="Please wait..."+this.counter.announce+" out of "+this.counter.running+" remaining."}}$("#upload-info").html(message);if(this.counter.running==0&&this.counter.announce+this.counter.success+this.counter.error>0){this.modal.enableButton("Reset")}else{this.modal.disableButton("Reset")}if(this.counter.running==0&&this.counter.announce>0){this.modal.enableButton("Start")}else{this.modal.disableButton("Start")}if(this.counter.running>0){this.modal.enableButton("Pause")}else{this.modal.disableButton("Pause")}if(this.counter.running==0){this.modal.enableButton("Choose local file");this.modal.enableButton("Choose FTP file");this.modal.enableButton("Create new file")}else{this.modal.disableButton("Choose local file");this.modal.disableButton("Choose FTP file");this.modal.disableButton("Create new file")}if(this.current_user&&this.options.ftp_upload_dir&&this.options.ftp_upload_site){this.modal.showButton("Choose FTP file")}else{this.modal.hideButton("Choose FTP file")}if(this.counter.announce+this.counter.success+this.counter.error>0){$(this.el).find("#upload-table").show()}else{$(this.el).find("#upload-table").hide()}},_upload_percentage:function(h,i){return(this.upload_completed+(h*i))/this.upload_size},_template:function(i,h){return'<div id="'+i+'" class="upload-box"><table id="upload-table" class="table table-striped" style="display: none;"><thead><tr><th>Name</th><th>Size</th><th>Type</th><th>Genome</th><th>Settings</th><th>Status</th><th></th></tr></thead><tbody></tbody></table></div><h6 id="'+h+'" class="upload-info"></h6>'}})});
\ No newline at end of file
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