commit/galaxy-central: 3 new changesets
3 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/2ae881148949/ Changeset: 2ae881148949 User: dannon Date: 2014-07-23 21:41:14 Summary: Fix 'decod_id' invocation to use the correct function when deleting user addresses. Affected #: 1 file diff -r 053943b668af334c480b464fe7351b50284b7099 -r 2ae881148949596af9c30f2c559dc8f627dda402 lib/galaxy/webapps/galaxy/controllers/user.py --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -1514,7 +1514,7 @@ @web.expose def delete_address( self, trans, cntrller, address_id=None, user_id=None ): try: - user_address = trans.sa_session.query( trans.app.model.UserAddress ).get( trans.security.decod_id( address_id ) ) + user_address = trans.sa_session.query( trans.app.model.UserAddress ).get( trans.security.decode_id( address_id ) ) except: message = 'Invalid address is (%s)' % address_id status = 'error' https://bitbucket.org/galaxy/galaxy-central/commits/4974ffd8b2cb/ Changeset: 4974ffd8b2cb User: dannon Date: 2014-07-23 21:42:23 Summary: Fix another variable definition issue in user address deletion. Affected #: 1 file diff -r 2ae881148949596af9c30f2c559dc8f627dda402 -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 lib/galaxy/webapps/galaxy/controllers/user.py --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -1522,7 +1522,7 @@ user_address.deleted = True trans.sa_session.add( user_address ) trans.sa_session.flush() - 'Address (%s) deleted' % user_address.desc + message = 'Address (%s) deleted' % user_address.desc status = 'done' return trans.response.send_redirect( web.url_for( controller='user', action='manage_user_info', https://bitbucket.org/galaxy/galaxy-central/commits/7aade8875ea4/ Changeset: 7aade8875ea4 User: dannon Date: 2014-07-23 22:27:42 Summary: Merge. Affected #: 60 files diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 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 @@ -12,7 +12,6 @@ import tool_shed.repository_types.util as rt_util from tool_shed.util import common_util -from tool_shed.util import datatype_util from tool_shed.util import encoding_util from tool_shed.util import hg_util from tool_shed.util import readme_util @@ -25,6 +24,7 @@ from tool_shed.galaxy_install import dependency_display from tool_shed.galaxy_install import install_manager +from tool_shed.galaxy_install.datatypes import custom_datatype_manager from tool_shed.galaxy_install.grids import admin_toolshed_grids from tool_shed.galaxy_install.metadata.installed_repository_metadata_manager import InstalledRepositoryMetadataManager from tool_shed.galaxy_install.repair_repository_manager import RepairRepositoryManager @@ -256,17 +256,17 @@ dmh.remove_from_data_manager( tool_shed_repository ) if tool_shed_repository.includes_datatypes: # Deactivate proprietary datatypes. - installed_repository_dict = datatype_util.load_installed_datatypes( trans.app, - tool_shed_repository, - repository_install_dir, - deactivate=True ) + cdl = custom_datatype_manager.CustomDatatypeLoader( trans.app ) + installed_repository_dict = cdl.load_installed_datatypes( tool_shed_repository, + repository_install_dir, + deactivate=True ) if installed_repository_dict: converter_path = installed_repository_dict.get( 'converter_path' ) if converter_path is not None: - datatype_util.load_installed_datatype_converters( trans.app, installed_repository_dict, deactivate=True ) + cdl.load_installed_datatype_converters( installed_repository_dict, deactivate=True ) display_path = installed_repository_dict.get( 'display_path' ) if display_path is not None: - datatype_util.load_installed_display_applications( trans.app, installed_repository_dict, deactivate=True ) + cdl.load_installed_display_applications( installed_repository_dict, deactivate=True ) if remove_from_disk_checked: try: # Remove the repository from disk. diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/galaxy/webapps/galaxy/controllers/history.py --- a/lib/galaxy/webapps/galaxy/controllers/history.py +++ b/lib/galaxy/webapps/galaxy/controllers/history.py @@ -195,6 +195,7 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesItemRatings, UsesHistoryMixin, UsesHistoryDatasetAssociationMixin, ExportsHistoryMixin, ImportsHistoryMixin ): + def __init__( self, app ): super( HistoryController, self ).__init__( app ) self.mgrs = util.bunch.Bunch( diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/galaxy/webapps/galaxy/controllers/page.py --- a/lib/galaxy/webapps/galaxy/controllers/page.py +++ b/lib/galaxy/webapps/galaxy/controllers/page.py @@ -1,5 +1,6 @@ from sqlalchemy import desc, and_ from galaxy import model, web +from galaxy import managers from galaxy.web import error, url_for from galaxy.model.item_attrs import UsesItemRatings from galaxy.web.base.controller import BaseUIController, SharableMixin, UsesHistoryMixin, UsesStoredWorkflowMixin, UsesVisualizationMixin @@ -285,6 +286,12 @@ _page_selection_grid = PageSelectionGrid() _visualization_selection_grid = VisualizationSelectionGrid() + def __init__( self, app ): + super( PageController, self ).__init__( app ) + self.mgrs = util.bunch.Bunch( + histories=managers.histories.HistoryManager() + ) + @web.expose @web.require_login() def list( self, trans, *args, **kwargs ): @@ -718,6 +725,7 @@ """ Returns html suitable for embedding in another page. """ + #TODO: should be moved to history controller and/or called via ajax from the template history = self.get_history( trans, id, False, True ) if not history: return None @@ -729,15 +737,22 @@ hda_dicts = [] datasets = self.get_history_datasets( trans, history ) - for hda in datasets: - hda_dict = self.get_hda_dict( trans, hda ) - hda_dict[ 'annotation' ] = self.get_item_annotation_str( trans.sa_session, history.user, hda ) - hda_dicts.append( hda_dict ) - history_dict = self.get_history_dict( trans, history, hda_dictionaries=hda_dicts ) - history_dict[ 'annotation' ] = history.annotation + #for hda in datasets: + # hda_dict = self.get_hda_dict( trans, hda ) + # hda_dict[ 'annotation' ] = self.get_item_annotation_str( trans.sa_session, history.user, hda ) + # hda_dicts.append( hda_dict ) + #history_dict = self.get_history_dict( trans, history, hda_dictionaries=hda_dicts ) + #history_dict[ 'annotation' ] = history.annotation + + # include all datasets: hidden, deleted, and purged + #TODO!: doubled query (hda_dictionaries + datasets) + history_data = self.mgrs.histories._get_history_data( trans, history ) + history_dictionary = history_data[ 'history' ] + hda_dictionaries = history_data[ 'contents' ] + history_dictionary[ 'annotation' ] = history.annotation filled = trans.fill_template( "history/embed.mako", item=history, item_data=datasets, - user_is_owner=user_is_owner, history_dict=history_dict, hda_dicts=hda_dicts ) + user_is_owner=user_is_owner, history_dict=history_dictionary, hda_dicts=hda_dictionaries ) return filled def _get_embed_html( self, trans, item_class, item_id ): diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/galaxy/webapps/tool_shed/controllers/repository.py --- a/lib/galaxy/webapps/tool_shed/controllers/repository.py +++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py @@ -1062,7 +1062,7 @@ action='browse_repositories', message=message, status=status ) ) - name = kwd.get( 'name', '' ) + name = kwd.get( 'name', '' ).strip() description = kwd.get( 'description', '' ) long_description = kwd.get( 'long_description', '' ) category_ids = util.listify( kwd.get( 'category_id', '' ) ) @@ -1262,7 +1262,11 @@ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans.app, repository_id, changeset_revision ) metadata = repository_metadata.metadata toolshed_base_url = str( web.url_for( '/', qualified=True ) ).rstrip( '/' ) + # Initialize the repository dependency RelationBuilder. rb = relation_builder.RelationBuilder( trans.app, repository, repository_metadata, toolshed_base_url ) + # Work-around to ensure repositories that contain packages needed only for compiling + # a dependent package are included in the capsule. + rb.set_filter_dependencies_needed_for_compiling( False ) # Get a dictionary of all repositories upon which the contents of the current repository_metadata record depend. repository_dependencies = rb.get_repository_dependencies_for_changeset_revision() if repository_dependencies: diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/tool_shed/capsule/capsule_manager.py --- a/lib/tool_shed/capsule/capsule_manager.py +++ b/lib/tool_shed/capsule/capsule_manager.py @@ -245,9 +245,13 @@ repository_metadata = suc.get_repository_metadata_by_changeset_revision( self.app, self.repository_id, self.changeset_revision ) - # Get a dictionary of all repositories upon which the contents of the current repository_metadata record depend. + # Get a dictionary of all repositories upon which the contents of the current + # repository_metadata record depend. toolshed_base_url = str( web.url_for( '/', qualified=True ) ).rstrip( '/' ) rb = RelationBuilder( self.app, repository, repository_metadata, toolshed_base_url ) + # Work-around to ensure repositories that contain packages needed only for compiling + # a dependent package are included in the capsule. + rb.set_filter_dependencies_needed_for_compiling( False ) repository_dependencies = rb.get_repository_dependencies_for_changeset_revision() repo = hg_util.get_repo_for_repository( self.app, repository=self.repository, diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/tool_shed/dependencies/repository/relation_builder.py --- a/lib/tool_shed/dependencies/repository/relation_builder.py +++ b/lib/tool_shed/dependencies/repository/relation_builder.py @@ -23,6 +23,11 @@ self.handled_key_rd_dicts = [] self.key_rd_dicts_to_be_processed = [] self.tool_shed_url = tool_shed_url + # This is a temporary work-around for handling repository dependencies that are needed + # only if compiling a dependent package. This value should be True unless exporting + # a repository capsule, in which case the set_filter_dependencies_needed_for_compiling() + # function is called. + self.filter_dependencies_needed_for_compiling = True def can_add_to_key_rd_dicts( self, key_rd_dict, key_rd_dicts ): """Handle the case where an update to the changeset revision was done.""" @@ -389,9 +394,12 @@ current_repository_key_rd_dicts = \ self.get_updated_changeset_revisions_for_repository_dependencies( current_repository_key_rd_dicts ) for key_rd_dict in current_repository_key_rd_dicts: - # Filter out repository dependencies that are required only if compiling the dependent - # repository's tool dependency. - key_rd_dict = self.filter_only_if_compiling_contained_td( key_rd_dict ) + if self.filter_dependencies_needed_for_compiling: + # Filter out repository dependencies that are required only if compiling the dependent + # repository's tool dependency. + # TODO: this temporary work-around should be removed when the underlying framework + # support for handling only_if_compiling_contained_td-flagged repositories is completed. + key_rd_dict = self.filter_only_if_compiling_contained_td( key_rd_dict ) if key_rd_dict: is_circular = False in_handled_key_rd_dicts = self.in_key_rd_dicts( key_rd_dict, self.handled_key_rd_dicts ) @@ -483,6 +491,9 @@ clean_key_rd_dicts.append( new_key_rd_dict ) return clean_key_rd_dicts + def set_filter_dependencies_needed_for_compiling( self, value ): + self.filter_dependencies_needed_for_compiling = asbool( value ) + def update_circular_repository_dependencies( self, repository_key, repository_dependency, repository_dependencies ): repository_dependency_as_key = self.get_repository_dependency_as_key( repository_dependency ) repository_key_as_repository_dependency = repository_key.split( container_util.STRSEP ) diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/tool_shed/galaxy_install/datatypes/custom_datatype_manager.py --- /dev/null +++ b/lib/tool_shed/galaxy_install/datatypes/custom_datatype_manager.py @@ -0,0 +1,218 @@ +import logging +import os +import tempfile + +from galaxy.util import asbool + +from tool_shed.util import basic_util +from tool_shed.util import hg_util +from tool_shed.util import tool_util +from tool_shed.util import shed_util_common as suc +from tool_shed.util import xml_util + +log = logging.getLogger( __name__ ) + + +class CustomDatatypeLoader( object ): + + def __init__( self, app ): + self.app = app + + def alter_config_and_load_prorietary_datatypes( self, datatypes_config, relative_install_dir, + deactivate=False, override=True ): + """ + Parse a custom datatypes config (a datatypes_conf.xml file included in an installed + tool shed repository) and add information to appropriate element attributes that will + enable custom datatype class modules, datatypes converters and display applications + to be discovered and properly imported by the datatypes registry. The value of override + will be False when a tool shed repository is being installed. Since installation is + occurring after the datatypes registry has been initialized, the registry's contents + cannot be overridden by conflicting data types. + """ + tree, error_message = xml_util.parse_xml( datatypes_config ) + if tree is None: + return None, None + datatypes_config_root = tree.getroot() + registration = datatypes_config_root.find( 'registration' ) + if registration is None: + # We have valid XML, but not a valid custom datatypes definition. + return None, None + sniffers = datatypes_config_root.find( 'sniffers' ) + converter_path, display_path = self.get_converter_and_display_paths( registration, + relative_install_dir ) + if converter_path: + # Path to datatype converters + registration.attrib[ 'proprietary_converter_path' ] = converter_path + if display_path: + # Path to datatype display applications + registration.attrib[ 'proprietary_display_path' ] = display_path + relative_path_to_datatype_file_name = None + datatype_files = datatypes_config_root.find( 'datatype_files' ) + datatype_class_modules = [] + if datatype_files is not None: + # The <datatype_files> tag set contains any number of <datatype_file> tags. + # <datatype_files> + # <datatype_file name="gmap.py"/> + # <datatype_file name="metagenomics.py"/> + # </datatype_files> + # We'll add attributes to the datatype tag sets so that the modules can be properly imported + # by the datatypes registry. + for elem in datatype_files.findall( 'datatype_file' ): + datatype_file_name = elem.get( 'name', None ) + if datatype_file_name: + # Find the file in the installed repository. + for root, dirs, files in os.walk( relative_install_dir ): + if root.find( '.hg' ) < 0: + for name in files: + if name == datatype_file_name: + datatype_class_modules.append( os.path.join( root, name ) ) + break + break + if datatype_class_modules: + for relative_path_to_datatype_file_name in datatype_class_modules: + datatype_file_name_path, datatype_file_name = os.path.split( relative_path_to_datatype_file_name ) + for elem in registration.findall( 'datatype' ): + # Handle 'type' attribute which should be something like one of the following: + # type="gmap:GmapDB" + # type="galaxy.datatypes.gmap:GmapDB" + dtype = elem.get( 'type', None ) + if dtype: + fields = dtype.split( ':' ) + proprietary_datatype_module = fields[ 0 ] + if proprietary_datatype_module.find( '.' ) >= 0: + # Handle the case where datatype_module is "galaxy.datatypes.gmap". + proprietary_datatype_module = proprietary_datatype_module.split( '.' )[ -1 ] + # The value of proprietary_path must be an absolute path due to job_working_directory. + elem.attrib[ 'proprietary_path' ] = os.path.abspath( datatype_file_name_path ) + elem.attrib[ 'proprietary_datatype_module' ] = proprietary_datatype_module + # Temporarily persist the custom datatypes configuration file so it can be loaded into the + # datatypes registry. + fd, proprietary_datatypes_config = tempfile.mkstemp( prefix="tmp-toolshed-acalpd" ) + os.write( fd, '<?xml version="1.0"?>\n' ) + os.write( fd, '<datatypes>\n' ) + os.write( fd, '%s' % xml_util.xml_to_string( registration ) ) + if sniffers is not None: + os.write( fd, '%s' % xml_util.xml_to_string( sniffers ) ) + os.write( fd, '</datatypes>\n' ) + os.close( fd ) + os.chmod( proprietary_datatypes_config, 0644 ) + # Load custom datatypes + self.app.datatypes_registry.load_datatypes( root_dir=self.app.config.root, + config=proprietary_datatypes_config, + deactivate=deactivate, + override=override ) + if deactivate: + # Reload the upload tool to eliminate deactivated datatype extensions from the file_type + # select list. + tool_util.reload_upload_tools( self.app ) + else: + self.append_to_datatypes_registry_upload_file_formats( registration ) + tool_util.reload_upload_tools( self.app ) + if datatype_files is not None: + try: + os.unlink( proprietary_datatypes_config ) + except: + pass + return converter_path, display_path + + def append_to_datatypes_registry_upload_file_formats( self, elem ): + # See if we have any datatypes that should be displayed in the upload tool's file_type select list. + for datatype_elem in elem.findall( 'datatype' ): + extension = datatype_elem.get( 'extension', None ) + display_in_upload = datatype_elem.get( 'display_in_upload', None ) + if extension is not None and display_in_upload is not None: + display_in_upload = asbool( str( display_in_upload ) ) + if display_in_upload and extension not in self.app.datatypes_registry.upload_file_formats: + self.app.datatypes_registry.upload_file_formats.append( extension ) + + def create_repository_dict_for_proprietary_datatypes( self, tool_shed, name, owner, installed_changeset_revision, + tool_dicts, converter_path=None, display_path=None ): + return dict( tool_shed=tool_shed, + repository_name=name, + repository_owner=owner, + installed_changeset_revision=installed_changeset_revision, + tool_dicts=tool_dicts, + converter_path=converter_path, + display_path=display_path ) + + def get_converter_and_display_paths( self, registration_elem, relative_install_dir ): + """ + Find the relative path to data type converters and display applications included + in installed tool shed repositories. + """ + converter_path = None + display_path = None + for elem in registration_elem.findall( 'datatype' ): + if not converter_path: + # If any of the <datatype> tag sets contain <converter> tags, set the converter_path + # if it is not already set. This requires developers to place all converters in the + # same subdirectory within the repository hierarchy. + for converter in elem.findall( 'converter' ): + converter_config = converter.get( 'file', None ) + if converter_config: + converter_config_file_name = basic_util.strip_path( converter_config ) + for root, dirs, files in os.walk( relative_install_dir ): + if root.find( '.hg' ) < 0: + for name in files: + if name == converter_config_file_name: + # The value of converter_path must be absolute due to job_working_directory. + converter_path = os.path.abspath( root ) + break + if converter_path: + break + if not display_path: + # If any of the <datatype> tag sets contain <display> tags, set the display_path + # if it is not already set. This requires developers to place all display acpplications + # in the same subdirectory within the repository hierarchy. + for display_app in elem.findall( 'display' ): + display_config = display_app.get( 'file', None ) + if display_config: + display_config_file_name = basic_util.strip_path( display_config ) + for root, dirs, files in os.walk( relative_install_dir ): + if root.find( '.hg' ) < 0: + for name in files: + if name == display_config_file_name: + # The value of display_path must be absolute due to job_working_directory. + display_path = os.path.abspath( root ) + break + if display_path: + break + if converter_path and display_path: + break + return converter_path, display_path + + def load_installed_datatype_converters( self, installed_repository_dict, deactivate=False ): + """Load or deactivate proprietary datatype converters.""" + self.app.datatypes_registry.load_datatype_converters( self.app.toolbox, + installed_repository_dict=installed_repository_dict, + deactivate=deactivate ) + + def load_installed_datatypes( self, repository, relative_install_dir, deactivate=False ): + """ + Load proprietary datatypes and return information needed for loading custom + datatypes converters and display applications later. + """ + metadata = repository.metadata + repository_dict = None + datatypes_config = hg_util.get_config_from_disk( suc.DATATYPES_CONFIG_FILENAME, relative_install_dir ) + if datatypes_config: + converter_path, display_path = \ + self.alter_config_and_load_prorietary_datatypes( datatypes_config, + relative_install_dir, + deactivate=deactivate ) + if converter_path or display_path: + # Create a dictionary of tool shed repository related information. + repository_dict = \ + self.create_repository_dict_for_proprietary_datatypes( tool_shed=repository.tool_shed, + name=repository.name, + owner=repository.owner, + installed_changeset_revision=repository.installed_changeset_revision, + tool_dicts=metadata.get( 'tools', [] ), + converter_path=converter_path, + display_path=display_path ) + return repository_dict + + def load_installed_display_applications( self, installed_repository_dict, deactivate=False ): + """Load or deactivate custom datatype display applications.""" + self.app.datatypes_registry.load_display_applications( installed_repository_dict=installed_repository_dict, + deactivate=deactivate ) diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/tool_shed/galaxy_install/install_manager.py --- a/lib/tool_shed/galaxy_install/install_manager.py +++ b/lib/tool_shed/galaxy_install/install_manager.py @@ -18,7 +18,6 @@ from tool_shed.util import basic_util from tool_shed.util import common_util -from tool_shed.util import datatype_util from tool_shed.util import encoding_util from tool_shed.util import hg_util from tool_shed.util import shed_util_common as suc @@ -26,6 +25,7 @@ from tool_shed.util import tool_util from tool_shed.util import xml_util +from tool_shed.galaxy_install.datatypes import custom_datatype_manager from tool_shed.galaxy_install.metadata.installed_repository_metadata_manager import InstalledRepositoryMetadataManager from tool_shed.galaxy_install.repository_dependencies import repository_dependency_manager from tool_shed.galaxy_install.tool_dependencies.recipe.env_file_builder import EnvFileBuilder @@ -594,18 +594,19 @@ files_dir = os.path.join( shed_config_dict[ 'tool_path' ], files_dir ) datatypes_config = hg_util.get_config_from_disk( suc.DATATYPES_CONFIG_FILENAME, files_dir ) # Load data types required by tools. + cdl = custom_datatype_manager.CustomDatatypeLoader( self.app ) converter_path, display_path = \ - datatype_util.alter_config_and_load_prorietary_datatypes( self.app, datatypes_config, files_dir, override=False ) + cdl.alter_config_and_load_prorietary_datatypes( datatypes_config, files_dir, override=False ) if converter_path or display_path: # Create a dictionary of tool shed repository related information. repository_dict = \ - datatype_util.create_repository_dict_for_proprietary_datatypes( tool_shed=tool_shed, - name=tool_shed_repository.name, - owner=tool_shed_repository.owner, - installed_changeset_revision=tool_shed_repository.installed_changeset_revision, - tool_dicts=metadata_dict.get( 'tools', [] ), - converter_path=converter_path, - display_path=display_path ) + cdl.create_repository_dict_for_proprietary_datatypes( tool_shed=tool_shed, + name=tool_shed_repository.name, + owner=tool_shed_repository.owner, + installed_changeset_revision=tool_shed_repository.installed_changeset_revision, + tool_dicts=metadata_dict.get( 'tools', [] ), + converter_path=converter_path, + display_path=display_path ) if converter_path: # Load proprietary datatype converters self.app.datatypes_registry.load_datatype_converters( self.app.toolbox, installed_repository_dict=repository_dict ) diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 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 @@ -7,12 +7,12 @@ from galaxy import util from tool_shed.util import common_util from tool_shed.util import container_util -from tool_shed.util import datatype_util from tool_shed.util import shed_util_common as suc from tool_shed.util import tool_dependency_util from tool_shed.util import xml_util from galaxy.model.orm import and_ +from tool_shed.galaxy_install.datatypes import custom_datatype_manager from tool_shed.galaxy_install.metadata.installed_repository_metadata_manager import InstalledRepositoryMetadataManager from tool_shed.galaxy_install.repository_dependencies import repository_dependency_manager from tool_shed.galaxy_install.tools import data_manager @@ -114,17 +114,17 @@ else: repository_install_dir = os.path.abspath( relative_install_dir ) # Activate proprietary datatypes. - installed_repository_dict = datatype_util.load_installed_datatypes( self.app, - repository, - repository_install_dir, - deactivate=False ) + cdl = custom_datatype_manager.CustomDatatypeLoader( self.app ) + installed_repository_dict = cdl.load_installed_datatypes( repository, + repository_install_dir, + deactivate=False ) if installed_repository_dict: converter_path = installed_repository_dict.get( 'converter_path' ) if converter_path is not None: - datatype_util.load_installed_datatype_converters( self.app, installed_repository_dict, deactivate=False ) + cdl.load_installed_datatype_converters( installed_repository_dict, deactivate=False ) display_path = installed_repository_dict.get( 'display_path' ) if display_path is not None: - datatype_util.load_installed_display_applications( self.app, installed_repository_dict, deactivate=False ) + cdl.load_installed_display_applications( installed_repository_dict, deactivate=False ) def add_entry_to_installed_repository_dependencies_of_installed_repositories( self, repository ): """ @@ -732,22 +732,24 @@ self.add_entry_to_installed_runtime_dependent_tool_dependencies_of_installed_tool_dependencies( tool_dependency ) def load_proprietary_datatypes( self ): + cdl = custom_datatype_manager.CustomDatatypeLoader( self.app ) for tool_shed_repository in self.context.query( self.install_model.ToolShedRepository ) \ - .filter( and_( self.install_model.ToolShedRepository.table.c.includes_datatypes==True, - self.install_model.ToolShedRepository.table.c.deleted==False ) ) \ - .order_by( self.install_model.ToolShedRepository.table.c.id ): + .filter( and_( self.install_model.ToolShedRepository.table.c.includes_datatypes==True, + self.install_model.ToolShedRepository.table.c.deleted==False ) ) \ + .order_by( self.install_model.ToolShedRepository.table.c.id ): relative_install_dir = self.get_repository_install_dir( tool_shed_repository ) if relative_install_dir: - installed_repository_dict = datatype_util.load_installed_datatypes( self.app, tool_shed_repository, relative_install_dir ) + installed_repository_dict = cdl.load_installed_datatypes( tool_shed_repository, relative_install_dir ) if installed_repository_dict: self.installed_repository_dicts.append( installed_repository_dict ) def load_proprietary_converters_and_display_applications( self, deactivate=False ): + cdl = custom_datatype_manager.CustomDatatypeLoader( self.app ) for installed_repository_dict in self.installed_repository_dicts: if installed_repository_dict[ 'converter_path' ]: - datatype_util.load_installed_datatype_converters( self.app, installed_repository_dict, deactivate=deactivate ) + cdl.load_installed_datatype_converters( installed_repository_dict, deactivate=deactivate ) if installed_repository_dict[ 'display_path' ]: - datatype_util.load_installed_display_applications( self.app, installed_repository_dict, deactivate=deactivate ) + cdl.load_installed_display_applications( installed_repository_dict, deactivate=deactivate ) def purge_repository( self, repository ): """Purge a repository with status New (a white ghost) from the database.""" diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/tool_shed/galaxy_install/tool_migration_manager.py --- a/lib/tool_shed/galaxy_install/tool_migration_manager.py +++ b/lib/tool_shed/galaxy_install/tool_migration_manager.py @@ -14,6 +14,7 @@ from galaxy.util.odict import odict from tool_shed.galaxy_install import install_manager +from tool_shed.galaxy_install.datatypes import custom_datatype_manager from tool_shed.galaxy_install.metadata.installed_repository_metadata_manager import InstalledRepositoryMetadataManager from tool_shed.galaxy_install.tools import tool_panel_manager @@ -22,7 +23,6 @@ from tool_shed.util import basic_util from tool_shed.util import common_util -from tool_shed.util import datatype_util from tool_shed.util import hg_util from tool_shed.util import shed_util_common as suc from tool_shed.util import tool_dependency_util @@ -492,6 +492,7 @@ print '\nThe ToolMigrationManager returned the following error while installing tool dependency ', installed_tool_dependency.name, ':' print installed_tool_dependency.error_message, '\n\n' if 'datatypes' in metadata_dict: + cdl = custom_datatype_manager.CustomDatatypeLoader( self.app ) tool_shed_repository.status = self.app.install_model.ToolShedRepository.installation_status.LOADING_PROPRIETARY_DATATYPES if not tool_shed_repository.includes_datatypes: tool_shed_repository.includes_datatypes = True @@ -499,21 +500,27 @@ self.app.install_model.context.flush() work_dir = tempfile.mkdtemp( prefix="tmp-toolshed-hrc" ) datatypes_config = hg_util.get_config_from_disk( suc.DATATYPES_CONFIG_FILENAME, repo_install_dir ) - # Load proprietary data types required by tools. The value of override is not important here since the Galaxy server will be started - # after this installation completes. - converter_path, display_path = datatype_util.alter_config_and_load_prorietary_datatypes( self.app, datatypes_config, repo_install_dir, override=False ) #repo_install_dir was relative_install_dir + # Load proprietary data types required by tools. The value of override is not + # important here since the Galaxy server will be started after this installation + #completes. + converter_path, display_path = \ + cdl.alter_config_and_load_prorietary_datatypes( datatypes_config, + repo_install_dir, + override=False ) if converter_path or display_path: # Create a dictionary of tool shed repository related information. - repository_dict = datatype_util.create_repository_dict_for_proprietary_datatypes( tool_shed=self.tool_shed_url, - name=tool_shed_repository.name, - owner=self.repository_owner, - installed_changeset_revision=tool_shed_repository.installed_changeset_revision, - tool_dicts=metadata_dict.get( 'tools', [] ), - converter_path=converter_path, - display_path=display_path ) + repository_dict = \ + cdl.create_repository_dict_for_proprietary_datatypes( tool_shed=self.tool_shed_url, + name=tool_shed_repository.name, + owner=self.repository_owner, + installed_changeset_revision=tool_shed_repository.installed_changeset_revision, + tool_dicts=metadata_dict.get( 'tools', [] ), + converter_path=converter_path, + display_path=display_path ) if converter_path: # Load proprietary datatype converters - self.app.datatypes_registry.load_datatype_converters( self.toolbox, installed_repository_dict=repository_dict ) + self.app.datatypes_registry.load_datatype_converters( self.toolbox, + installed_repository_dict=repository_dict ) if display_path: # Load proprietary datatype display applications self.app.datatypes_registry.load_display_applications( installed_repository_dict=repository_dict ) diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 lib/tool_shed/util/datatype_util.py --- a/lib/tool_shed/util/datatype_util.py +++ /dev/null @@ -1,187 +0,0 @@ -import logging -import os -import tempfile -from galaxy import eggs -from galaxy.util import asbool -from tool_shed.util import basic_util -from tool_shed.util import hg_util -from tool_shed.util import tool_util -from tool_shed.util import xml_util -import tool_shed.util.shed_util_common as suc - -log = logging.getLogger( __name__ ) - -def alter_config_and_load_prorietary_datatypes( app, datatypes_config, relative_install_dir, deactivate=False, override=True ): - """ - Parse a proprietary datatypes config (a datatypes_conf.xml file included in an installed tool shed repository) and - add information to appropriate element attributes that will enable proprietary datatype class modules, datatypes converters - and display applications to be discovered and properly imported by the datatypes registry. The value of override will - be False when a tool shed repository is being installed. Since installation is occurring after the datatypes registry - has been initialized, the registry's contents cannot be overridden by conflicting data types. - """ - tree, error_message = xml_util.parse_xml( datatypes_config ) - if tree is None: - return None, None - datatypes_config_root = tree.getroot() - registration = datatypes_config_root.find( 'registration' ) - if registration is None: - # We have valid XML, but not a valid proprietary datatypes definition. - return None, None - sniffers = datatypes_config_root.find( 'sniffers' ) - converter_path, display_path = get_converter_and_display_paths( registration, relative_install_dir ) - if converter_path: - # Path to datatype converters - registration.attrib[ 'proprietary_converter_path' ] = converter_path - if display_path: - # Path to datatype display applications - registration.attrib[ 'proprietary_display_path' ] = display_path - relative_path_to_datatype_file_name = None - datatype_files = datatypes_config_root.find( 'datatype_files' ) - datatype_class_modules = [] - if datatype_files is not None: - # The <datatype_files> tag set contains any number of <datatype_file> tags. - # <datatype_files> - # <datatype_file name="gmap.py"/> - # <datatype_file name="metagenomics.py"/> - # </datatype_files> - # We'll add attributes to the datatype tag sets so that the modules can be properly imported by the datatypes registry. - for elem in datatype_files.findall( 'datatype_file' ): - datatype_file_name = elem.get( 'name', None ) - if datatype_file_name: - # Find the file in the installed repository. - for root, dirs, files in os.walk( relative_install_dir ): - if root.find( '.hg' ) < 0: - for name in files: - if name == datatype_file_name: - datatype_class_modules.append( os.path.join( root, name ) ) - break - break - if datatype_class_modules: - for relative_path_to_datatype_file_name in datatype_class_modules: - datatype_file_name_path, datatype_file_name = os.path.split( relative_path_to_datatype_file_name ) - for elem in registration.findall( 'datatype' ): - # Handle 'type' attribute which should be something like one of the following: - # type="gmap:GmapDB" - # type="galaxy.datatypes.gmap:GmapDB" - dtype = elem.get( 'type', None ) - if dtype: - fields = dtype.split( ':' ) - proprietary_datatype_module = fields[ 0 ] - if proprietary_datatype_module.find( '.' ) >= 0: - # Handle the case where datatype_module is "galaxy.datatypes.gmap". - proprietary_datatype_module = proprietary_datatype_module.split( '.' )[ -1 ] - # The value of proprietary_path must be an absolute path due to job_working_directory. - elem.attrib[ 'proprietary_path' ] = os.path.abspath( datatype_file_name_path ) - elem.attrib[ 'proprietary_datatype_module' ] = proprietary_datatype_module - # Temporarily persist the proprietary datatypes configuration file so it can be loaded into the datatypes registry. - fd, proprietary_datatypes_config = tempfile.mkstemp( prefix="tmp-toolshed-acalpd" ) - os.write( fd, '<?xml version="1.0"?>\n' ) - os.write( fd, '<datatypes>\n' ) - os.write( fd, '%s' % xml_util.xml_to_string( registration ) ) - if sniffers is not None: - os.write( fd, '%s' % xml_util.xml_to_string( sniffers ) ) - os.write( fd, '</datatypes>\n' ) - os.close( fd ) - os.chmod( proprietary_datatypes_config, 0644 ) - # Load proprietary datatypes - app.datatypes_registry.load_datatypes( root_dir=app.config.root, config=proprietary_datatypes_config, deactivate=deactivate, override=override ) - if deactivate: - # Reload the upload tool to eliminate deactivated datatype extensions from the file_type select list. - tool_util.reload_upload_tools( app ) - else: - append_to_datatypes_registry_upload_file_formats( app, registration ) - tool_util.reload_upload_tools( app ) - if datatype_files is not None: - try: - os.unlink( proprietary_datatypes_config ) - except: - pass - return converter_path, display_path - -def append_to_datatypes_registry_upload_file_formats( app, elem ): - # See if we have any datatypes that should be displayed in the upload tool's file_type select list. - for datatype_elem in elem.findall( 'datatype' ): - extension = datatype_elem.get( 'extension', None ) - display_in_upload = datatype_elem.get( 'display_in_upload', None ) - if extension is not None and display_in_upload is not None: - display_in_upload = asbool( str( display_in_upload ) ) - if display_in_upload and extension not in app.datatypes_registry.upload_file_formats: - app.datatypes_registry.upload_file_formats.append( extension ) - -def create_repository_dict_for_proprietary_datatypes( tool_shed, name, owner, installed_changeset_revision, tool_dicts, converter_path=None, display_path=None ): - return dict( tool_shed=tool_shed, - repository_name=name, - repository_owner=owner, - installed_changeset_revision=installed_changeset_revision, - tool_dicts=tool_dicts, - converter_path=converter_path, - display_path=display_path ) - -def get_converter_and_display_paths( registration_elem, relative_install_dir ): - """Find the relative path to data type converters and display applications included in installed tool shed repositories.""" - converter_path = None - display_path = None - for elem in registration_elem.findall( 'datatype' ): - if not converter_path: - # If any of the <datatype> tag sets contain <converter> tags, set the converter_path - # if it is not already set. This requires developers to place all converters in the - # same subdirectory within the repository hierarchy. - for converter in elem.findall( 'converter' ): - converter_config = converter.get( 'file', None ) - if converter_config: - converter_config_file_name = basic_util.strip_path( converter_config ) - for root, dirs, files in os.walk( relative_install_dir ): - if root.find( '.hg' ) < 0: - for name in files: - if name == converter_config_file_name: - # The value of converter_path must be absolute due to job_working_directory. - converter_path = os.path.abspath( root ) - break - if converter_path: - break - if not display_path: - # If any of the <datatype> tag sets contain <display> tags, set the display_path - # if it is not already set. This requires developers to place all display acpplications - # in the same subdirectory within the repository hierarchy. - for display_app in elem.findall( 'display' ): - display_config = display_app.get( 'file', None ) - if display_config: - display_config_file_name = basic_util.strip_path( display_config ) - for root, dirs, files in os.walk( relative_install_dir ): - if root.find( '.hg' ) < 0: - for name in files: - if name == display_config_file_name: - # The value of display_path must be absolute due to job_working_directory. - display_path = os.path.abspath( root ) - break - if display_path: - break - if converter_path and display_path: - break - return converter_path, display_path - -def load_installed_datatype_converters( app, installed_repository_dict, deactivate=False ): - # Load or deactivate proprietary datatype converters - app.datatypes_registry.load_datatype_converters( app.toolbox, installed_repository_dict=installed_repository_dict, deactivate=deactivate ) - -def load_installed_datatypes( app, repository, relative_install_dir, deactivate=False ): - # Load proprietary datatypes and return information needed for loading proprietary datatypes converters and display applications later. - metadata = repository.metadata - repository_dict = None - datatypes_config = hg_util.get_config_from_disk( suc.DATATYPES_CONFIG_FILENAME, relative_install_dir ) - if datatypes_config: - converter_path, display_path = alter_config_and_load_prorietary_datatypes( app, datatypes_config, relative_install_dir, deactivate=deactivate ) - if converter_path or display_path: - # Create a dictionary of tool shed repository related information. - repository_dict = create_repository_dict_for_proprietary_datatypes( tool_shed=repository.tool_shed, - name=repository.name, - owner=repository.owner, - installed_changeset_revision=repository.installed_changeset_revision, - tool_dicts=metadata.get( 'tools', [] ), - converter_path=converter_path, - display_path=display_path ) - return repository_dict - -def load_installed_display_applications( app, installed_repository_dict, deactivate=False ): - # Load or deactivate proprietary datatype display applications - app.datatypes_registry.load_display_applications( installed_repository_dict=installed_repository_dict, deactivate=deactivate ) diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 static/scripts/mvc/base-mvc.js --- a/static/scripts/mvc/base-mvc.js +++ b/static/scripts/mvc/base-mvc.js @@ -14,7 +14,7 @@ * @example * // Add to your models/views at the definition using chaining: * var MyModel = Backbone.Model.extend( LoggableMixin ).extend({ // ... }); - * + * * // or - more explicitly AFTER the definition: * var MyModel = Backbone.Model.extend({ * logger : console @@ -208,8 +208,23 @@ }; //============================================================================== -return { - LoggableMixin : LoggableMixin, - SessionStorageModel : SessionStorageModel, - HiddenUntilActivatedViewMixin : HiddenUntilActivatedViewMixin -};}); +function mixin( mixinHash1, /* mixinHash2, etc: ... variadic */ propsHash ){ + // usage: var NewModel = Something.extend( mixin( MyMixinA, MyMixinB, { ... }) ); + //NOTE: this does not combine any hashes (like events, etc.) and you're expected to handle that + + // simple reversal of param order on _.defaults() - to show mixins in top of definition + var args = Array.prototype.slice.call( arguments, 0 ), + lastArg = args.pop(); + args.unshift( lastArg ); + return _.defaults.apply( _, args ); +} + + +//============================================================================== + return { + LoggableMixin : LoggableMixin, + SessionStorageModel : SessionStorageModel, + HiddenUntilActivatedViewMixin : HiddenUntilActivatedViewMixin, + mixin : mixin + }; +}); diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 static/scripts/mvc/collection/collection-model.js --- /dev/null +++ b/static/scripts/mvc/collection/collection-model.js @@ -0,0 +1,250 @@ +define([ + "mvc/dataset/hda-model", + "mvc/base-mvc", + "utils/localization" +], function( HDA_MODEL, BASE_MVC, _l ){ +//============================================================================== +/** @class Backbone model for Dataset collection elements. + * DC Elements contain a sub-model named 'object'. This class moves that + * 'object' from the JSON in the attributes list to a full, instantiated + * sub-model found in this.object. This is done on intialization and + * everytime the 'change:object' event is fired. + * + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var DatasetCollectionElement = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend( +/** @lends DatasetCollectionElement.prototype */{ + //TODO:?? this model may be unneccessary - it reflects the api structure, but... + // if we munge the element with the element.object at parse, we can flatten the entire hierarchy + + /** logger used to record this.log messages, commonly set to console */ + // comment this out to suppress log output + //logger : console, + + defaults : { + id : null, + model_class : 'DatasetCollectionElement', + element_identifier : null, + element_index : null, + element_type : null + }, + + /** Set up. + * @see Backbone.Collection#initialize + */ + initialize : function( model, options ){ + this.info( this + '.initialize:', model, options ); + options = options || {}; + //this._setUpListeners(); + + this.object = this._createObjectModel(); + this.on( 'change:object', function(){ + //console.log( 'change:object' ); +//TODO: prob. better to update the sub-model instead of re-creating it + this.object = this._createObjectModel(); + }); + }, + + _createObjectModel : function(){ + //console.log( '_createObjectModel', this.get( 'object' ), this.object ); + //TODO: same patterns as HDCA _createElementsModel - refactor to BASE_MVC.hasSubModel? + if( _.isUndefined( this.object ) ){ this.object = null; } + if( !this.get( 'object' ) ){ return this.object; } + + var object = this.get( 'object' ); + this.unset( 'object', { silent: true }); + + this.debug( 'DCE, element_type:', this.get( 'element_type' ) ); + switch( this.get( 'element_type' ) ){ + case 'dataset_collection': + this.object = new DatasetCollection( object ); + break; + case 'hda': + this.object = new HDA_MODEL.HistoryDatasetAssociation( object ); + break; + default: + throw new TypeError( 'Unknown element_type: ' + this.get( 'element_type' ) ); + } + return this.object; + }, + + /** String representation. */ + toString : function(){ + var objStr = ( this.object )?( '' + this.object ):( this.get( 'element_identifier' ) ); + return ([ 'DatasetCollectionElement(', objStr, ')' ].join( '' )); + } +}); + + +//============================================================================== +/** @class Backbone collection for DCEs. + * NOTE: used *only* in second level of list:paired collections (a + * collection that contains collections) + * + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var DatasetCollectionElementCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend( +/** @lends DatasetCollectionElementCollection.prototype */{ + model: DatasetCollectionElement, + + // comment this out to suppress log output + /** logger used to record this.log messages, commonly set to console */ + //logger : console, + + /** Set up. + * @see Backbone.Collection#initialize + */ + initialize : function( models, options ){ + options = options || {}; + this.info( this + '.initialize:', models, options ); + //this._setUpListeners(); + }, + + /** String representation. */ + toString : function(){ + return ([ 'DatasetCollectionElementCollection(', this.length, ')' ].join( '' )); + } +}); + + +//============================================================================== +/** @class Backbone model for Dataset Collections. + * DCs contain a bbone collection named 'elements' using the class found in + * this.collectionClass (gen. DatasetCollectionElementCollection). DCs move + * that 'object' from the JSON in the attributes list to a full, instantiated + * collection found in this.elements. This is done on intialization and + * everytime the 'change:elements' event is fired. + * + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var DatasetCollection = Backbone.Model.extend( BASE_MVC.LoggableMixin ).extend( +/** @lends ListDatasetCollection.prototype */{ + + //logger : console, + + /** default attributes for a model */ + defaults : { + collection_type : 'list' + }, + + collectionClass : DatasetCollectionElementCollection, + + /** */ + initialize : function( model, options ){ + this.info( 'DatasetCollection.initialize:', model, options ); + //historyContent.HistoryContent.prototype.initialize.call( this, attrs, options ); + this.elements = this._createElementsModel(); +//TODO:?? no way to use parse here? + this.on( 'change:elements', function(){ + this.log( 'change:elements' ); +//TODO: prob. better to update the collection instead of re-creating it + this.elements = this._createElementsModel(); + }); + }, + + /** move elements model attribute to full collection */ + _createElementsModel : function(){ + this.log( '_createElementsModel', this.get( 'elements' ), this.elements ); +//TODO: same patterns as DatasetCollectionElement _createObjectModel - refactor to BASE_MVC.hasSubModel? + var elements = this.get( 'elements' ) || []; + this.info( 'elements:', elements ); + this.unset( 'elements', { silent: true }); + this.elements = new this.collectionClass( elements ); + return this.elements; + }, + + hasDetails : function(){ +//TODO: this is incorrect for (accidentally) empty collections + return this.elements.length !== 0; + }, + + // ........................................................................ misc + /** String representation */ + toString : function(){ + var idAndName = [ this.get( 'id' ), this.get( 'name' ) || this.get( 'element_identifier' ) ]; + return 'DatasetCollection(' + ( idAndName.join(',') ) + ')'; + } +}); + + +//============================================================================== +/** @class Backbone collection for a collection of collection collections collecting correctly. */ +var DatasetCollectionCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend({ + + model: DatasetCollection, + + ///** logger used to record this.log messages, commonly set to console */ + //// comment this out to suppress log output + //logger : console, + + /** Set up. + * @see Backbone.Collection#initialize + */ + initialize : function( models, options ){ + options = options || {}; + this.info( 'DatasetCollectionCollection.initialize:', models, options ); + //this._setUpListeners(); + }, + + /** String representation. */ + toString : function(){ + return ([ 'DatasetCollectionCollection(', this.get( 'name' ), ')' ].join( '' )); + } +}); + + +//NOTE: the following prototypes may not be necessary - but I wanted to specifiy +// them (for now) and allow for the possibility of unique functionality +//============================================================================== +var ListDatasetCollection = DatasetCollection.extend( +/** @lends ListDatasetCollection.prototype */{ + + /** String representation. */ + toString : function(){ + return ([ 'ListDatasetCollection(', this.get( 'name' ), ')' ].join( '' )); + } +}); + + +//============================================================================== +var PairDatasetCollection = DatasetCollection.extend( +/** @lends ListDatasetCollection.prototype */{ + + /** String representation. */ + toString : function(){ + return ([ 'PairDatasetCollection(', this.get( 'name' ), ')' ].join( '' )); + } +}); + + +//============================================================================== +var ListPairedDatasetCollection = DatasetCollection.extend( +/** @lends ListDatasetCollection.prototype */{ + + // list:paired is the only collection that itself contains collections + //collectionClass : DatasetCollectionCollection, + + /** String representation. */ + toString : function(){ + return ([ 'ListPairedDatasetCollection(', this.get( 'name' ), ')' ].join( '' )); + } +}); + + +//============================================================================== + return { + DatasetCollectionElement : DatasetCollectionElement, + DatasetCollectionElementCollection : DatasetCollectionElementCollection, + DatasetCollection : DatasetCollection, + DatasetCollectionCollection : DatasetCollectionCollection, + ListDatasetCollection : ListDatasetCollection, + PairDatasetCollection : PairDatasetCollection, + ListPairedDatasetCollection : ListPairedDatasetCollection + }; +}); diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 static/scripts/mvc/collection/collection-panel.js --- /dev/null +++ b/static/scripts/mvc/collection/collection-panel.js @@ -0,0 +1,326 @@ +define([ + "mvc/collection/dataset-collection-base", + "mvc/dataset/hda-base", + "mvc/base-mvc", + "utils/localization" +], function( DC_BASE, HDA_BASE, BASE_MVC, _l ){ +/* ============================================================================= +TODO: + +============================================================================= */ +/** @class non-editable, read-only View/Controller for a dataset collection. + * @name CollectionPanel + * + * @augments Backbone.View + * @borrows LoggableMixin#logger as #logger + * @borrows LoggableMixin#log as #log + * @constructs + */ +var CollectionPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend( +/** @lends CollectionPanel.prototype */{ + + /** logger used to record this.log messages, commonly set to console */ + // comment this out to suppress log output + //logger : console, + + tagName : 'div', + className : 'history-panel', + + /** (in ms) that jquery effects will use */ + fxSpeed : 'fast', + + // ......................................................................... SET UP + /** Set up the view, set up storage, bind listeners to HistoryContents events + * @param {Object} attributes optional settings for the panel + */ + initialize : function( attributes ){ + attributes = attributes || {}; + // set the logger if requested + if( attributes.logger ){ + this.logger = attributes.logger; + } + this.log( this + '.initialize:', attributes ); + + this.hasUser = attributes.hasUser; + this.HDAViewClass = attributes.HDAViewClass || HDA_BASE.HDABaseView; + }, + + /** 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(){ + // debugging + //if( this.logger ){ + this.on( 'all', function( event ){ + this.log( this + '', arguments ); + }, this ); + //} + return this; + }, + + // ------------------------------------------------------------------------ history/hda event listening + /** listening for history and HDA events */ + _setUpModelEventHandlers : function(){ + return 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 ){ + this.log( 'render:', speed, callback ); + // send a speed of 0 to have no fade in/out performed + speed = ( speed === undefined )?( this.fxSpeed ):( speed ); + //console.debug( this + '.render, fxSpeed:', speed ); + var panel = this, + $newRender; + + // handle the possibility of no model (can occur if fetching the model returns an error) + if( !this.model ){ + return this; + } + $newRender = this.renderModel(); + + // fade out existing, swap with the new, fade in, set up behaviours + $( panel ).queue( 'fx', [ + function( 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() ); + } + 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 history data + * @returns {jQuery} dom fragment as temporary container to be swapped out later + */ + renderModel : function( ){ + // tmp div for final swap in render + var $newRender = $( '<div/>' ).append( CollectionPanel.templates.panel( this.model.toJSON() ) ); + this._setUpBehaviours( $newRender ); + this.renderContents( $newRender ); + return $newRender; + }, + + /** Set up HistoryPanel js/widget behaviours */ + _setUpBehaviours : function( $where ){ + //TODO: these should be either sub-MVs, or handled by events + $where = $where || this.$el; + $where.find( '[title]' ).tooltip({ placement: 'bottom' }); + return this; + }, + + // ------------------------------------------------------------------------ sub-$element shortcuts + /** the scroll container for this panel - can be $el, $el.parent(), or grandparent depending on context */ + $container : function(){ + return ( this.findContainerFn )?( this.findContainerFn.call( this ) ):( this.$el.parent() ); + }, + /** where hdaViews are attached */ + $datasetsList : function( $where ){ + return ( $where || this.$el ).find( '.datasets-list' ); + }, + + // ------------------------------------------------------------------------ sub-views + /** 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 + */ + renderContents : function( $whereTo ){ + //console.debug( 'renderContents, elements:', this.model.elements ); + $whereTo = $whereTo || this.$el; + + var panel = this, + contentViews = {}, + visibleContents = this.model.elements || []; + //this.log( 'renderContents, visibleContents:', visibleContents, $whereTo ); + + this.$datasetsList( $whereTo ).empty(); + if( visibleContents && visibleContents.length ){ + visibleContents.each( function( content ){ + var contentId = content.id, + contentView = panel._createContentView( content ); + contentViews[ contentId ] = contentView; + panel.attachContentView( contentView.render(), $whereTo ); + }); + } + this.contentViews = contentViews; + return this.contentViews; + }, + + /** + * @param {HistoryDatasetAssociation} content + */ + _createContentView : function( content ){ + //console.debug( 'content json:', JSON.stringify( content, null, ' ' ) ); + var contentView = null, + ContentClass = this._getContentClass( content ); + //console.debug( 'content.object json:', JSON.stringify( content.object, null, ' ' ) ); + //console.debug( 'ContentClass:', ContentClass ); + //console.debug( 'content:', content ); + //console.debug( 'content.object:', content.object ); + contentView = new ContentClass({ + model : content.object, + linkTarget : this.linkTarget, + //draggable : true, + hasUser : this.hasUser, + logger : this.logger + }); + //this._setUpHdaListeners( contentView ); + return contentView; + }, + + _getContentClass : function( content ){ + switch( content.get( 'element_type' ) ){ + case 'hda': + return this.HDAViewClass; + case 'dataset_collection': + return DC_BASE.NestedDCEBaseView; + } + throw new TypeError( 'Unknown element type:', content.get( 'element_type' ) ); + }, + +// /** Set up HistoryPanel listeners for HDAView events. Currently binds: +// * HDAView#body-visible, HDAView#body-hidden to store expanded states +// * @param {HDAView} hdaView HDAView (base or edit) to listen to +// */ +// _setUpHdaListeners : function( hdaView ){ +// var panel = this; +// hdaView.on( 'error', function( model, xhr, options, msg ){ +// panel.errorHandler( model, xhr, options, msg ); +// }); +// // maintain a list of hdas whose bodies are expanded +// hdaView.on( 'body-expanded', function( model ){ +// panel.storage.addExpandedHda( model ); +// }); +// hdaView.on( 'body-collapsed', function( id ){ +// panel.storage.removeExpandedHda( id ); +// }); +// return this; +// }, + + /** attach an contentView to the panel */ + attachContentView : function( contentView, $whereTo ){ + $whereTo = $whereTo || this.$el; + var $datasetsList = this.$datasetsList( $whereTo ); + $datasetsList.append( contentView.$el ); + return this; + }, + + // ------------------------------------------------------------------------ panel events + /** event map */ + events : { + 'click .panel-navigation-back' : 'close' + }, + + /** */ + close : function( event ){ + this.$el.remove(); + this.trigger( 'collection-close' ); + }, + + // ........................................................................ misc + /** Return a string rep of the history */ + toString : function(){ + return 'CollectionPanel(' + (( this.model )?( this.model.get( 'name' )):( '' )) + ')'; + } +}); + + +//------------------------------------------------------------------------------ TEMPLATES +var _panelTemplate = [ + '<div class="history-controls">', + '<div class="panel-navigation">', + '<a class="panel-navigation-back" href="javascript:void(0)">', _l( 'Back' ), '</a>', + '</div>', + + '<div class="history-title">', + '<% if( collection.name ){ %>', + '<div class="history-name"><%= collection.hid %> : <%= collection.name %></div>', + '<% } %>', + '</div>', + + //'<div class="history-subtitle clear">', + // '<% if( history.nice_size ){ %>', + // '<div class="history-size"><%= history.nice_size %></div>', + // '<% } %>', + // '<div class="history-secondary-actions"></div>', + //'</div>', + // + //'<% if( history.deleted ){ %>', + // '<div class="warningmessagesmall"><strong>', + // _l( 'You are currently viewing a deleted history!' ), + // '</strong></div>', + //'<% } %>', + // + //'<div class="message-container">', + // '<% if( history.message ){ %>', + // // should already be localized + // '<div class="<%= history.status %>message"><%= history.message %></div>', + // '<% } %>', + //'</div>', + // + //'<div class="quota-message errormessage">', + // _l( 'You are over your disk quota' ), '. ', + // _l( 'Tool execution is on hold until your disk usage drops below your allocated quota' ), '.', + //'</div>', + // + //'<div class="tags-display"></div>', + //'<div class="annotation-display"></div>', + //'<div class="history-dataset-actions">', + // '<div class="btn-group">', + // '<button class="history-select-all-datasets-btn btn btn-default"', + // 'data-mode="select">', _l( 'All' ), '</button>', + // '<button class="history-deselect-all-datasets-btn btn btn-default"', + // 'data-mode="select">', _l( 'None' ), '</button>', + // '</div>', + // '<button class="history-dataset-action-popup-btn btn btn-default">', + // _l( 'For all selected' ), '...</button>', + //'</div>', + '</div>', + // end history controls + + // where the datasets/hdas are added + '<div class="datasets-list"></div>' + +].join( '' ); + +CollectionPanel.templates = { + panel : function( JSON ){ + return _.template( _panelTemplate, JSON, { variable: 'collection' }); + } +}; + + +//============================================================================== + return { + CollectionPanel: CollectionPanel + }; +}); diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 static/scripts/mvc/collection/dataset-collection-base.js --- a/static/scripts/mvc/collection/dataset-collection-base.js +++ b/static/scripts/mvc/collection/dataset-collection-base.js @@ -1,328 +1,151 @@ define([ - "mvc/history/history-content-base-view", + "mvc/base-mvc", "utils/localization" -], function( historyContentBaseView, _l ){ +], function( BASE_MVC, _l ){ /* global Backbone, LoggableMixin */ //============================================================================== -/** @class Read only view for HistoryDatasetCollectionAssociation. - * @name HDABaseView +/** @class Read only view for DatasetCollection. + * @name DCBaseView * * @augments Backbone.View * @borrows LoggableMixin#logger as #logger * @borrows LoggableMixin#log as #log * @constructs */ -var DatasetCollectionBaseView = historyContentBaseView.HistoryContentBaseView.extend({ - className : "dataset hda history-panel-hda", - id : function(){ return 'hdca-' + this.model.get( 'id' ); }, +var DCBaseView = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({ + + /** logger used to record this.log messages, commonly set to console */ + // comment this out to suppress log output + //logger : console, + + /** */ + className : "dataset-collection", + /** */ + fxSpeed : 'fast', /** */ initialize : function( attributes ){ if( attributes.logger ){ this.logger = this.model.logger = attributes.logger; } - this.log( this + '.initialize:', attributes ); - /** is the view currently in selection mode? */ - this.selectable = attributes.selectable || false; - //this.log( '\t selectable:', this.selectable ); - /** is the view currently selected? */ - this.selected = attributes.selected || false; - /** is the body of this collection view expanded/not? */ - this.expanded = attributes.expanded || false; + this.log( 'DCBaseView.initialize:', attributes ); }, - /** */ - render : function( fade ){ - var $newRender = this._buildNewRender(); - - this._queueNewRender( $newRender, fade ); - return this; - }, - - /** */ - _buildNewRender : function(){ - var $newRender = $( DatasetCollectionBaseView.templates.skeleton( this.model.toJSON() ) ); - $newRender.find( '.dataset-primary-actions' ).append( this._render_titleButtons() ); - $newRender.children( '.dataset-body' ).replaceWith( this._render_body() ); - this._setUpBehaviors( $newRender ); - return $newRender; - }, - - /** */ - _queueNewRender : function( $newRender, fade ) { - fade = ( fade === undefined )?( true ):( fade ); - var view = this; - - // fade the old render out (if desired) - if( fade ){ - $( view ).queue( function( next ){ this.$el.fadeOut( view.fxSpeed, next ); }); - } - // empty the old render, update to any new HDA state, swap in the new render contents, handle multi-select - $( view ).queue( function( next ){ - this.$el.empty() - .attr( 'class', view.className ).addClass( 'state-' + view.model.get( 'state' ) ) - .append( $newRender.children() ); - if( this.selectable ){ this.showSelector( 0 ); } - next(); - }); - // fade the new in - if( fade ){ - $( view ).queue( function( next ){ this.$el.fadeIn( view.fxSpeed, next ); }); - } - // trigger an event to know we're ready - $( view ).queue( function( next ){ - this.trigger( 'rendered', view ); - if( this.model.inReadyState() ){ - this.trigger( 'rendered:ready', view ); - } - if( this.draggable ){ this.draggableOn(); } - next(); - }); - }, - - // ................................................................................ titlebar buttons - /** Render icon-button group for the common, most easily accessed actions. - * @returns {jQuery} rendered DOM - */ - _render_titleButtons : function(){ - // render just the display for read-only - return [ ]; - }, - - // ......................................................................... state body renderers - /** Render the enclosing div of the collection body and, if expanded, the html in the body - * @returns {jQuery} rendered DOM - */ - _render_body : function(){ - var $body = $( '<div>Error: unknown state "' + this.model.get( 'state' ) + '".</div>' ), - // cheesy: get function by assumed matching name - renderFn = this[ '_render_body_' + this.model.get( 'state' ) ]; - if( _.isFunction( renderFn ) ){ - $body = renderFn.call( this ); - } - this._setUpBehaviors( $body ); - - // only render the body html if it's being shown - if( this.expanded ){ - $body.show(); - } - return $body; - }, - - /** set up js behaviors, event handlers for elements within the given container - * @param {jQuery} $container jq object that contains the elements to process (defaults to this.$el) - */ - _setUpBehaviors : function( $container ){ - $container = $container || this.$el; - // set up canned behavior on children (bootstrap, popupmenus, editable_text, etc.) - make_popup_menus( $container ); - $container.find( '[title]' ).tooltip({ placement : 'bottom' }); - }, - - // TODO: Eliminate duplication between following event map and one for HDAs. - - // ......................................................................... events - /** event map */ - events : { - // expand the body when the title is clicked or when in focus and space or enter is pressed - 'click .dataset-title-bar' : 'toggleBodyVisibility', - 'keydown .dataset-title-bar' : 'toggleBodyVisibility', - - // toggle selected state - 'click .dataset-selector' : 'toggleSelect' - }, - - /** Show or hide the body/details of history content. - * note: if the model does not have detailed data, fetch that data before showing the body - * @param {Event} event the event that triggered this (@link HDABaseView#events) - * @param {Boolean} expanded if true, expand; if false, collapse - * @fires body-expanded when a body has been expanded - * @fires body-collapsed when a body has been collapsed - */ - toggleBodyVisibility : function( event, expand ){ - // bail (with propagation) if keydown and not space or enter - var KEYCODE_SPACE = 32, KEYCODE_RETURN = 13; - if( event && ( event.type === 'keydown' ) - && !( event.keyCode === KEYCODE_SPACE || event.keyCode === KEYCODE_RETURN ) ){ - return true; - } - - var $body = this.$el.find( '.dataset-body' ); - expand = ( expand === undefined )?( !$body.is( ':visible' ) ):( expand ); - if( expand ){ - this.expandBody(); - } else { - this.collapseBody(); - } - return false; - }, - - /** Render and show the full, detailed body of this view including extra data and controls. - * @fires body-expanded when a body has been expanded - */ - expandBody : function(){ - var contentView = this; - - function _renderBodyAndExpand(){ - contentView.$el.children( '.dataset-body' ).replaceWith( contentView._render_body() ); - contentView.$el.children( '.dataset-body' ).slideDown( contentView.fxSpeed, function(){ - contentView.expanded = true; - contentView.trigger( 'body-expanded', contentView.model ); - }); - } - // TODO: Fetch more details like HDA view... - _renderBodyAndExpand(); - }, - - /** Hide the body/details of an HDA. - * @fires body-collapsed when a body has been collapsed - */ - collapseBody : function(){ - var hdaView = this; - this.$el.children( '.dataset-body' ).slideUp( hdaView.fxSpeed, function(){ - hdaView.expanded = false; - hdaView.trigger( 'body-collapsed', hdaView.model.id ); - }); - }, - - /** Render an 'ok' collection. - * @param {jQuery} parent DOM to which to append this body - */ - _render_body_ok : function(){ - // most common state renderer and the most complicated - var $body = $( DatasetCollectionBaseView.templates.body( this.model.toJSON() ) ); - - // return shortened form if del'd (no display apps or peek?) - if( this.model.get( 'deleted' ) ){ - return $body; - } - - return $body; - }, - - // ......................................................................... selection - /** display a (fa-icon) checkbox on the left of the hda that fires events when checked - * Note: this also hides the primary actions - */ - showSelector : function(){ - // make sure selected state is represented properly - if( this.selected ){ - this.select( null, true ); - } - - this.selectable = true; - this.trigger( 'selectable', true, this ); - - this.$( '.dataset-primary-actions' ).hide(); - this.$( '.dataset-selector' ).show(); - }, - - /** remove the selection checkbox */ - hideSelector : function(){ - // reverse the process from showSelect - this.selectable = false; - this.trigger( 'selectable', false, this ); - - this.$( '.dataset-selector' ).hide(); - this.$( '.dataset-primary-actions' ).show(); - }, - - toggleSelector : function(){ - if( !this.$el.find( '.dataset-selector' ).is( ':visible' ) ){ - this.showSelector(); - } else { - this.hideSelector(); - } - }, - - /** event handler for selection (also programmatic selection) - */ - select : function( event ){ - // switch icon, set selected, and trigger event - this.$el.find( '.dataset-selector span' ) - .removeClass( 'fa-square-o' ).addClass( 'fa-check-square-o' ); - if( !this.selected ){ - this.trigger( 'selected', this, event ); - this.selected = true; - } - return false; - }, - - /** event handler for clearing selection (also programmatic deselection) - */ - deselect : function( event ){ - // switch icon, set selected, and trigger event - this.$el.find( '.dataset-selector span' ) - .removeClass( 'fa-check-square-o' ).addClass( 'fa-square-o' ); - if( this.selected ){ - this.trigger( 'de-selected', this, event ); - this.selected = false; - } - return false; - }, - - toggleSelect : function( event ){ - if( this.selected ){ - this.deselect( event ); - } else { - this.select( event ); - } - }, +//TODO: render has been removed from the inheritance chain here, so this won't work when called as is // ......................................................................... misc /** String representation */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'HDCABaseView(' + modelString + ')'; + return 'DCBaseView(' + modelString + ')'; } }); -//------------------------------------------------------------------------------ TEMPLATES -//TODO: possibly break these out into a sep. module -var skeletonTemplate = _.template([ - '<div class="dataset hda">', - '<div class="dataset-warnings">', - '<% if ( collection.deleted ) { %>', - '<div class="dataset-deleted-msg warningmessagesmall"><strong>', - _l( 'This collection has been deleted.' ), +/** templates for DCBaseViews (skeleton and body) */ +DCBaseView.templates = (function(){ +// use closure to run underscore template fn only once at module load + var skeletonTemplate = _.template([ + '<div class="dataset hda">', + '<div class="dataset-warnings">', + '<% if ( collection.deleted ) { %>', + '<div class="dataset-deleted-msg warningmessagesmall"><strong>', + _l( 'This collection has been deleted.' ), + '</div>', + '<% } %>', + '<% if ( !collection.visible ) { %>', + '<div class="dataset-hidden-msg warningmessagesmall"><strong>', + _l( 'This collection has been hidden.' ), + '</div>', + '<% } %>', + '</div>', + '<div class="dataset-primary-actions"></div>', + '<div class="dataset-title-bar clear" tabindex="0">', + '<span class="dataset-state-icon state-icon"></span>', + '<div class="dataset-title">', + '<span class="dataset-name"><%- collection.name %></span>', '</div>', - '<% } %>', - '<% if ( !collection.visible ) { %>', - '<div class="dataset-hidden-msg warningmessagesmall"><strong>', - _l( 'This collection has been hidden.' ), - '</div>', - '<% } %>', - '</div>', - '<div class="dataset-selector"><span class="fa fa-2x fa-square-o"></span></div>', - '<div class="dataset-primary-actions"></div>', - '<div class="dataset-title-bar clear" tabindex="0">', - '<span class="dataset-state-icon state-icon"></span>', - '<div class="dataset-title">', - '<span class="hda-hid"><%= collection.hid %></span> ', - '<span class="dataset-name"><%= collection.name %></span>', '</div>', - '</div>', - '<div class="dataset-body"></div>', - '</div>' -].join( '' )); + '<div class="dataset-body"></div>', + '</div>' + ].join( '' )); -var bodyTemplate = _.template([ - '<div class="dataset-body">', - '<div class="dataset-summary">', - _l( 'A dataset collection.' ), - '</div>' -].join( '' )); + var bodyTemplate = _.template([ + '<div class="dataset-body">', + '<div class="dataset-summary">', + _l( 'A dataset collection.' ), + '</div>' + ].join( '' )); -DatasetCollectionBaseView.templates = { // we override here in order to pass the localizer (_L) into the template scope - since we use it as a fn within - skeleton : function( collectionJSON ){ - return skeletonTemplate({ _l: _l, collection: collectionJSON }); - }, - body : function( collectionJSON ){ - return bodyTemplate({ _l: _l, collection: collectionJSON }); - } -}; + return { + skeleton : function( collectionJSON ){ + return skeletonTemplate({ _l: _l, collection: collectionJSON }); + }, + body : function( collectionJSON ){ + return bodyTemplate({ _l: _l, collection: collectionJSON }); + } + }; +}()); + + +//TODO: unused +////============================================================================== +///** @class Read only view for DatasetCollectionElement. +// * @name DCEBaseView +// * +// * @augments Backbone.View +// * @borrows LoggableMixin#logger as #logger +// * @borrows LoggableMixin#log as #log +// * @constructs +// */ +//var NestedDCBaseView = DCBaseView.extend({ +// +// logger : console, +// +// /** */ +// initialize : function( attributes ){ +// if( attributes.logger ){ this.logger = this.model.logger = attributes.logger; } +// this.warn( this + '.initialize:', attributes ); +// DCBaseView.prototype.initialize.call( this, attributes ); +// }, +// +// _template : function(){ +// this.debug( this.model ); +// this.debug( this.model.toJSON() ); +// return NestedDCBaseView.templates.skeleton( this.model.toJSON() ); +// }, +// +// // ......................................................................... misc +// /** String representation */ +// toString : function(){ +// var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); +// return 'NestedDCBaseView(' + modelString + ')'; +// } +//}); +// +////------------------------------------------------------------------------------ TEMPLATES +////TODO: possibly break these out into a sep. module +//NestedDCBaseView.templates = (function(){ +// var skeleton = _.template([ +// '<div class="dataset hda history-panel-hda state-ok">', +// '<div class="dataset-primary-actions"></div>', +// '<div class="dataset-title-bar clear" tabindex="0">', +// '<div class="dataset-title">', +// '<span class="dataset-name"><%= collection.name %></span>', +// '</div>', +// '</div>', +// '</div>' +// ].join( '' )); +// // we override here in order to pass the localizer (_L) into the template scope - since we use it as a fn within +// return { +// skeleton : function( json ){ +// return skeleton({ _l: _l, collection: json }); +// } +// }; +//}()); + //============================================================================== return { - DatasetCollectionBaseView : DatasetCollectionBaseView + DCBaseView : DCBaseView, + //NestedDCBaseView : NestedDCBaseView, }; }); diff -r 4974ffd8b2cb5ee994a0d517c2332261898d4d46 -r 7aade8875ea4dde276b33922bbc7fdbc0630a9f5 static/scripts/mvc/collection/dataset-collection-edit.js --- a/static/scripts/mvc/collection/dataset-collection-edit.js +++ b/static/scripts/mvc/collection/dataset-collection-edit.js @@ -1,75 +1,36 @@ define([ - "mvc/dataset/hda-model", + "mvc/dataset/states", "mvc/collection/dataset-collection-base", "utils/localization" -], function( hdaModel, datasetCollectionBase, _l ){ +], function( STATES, DC_BASE_VIEW, _l ){ //============================================================================== -/** @class Editing view for HistoryDatasetCollectionAssociation. +var _super = DC_BASE_VIEW.DCBaseView; +/** @class Editing view for DatasetCollection. * @name DatasetCollectionEditView * - * @augments DatasetCollectionBaseView + * @augments DCBaseView * @constructs */ -var DatasetCollectionEditView = datasetCollectionBase.DatasetCollectionBaseView.extend( { +var DCEditView = _super.extend({ + + /** logger used to record this.log messages, commonly set to console */ + // comment this out to suppress log output + //logger : console, initialize : function( attributes ){ - datasetCollectionBase.DatasetCollectionBaseView.prototype.initialize.call( this, attributes ); - }, - - // ......................................................................... edit attr, delete - /** Render icon-button group for the common, most easily accessed actions. - * Overrides _render_titleButtons to include editing related buttons. - * @see DatasetCollectionBaseView#_render_titleButtons - * @returns {jQuery} rendered DOM - */ - _render_titleButtons : function(){ - // render the display, edit attr and delete icon-buttons - return datasetCollectionBase.DatasetCollectionBaseView.prototype._render_titleButtons.call( this ).concat([ - this._render_deleteButton() - ]); - }, - - /** Render icon-button to delete this hda. - * @returns {jQuery} rendered DOM - */ - _render_deleteButton : function(){ - // don't show delete if... - if( ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NEW ) - || ( this.model.get( 'state' ) === hdaModel.HistoryDatasetAssociation.STATES.NOT_VIEWABLE ) - || ( !this.model.get( 'accessible' ) ) ){ - return null; - } - - var self = this, - deleteBtnData = { - title : _l( 'Delete' ), - classes : 'dataset-delete', - onclick : function() { - // ...bler... tooltips being left behind in DOM (hover out never called on deletion) - self.$el.find( '.icon-btn.dataset-delete' ).trigger( 'mouseout' ); - self.model[ 'delete' ](); - } - }; - if( this.model.get( 'deleted' ) ){ - deleteBtnData = { - title : _l( 'Dataset collection is already deleted' ), - disabled : true - }; - } - deleteBtnData.faIcon = 'fa-times'; - return faIconButton( deleteBtnData ); + _super.prototype.initialize.call( this, attributes ); }, // ......................................................................... misc /** string rep */ toString : function(){ var modelString = ( this.model )?( this.model + '' ):( '(no model)' ); - return 'HDCAEditView(' + modelString + ')'; + return 'DCEditView(' + modelString + ')'; } }); //============================================================================== return { - DatasetCollectionEditView : DatasetCollectionEditView + DCEditView : DCEditView }; }); This diff is so big that we needed to truncate the remainder. 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.
participants (1)
-
commits-noreply@bitbucket.org