commit/galaxy-central: 7 new changesets
7 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/ed215c6af5a0/ Changeset: ed215c6af5a0 User: davebgx Date: 2014-08-27 20:55:43 Summary: Add feature to download a tarball containing tool XML, tool wrapper script, test inputs and outputs, and tool data table definitions + sample .loc file. Affected #: 5 files diff -r a66a80701913bb99e8abd12235c1ca82dc508f57 -r ed215c6af5a08a0e09184555c000e8aaffa5b27b lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -12,6 +12,7 @@ import shutil import sys import string +import tarfile import tempfile import threading import traceback @@ -722,6 +723,78 @@ ToolClass = Tool return ToolClass( config_file, root, self.app, guid=guid, repository_id=repository_id, **kwds ) + def package_tool( self, trans, tool_id ): + """ + Create a tarball with the tool's xml, help images, and test data. + :param trans: the web transaction + :param tool_id: the tool ID from app.toolbox + :returns: tuple of tarball filename, success True/False, message/None + """ + message = '' + success = True + # Make sure the tool is actually loaded. + if tool_id not in self.tools_by_id: + return None, False, "No tool with id %s" % tool_id + else: + tool = self.tools_by_id[ tool_id ] + tarball_files = [] + tool_tup = ( os.path.abspath( tool.config_file ), os.path.split( tool.config_file )[-1] ) + tarball_files.append( tool_tup ) + tool_command = tool.command.split( ' ' )[0] + tool_path = os.path.dirname( tool_tup[0] ) + # Add the tool XML to the tuple that will be used to populate the tarball. + if os.path.exists( os.path.join( tool_path, tool_command ) ): + tarball_files.append( ( os.path.join( tool_path, tool_command ), tool_command ) ) + tests = tool.tests + # Find tests, and check them for test data. + if tests is not None: + for test in tests: + # Add input file tuples to the list. + for input in test.inputs: + for input_value in test.inputs[ input ]: + input_path = os.path.abspath( os.path.join( 'test-data', input_value ) ) + if os.path.exists( input_path ): + td_tup = ( input_path, os.path.join( 'test-data', input_value ) ) + tarball_files.append( td_tup ) + # And add output file tuples to the list. + for label, filename, _ in test.outputs: + output_filepath = os.path.abspath( os.path.join( 'test-data', filename ) ) + if os.path.exists( output_filepath ): + td_tup = ( output_filepath, os.path.join( 'test-data', filename ) ) + tarball_files.append( td_tup ) + for param in tool.input_params: + # Check for tool data table definitions. + if hasattr( param, 'options' ): + if hasattr( param.options, 'tool_data_table' ): + for fnam in param.options.tool_data_table.filenames: + if not param.options.tool_data_table.filenames[ fnam ][ 'from_shed_config' ]: + tar_file = param.options.tool_data_table.filenames[ fnam ][ 'filename' ] + '.sample' + sample_file = os.path.join( param.options.tool_data_table.filenames[ fnam ][ 'tool_data_path' ], + tar_file ) + # Use the .sample file, if one exists. If not, skip this data table. + if os.path.exists( sample_file ): + tarfile_path, tarfile_name = os.path.split( tar_file ) + tarfile_path = os.path.join( 'tool-data', tarfile_name ) + sample_name = tarfile_path + '.sample' + tarball_files.append( ( sample_file, tarfile_path ) ) + # Put the data table definition XML in a temporary file. + table_definition = '<?xml version="1.0" encoding="utf-8"?>\n<tables>\n %s</tables>' + table_definition = table_definition % param.options.tool_data_table.xml_string + fd, table_conf = tempfile.mkstemp() + os.close( fd ) + file( table_conf, 'w' ).write( table_definition ) + tarball_files.append( ( table_conf, os.path.join( 'tool-data', 'tool_data_table_conf.xml.sample' ) ) ) + # Create the tarball. + fd, tarball_archive = tempfile.mkstemp( suffix='.tgz' ) + os.close( fd ) + tarball = tarfile.open( name=tarball_archive, mode='w:gz' ) + # Add the files from the previously generated list. + for fspath, tarpath in tarball_files: + tarball.add( fspath, arcname=tarpath ) + tarball.close() + return tarball_archive, True, None + return None, False, "An unknown error occurred." + def reload_tool_by_id( self, tool_id ): """ Attempt to reload the tool identified by 'tool_id', if successful diff -r a66a80701913bb99e8abd12235c1ca82dc508f57 -r ed215c6af5a08a0e09184555c000e8aaffa5b27b lib/galaxy/tools/data/__init__.py --- a/lib/galaxy/tools/data/__init__.py +++ b/lib/galaxy/tools/data/__init__.py @@ -240,6 +240,7 @@ def __init__( self, config_element, tool_data_path, from_shed_config = False): super( TabularToolDataTable, self ).__init__( config_element, tool_data_path, from_shed_config) + self.config_element = config_element self.data = [] self.configure_and_load( config_element, tool_data_path, from_shed_config) @@ -513,6 +514,10 @@ else: replace = " " return map( lambda x: x.replace( separator, replace ), fields ) + + @property + def xml_string( self ): + return util.xml_to_string( self.config_element ) # Registry of tool data types by type_key tool_data_table_types = dict( [ ( cls.type_key, cls ) for cls in [ TabularToolDataTable ] ] ) diff -r a66a80701913bb99e8abd12235c1ca82dc508f57 -r ed215c6af5a08a0e09184555c000e8aaffa5b27b lib/galaxy/web/base/controllers/admin.py --- a/lib/galaxy/web/base/controllers/admin.py +++ b/lib/galaxy/web/base/controllers/admin.py @@ -1,4 +1,5 @@ import logging +import os from datetime import datetime, timedelta from galaxy import util, web from galaxy.model.orm import and_, func, or_ @@ -58,6 +59,34 @@ @web.expose @web.require_admin + def package_tool( self, trans, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + toolbox = self.app.toolbox + tool_id = None + if params.get( 'package_tool_button', False ): + tool_id = params.get('tool_id', None) + galaxy.queue_worker.send_control_task(trans, 'package_tool', noop_self=True, kwargs={'tool_id': tool_id} ) + tool_tarball, success, message = trans.app.toolbox.package_tool( trans, tool_id ) + if success: + trans.response.set_content_type( 'application/x-gzip' ) + download_file = open( tool_tarball ) + os.unlink( tool_tarball ) + tarball_path, filename = os.path.split( tool_tarball ) + trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s.tgz"' % ( tool_id ) + os.removedirs( tarball_path ) + return download_file + else: + status = 'error' + return trans.fill_template( '/admin/package_tool.mako', + tool_id=tool_id, + toolbox=toolbox, + message=message, + status=status ) + + @web.expose + @web.require_admin def reload_tool( self, trans, **kwd ): params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) diff -r a66a80701913bb99e8abd12235c1ca82dc508f57 -r ed215c6af5a08a0e09184555c000e8aaffa5b27b templates/admin/package_tool.mako --- /dev/null +++ b/templates/admin/package_tool.mako @@ -0,0 +1,53 @@ +<%inherit file="/base.mako"/> +<%namespace file="/message.mako" import="render_msg" /> +<% from galaxy.tools import Tool, ToolSection %> + +<script type="text/javascript"> +$().ready(function() { +%if tool_id: + var focus_el = $("input[name=package_tool_button]"); +%else: + var focus_el = $("select[name=tool_id]"); +%endif + focus_el.focus(); +}); +</script> + +%if message: + ${render_msg( message, status )} +%endif + +<div class="toolForm"> + <div class="toolFormTitle">Download Tarball For ToolShed</div> + <div class="toolFormBody"> + <form name="package_tool" id="package_tool" action="${h.url_for( controller='admin', action='package_tool' )}" method="post" > + <div class="form-row"> + <label> + Tool to bundle: + </label> + <select name="tool_id"> + %for key, val in toolbox.tool_panel.items(): + %if isinstance( val, Tool ): + <option value="${val.id}">${val.name}</option> + %elif isinstance( val, ToolSection ): + <optgroup label="${val.name}"> + <% section = val %> + %for section_key, section_val in section.elems.items(): + %if isinstance( section_val, Tool ): + <% selected_str = "" %> + %if section_val.id == tool_id: + <% selected_str = " selected=\"selected\"" %> + %endif + <option value="${section_val.id}"${selected_str}>${section_val.name}</option> + %endif + %endfor + %endif + %endfor + </select> + </div> + <div class="form-row"> + <input type="submit" name="package_tool_button" value="Download"/> + </div> + </form> + </div> +</div> diff -r a66a80701913bb99e8abd12235c1ca82dc508f57 -r ed215c6af5a08a0e09184555c000e8aaffa5b27b templates/webapps/galaxy/admin/index.mako --- a/templates/webapps/galaxy/admin/index.mako +++ b/templates/webapps/galaxy/admin/index.mako @@ -79,6 +79,7 @@ <div class="toolTitle"><a href="${h.url_for( controller='admin', action='view_datatypes_registry' )}" target="galaxy_main">View data types registry</a></div><div class="toolTitle"><a href="${h.url_for( controller='admin', action='view_tool_data_tables' )}" target="galaxy_main">View data tables registry</a></div><div class="toolTitle"><a href="${h.url_for( controller='admin', action='tool_versions' )}" target="galaxy_main">View tool lineage</a></div> + <div class="toolTitle"><a href="${h.url_for( controller='admin', action='package_tool' )}" target="galaxy_main">Download tool tarball</a></div><div class="toolTitle"><a href="${h.url_for( controller='admin', action='reload_tool' )}" target="galaxy_main">Reload a tool's configuration</a></div><div class="toolTitle"><a href="${h.url_for( controller='admin', action='memdump' )}" target="galaxy_main">Profile memory usage</a></div><div class="toolTitle"><a href="${h.url_for( controller='admin', action='jobs' )}" target="galaxy_main">Manage jobs</a></div> https://bitbucket.org/galaxy/galaxy-central/commits/a765d16b04f1/ Changeset: a765d16b04f1 User: davebgx Date: 2014-08-28 18:39:12 Summary: Merge tip. Affected #: 24 files diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 .hgtags --- a/.hgtags +++ b/.hgtags @@ -18,4 +18,4 @@ 81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04 2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10 ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11 -7e22f35798522100ff03e1fdd4eced962b292360 latest_2014.08.11 +109b170188e97fbfc2c998ec174aff9546dd1bd8 latest_2014.08.11 diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 config/plugins/visualizations/circster/config/circster.xml --- a/config/plugins/visualizations/circster/config/circster.xml +++ b/config/plugins/visualizations/circster/config/circster.xml @@ -4,13 +4,13 @@ <data_sources><data_source><model_class>HistoryDatasetAssociation</model_class> - <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test> + <test type="not_eq" test_attr="datatype.track_type">None</test><to_param param_attr="id">dataset_id</to_param><to_param assign="hda">hda_ldda</to_param></data_source><data_source><model_class>LibraryDatasetDatasetAssociation</model_class> - <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test> + <test type="not_eq" test_attr="datatype.track_type">None</test><to_param param_attr="id">dataset_id</to_param><to_param assign="ldda">hda_ldda</to_param></data_source> diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 config/plugins/visualizations/trackster/config/trackster.xml --- a/config/plugins/visualizations/trackster/config/trackster.xml +++ b/config/plugins/visualizations/trackster/config/trackster.xml @@ -5,14 +5,14 @@ <data_sources><data_source><model_class>HistoryDatasetAssociation</model_class> - <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test> + <test type="not_eq" test_attr="datatype.track_type">None</test><to_param param_attr="id">dataset_id</to_param><to_param assign="hda">hda_ldda</to_param><to_param param_attr="dbkey">dbkey</to_param></data_source><data_source><model_class>LibraryDatasetDatasetAssociation</model_class> - <test type="isinstance" test_attr="datatype" result_type="datatype">data.Data</test> + <test type="not_eq" test_attr="datatype.track_type">None</test><to_param param_attr="id">dataset_id</to_param><to_param assign="ldda">hda_ldda</to_param></data_source> diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 config/plugins/visualizations/visualization.dtd --- a/config/plugins/visualizations/visualization.dtd +++ b/config/plugins/visualizations/visualization.dtd @@ -33,7 +33,8 @@ Currently, all tests are OR'd and there is no logical grouping. Tests are run in order. (text): the text of this element is what the given target will be compared to (REQUIRED) type: what type of test to run (e.g. when the target is an HDA the test will often be of type 'isinstance' - and test whether the HDA's datatype isinstace of a class) + and test whether the HDA's datatype isinstace of a class). + See lib/galaxy/visualizations/registry.py, DataSourceParser.parse_tests for test type options. DEFAULT: string comparison. test_attr: what attribute of the target object should be used in the test. For instance, 'datatype' will attempt to get the HDA.datatype from a target HDA. If the given object doesn't have diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 lib/galaxy/dataset_collections/structure.py --- a/lib/galaxy/dataset_collections/structure.py +++ b/lib/galaxy/dataset_collections/structure.py @@ -35,9 +35,9 @@ return self._walk_collections( dict_map( lambda hdca: hdca.collection, hdca_dict ) ) def _walk_collections( self, collection_dict ): - for ( identifier, substructure ) in self.children: + for index, ( identifier, substructure ) in enumerate( self.children ): def element( collection ): - return collection[ identifier ] + return collection[ index ] if substructure.is_leaf: yield dict_map( element, collection_dict ) diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 lib/galaxy/datatypes/binary.py --- a/lib/galaxy/datatypes/binary.py +++ b/lib/galaxy/datatypes/binary.py @@ -11,10 +11,7 @@ import struct import subprocess import tempfile -import zipfile -import sqlite3 -from urllib import urlencode, quote_plus from galaxy import eggs eggs.require( "bx-python" ) @@ -22,7 +19,6 @@ from galaxy.datatypes.metadata import MetadataElement,ListParameter,DictParameter from galaxy.datatypes import metadata -from galaxy.datatypes.sniff import * import dataproviders log = logging.getLogger(__name__) @@ -580,14 +576,12 @@ except Exception, exc: pass - # Connects and runs a query that should work on any real database - # If the file is not sqlite, an exception will be thrown and the sniffer will return false def sniff( self, filename ): + # The first 16 bytes of any SQLite3 database file is 'SQLite format 3\0', and the file is binary. For details + # about the format, see http://www.sqlite.org/fileformat.html try: - conn = sqlite3.connect(filename) - schema_version=conn.cursor().execute("pragma schema_version").fetchone() - conn.close() - if schema_version is not None: + header = open(filename).read(16) + if binascii.b2a_hex(header) == binascii.hexlify('SQLite format 3\0'): return True return False except: @@ -622,5 +616,5 @@ return dataproviders.dataset.SQliteDataProvider( dataset_source, **settings ) -Binary.register_sniffable_binary_format("sqlite","sqlite",SQlite) +Binary.register_sniffable_binary_format("sqlite", "sqlite", SQlite) diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 lib/galaxy/visualization/registry.py --- a/lib/galaxy/visualization/registry.py +++ b/lib/galaxy/visualization/registry.py @@ -203,6 +203,7 @@ #log.debug( '\t passed model_class' ) # tests are optional - default is the above class test +#TODO: not true: must have test currently tests = data_source[ 'tests' ] if tests and not self.is_object_applicable( trans, target_object, tests ): continue @@ -407,6 +408,7 @@ # allow manually turning off a vis by checking for a disabled property if 'disabled' in xml_tree.attrib: +#TODO: differentiate between disabled and failed to parse, log.warn only on failure, log.info otherwise return None # a text display name for end user links @@ -627,6 +629,13 @@ test_fn = lambda o, result: ( hasattr( getter( o ), 'has_dataprovider' ) and getter( o ).has_dataprovider( result ) ) + elif test_type == 'has_attribute': + # does the object itself have attr in 'result' (no equivalence checking) + test_fn = lambda o, result: hasattr( getter( o ), result ) + + elif test_type == 'not_eq': + test_fn = lambda o, result: str( getter( o ) ) != result + else: # default to simple (string) equilavance (coercing the test_attr to a string) test_fn = lambda o, result: str( getter( o ) ) == result diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 lib/galaxy/web/base/controller.py --- a/lib/galaxy/web/base/controller.py +++ b/lib/galaxy/web/base/controller.py @@ -27,7 +27,7 @@ from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea, TextField from galaxy.web.form_builder import build_select_field, HistoryField, PasswordField, WorkflowField, WorkflowMappingField from galaxy.workflow.modules import module_factory, WorkflowModuleInjector, MissingToolException -from galaxy.model.orm import eagerload, eagerload_all, desc +from galaxy.model.orm import eagerload, eagerload_all, desc, not_ from galaxy.security.validate_user_input import validate_publicname from galaxy.util.sanitize_html import sanitize_html from galaxy.model.item_attrs import Dictifiable, UsesAnnotations @@ -2683,7 +2683,7 @@ item = self.get_item( trans, id ) if item: # Only update slug if slug is not already in use. - if trans.sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug, importable=True ).count() == 0: + if trans.sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug ).count() == 0: item.slug = new_slug trans.sa_session.flush() @@ -2718,7 +2718,9 @@ # add integer to end. new_slug = slug_base count = 1 - while sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug, importable=True ).count() != 0: + # Ensure unique across model class and user and don't include this item + # in the check in case it has previously been assigned a valid slug. + while sa_session.query( item.__class__ ).filter( item.__class__.user == item.user, item.__class__.slug == new_slug, item.__class__.id != item.id).count() != 0: # Slug taken; choose a new slug based on count. This approach can # handle numerous items with the same name gracefully. new_slug = '%s-%i' % ( slug_base, count ) diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 lib/galaxy/webapps/galaxy/api/libraries.py --- a/lib/galaxy/webapps/galaxy/api/libraries.py +++ b/lib/galaxy/webapps/galaxy/api/libraries.py @@ -342,6 +342,7 @@ raise exceptions.InternalServerError( 'Error loading from the database.' + str(e)) return role + @expose_api def set_permissions( self, trans, encoded_library_id, **kwd ): """ @@ -385,7 +386,11 @@ action = kwd.get( 'action', None ) if action is None: - raise exceptions.RequestParameterMissingException( 'The mandatory parameter "action" is missing.' ) + payload = kwd.get( 'payload', None ) + if payload is not None: + return self.set_permissions_old( trans, library, payload, **kwd ) + else: + raise exceptions.RequestParameterMissingException( 'The mandatory parameter "action" is missing.' ) elif action == 'remove_restrictions': trans.app.security_agent.make_library_public( library ) if not trans.app.security_agent.library_is_public( library ): @@ -397,7 +402,6 @@ invalid_access_roles_names = [] for role_id in new_access_roles_ids: role = self._load_role( trans, role_id ) - # Check whether role is in the set of allowed roles valid_roles, total_roles = trans.app.security_agent.get_valid_roles( trans, library, is_library_access=True ) if role in valid_roles: valid_access_roles.append( role ) @@ -411,7 +415,6 @@ invalid_add_roles_names = [] for role_id in new_add_roles_ids: role = self._load_role( trans, role_id ) - # Check whether role is in the set of allowed roles valid_roles, total_roles = trans.app.security_agent.get_valid_roles( trans, library ) if role in valid_roles: valid_add_roles.append( role ) @@ -425,7 +428,6 @@ invalid_manage_roles_names = [] for role_id in new_manage_roles_ids: role = self._load_role( trans, role_id ) - # Check whether role is in the set of allowed roles valid_roles, total_roles = trans.app.security_agent.get_valid_roles( trans, library ) if role in valid_roles: valid_manage_roles.append( role ) @@ -439,7 +441,6 @@ invalid_modify_roles_names = [] for role_id in new_modify_roles_ids: role = self._load_role( trans, role_id ) - # Check whether role is in the set of allowed roles valid_roles, total_roles = trans.app.security_agent.get_valid_roles( trans, library ) if role in valid_roles: valid_modify_roles.append( role ) @@ -454,6 +455,9 @@ permissions.update( { trans.app.security_agent.permitted_actions.LIBRARY_MODIFY : valid_modify_roles } ) trans.app.security_agent.set_all_library_permissions( trans, library, permissions ) + trans.sa_session.refresh( library ) + # Copy the permissions to the root folder + trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder ) else: raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.' 'Allowed values are: "remove_restrictions", set_permissions"' ) @@ -486,3 +490,25 @@ return dict( access_library_role_list=access_library_role_list, modify_library_role_list=modify_library_role_list, manage_library_role_list=manage_library_role_list, add_library_item_role_list=add_library_item_role_list ) + def set_permissions_old( self, trans, library, payload, **kwd ): + """ + *** old implementation for backward compatibility *** + + POST /api/libraries/{encoded_library_id}/permissions + Updates the library permissions. + """ + params = galaxy.util.Params( payload ) + permissions = {} + for k, v in trans.app.model.Library.permitted_actions.items(): + role_params = params.get( k + '_in', [] ) + in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in galaxy.util.listify( role_params ) ] + permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles + trans.app.security_agent.set_all_library_permissions( trans, library, permissions ) + trans.sa_session.refresh( library ) + # Copy the permissions to the root folder + trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder ) + message = "Permissions updated for library '%s'." % library.name + + item = library.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id , 'root_folder_id' : trans.security.encode_id } ) + return item + diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 lib/galaxy/webapps/galaxy/api/permissions.py --- a/lib/galaxy/webapps/galaxy/api/permissions.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -API operations on the permissions of a library. -""" -import logging, os, string, shutil, urllib, re, socket -from cgi import escape, FieldStorage -import galaxy.util -from galaxy import util, datatypes, jobs, web -from galaxy.web.base.controller import * -from galaxy.util.sanitize_html import sanitize_html -from galaxy.model.orm import * - -log = logging.getLogger( __name__ ) - - -class PermissionsController( BaseAPIController ): - - # Method not ideally named - @web.expose_api - def create( self, trans, library_id, payload, **kwd ): - """ - POST /api/libraries/{encoded_library_id}/permissions - Updates the library permissions. - """ - if not trans.user_is_admin(): - trans.response.status = 403 - return "You are not authorized to update library permissions." - - params = galaxy.util.Params( payload ) - try: - decoded_library_id = trans.security.decode_id( library_id ) - except TypeError: - trans.response.status = 400 - return "Malformed library id ( %s ) specified, unable to decode." % str( library_id ) - - try: - library = trans.sa_session.query( trans.app.model.Library ).get( decoded_library_id ) - except: - library = None - - permissions = {} - for k, v in trans.app.model.Library.permitted_actions.items(): - role_params = params.get( k + '_in', [] ) - in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( trans.security.decode_id( x ) ) for x in galaxy.util.listify( role_params ) ] - permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles - trans.app.security_agent.set_all_library_permissions( trans, library, permissions ) - trans.sa_session.refresh( library ) - # Copy the permissions to the root folder - trans.app.security_agent.copy_library_permissions( trans, library, library.root_folder ) - message = "Permissions updated for library '%s'." % library.name - - item = library.to_dict( view='element', value_mapper={ 'id' : trans.security.encode_id , 'root_folder_id' : trans.security.encode_id } ) - return item diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 static/scripts/mvc/collection/paired-collection-creator.js --- a/static/scripts/mvc/collection/paired-collection-creator.js +++ b/static/scripts/mvc/collection/paired-collection-creator.js @@ -27,11 +27,14 @@ className : 'dataset paired', initialize : function( attributes ){ + //console.debug( 'PairView.initialize:', attributes ); this.pair = attributes.pair || {}; }, render : function(){ - this.$el.attr( 'draggable', true ) + this.$el + .attr( 'draggable', true ) + .data( 'pair', this.pair ) .html( _.template([ '<span class="forward-dataset-name flex-column"><%= pair.forward.name %></span>', '<span class="pair-name-column flex-column">', @@ -40,7 +43,51 @@ '<span class="reverse-dataset-name flex-column"><%= pair.reverse.name %></span>' ].join(''), { pair: this.pair })) .addClass( 'flex-column-container' ); + +//TODO: would be good to get the unpair-btn into this view - but haven't found a way with css + return this; + }, + + events : { + 'dragstart' : '_dragstart', + 'dragend' : '_dragend', + 'dragover' : '_sendToParent', + 'drop' : '_sendToParent' + }, + + /** dragging pairs for re-ordering */ + _dragstart : function( ev ){ + //console.debug( this, '_dragstartPair', ev ); + ev.currentTarget.style.opacity = '0.4'; + if( ev.originalEvent ){ ev = ev.originalEvent; } + + ev.dataTransfer.effectAllowed = 'move'; + ev.dataTransfer.setData( 'text/plain', JSON.stringify( this.pair ) ); + + //ev.dataTransfer.setDragImage( null, 0, 0 ); + + // the canvas can be used to create the image + //ev.dataTransfer.setDragImage( canvasCrossHairs(), 25, 25 ); + + //console.debug( 'ev.dataTransfer:', ev.dataTransfer ); + this.$el.parent().trigger( 'pair.dragstart', [ this ] ); + }, + /** dragging pairs for re-ordering */ + _dragend : function( ev ){ + //console.debug( this, '_dragendPair', ev ); + ev.currentTarget.style.opacity = '1.0'; + this.$el.parent().trigger( 'pair.dragend', [ this ] ); + }, + + /** manually bubble up an event to the parent/container */ + _sendToParent : function( ev ){ + this.$el.parent().trigger( ev ); + }, + + /** string rep */ + toString : function(){ + return 'PairView(' + this.pair.name + ')'; } }); @@ -106,6 +153,9 @@ /** is the paired panel shown? */ this.pairedPanelHidden = false; + /** DOM elements currently being dragged */ + this.$dragging = null; + this._dataSetUp(); this._setUpBehaviors(); @@ -929,8 +979,17 @@ 'mousedown .flexible-partition-drag' : '_startPartitionDrag', // paired 'click .paired-columns .dataset.paired' : 'selectPair', + 'click .paired-columns' : 'clearSelectedPaired', 'click .paired-columns .pair-name' : '_clickPairName', 'click .unpair-btn' : '_clickUnpair', + // paired - drop target + //'dragenter .paired-columns' : '_dragenterPairedColumns', + //'dragleave .paired-columns .column-datasets': '_dragleavePairedColumns', + 'dragover .paired-columns .column-datasets' : '_dragoverPairedColumns', + 'drop .paired-columns .column-datasets' : '_dropPairedColumns', + + 'pair.dragstart .paired-columns .column-datasets' : '_pairDragstart', + 'pair.dragend .paired-columns .column-datasets' : '_pairDragend', // footer 'change .remove-extensions' : function( ev ){ this.toggleExtensions(); }, @@ -1226,9 +1285,15 @@ // ........................................................................ paired /** select a pair when clicked */ selectPair : function( ev ){ + ev.stopPropagation(); $( ev.currentTarget ).toggleClass( 'selected' ); }, + /** deselect all pairs */ + clearSelectedPaired : function( ev ){ + this.$( '.paired-columns .dataset.selected' ).removeClass( 'selected' ); + }, + /** rename a pair when the pair name is clicked */ _clickPairName : function( ev ){ ev.stopPropagation(); @@ -1255,6 +1320,94 @@ this._unpair( this.paired[ pairIndex ] ); }, + // ........................................................................ paired - drag and drop re-ordering + //_dragenterPairedColumns : function( ev ){ + // console.debug( '_dragenterPairedColumns:', ev ); + //}, + //_dragleavePairedColumns : function( ev ){ + // //console.debug( '_dragleavePairedColumns:', ev ); + //}, + /** track the mouse drag over the paired list adding a placeholder to show where the drop would occur */ + _dragoverPairedColumns : function( ev ){ + //console.debug( '_dragoverPairedColumns:', ev ); + ev.preventDefault(); + + var $list = this.$( '.paired-columns .column-datasets' ), + offset = $list.offset(); + //console.debug( ev.originalEvent.clientX, ev.originalEvent.clientY ); + var $nearest = this._getNearestPairedDatasetLi( ev.originalEvent.clientY ); + //console.debug( ev.originalEvent.clientX - offset.left, ev.originalEvent.clientY - offset.top ); + + $( '.paired-drop-placeholder' ).remove(); + var $placeholder = $( '<div class="paired-drop-placeholder"></div>') + if( !$nearest.size() ){ + $list.append( $placeholder ); + } else { + $nearest.before( $placeholder ); + } + }, + /** get the nearest *previous* paired dataset PairView based on the mouse's Y coordinate. + * If the y is at the end of the list, return an empty jQuery object. + */ + _getNearestPairedDatasetLi : function( y ){ + var WIGGLE = 4, + lis = this.$( '.paired-columns .column-datasets li' ).toArray(); +//TODO: better way? + for( var i=0; i<lis.length; i++ ){ + var $li = $( lis[i] ), + top = $li.offset().top, + halfHeight = Math.floor( $li.outerHeight() / 2 ) + WIGGLE; + if( top + halfHeight > y && top - halfHeight < y ){ + //console.debug( y, top + halfHeight, top - halfHeight ) + return $li; + } + } + return $(); + }, + /** drop (dragged/selected PairViews) onto the list, re-ordering both the DOM and the internal array of pairs */ + _dropPairedColumns : function( ev ){ + // both required for firefox + ev.preventDefault(); + ev.dataTransfer.dropEffect = 'move'; + + var $nearest = this._getNearestPairedDatasetLi( ev.originalEvent.clientY ); + if( $nearest.size() ){ + this.$dragging.insertBefore( $nearest ); + + } else { + // no nearest before - insert after last element (unpair button) + this.$dragging.insertAfter( this.$( '.paired-columns .unpair-btn' ).last() ); + } + // resync the creator's list of paired based on the new DOM order + this._syncPairsToDom(); + return false; + }, + /** resync the creator's list of paired based on the DOM order of pairs */ + _syncPairsToDom : function(){ + var newPaired = []; +//TODO: ugh + this.$( '.paired-columns .dataset.paired' ).each( function(){ + newPaired.push( $( this ).data( 'pair' ) ); + }); + //console.debug( newPaired ); + this.paired = newPaired; + this._renderPaired(); + }, + /** drag communication with pair sub-views: dragstart */ + _pairDragstart : function( ev, pair ){ + //console.debug( '_pairDragstart', ev, pair ) + // auto select the pair causing the event and move all selected + pair.$el.addClass( 'selected' ); + var $selected = this.$( '.paired-columns .dataset.selected' ); + this.$dragging = $selected; + }, + /** drag communication with pair sub-views: dragend - remove the placeholder */ + _pairDragend : function( ev, pair ){ + //console.debug( '_pairDragend', ev, pair ) + $( '.paired-drop-placeholder' ).remove(); + this.$dragging = null; + }, + // ........................................................................ footer toggleExtensions : function( force ){ var creator = this; diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 static/scripts/packed/mvc/collection/paired-collection-creator.js --- a/static/scripts/packed/mvc/collection/paired-collection-creator.js +++ b/static/scripts/packed/mvc/collection/paired-collection-creator.js @@ -1,1 +1,1 @@ -define(["utils/levenshtein","mvc/base-mvc","utils/localization"],function(g,a,d){var f=Backbone.View.extend(a.LoggableMixin).extend({tagName:"li",className:"dataset paired",initialize:function(h){this.pair=h.pair||{}},render:function(){this.$el.attr("draggable",true).html(_.template(['<span class="forward-dataset-name flex-column"><%= pair.forward.name %></span>','<span class="pair-name-column flex-column">','<span class="pair-name"><%= pair.name %></span>',"</span>",'<span class="reverse-dataset-name flex-column"><%= pair.reverse.name %></span>'].join(""),{pair:this.pair})).addClass("flex-column-container");return this}});var e=Backbone.View.extend(a.LoggableMixin).extend({className:"collection-creator flex-row-container",initialize:function(h){h=_.defaults(h,{datasets:[],filters:this.DEFAULT_FILTERS,automaticallyPair:true,matchPercentage:1,strategy:"lcs"});this.initialList=h.datasets;this.historyId=h.historyId;this.filters=this.commonFilters[h.filters]||this.commonFilters[this.DEFAULT_FILTERS];if(_.isArray(h.filters)){this.filters=h.filters}this.automaticallyPair=h.automaticallyPair;this.matchPercentage=h.matchPercentage;this.strategy=this.strategies[h.strategy]||this.strategies[this.DEFAULT_STRATEGY];if(_.isFunction(h.strategy)){this.strategy=h.strategy}this.removeExtensions=true;this.oncancel=h.oncancel;this.oncreate=h.oncreate;this.unpairedPanelHidden=false;this.pairedPanelHidden=false;this._dataSetUp();this._setUpBehaviors()},commonFilters:{none:["",""],illumina:["_1","_2"]},DEFAULT_FILTERS:"illumina",strategies:{lcs:"autoPairLCSs",levenshtein:"autoPairLevenshtein"},DEFAULT_STRATEGY:"lcs",_dataSetUp:function(){this.paired=[];this.unpaired=[];this.selectedIds=[];this._sortInitialList();this._ensureIds();this.unpaired=this.initialList.slice(0);if(this.automaticallyPair){this.autoPair()}},_sortInitialList:function(){this._sortDatasetList(this.initialList)},_sortDatasetList:function(h){h.sort(function(j,i){return naturalSort(j.name,i.name)});return h},_ensureIds:function(){this.initialList.forEach(function(h){if(!h.hasOwnProperty("id")){h.id=_.uniqueId()}});return this.initialList},_splitByFilters:function(j){var i=[],h=[];this.unpaired.forEach(function(k){if(this._filterFwdFn(k)){i.push(k)}if(this._filterRevFn(k)){h.push(k)}}.bind(this));return[i,h]},_filterFwdFn:function(i){var h=new RegExp(this.filters[0]);return h.test(i.name)},_filterRevFn:function(i){var h=new RegExp(this.filters[1]);return h.test(i.name)},_addToUnpaired:function(i){var h=function(j,l){if(j===l){return j}var k=Math.floor((l-j)/2)+j,m=naturalSort(i.name,this.unpaired[k].name);if(m<0){return h(j,k)}else{if(m>0){return h(k+1,l)}}while(this.unpaired[k]&&this.unpaired[k].name===i.name){k++}return k}.bind(this);this.unpaired.splice(h(0,this.unpaired.length),0,i)},autoPair:function(h){h=h||this.strategy;this.simpleAutoPair();return this[h].call(this)},simpleAutoPair:function(){var n=0,l,r=this._splitByFilters(),h=r[0],q=r[1],p,s,k=false;while(n<h.length){var m=h[n];p=m.name.replace(this.filters[0],"");k=false;for(l=0;l<q.length;l++){var o=q[l];s=o.name.replace(this.filters[1],"");if(m!==o&&p===s){k=true;this._pair(h.splice(n,1)[0],q.splice(l,1)[0],{silent:true});break}}if(!k){n+=1}}},autoPairLevenshtein:function(){var o=0,m,t=this._splitByFilters(),h=t[0],r=t[1],q,v,k,s,l;while(o<h.length){var n=h[o];q=n.name.replace(this.filters[0],"");l=Number.MAX_VALUE;for(m=0;m<r.length;m++){var p=r[m];v=p.name.replace(this.filters[1],"");if(n!==p){if(q===v){s=m;l=0;break}k=levenshteinDistance(q,v);if(k<l){s=m;l=k}}}var u=1-(l/(Math.max(q.length,v.length)));if(u>=this.matchPercentage){this._pair(h.splice(o,1)[0],r.splice(s,1)[0],{silent:true});if(h.length<=0||r.length<=0){return}}else{o+=1}}},autoPairLCSs:function(){var m=0,k,t=this._splitByFilters(),h=t[0],r=t[1],q,w,v,s,o;if(!h.length||!r.length){return}while(m<h.length){var l=h[m];q=l.name.replace(this.filters[0],"");o=0;for(k=0;k<r.length;k++){var p=r[k];w=p.name.replace(this.filters[1],"");if(l!==p){if(q===w){s=k;o=q.length;break}var n=this._naiveStartingAndEndingLCS(q,w);v=n.length;if(v>o){s=k;o=v}}}var u=o/(Math.min(q.length,w.length));if(u>=this.matchPercentage){this._pair(h.splice(m,1)[0],r.splice(s,1)[0],{silent:true});if(h.length<=0||r.length<=0){return}}else{m+=1}}},_naiveStartingAndEndingLCS:function(m,k){var n="",o="",l=0,h=0;while(l<m.length&&l<k.length){if(m[l]!==k[l]){break}n+=m[l];l+=1}if(l===m.length){return m}if(l===k.length){return k}l=(m.length-1);h=(k.length-1);while(l>=0&&h>=0){if(m[l]!==k[h]){break}o=[m[l],o].join("");l-=1;h-=1}return n+o},_pair:function(j,h,i){i=i||{};var k=this._createPair(j,h,i.name);this.paired.push(k);this.unpaired=_.without(this.unpaired,j,h);if(!i.silent){this.trigger("pair:new",k)}return k},_createPair:function(j,h,i){if(!(j&&h)||(j===h)){throw new Error("Bad pairing: "+[JSON.stringify(j),JSON.stringify(h)])}i=i||this._guessNameForPair(j,h);return{forward:j,name:i,reverse:h}},_guessNameForPair:function(j,h,k){k=(k!==undefined)?(k):(this.removeExtensions);var i=this._naiveStartingAndEndingLCS(j.name.replace(this.filters[0],""),h.name.replace(this.filters[1],""));if(k){var l=i.lastIndexOf(".");if(l>0){i=i.slice(0,l)}}return i||(j.name+" & "+h.name)},_unpair:function(i,h){h=h||{};if(!i){throw new Error("Bad pair: "+JSON.stringify(i))}this.paired=_.without(this.paired,i);this._addToUnpaired(i.forward);this._addToUnpaired(i.reverse);if(!h.silent){this.trigger("pair:unpair",[i])}return i},unpairAll:function(){var h=[];while(this.paired.length){h.push(this._unpair(this.paired[0],{silent:true}))}this.trigger("pair:unpair",h)},_pairToJSON:function(h){return{collection_type:"paired",src:"new_collection",name:h.name,element_identifiers:[{name:"forward",id:h.forward.id,src:"hda"},{name:"reverse",id:h.reverse.id,src:"hda"}]}},createList:function(){var j=this,i;if(j.historyId){i="/api/histories/"+this.historyId+"/contents/dataset_collections"}var h={type:"dataset_collection",collection_type:"list:paired",name:_.escape(j.$(".collection-name").val()),element_identifiers:j.paired.map(function(k){return j._pairToJSON(k)})};return jQuery.ajax(i,{type:"POST",contentType:"application/json",dataType:"json",data:JSON.stringify(h)}).fail(function(m,k,l){j._ajaxErrHandler(m,k,l)}).done(function(k,l,m){j.trigger("collection:created",k,l,m);if(typeof j.oncreate==="function"){j.oncreate.call(this,k,l,m)}})},_ajaxErrHandler:function(k,h,j){this.error(k,h,j);var i=d("An error occurred while creating this collection");if(k){if(k.readyState===0&&k.status===0){i+=": "+d("Galaxy could not be reached and may be updating.")+d(" Try again in a few minutes.")}else{if(k.responseJSON){i+="<br /><pre>"+JSON.stringify(k.responseJSON)+"</pre>"}else{i+=": "+j}}}creator._showAlert(i,"alert-danger")},render:function(h,i){this.$el.empty().html(e.templates.main());this._renderHeader(h);this._renderMiddle(h);this._renderFooter(h);this._addPluginComponents();return this},_renderHeader:function(i,j){var h=this.$(".header").empty().html(e.templates.header()).find(".help-content").prepend($(e.templates.helpContent()));this._renderFilters();return h},_renderFilters:function(){return this.$(".forward-column .column-header input").val(this.filters[0]).add(this.$(".reverse-column .column-header input").val(this.filters[1]))},_renderMiddle:function(i,j){var h=this.$(".middle").empty().html(e.templates.middle());if(this.unpairedPanelHidden){this.$(".unpaired-columns").hide()}else{if(this.pairedPanelHidden){this.$(".paired-columns").hide()}}this._renderUnpaired();this._renderPaired();return h},_renderUnpaired:function(m,n){var k=this,l,i,h=[],j=this._splitByFilters();this.$(".forward-column .title").text([j[0].length,d("unpaired forward")].join(" "));this.$(".forward-column .unpaired-info").text(this._renderUnpairedDisplayStr(this.unpaired.length-j[0].length));this.$(".reverse-column .title").text([j[1].length,d("unpaired reverse")].join(" "));this.$(".reverse-column .unpaired-info").text(this._renderUnpairedDisplayStr(this.unpaired.length-j[1].length));this.$(".unpaired-columns .column-datasets").empty();this.$(".autopair-link").toggle(this.unpaired.length!==0);if(this.unpaired.length===0){this._renderUnpairedEmpty();return}i=j[1].map(function(p,o){if((j[0][o]!==undefined)&&(j[0][o]!==p)){h.push(k._renderPairButton())}return k._renderUnpairedDataset(p)});l=j[0].map(function(o){return k._renderUnpairedDataset(o)});if(!l.length&&!i.length){this._renderUnpairedNotShown();return}this.$(".unpaired-columns .forward-column .column-datasets").append(l).add(this.$(".unpaired-columns .paired-column .column-datasets").append(h)).add(this.$(".unpaired-columns .reverse-column .column-datasets").append(i));this._adjUnpairedOnScrollbar()},_renderUnpairedDisplayStr:function(h){return["(",h," ",d("filtered out"),")"].join("")},_renderUnpairedDataset:function(h){return $("<li/>").attr("id","dataset-"+h.id).addClass("dataset unpaired").attr("draggable",true).addClass(h.selected?"selected":"").append($("<span/>").addClass("dataset-name").text(h.name)).data("dataset",h)},_renderPairButton:function(){return $("<li/>").addClass("dataset unpaired").append($("<span/>").addClass("dataset-name").text(d("Pair these datasets")))},_renderUnpairedEmpty:function(){var h=$('<div class="empty-message"></div>').text("("+d("no remaining unpaired datasets")+")");this.$(".unpaired-columns .paired-column .column-datasets").empty().prepend(h);return h},_renderUnpairedNotShown:function(){var h=$('<div class="empty-message"></div>').text("("+d("no datasets were found matching the current filters")+")");this.$(".unpaired-columns .paired-column .column-datasets").empty().prepend(h);return h},_adjUnpairedOnScrollbar:function(){var k=this.$(".unpaired-columns").last(),l=this.$(".unpaired-columns .reverse-column .dataset").first();if(!l.size()){return}var h=k.offset().left+k.outerWidth(),j=l.offset().left+l.outerWidth(),i=Math.floor(h)-Math.floor(j);this.$(".unpaired-columns .forward-column").css("margin-left",(i>0)?i:0)},_renderPaired:function(i,j){this.$(".paired-column-title .title").text([this.paired.length,d("paired")].join(" "));this.$(".unpair-all-link").toggle(this.paired.length!==0);if(this.paired.length===0){this._renderPairedEmpty();return}else{this.$(".remove-extensions-link").show()}this.$(".paired-columns .column-datasets").empty();var h=this;this.paired.forEach(function(m,k){var l=new f({pair:m});h.$(".paired-columns .column-datasets").append(l.render().$el).append(['<button class="unpair-btn">','<span class="fa fa-unlink" title="',d("Unpair"),'"></span>',"</button>"].join(""))})},_renderPairedEmpty:function(){var h=$('<div class="empty-message"></div>').text("("+d("no paired datasets yet")+")");this.$(".paired-columns .column-datasets").empty().prepend(h);return h},_renderFooter:function(i,j){var h=this.$(".footer").empty().html(e.templates.footer());this.$(".remove-extensions").prop("checked",this.removeExtensions);if(typeof this.oncancel==="function"){this.$(".cancel-create.btn").show()}return h},_addPluginComponents:function(){this._chooseFiltersPopover(".choose-filters-link");this.$(".help-content i").hoverhighlight(".collection-creator","rgba( 64, 255, 255, 1.0 )")},_chooseFiltersPopover:function(h){function i(l,k){return['<button class="filter-choice btn" ','data-forward="',l,'" data-reverse="',k,'">',d("Forward"),": ",l,", ",d("Reverse"),": ",k,"</button>"].join("")}var j=$(_.template(['<div class="choose-filters">','<div class="help">',d("Choose from the following filters to change which unpaired reads are shown in the display"),":</div>",i("_1","_2"),i("_R1","_R2"),"</div>"].join(""),{}));return this.$(h).popover({container:".collection-creator",placement:"bottom",html:true,content:j})},_validationWarning:function(i,h){var j="validation-warning";if(i==="name"){i=this.$(".collection-name").add(this.$(".collection-name-prompt"));this.$(".collection-name").focus().select()}if(h){i=i||this.$("."+j);i.removeClass(j)}else{i.addClass(j)}},_setUpBehaviors:function(){this.on("pair:new",function(){this._renderUnpaired();this._renderPaired();this.$(".paired-columns").scrollTop(8000000)});this.on("pair:unpair",function(h){this._renderUnpaired();this._renderPaired();this.splitView()});this.on("filter-change",function(){this.filters=[this.$(".forward-unpaired-filter input").val(),this.$(".reverse-unpaired-filter input").val()];this._renderFilters();this._renderUnpaired()});this.on("autopair",function(){this._renderUnpaired();this._renderPaired();var h,i=null;if(this.paired.length){i="alert-success";h=this.paired.length+" "+d("pairs created");if(!this.unpaired.length){h+=": "+d("all datasets have been successfully paired");this.hideUnpaired()}}else{h=d("Could not automatically create any pairs from the given dataset names")}this._showAlert(h,i)});return this},events:{"click .more-help":"_clickMoreHelp","click .less-help":"_clickLessHelp","click .header .alert button":"_hideAlert","click .forward-column .column-title":"_clickShowOnlyUnpaired","click .reverse-column .column-title":"_clickShowOnlyUnpaired","click .unpair-all-link":"_clickUnpairAll","change .forward-unpaired-filter input":function(h){this.trigger("filter-change")},"focus .forward-unpaired-filter input":function(h){$(h.currentTarget).select()},"click .autopair-link":"_clickAutopair","click .choose-filters .filter-choice":"_clickFilterChoice","click .clear-filters-link":"_clearFilters","change .reverse-unpaired-filter input":function(h){this.trigger("filter-change")},"focus .reverse-unpaired-filter input":function(h){$(h.currentTarget).select()},"click .forward-column .dataset.unpaired":"_clickUnpairedDataset","click .reverse-column .dataset.unpaired":"_clickUnpairedDataset","click .paired-column .dataset.unpaired":"_clickPairRow","click .unpaired-columns":"clearSelectedUnpaired","mousedown .unpaired-columns .dataset":"_mousedownUnpaired","click .paired-column-title":"_clickShowOnlyPaired","mousedown .flexible-partition-drag":"_startPartitionDrag","click .paired-columns .dataset.paired":"selectPair","click .paired-columns .pair-name":"_clickPairName","click .unpair-btn":"_clickUnpair","change .remove-extensions":function(h){this.toggleExtensions()},"change .collection-name":"_changeName","click .cancel-create":function(h){if(typeof this.oncancel==="function"){this.oncancel.call(this)}},"click .create-collection":"_clickCreate"},_clickMoreHelp:function(h){this.$(".main-help").addClass("expanded");this.$(".more-help").hide()},_clickLessHelp:function(h){this.$(".main-help").removeClass("expanded");this.$(".more-help").show()},_showAlert:function(i,h){h=h||"alert-danger";this.$(".main-help").hide();this.$(".header .alert").attr("class","alert alert-dismissable").addClass(h).show().find(".alert-message").html(i)},_hideAlert:function(h){this.$(".main-help").show();this.$(".header .alert").hide()},_clickShowOnlyUnpaired:function(h){if(this.$(".paired-columns").is(":visible")){this.hidePaired()}else{this.splitView()}},_clickShowOnlyPaired:function(h){if(this.$(".unpaired-columns").is(":visible")){this.hideUnpaired()}else{this.splitView()}},hideUnpaired:function(h,i){this.unpairedPanelHidden=true;this.pairedPanelHidden=false;this._renderMiddle(h,i)},hidePaired:function(h,i){this.unpairedPanelHidden=false;this.pairedPanelHidden=true;this._renderMiddle(h,i)},splitView:function(h,i){this.unpairedPanelHidden=this.pairedPanelHidden=false;this._renderMiddle(h,i);return this},_clickUnpairAll:function(h){this.unpairAll()},_clickAutopair:function(i){var h=this.autoPair();this.trigger("autopair",h)},_clickFilterChoice:function(i){var h=$(i.currentTarget);this.$(".forward-unpaired-filter input").val(h.data("forward"));this.$(".reverse-unpaired-filter input").val(h.data("reverse"));this._hideChooseFilters();this.trigger("filter-change")},_hideChooseFilters:function(){this.$(".choose-filters-link").popover("hide");this.$(".popover").css("display","none")},_clearFilters:function(h){this.$(".forward-unpaired-filter input").val("");this.$(".reverse-unpaired-filter input").val("");this.trigger("filter-change")},_clickUnpairedDataset:function(h){h.stopPropagation();return this.toggleSelectUnpaired($(h.currentTarget))},toggleSelectUnpaired:function(j,i){i=i||{};var k=j.data("dataset"),h=i.force!==undefined?i.force:!j.hasClass("selected");if(!j.size()||k===undefined){return j}if(h){j.addClass("selected");if(!i.waitToPair){this.pairAllSelected()}}else{j.removeClass("selected")}return j},pairAllSelected:function(i){i=i||{};var j=this,k=[],h=[],l=[];j.$(".unpaired-columns .forward-column .dataset.selected").each(function(){k.push($(this).data("dataset"))});j.$(".unpaired-columns .reverse-column .dataset.selected").each(function(){h.push($(this).data("dataset"))});k.length=h.length=Math.min(k.length,h.length);k.forEach(function(n,m){try{l.push(j._pair(n,h[m],{silent:true}))}catch(o){j.error(o)}});if(l.length&&!i.silent){this.trigger("pair:new",l)}return l},clearSelectedUnpaired:function(){this.$(".unpaired-columns .dataset.selected").removeClass("selected")},_mousedownUnpaired:function(j){if(j.shiftKey){var i=this,h=$(j.target).addClass("selected"),k=function(l){i.$(l.target).filter(".dataset").addClass("selected")};h.parent().on("mousemove",k);$(document).one("mouseup",function(l){h.parent().off("mousemove",k);i.pairAllSelected()})}},_clickPairRow:function(j){var k=$(j.currentTarget).index(),i=$(".unpaired-columns .forward-column .dataset").eq(k).data("dataset"),h=$(".unpaired-columns .reverse-column .dataset").eq(k).data("dataset");this._pair(i,h)},_startPartitionDrag:function(i){var h=this,l=i.pageY;$("body").css("cursor","ns-resize");h.$(".flexible-partition-drag").css("color","black");function k(m){h.$(".flexible-partition-drag").css("color","");$("body").css("cursor","").unbind("mousemove",j)}function j(m){var n=m.pageY-l;if(!h.adjPartition(n)){$("body").trigger("mouseup")}h._adjUnpairedOnScrollbar();l+=n}$("body").mousemove(j);$("body").one("mouseup",k)},adjPartition:function(i){var h=this.$(".unpaired-columns"),j=this.$(".paired-columns"),k=parseInt(h.css("height"),10),l=parseInt(j.css("height"),10);k=Math.max(10,k+i);l=l-i;var m=i<0;if(m){if(this.unpairedPanelHidden){return false}else{if(k<=10){this.hideUnpaired();return false}}}else{if(this.unpairedPanelHidden){h.show();this.unpairedPanelHidden=false}}if(!m){if(this.pairedPanelHidden){return false}else{if(l<=15){this.hidePaired();return false}}}else{if(this.pairedPanelHidden){j.show();this.pairedPanelHidden=false}}h.css({height:k+"px",flex:"0 0 auto"});return true},selectPair:function(h){$(h.currentTarget).toggleClass("selected")},_clickPairName:function(j){j.stopPropagation();var i=$(j.currentTarget),k=this.paired[i.parent().index()],h=prompt("Enter a new name for the pair:",k.name);if(h){k.name=h;k.customizedName=true;i.text(k.name)}},_clickUnpair:function(i){var h=Math.floor($(i.currentTarget).index()/2);this._unpair(this.paired[h])},toggleExtensions:function(i){var h=this;h.removeExtensions=(i!==undefined)?(i):(!h.removeExtensions);_.each(h.paired,function(j){if(j.customizedName){return}j.name=h._guessNameForPair(j.forward,j.reverse)});h._renderPaired();h._renderFooter()},_changeName:function(h){this._validationWarning("name",!!this._getName())},_getName:function(){return _.escape(this.$(".collection-name").val())},_clickCreate:function(i){var h=this._getName();if(!h){this._validationWarning("name")}else{this.createList()}},_printList:function(i){var h=this;_.each(i,function(j){if(i===h.paired){h._printPair(j)}else{}})},_printPair:function(h){this.debug(h.forward.name,h.reverse.name,": ->",h.name)},toString:function(){return"PairedCollectionCreator"}});e.templates=e.templates||{main:_.template(['<div class="header flex-row no-flex"></div>','<div class="middle flex-row flex-row-container"></div>','<div class="footer flex-row no-flex">'].join("")),header:_.template(['<div class="main-help well clear">','<a class="more-help" href="javascript:void(0);">',d("More help"),"</a>",'<div class="help-content">','<a class="less-help" href="javascript:void(0);">',d("Less"),"</a>","</div>","</div>",'<div class="alert alert-dismissable">','<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>','<span class="alert-message"></span>',"</div>",'<div class="column-headers vertically-spaced flex-column-container">','<div class="forward-column flex-column column">','<div class="column-header">','<div class="column-title">','<span class="title">',d("Unpaired forward"),"</span>",'<span class="title-info unpaired-info"></span>',"</div>",'<div class="unpaired-filter forward-unpaired-filter pull-left">','<input class="search-query" placeholder="',d("Filter this list"),'" />',"</div>","</div>","</div>",'<div class="paired-column flex-column no-flex column">','<div class="column-header">','<a class="choose-filters-link" href="javascript:void(0)">',d("Choose filters"),"</a>",'<a class="clear-filters-link" href="javascript:void(0);">',d("Clear filters"),"</a><br />",'<a class="autopair-link" href="javascript:void(0);">',d("Auto-pair"),"</a>","</div>","</div>",'<div class="reverse-column flex-column column">','<div class="column-header">','<div class="column-title">','<span class="title">',d("Unpaired reverse"),"</span>",'<span class="title-info unpaired-info"></span>',"</div>",'<div class="unpaired-filter reverse-unpaired-filter pull-left">','<input class="search-query" placeholder="',d("Filter this list"),'" />',"</div>","</div>","</div>","</div>"].join("")),middle:_.template(['<div class="unpaired-columns flex-column-container scroll-container flex-row">','<div class="forward-column flex-column column">','<ol class="column-datasets"></ol>',"</div>",'<div class="paired-column flex-column no-flex column">','<ol class="column-datasets"></ol>',"</div>",'<div class="reverse-column flex-column column">','<ol class="column-datasets"></ol>',"</div>","</div>",'<div class="flexible-partition">','<div class="flexible-partition-drag" title="',d("Drag to change"),'"></div>','<div class="column-header">','<div class="column-title paired-column-title">','<span class="title"></span>',"</div>",'<a class="unpair-all-link" href="javascript:void(0);">',d("Unpair all"),"</a>","</div>","</div>",'<div class="paired-columns flex-column-container scroll-container flex-row">','<ol class="column-datasets"></ol>',"</div>"].join("")),footer:_.template(['<div class="attributes clear">','<div class="clear">','<label class="remove-extensions-prompt pull-right">',d("Remove file extensions from pair names"),"?",'<input class="remove-extensions pull-right" type="checkbox" />',"</label>","</div>",'<div class="clear">','<input class="collection-name form-control pull-right" ','placeholder="',d("Enter a name for your new list"),'" />','<div class="collection-name-prompt pull-right">',d("Name"),":</div>","</div>","</div>",'<div class="actions clear vertically-spaced">','<div class="other-options pull-left">','<button class="cancel-create btn" tabindex="-1">',d("Cancel"),"</button>",'<div class="create-other btn-group dropup">','<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">',d("Create a different kind of collection"),' <span class="caret"></span>',"</button>",'<ul class="dropdown-menu" role="menu">','<li><a href="#">',d("Create a <i>single</i> pair"),"</a></li>",'<li><a href="#">',d("Create a list of <i>unpaired</i> datasets"),"</a></li>","</ul>","</div>","</div>",'<div class="main-options pull-right">','<button class="create-collection btn btn-primary">',d("Create list"),"</button>","</div>","</div>"].join("")),helpContent:_.template(["<p>",d(["Collections of paired datasets are ordered lists of dataset pairs (often forward and reverse reads). ","These collections can be passed to tools and workflows in order to have analyses done on each member of ","the entire group. This interface allows you to create a collection, choose which datasets are paired, ","and re-order the final collection."].join("")),"</p>","<p>",d(['Unpaired datasets are shown in the <i data-target=".unpaired-columns">unpaired section</i> ',"(hover over the underlined words to highlight below). ",'Paired datasets are shown in the <i data-target=".paired-columns">paired section</i>.',"<ul>To pair datasets, you can:","<li>Click a dataset in the ",'<i data-target=".unpaired-columns .forward-column .column-datasets,','.unpaired-columns .forward-column">forward column</i> ',"to select it then click a dataset in the ",'<i data-target=".unpaired-columns .reverse-column .column-datasets,','.unpaired-columns .reverse-column">reverse column</i>.',"</li>",'<li>Click one of the "Pair these datasets" buttons in the ','<i data-target=".unpaired-columns .paired-column .column-datasets,','.unpaired-columns .paired-column">middle column</i> ',"to pair the datasets in a particular row.","</li>",'<li>Click <i data-target=".autopair-link">"Auto-pair"</i> ',"to have your datasets automatically paired based on name.","</li>","</ul>"].join("")),"</p>","<p>",d(["<ul>You can filter what is shown in the unpaired sections by:","<li>Entering partial dataset names in either the ",'<i data-target=".forward-unpaired-filter input">forward filter</i> or ','<i data-target=".reverse-unpaired-filter input">reverse filter</i>.',"</li>","<li>Choosing from a list of preset filters by clicking the ",'<i data-target=".choose-filters-link">"Choose filters" link</i>.',"</li>","<li>Entering regular expressions to match dataset names. See: ",'<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expres..."',' target="_blank">MDN\'s JavaScript Regular Expression Tutorial</a>. ',"Note: forward slashes (\\) are not needed.","</li>","<li>Clearing the filters by clicking the ",'<i data-target=".clear-filters-link">"Clear filters" link</i>.',"</li>","</ul>"].join("")),"</p>","<p>",d(["To unpair individual dataset pairs, click the ",'<i data-target=".unpair-btn">unpair buttons ( <span class="fa fa-unlink"></span> )</i>. ','Click the <i data-target=".unpair-all-link">"Unpair all" link</i> to unpair all pairs.'].join("")),"</p>","<p>",d(['You can include or remove the file extensions (e.g. ".fastq") from your pair names by toggling the ','<i data-target=".remove-extensions-prompt">"Remove file extensions from pair names?"</i> control.'].join("")),"</p>","<p>",d(['Once your collection is complete, enter a <i data-target=".collection-name">name</i> and ','click <i data-target=".create-collection">"Create list"</i>. ',"(Note: you do not have to pair all unpaired datasets to finish.)"].join("")),"</p>"].join(""))};(function(){jQuery.fn.extend({hoverhighlight:function h(j,i){j=j||"body";if(!this.size()){return this}$(this).each(function(){var l=$(this),k=l.data("target");if(k){l.mouseover(function(m){$(k,j).css({background:i})}).mouseout(function(m){$(k).css({background:""})})}});return this}})}());var b=function c(j,h){h=_.defaults(h||{},{datasets:j,oncancel:function(){Galaxy.modal.hide()},oncreate:function(){Galaxy.modal.hide();Galaxy.currHistoryPanel.refreshContents()}});if(!window.Galaxy||!Galaxy.modal){throw new Error("Galaxy or Galaxy.modal not found")}var i=new e(h).render();Galaxy.modal.show({title:"Create a collection of paired datasets",body:i.$el,width:"80%",height:"800px",closing_events:true});window.PCC=i;return i};return{PairedCollectionCreator:e,pairedCollectionCreatorModal:b}}); \ No newline at end of file +define(["utils/levenshtein","mvc/base-mvc","utils/localization"],function(g,a,d){var f=Backbone.View.extend(a.LoggableMixin).extend({tagName:"li",className:"dataset paired",initialize:function(h){this.pair=h.pair||{}},render:function(){this.$el.attr("draggable",true).data("pair",this.pair).html(_.template(['<span class="forward-dataset-name flex-column"><%= pair.forward.name %></span>','<span class="pair-name-column flex-column">','<span class="pair-name"><%= pair.name %></span>',"</span>",'<span class="reverse-dataset-name flex-column"><%= pair.reverse.name %></span>'].join(""),{pair:this.pair})).addClass("flex-column-container");return this},events:{dragstart:"_dragstart",dragend:"_dragend",dragover:"_sendToParent",drop:"_sendToParent"},_dragstart:function(h){h.currentTarget.style.opacity="0.4";if(h.originalEvent){h=h.originalEvent}h.dataTransfer.effectAllowed="move";h.dataTransfer.setData("text/plain",JSON.stringify(this.pair));this.$el.parent().trigger("pair.dragstart",[this])},_dragend:function(h){h.currentTarget.style.opacity="1.0";this.$el.parent().trigger("pair.dragend",[this])},_sendToParent:function(h){this.$el.parent().trigger(h)},toString:function(){return"PairView("+this.pair.name+")"}});var e=Backbone.View.extend(a.LoggableMixin).extend({className:"collection-creator flex-row-container",initialize:function(h){h=_.defaults(h,{datasets:[],filters:this.DEFAULT_FILTERS,automaticallyPair:true,matchPercentage:1,strategy:"lcs"});this.initialList=h.datasets;this.historyId=h.historyId;this.filters=this.commonFilters[h.filters]||this.commonFilters[this.DEFAULT_FILTERS];if(_.isArray(h.filters)){this.filters=h.filters}this.automaticallyPair=h.automaticallyPair;this.matchPercentage=h.matchPercentage;this.strategy=this.strategies[h.strategy]||this.strategies[this.DEFAULT_STRATEGY];if(_.isFunction(h.strategy)){this.strategy=h.strategy}this.removeExtensions=true;this.oncancel=h.oncancel;this.oncreate=h.oncreate;this.unpairedPanelHidden=false;this.pairedPanelHidden=false;this.$dragging=null;this._dataSetUp();this._setUpBehaviors()},commonFilters:{none:["",""],illumina:["_1","_2"]},DEFAULT_FILTERS:"illumina",strategies:{lcs:"autoPairLCSs",levenshtein:"autoPairLevenshtein"},DEFAULT_STRATEGY:"lcs",_dataSetUp:function(){this.paired=[];this.unpaired=[];this.selectedIds=[];this._sortInitialList();this._ensureIds();this.unpaired=this.initialList.slice(0);if(this.automaticallyPair){this.autoPair()}},_sortInitialList:function(){this._sortDatasetList(this.initialList)},_sortDatasetList:function(h){h.sort(function(j,i){return naturalSort(j.name,i.name)});return h},_ensureIds:function(){this.initialList.forEach(function(h){if(!h.hasOwnProperty("id")){h.id=_.uniqueId()}});return this.initialList},_splitByFilters:function(j){var i=[],h=[];this.unpaired.forEach(function(k){if(this._filterFwdFn(k)){i.push(k)}if(this._filterRevFn(k)){h.push(k)}}.bind(this));return[i,h]},_filterFwdFn:function(i){var h=new RegExp(this.filters[0]);return h.test(i.name)},_filterRevFn:function(i){var h=new RegExp(this.filters[1]);return h.test(i.name)},_addToUnpaired:function(i){var h=function(j,l){if(j===l){return j}var k=Math.floor((l-j)/2)+j,m=naturalSort(i.name,this.unpaired[k].name);if(m<0){return h(j,k)}else{if(m>0){return h(k+1,l)}}while(this.unpaired[k]&&this.unpaired[k].name===i.name){k++}return k}.bind(this);this.unpaired.splice(h(0,this.unpaired.length),0,i)},autoPair:function(h){h=h||this.strategy;this.simpleAutoPair();return this[h].call(this)},simpleAutoPair:function(){var n=0,l,r=this._splitByFilters(),h=r[0],q=r[1],p,s,k=false;while(n<h.length){var m=h[n];p=m.name.replace(this.filters[0],"");k=false;for(l=0;l<q.length;l++){var o=q[l];s=o.name.replace(this.filters[1],"");if(m!==o&&p===s){k=true;this._pair(h.splice(n,1)[0],q.splice(l,1)[0],{silent:true});break}}if(!k){n+=1}}},autoPairLevenshtein:function(){var o=0,m,t=this._splitByFilters(),h=t[0],r=t[1],q,v,k,s,l;while(o<h.length){var n=h[o];q=n.name.replace(this.filters[0],"");l=Number.MAX_VALUE;for(m=0;m<r.length;m++){var p=r[m];v=p.name.replace(this.filters[1],"");if(n!==p){if(q===v){s=m;l=0;break}k=levenshteinDistance(q,v);if(k<l){s=m;l=k}}}var u=1-(l/(Math.max(q.length,v.length)));if(u>=this.matchPercentage){this._pair(h.splice(o,1)[0],r.splice(s,1)[0],{silent:true});if(h.length<=0||r.length<=0){return}}else{o+=1}}},autoPairLCSs:function(){var m=0,k,t=this._splitByFilters(),h=t[0],r=t[1],q,w,v,s,o;if(!h.length||!r.length){return}while(m<h.length){var l=h[m];q=l.name.replace(this.filters[0],"");o=0;for(k=0;k<r.length;k++){var p=r[k];w=p.name.replace(this.filters[1],"");if(l!==p){if(q===w){s=k;o=q.length;break}var n=this._naiveStartingAndEndingLCS(q,w);v=n.length;if(v>o){s=k;o=v}}}var u=o/(Math.min(q.length,w.length));if(u>=this.matchPercentage){this._pair(h.splice(m,1)[0],r.splice(s,1)[0],{silent:true});if(h.length<=0||r.length<=0){return}}else{m+=1}}},_naiveStartingAndEndingLCS:function(m,k){var n="",o="",l=0,h=0;while(l<m.length&&l<k.length){if(m[l]!==k[l]){break}n+=m[l];l+=1}if(l===m.length){return m}if(l===k.length){return k}l=(m.length-1);h=(k.length-1);while(l>=0&&h>=0){if(m[l]!==k[h]){break}o=[m[l],o].join("");l-=1;h-=1}return n+o},_pair:function(j,h,i){i=i||{};var k=this._createPair(j,h,i.name);this.paired.push(k);this.unpaired=_.without(this.unpaired,j,h);if(!i.silent){this.trigger("pair:new",k)}return k},_createPair:function(j,h,i){if(!(j&&h)||(j===h)){throw new Error("Bad pairing: "+[JSON.stringify(j),JSON.stringify(h)])}i=i||this._guessNameForPair(j,h);return{forward:j,name:i,reverse:h}},_guessNameForPair:function(j,h,k){k=(k!==undefined)?(k):(this.removeExtensions);var i=this._naiveStartingAndEndingLCS(j.name.replace(this.filters[0],""),h.name.replace(this.filters[1],""));if(k){var l=i.lastIndexOf(".");if(l>0){i=i.slice(0,l)}}return i||(j.name+" & "+h.name)},_unpair:function(i,h){h=h||{};if(!i){throw new Error("Bad pair: "+JSON.stringify(i))}this.paired=_.without(this.paired,i);this._addToUnpaired(i.forward);this._addToUnpaired(i.reverse);if(!h.silent){this.trigger("pair:unpair",[i])}return i},unpairAll:function(){var h=[];while(this.paired.length){h.push(this._unpair(this.paired[0],{silent:true}))}this.trigger("pair:unpair",h)},_pairToJSON:function(h){return{collection_type:"paired",src:"new_collection",name:h.name,element_identifiers:[{name:"forward",id:h.forward.id,src:"hda"},{name:"reverse",id:h.reverse.id,src:"hda"}]}},createList:function(){var j=this,i;if(j.historyId){i="/api/histories/"+this.historyId+"/contents/dataset_collections"}var h={type:"dataset_collection",collection_type:"list:paired",name:_.escape(j.$(".collection-name").val()),element_identifiers:j.paired.map(function(k){return j._pairToJSON(k)})};return jQuery.ajax(i,{type:"POST",contentType:"application/json",dataType:"json",data:JSON.stringify(h)}).fail(function(m,k,l){j._ajaxErrHandler(m,k,l)}).done(function(k,l,m){j.trigger("collection:created",k,l,m);if(typeof j.oncreate==="function"){j.oncreate.call(this,k,l,m)}})},_ajaxErrHandler:function(k,h,j){this.error(k,h,j);var i=d("An error occurred while creating this collection");if(k){if(k.readyState===0&&k.status===0){i+=": "+d("Galaxy could not be reached and may be updating.")+d(" Try again in a few minutes.")}else{if(k.responseJSON){i+="<br /><pre>"+JSON.stringify(k.responseJSON)+"</pre>"}else{i+=": "+j}}}creator._showAlert(i,"alert-danger")},render:function(h,i){this.$el.empty().html(e.templates.main());this._renderHeader(h);this._renderMiddle(h);this._renderFooter(h);this._addPluginComponents();return this},_renderHeader:function(i,j){var h=this.$(".header").empty().html(e.templates.header()).find(".help-content").prepend($(e.templates.helpContent()));this._renderFilters();return h},_renderFilters:function(){return this.$(".forward-column .column-header input").val(this.filters[0]).add(this.$(".reverse-column .column-header input").val(this.filters[1]))},_renderMiddle:function(i,j){var h=this.$(".middle").empty().html(e.templates.middle());if(this.unpairedPanelHidden){this.$(".unpaired-columns").hide()}else{if(this.pairedPanelHidden){this.$(".paired-columns").hide()}}this._renderUnpaired();this._renderPaired();return h},_renderUnpaired:function(m,n){var k=this,l,i,h=[],j=this._splitByFilters();this.$(".forward-column .title").text([j[0].length,d("unpaired forward")].join(" "));this.$(".forward-column .unpaired-info").text(this._renderUnpairedDisplayStr(this.unpaired.length-j[0].length));this.$(".reverse-column .title").text([j[1].length,d("unpaired reverse")].join(" "));this.$(".reverse-column .unpaired-info").text(this._renderUnpairedDisplayStr(this.unpaired.length-j[1].length));this.$(".unpaired-columns .column-datasets").empty();this.$(".autopair-link").toggle(this.unpaired.length!==0);if(this.unpaired.length===0){this._renderUnpairedEmpty();return}i=j[1].map(function(p,o){if((j[0][o]!==undefined)&&(j[0][o]!==p)){h.push(k._renderPairButton())}return k._renderUnpairedDataset(p)});l=j[0].map(function(o){return k._renderUnpairedDataset(o)});if(!l.length&&!i.length){this._renderUnpairedNotShown();return}this.$(".unpaired-columns .forward-column .column-datasets").append(l).add(this.$(".unpaired-columns .paired-column .column-datasets").append(h)).add(this.$(".unpaired-columns .reverse-column .column-datasets").append(i));this._adjUnpairedOnScrollbar()},_renderUnpairedDisplayStr:function(h){return["(",h," ",d("filtered out"),")"].join("")},_renderUnpairedDataset:function(h){return $("<li/>").attr("id","dataset-"+h.id).addClass("dataset unpaired").attr("draggable",true).addClass(h.selected?"selected":"").append($("<span/>").addClass("dataset-name").text(h.name)).data("dataset",h)},_renderPairButton:function(){return $("<li/>").addClass("dataset unpaired").append($("<span/>").addClass("dataset-name").text(d("Pair these datasets")))},_renderUnpairedEmpty:function(){var h=$('<div class="empty-message"></div>').text("("+d("no remaining unpaired datasets")+")");this.$(".unpaired-columns .paired-column .column-datasets").empty().prepend(h);return h},_renderUnpairedNotShown:function(){var h=$('<div class="empty-message"></div>').text("("+d("no datasets were found matching the current filters")+")");this.$(".unpaired-columns .paired-column .column-datasets").empty().prepend(h);return h},_adjUnpairedOnScrollbar:function(){var k=this.$(".unpaired-columns").last(),l=this.$(".unpaired-columns .reverse-column .dataset").first();if(!l.size()){return}var h=k.offset().left+k.outerWidth(),j=l.offset().left+l.outerWidth(),i=Math.floor(h)-Math.floor(j);this.$(".unpaired-columns .forward-column").css("margin-left",(i>0)?i:0)},_renderPaired:function(i,j){this.$(".paired-column-title .title").text([this.paired.length,d("paired")].join(" "));this.$(".unpair-all-link").toggle(this.paired.length!==0);if(this.paired.length===0){this._renderPairedEmpty();return}else{this.$(".remove-extensions-link").show()}this.$(".paired-columns .column-datasets").empty();var h=this;this.paired.forEach(function(m,k){var l=new f({pair:m});h.$(".paired-columns .column-datasets").append(l.render().$el).append(['<button class="unpair-btn">','<span class="fa fa-unlink" title="',d("Unpair"),'"></span>',"</button>"].join(""))})},_renderPairedEmpty:function(){var h=$('<div class="empty-message"></div>').text("("+d("no paired datasets yet")+")");this.$(".paired-columns .column-datasets").empty().prepend(h);return h},_renderFooter:function(i,j){var h=this.$(".footer").empty().html(e.templates.footer());this.$(".remove-extensions").prop("checked",this.removeExtensions);if(typeof this.oncancel==="function"){this.$(".cancel-create.btn").show()}return h},_addPluginComponents:function(){this._chooseFiltersPopover(".choose-filters-link");this.$(".help-content i").hoverhighlight(".collection-creator","rgba( 64, 255, 255, 1.0 )")},_chooseFiltersPopover:function(h){function i(l,k){return['<button class="filter-choice btn" ','data-forward="',l,'" data-reverse="',k,'">',d("Forward"),": ",l,", ",d("Reverse"),": ",k,"</button>"].join("")}var j=$(_.template(['<div class="choose-filters">','<div class="help">',d("Choose from the following filters to change which unpaired reads are shown in the display"),":</div>",i("_1","_2"),i("_R1","_R2"),"</div>"].join(""),{}));return this.$(h).popover({container:".collection-creator",placement:"bottom",html:true,content:j})},_validationWarning:function(i,h){var j="validation-warning";if(i==="name"){i=this.$(".collection-name").add(this.$(".collection-name-prompt"));this.$(".collection-name").focus().select()}if(h){i=i||this.$("."+j);i.removeClass(j)}else{i.addClass(j)}},_setUpBehaviors:function(){this.on("pair:new",function(){this._renderUnpaired();this._renderPaired();this.$(".paired-columns").scrollTop(8000000)});this.on("pair:unpair",function(h){this._renderUnpaired();this._renderPaired();this.splitView()});this.on("filter-change",function(){this.filters=[this.$(".forward-unpaired-filter input").val(),this.$(".reverse-unpaired-filter input").val()];this._renderFilters();this._renderUnpaired()});this.on("autopair",function(){this._renderUnpaired();this._renderPaired();var h,i=null;if(this.paired.length){i="alert-success";h=this.paired.length+" "+d("pairs created");if(!this.unpaired.length){h+=": "+d("all datasets have been successfully paired");this.hideUnpaired()}}else{h=d("Could not automatically create any pairs from the given dataset names")}this._showAlert(h,i)});return this},events:{"click .more-help":"_clickMoreHelp","click .less-help":"_clickLessHelp","click .header .alert button":"_hideAlert","click .forward-column .column-title":"_clickShowOnlyUnpaired","click .reverse-column .column-title":"_clickShowOnlyUnpaired","click .unpair-all-link":"_clickUnpairAll","change .forward-unpaired-filter input":function(h){this.trigger("filter-change")},"focus .forward-unpaired-filter input":function(h){$(h.currentTarget).select()},"click .autopair-link":"_clickAutopair","click .choose-filters .filter-choice":"_clickFilterChoice","click .clear-filters-link":"_clearFilters","change .reverse-unpaired-filter input":function(h){this.trigger("filter-change")},"focus .reverse-unpaired-filter input":function(h){$(h.currentTarget).select()},"click .forward-column .dataset.unpaired":"_clickUnpairedDataset","click .reverse-column .dataset.unpaired":"_clickUnpairedDataset","click .paired-column .dataset.unpaired":"_clickPairRow","click .unpaired-columns":"clearSelectedUnpaired","mousedown .unpaired-columns .dataset":"_mousedownUnpaired","click .paired-column-title":"_clickShowOnlyPaired","mousedown .flexible-partition-drag":"_startPartitionDrag","click .paired-columns .dataset.paired":"selectPair","click .paired-columns":"clearSelectedPaired","click .paired-columns .pair-name":"_clickPairName","click .unpair-btn":"_clickUnpair","dragover .paired-columns .column-datasets":"_dragoverPairedColumns","drop .paired-columns .column-datasets":"_dropPairedColumns","pair.dragstart .paired-columns .column-datasets":"_pairDragstart","pair.dragend .paired-columns .column-datasets":"_pairDragend","change .remove-extensions":function(h){this.toggleExtensions()},"change .collection-name":"_changeName","click .cancel-create":function(h){if(typeof this.oncancel==="function"){this.oncancel.call(this)}},"click .create-collection":"_clickCreate"},_clickMoreHelp:function(h){this.$(".main-help").addClass("expanded");this.$(".more-help").hide()},_clickLessHelp:function(h){this.$(".main-help").removeClass("expanded");this.$(".more-help").show()},_showAlert:function(i,h){h=h||"alert-danger";this.$(".main-help").hide();this.$(".header .alert").attr("class","alert alert-dismissable").addClass(h).show().find(".alert-message").html(i)},_hideAlert:function(h){this.$(".main-help").show();this.$(".header .alert").hide()},_clickShowOnlyUnpaired:function(h){if(this.$(".paired-columns").is(":visible")){this.hidePaired()}else{this.splitView()}},_clickShowOnlyPaired:function(h){if(this.$(".unpaired-columns").is(":visible")){this.hideUnpaired()}else{this.splitView()}},hideUnpaired:function(h,i){this.unpairedPanelHidden=true;this.pairedPanelHidden=false;this._renderMiddle(h,i)},hidePaired:function(h,i){this.unpairedPanelHidden=false;this.pairedPanelHidden=true;this._renderMiddle(h,i)},splitView:function(h,i){this.unpairedPanelHidden=this.pairedPanelHidden=false;this._renderMiddle(h,i);return this},_clickUnpairAll:function(h){this.unpairAll()},_clickAutopair:function(i){var h=this.autoPair();this.trigger("autopair",h)},_clickFilterChoice:function(i){var h=$(i.currentTarget);this.$(".forward-unpaired-filter input").val(h.data("forward"));this.$(".reverse-unpaired-filter input").val(h.data("reverse"));this._hideChooseFilters();this.trigger("filter-change")},_hideChooseFilters:function(){this.$(".choose-filters-link").popover("hide");this.$(".popover").css("display","none")},_clearFilters:function(h){this.$(".forward-unpaired-filter input").val("");this.$(".reverse-unpaired-filter input").val("");this.trigger("filter-change")},_clickUnpairedDataset:function(h){h.stopPropagation();return this.toggleSelectUnpaired($(h.currentTarget))},toggleSelectUnpaired:function(j,i){i=i||{};var k=j.data("dataset"),h=i.force!==undefined?i.force:!j.hasClass("selected");if(!j.size()||k===undefined){return j}if(h){j.addClass("selected");if(!i.waitToPair){this.pairAllSelected()}}else{j.removeClass("selected")}return j},pairAllSelected:function(i){i=i||{};var j=this,k=[],h=[],l=[];j.$(".unpaired-columns .forward-column .dataset.selected").each(function(){k.push($(this).data("dataset"))});j.$(".unpaired-columns .reverse-column .dataset.selected").each(function(){h.push($(this).data("dataset"))});k.length=h.length=Math.min(k.length,h.length);k.forEach(function(n,m){try{l.push(j._pair(n,h[m],{silent:true}))}catch(o){j.error(o)}});if(l.length&&!i.silent){this.trigger("pair:new",l)}return l},clearSelectedUnpaired:function(){this.$(".unpaired-columns .dataset.selected").removeClass("selected")},_mousedownUnpaired:function(j){if(j.shiftKey){var i=this,h=$(j.target).addClass("selected"),k=function(l){i.$(l.target).filter(".dataset").addClass("selected")};h.parent().on("mousemove",k);$(document).one("mouseup",function(l){h.parent().off("mousemove",k);i.pairAllSelected()})}},_clickPairRow:function(j){var k=$(j.currentTarget).index(),i=$(".unpaired-columns .forward-column .dataset").eq(k).data("dataset"),h=$(".unpaired-columns .reverse-column .dataset").eq(k).data("dataset");this._pair(i,h)},_startPartitionDrag:function(i){var h=this,l=i.pageY;$("body").css("cursor","ns-resize");h.$(".flexible-partition-drag").css("color","black");function k(m){h.$(".flexible-partition-drag").css("color","");$("body").css("cursor","").unbind("mousemove",j)}function j(m){var n=m.pageY-l;if(!h.adjPartition(n)){$("body").trigger("mouseup")}h._adjUnpairedOnScrollbar();l+=n}$("body").mousemove(j);$("body").one("mouseup",k)},adjPartition:function(i){var h=this.$(".unpaired-columns"),j=this.$(".paired-columns"),k=parseInt(h.css("height"),10),l=parseInt(j.css("height"),10);k=Math.max(10,k+i);l=l-i;var m=i<0;if(m){if(this.unpairedPanelHidden){return false}else{if(k<=10){this.hideUnpaired();return false}}}else{if(this.unpairedPanelHidden){h.show();this.unpairedPanelHidden=false}}if(!m){if(this.pairedPanelHidden){return false}else{if(l<=15){this.hidePaired();return false}}}else{if(this.pairedPanelHidden){j.show();this.pairedPanelHidden=false}}h.css({height:k+"px",flex:"0 0 auto"});return true},selectPair:function(h){h.stopPropagation();$(h.currentTarget).toggleClass("selected")},clearSelectedPaired:function(h){this.$(".paired-columns .dataset.selected").removeClass("selected")},_clickPairName:function(j){j.stopPropagation();var i=$(j.currentTarget),k=this.paired[i.parent().index()],h=prompt("Enter a new name for the pair:",k.name);if(h){k.name=h;k.customizedName=true;i.text(k.name)}},_clickUnpair:function(i){var h=Math.floor($(i.currentTarget).index()/2);this._unpair(this.paired[h])},_dragoverPairedColumns:function(k){k.preventDefault();var i=this.$(".paired-columns .column-datasets"),l=i.offset();var j=this._getNearestPairedDatasetLi(k.originalEvent.clientY);$(".paired-drop-placeholder").remove();var h=$('<div class="paired-drop-placeholder"></div>');if(!j.size()){i.append(h)}else{j.before(h)}},_getNearestPairedDatasetLi:function(o){var l=4,j=this.$(".paired-columns .column-datasets li").toArray();for(var k=0;k<j.length;k++){var n=$(j[k]),m=n.offset().top,h=Math.floor(n.outerHeight()/2)+l;if(m+h>o&&m-h<o){return n}}return $()},_dropPairedColumns:function(i){i.preventDefault();i.dataTransfer.dropEffect="move";var h=this._getNearestPairedDatasetLi(i.originalEvent.clientY);if(h.size()){this.$dragging.insertBefore(h)}else{this.$dragging.insertAfter(this.$(".paired-columns .unpair-btn").last())}this._syncPairsToDom();return false},_syncPairsToDom:function(){var h=[];this.$(".paired-columns .dataset.paired").each(function(){h.push($(this).data("pair"))});this.paired=h;this._renderPaired()},_pairDragstart:function(i,j){j.$el.addClass("selected");var h=this.$(".paired-columns .dataset.selected");this.$dragging=h},_pairDragend:function(h,i){$(".paired-drop-placeholder").remove();this.$dragging=null},toggleExtensions:function(i){var h=this;h.removeExtensions=(i!==undefined)?(i):(!h.removeExtensions);_.each(h.paired,function(j){if(j.customizedName){return}j.name=h._guessNameForPair(j.forward,j.reverse)});h._renderPaired();h._renderFooter()},_changeName:function(h){this._validationWarning("name",!!this._getName())},_getName:function(){return _.escape(this.$(".collection-name").val())},_clickCreate:function(i){var h=this._getName();if(!h){this._validationWarning("name")}else{this.createList()}},_printList:function(i){var h=this;_.each(i,function(j){if(i===h.paired){h._printPair(j)}else{}})},_printPair:function(h){this.debug(h.forward.name,h.reverse.name,": ->",h.name)},toString:function(){return"PairedCollectionCreator"}});e.templates=e.templates||{main:_.template(['<div class="header flex-row no-flex"></div>','<div class="middle flex-row flex-row-container"></div>','<div class="footer flex-row no-flex">'].join("")),header:_.template(['<div class="main-help well clear">','<a class="more-help" href="javascript:void(0);">',d("More help"),"</a>",'<div class="help-content">','<a class="less-help" href="javascript:void(0);">',d("Less"),"</a>","</div>","</div>",'<div class="alert alert-dismissable">','<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>','<span class="alert-message"></span>',"</div>",'<div class="column-headers vertically-spaced flex-column-container">','<div class="forward-column flex-column column">','<div class="column-header">','<div class="column-title">','<span class="title">',d("Unpaired forward"),"</span>",'<span class="title-info unpaired-info"></span>',"</div>",'<div class="unpaired-filter forward-unpaired-filter pull-left">','<input class="search-query" placeholder="',d("Filter this list"),'" />',"</div>","</div>","</div>",'<div class="paired-column flex-column no-flex column">','<div class="column-header">','<a class="choose-filters-link" href="javascript:void(0)">',d("Choose filters"),"</a>",'<a class="clear-filters-link" href="javascript:void(0);">',d("Clear filters"),"</a><br />",'<a class="autopair-link" href="javascript:void(0);">',d("Auto-pair"),"</a>","</div>","</div>",'<div class="reverse-column flex-column column">','<div class="column-header">','<div class="column-title">','<span class="title">',d("Unpaired reverse"),"</span>",'<span class="title-info unpaired-info"></span>',"</div>",'<div class="unpaired-filter reverse-unpaired-filter pull-left">','<input class="search-query" placeholder="',d("Filter this list"),'" />',"</div>","</div>","</div>","</div>"].join("")),middle:_.template(['<div class="unpaired-columns flex-column-container scroll-container flex-row">','<div class="forward-column flex-column column">','<ol class="column-datasets"></ol>',"</div>",'<div class="paired-column flex-column no-flex column">','<ol class="column-datasets"></ol>',"</div>",'<div class="reverse-column flex-column column">','<ol class="column-datasets"></ol>',"</div>","</div>",'<div class="flexible-partition">','<div class="flexible-partition-drag" title="',d("Drag to change"),'"></div>','<div class="column-header">','<div class="column-title paired-column-title">','<span class="title"></span>',"</div>",'<a class="unpair-all-link" href="javascript:void(0);">',d("Unpair all"),"</a>","</div>","</div>",'<div class="paired-columns flex-column-container scroll-container flex-row">','<ol class="column-datasets"></ol>',"</div>"].join("")),footer:_.template(['<div class="attributes clear">','<div class="clear">','<label class="remove-extensions-prompt pull-right">',d("Remove file extensions from pair names"),"?",'<input class="remove-extensions pull-right" type="checkbox" />',"</label>","</div>",'<div class="clear">','<input class="collection-name form-control pull-right" ','placeholder="',d("Enter a name for your new list"),'" />','<div class="collection-name-prompt pull-right">',d("Name"),":</div>","</div>","</div>",'<div class="actions clear vertically-spaced">','<div class="other-options pull-left">','<button class="cancel-create btn" tabindex="-1">',d("Cancel"),"</button>",'<div class="create-other btn-group dropup">','<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">',d("Create a different kind of collection"),' <span class="caret"></span>',"</button>",'<ul class="dropdown-menu" role="menu">','<li><a href="#">',d("Create a <i>single</i> pair"),"</a></li>",'<li><a href="#">',d("Create a list of <i>unpaired</i> datasets"),"</a></li>","</ul>","</div>","</div>",'<div class="main-options pull-right">','<button class="create-collection btn btn-primary">',d("Create list"),"</button>","</div>","</div>"].join("")),helpContent:_.template(["<p>",d(["Collections of paired datasets are ordered lists of dataset pairs (often forward and reverse reads). ","These collections can be passed to tools and workflows in order to have analyses done on each member of ","the entire group. This interface allows you to create a collection, choose which datasets are paired, ","and re-order the final collection."].join("")),"</p>","<p>",d(['Unpaired datasets are shown in the <i data-target=".unpaired-columns">unpaired section</i> ',"(hover over the underlined words to highlight below). ",'Paired datasets are shown in the <i data-target=".paired-columns">paired section</i>.',"<ul>To pair datasets, you can:","<li>Click a dataset in the ",'<i data-target=".unpaired-columns .forward-column .column-datasets,','.unpaired-columns .forward-column">forward column</i> ',"to select it then click a dataset in the ",'<i data-target=".unpaired-columns .reverse-column .column-datasets,','.unpaired-columns .reverse-column">reverse column</i>.',"</li>",'<li>Click one of the "Pair these datasets" buttons in the ','<i data-target=".unpaired-columns .paired-column .column-datasets,','.unpaired-columns .paired-column">middle column</i> ',"to pair the datasets in a particular row.","</li>",'<li>Click <i data-target=".autopair-link">"Auto-pair"</i> ',"to have your datasets automatically paired based on name.","</li>","</ul>"].join("")),"</p>","<p>",d(["<ul>You can filter what is shown in the unpaired sections by:","<li>Entering partial dataset names in either the ",'<i data-target=".forward-unpaired-filter input">forward filter</i> or ','<i data-target=".reverse-unpaired-filter input">reverse filter</i>.',"</li>","<li>Choosing from a list of preset filters by clicking the ",'<i data-target=".choose-filters-link">"Choose filters" link</i>.',"</li>","<li>Entering regular expressions to match dataset names. See: ",'<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expres..."',' target="_blank">MDN\'s JavaScript Regular Expression Tutorial</a>. ',"Note: forward slashes (\\) are not needed.","</li>","<li>Clearing the filters by clicking the ",'<i data-target=".clear-filters-link">"Clear filters" link</i>.',"</li>","</ul>"].join("")),"</p>","<p>",d(["To unpair individual dataset pairs, click the ",'<i data-target=".unpair-btn">unpair buttons ( <span class="fa fa-unlink"></span> )</i>. ','Click the <i data-target=".unpair-all-link">"Unpair all" link</i> to unpair all pairs.'].join("")),"</p>","<p>",d(['You can include or remove the file extensions (e.g. ".fastq") from your pair names by toggling the ','<i data-target=".remove-extensions-prompt">"Remove file extensions from pair names?"</i> control.'].join("")),"</p>","<p>",d(['Once your collection is complete, enter a <i data-target=".collection-name">name</i> and ','click <i data-target=".create-collection">"Create list"</i>. ',"(Note: you do not have to pair all unpaired datasets to finish.)"].join("")),"</p>"].join(""))};(function(){jQuery.fn.extend({hoverhighlight:function h(j,i){j=j||"body";if(!this.size()){return this}$(this).each(function(){var l=$(this),k=l.data("target");if(k){l.mouseover(function(m){$(k,j).css({background:i})}).mouseout(function(m){$(k).css({background:""})})}});return this}})}());var b=function c(j,h){h=_.defaults(h||{},{datasets:j,oncancel:function(){Galaxy.modal.hide()},oncreate:function(){Galaxy.modal.hide();Galaxy.currHistoryPanel.refreshContents()}});if(!window.Galaxy||!Galaxy.modal){throw new Error("Galaxy or Galaxy.modal not found")}var i=new e(h).render();Galaxy.modal.show({title:"Create a collection of paired datasets",body:i.$el,width:"80%",height:"800px",closing_events:true});window.PCC=i;return i};return{PairedCollectionCreator:e,pairedCollectionCreatorModal:b}}); \ No newline at end of file diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 static/style/blue/base.css --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -1870,6 +1870,8 @@ .collection-creator .flexible-partition .column-header .remove-extensions-link{display:none} .collection-creator .paired-columns{height:0;border:1px solid lightgrey;border-width:1px 0 1px 0;margin-bottom:8px}.collection-creator .paired-columns .column-datasets{width:100%;overflow:auto} .collection-creator .paired-columns .unpair-btn{float:right;margin-top:-32px;width:31px;height:32px;border-color:transparent;background:transparent;font-size:120%}.collection-creator .paired-columns .unpair-btn:hover{border-color:#BFBFBF;background:#DEDEDE} +.collection-creator .paired-columns .paired-drop-placeholder{width:60px;height:3px;margin:2px 0px 0px 14px;background:black}.collection-creator .paired-columns .paired-drop-placeholder:before{float:left;font-size:120%;margin:-9px 0 0 -8px;font-family:FontAwesome;content:'\f0da'} +.collection-creator .paired-columns .paired-drop-placeholder:last-child{margin-bottom:8px} .collection-creator .paired-columns .empty-message{text-align:center} .collection-creator .footer{padding-bottom:8px}.collection-creator .footer .attributes .remove-extensions-prompt{line-height:32px}.collection-creator .footer .attributes .remove-extensions-prompt .remove-extensions{display:inline-block;width:24px;height:24px} .collection-creator .footer .attributes .collection-name-prompt{margin:5px 4px 0 0} diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 static/style/src/less/ui/paired-collection-creator.less --- a/static/style/src/less/ui/paired-collection-creator.less +++ b/static/style/src/less/ui/paired-collection-creator.less @@ -374,6 +374,22 @@ background: #DEDEDE; } } + .paired-drop-placeholder { + width : 60px; + height : 3px; + margin : 2px 0px 0px 14px; + background : black; + &:before { + float: left; + font-size: 120%; + margin: -9px 0px 0px -8px; + font-family: FontAwesome; + content: '\f0da'; + } + &:last-child { + margin-bottom: 8px; + } + } .empty-message { text-align: center; } diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 templates/base/base_panels.mako --- a/templates/base/base_panels.mako +++ b/templates/base/base_panels.mako @@ -106,7 +106,6 @@ ## Scripts can be loaded later since they progressively add features to ## the panels, but do not change layout ${h.js( - 'libs/jquery/jquery.event.drag', 'libs/jquery/jquery.event.hover', 'libs/jquery/jquery.form', 'libs/jquery/jquery.rating', diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/api/helpers.py --- a/test/api/helpers.py +++ b/test/api/helpers.py @@ -11,7 +11,6 @@ # Simple workflow that takes an input and filters with random lines twice in a # row - first grabbing 8 lines at random and then 6. workflow_random_x2_str = resource_string( __name__, "test_workflow_2.ga" ) -workflow_two_paired_str = resource_string( __name__, "test_workflow_two_paired.ga" ) DEFAULT_HISTORY_TIMEOUT = 10 # Secs to wait on history to turn ok @@ -161,8 +160,11 @@ def load_random_x2_workflow( self, name ): return self.load_workflow( name, content=workflow_random_x2_str ) - def load_two_paired_workflow( self, name ): - return self.load_workflow( name, content=workflow_two_paired_str ) + def load_workflow_from_resource( self, name, filename=None ): + if filename is None: + filename = "%s.ga" % name + content = resource_string( __name__, filename ) + return self.load_workflow( name, content=content ) def simple_workflow( self, name, **create_kwds ): workflow = self.load_workflow( name ) @@ -323,8 +325,14 @@ def list_identifiers( self, history_id, contents=None ): count = 3 if not contents else len( contents ) - hdas = self.__datasets( history_id, count=count, contents=contents ) - hda_to_identifier = lambda ( i, hda ): dict( name="data%d" % ( i + 1 ), src="hda", id=hda[ "id" ] ) + # Contents can be a list of strings (with name auto-assigned here) or a list of + # 2-tuples of form (name, dataset_content). + if contents and isinstance(contents[0], tuple): + hdas = self.__datasets( history_id, count=count, contents=[c[1] for c in contents] ) + hda_to_identifier = lambda ( i, hda ): dict( name=contents[i][0], src="hda", id=hda[ "id" ] ) + else: + hdas = self.__datasets( history_id, count=count, contents=contents ) + hda_to_identifier = lambda ( i, hda ): dict( name="data%d" % ( i + 1 ), src="hda", id=hda[ "id" ] ) element_identifiers = map( hda_to_identifier, enumerate( hdas ) ) return element_identifiers diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/api/test_workflow_matching_lists.ga --- /dev/null +++ b/test/api/test_workflow_matching_lists.ga @@ -0,0 +1,117 @@ +{ + "a_galaxy_workflow": "true", + "annotation": "", + "format-version": "0.1", + "name": "test_workflow_matching_lists", + "steps": { + "0": { + "annotation": "", + "id": 0, + "input_connections": {}, + "inputs": [ + { + "description": "", + "name": "list1" + } + ], + "name": "Input dataset collection", + "outputs": [], + "position": { + "left": 139.833336353302, + "top": 162.33334398269653 + }, + "tool_errors": null, + "tool_id": null, + "tool_state": "{\"collection_type\": \"list\", \"name\": \"list1\"}", + "tool_version": null, + "type": "data_collection_input", + "user_outputs": [] + }, + "1": { + "annotation": "", + "id": 1, + "input_connections": {}, + "inputs": [ + { + "description": "", + "name": "list2" + } + ], + "name": "Input dataset collection", + "outputs": [], + "position": { + "left": 141.864586353302, + "top": 272.3680577278137 + }, + "tool_errors": null, + "tool_id": null, + "tool_state": "{\"collection_type\": \"list\", \"name\": \"list2\"}", + "tool_version": null, + "type": "data_collection_input", + "user_outputs": [] + }, + "2": { + "annotation": "", + "id": 2, + "input_connections": { + "input1": { + "id": 0, + "output_name": "output" + }, + "queries_0|input2": { + "id": 1, + "output_name": "output" + } + }, + "inputs": [], + "name": "Concatenate datasets (for test workflows)", + "outputs": [ + { + "name": "out_file1", + "type": "input" + } + ], + "position": { + "left": 453.40974473953247, + "top": 203.4097294807434 + }, + "post_job_actions": {}, + "tool_errors": null, + "tool_id": "cat", + "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\", \"queries\": \"[{\\\"input2\\\": null, \\\"__index__\\\": 0}]\"}", + "tool_version": "1.0.0", + "type": "tool", + "user_outputs": [] + }, + "3": { + "annotation": "", + "id": 3, + "input_connections": { + "input1": { + "id": 2, + "output_name": "out_file1" + } + }, + "inputs": [], + "name": "Concatenate dataset list (for test workflows)", + "outputs": [ + { + "name": "out_file1", + "type": "input" + } + ], + "position": { + "left": 828.93061876297, + "top": 217.4201512336731 + }, + "post_job_actions": {}, + "tool_errors": null, + "tool_id": "cat_list", + "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"input1\": \"null\"}", + "tool_version": "1.0.0", + "type": "tool", + "user_outputs": [] + } + }, + "uuid": "54aadd3b-9d2b-436a-acfa-246a8c251651" +} \ No newline at end of file diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/api/test_workflow_two_paired.ga --- a/test/api/test_workflow_two_paired.ga +++ /dev/null @@ -1,116 +0,0 @@ -{ - "a_galaxy_workflow": "true", - "annotation": "", - "format-version": "0.1", - "name": "MultipairTest223", - "steps": { - "0": { - "annotation": "", - "id": 0, - "input_connections": {}, - "inputs": [ - { - "description": "", - "name": "f1" - } - ], - "name": "Input dataset collection", - "outputs": [], - "position": { - "left": 302.3333435058594, - "top": 330 - }, - "tool_errors": null, - "tool_id": null, - "tool_state": "{\"collection_type\": \"paired\", \"name\": \"f1\"}", - "tool_version": null, - "type": "data_collection_input", - "user_outputs": [] - }, - "1": { - "annotation": "", - "id": 1, - "input_connections": {}, - "inputs": [ - { - "description": "", - "name": "f2" - } - ], - "name": "Input dataset collection", - "outputs": [], - "position": { - "left": 288.3333435058594, - "top": 446 - }, - "tool_errors": null, - "tool_id": null, - "tool_state": "{\"collection_type\": \"paired\", \"name\": \"f2\"}", - "tool_version": null, - "type": "data_collection_input", - "user_outputs": [] - }, - "2": { - "annotation": "", - "id": 2, - "input_connections": { - "kind|f1": { - "id": 0, - "output_name": "output" - }, - "kind|f2": { - "id": 1, - "output_name": "output" - } - }, - "inputs": [], - "name": "collection_two_paired", - "outputs": [ - { - "name": "out1", - "type": "txt" - } - ], - "position": { - "left": 782.3333740234375, - "top": 200 - }, - "post_job_actions": {}, - "tool_errors": null, - "tool_id": "collection_two_paired", - "tool_state": "{\"__page__\": 0, \"kind\": \"{\\\"f1\\\": null, \\\"f2\\\": null, \\\"collection_type\\\": \\\"paired\\\", \\\"__current_case__\\\": 0}\", \"__rerun_remap_job_id__\": null}", - "tool_version": "0.1.0", - "type": "tool", - "user_outputs": [] - }, - "3": { - "annotation": "", - "id": 3, - "input_connections": { - "cond1|input1": { - "id": 2, - "output_name": "out1" - } - }, - "inputs": [], - "name": "Concatenate datasets", - "outputs": [ - { - "name": "out_file1", - "type": "input" - } - ], - "position": { - "left": 1239.3333740234375, - "top": 108.97916793823242 - }, - "post_job_actions": {}, - "tool_errors": null, - "tool_id": "cat2", - "tool_state": "{\"__page__\": 0, \"__rerun_remap_job_id__\": null, \"cond1\": \"{\\\"datatype\\\": \\\"txt\\\", \\\"input1\\\": null, \\\"__current_case__\\\": 0}\"}", - "tool_version": "1.0.0", - "type": "tool", - "user_outputs": [] - } - } -} \ No newline at end of file diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/api/test_workflows.py --- a/test/api/test_workflows.py +++ b/test/api/test_workflows.py @@ -149,16 +149,16 @@ run_workflow_response = self._post( "workflows", data=workflow_request ) self._assert_status_code_is( run_workflow_response, 403 ) - @skip_without_tool( "cat1" ) - @skip_without_tool( "collection_two_paired" ) - def test_run_workflow_collection_params( self ): - workflow = self.workflow_populator.load_two_paired_workflow( name="test_for_run_two_paired" ) + @skip_without_tool( "cat" ) + @skip_without_tool( "cat_list" ) + def test_workflow_run_with_matching_lists( self ): + workflow = self.workflow_populator.load_workflow_from_resource( "test_workflow_matching_lists" ) workflow_id = self.workflow_populator.create_workflow( workflow ) history_id = self.dataset_populator.new_history() - hdca1 = self.dataset_collection_populator.create_pair_in_history( history_id, contents=["1 2 3", "4 5 6"] ).json() - hdca2 = self.dataset_collection_populator.create_pair_in_history( history_id, contents=["7 8 9", "0 a b"] ).json() + hdca1 = self.dataset_collection_populator.create_list_in_history( history_id, contents=[("sample1-1", "1 2 3"), ("sample2-1", "7 8 9")] ).json() + hdca2 = self.dataset_collection_populator.create_list_in_history( history_id, contents=[("sample1-2", "4 5 6"), ("sample2-2", "0 a b")] ).json() self.dataset_populator.wait_for_history( history_id, assert_ok=True ) - label_map = { "f1": self._ds_entry( hdca1 ), "f2": self._ds_entry( hdca2 ) } + label_map = { "list1": self._ds_entry( hdca1 ), "list2": self._ds_entry( hdca2 ) } workflow_request = dict( history="hist_id=%s" % history_id, workflow_id=workflow_id, diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/functional/tools/README.txt --- a/test/functional/tools/README.txt +++ b/test/functional/tools/README.txt @@ -1,3 +1,15 @@ -This directory contains tools only useful for testing the tool test framework -and demonstrating it features. Run the driver script 'run_functional_tests.sh' -with '-framework' as first argument to run through these tests. +This directory contains tools only useful for testing and +demonstrating aspects of the tool syntax. Run the test driver script +'run_tests.sh' with the '-framework' as first argument to run through +these tests. Pass in an '-id' along with one of these tool ids to test +a single tool. + +Some API tests use these tools to test various features of the API, +tool, and workflow subsystems. Pass the arugment +'-with_framework_test_tools' to 'run_tests.sh' in addition to '-api' +to ensure these tools get loaded during the testing process. + +Finally, to play around witht these tools interactively - simply +replace the 'universe_wsgi.ini' option 'tool_config_file' with: + +tool_config_file = test/functional/tools/samples_tool_conf.xml diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/functional/tools/for_workflows/cat.xml --- /dev/null +++ b/test/functional/tools/for_workflows/cat.xml @@ -0,0 +1,19 @@ +<tool id="cat" name="Concatenate datasets (for test workflows)"> + <description>tail-to-head</description> + <command> + cat $input1 #for $q in $queries# ${q.input2} #end for# > $out_file1 + </command> + <inputs> + <param name="input1" type="data" label="Concatenate Dataset"/> + <repeat name="queries" title="Dataset"> + <param name="input2" type="data" label="Select" /> + </repeat> + </inputs> + <outputs> + <data name="out_file1" format="input" metadata_source="input1"/> + </outputs> + <tests> + </tests> + <help> + </help> +</tool> diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/functional/tools/for_workflows/cat_list.xml --- /dev/null +++ b/test/functional/tools/for_workflows/cat_list.xml @@ -0,0 +1,16 @@ +<tool id="cat_list" name="Concatenate dataset list (for test workflows)"> + <description>tail-to-head</description> + <command> + cat #for $q in $input1# $q #end for# > $out_file1 + </command> + <inputs> + <param name="input1" type="data" label="Concatenate Dataset" multiple="true" /> + </inputs> + <outputs> + <data name="out_file1" format="input" metadata_source="input1"/> + </outputs> + <tests> + </tests> + <help> + </help> +</tool> diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/functional/tools/for_workflows/head.xml --- /dev/null +++ b/test/functional/tools/for_workflows/head.xml @@ -0,0 +1,13 @@ +<tool id="head" name="Select first"> + <description>lines from a dataset</description> + <command>head $input $lineNum > $out_file1</command> + <inputs> + <param name="lineNum" size="5" type="integer" value="10" label="Select first" help="lines"/> + <param format="txt" name="input" type="data" label="from"/> + </inputs> + <outputs> + <data format="input" name="out_file1" metadata_source="input"/> + </outputs> + <help> + </help> +</tool> diff -r ed215c6af5a08a0e09184555c000e8aaffa5b27b -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 test/functional/tools/samples_tool_conf.xml --- a/test/functional/tools/samples_tool_conf.xml +++ b/test/functional/tools/samples_tool_conf.xml @@ -23,4 +23,10 @@ <tool file="collection_mixed_param.xml" /><tool file="collection_two_paired.xml" /><tool file="collection_optional_param.xml" /> -</toolbox> \ No newline at end of file + + <!-- Tools interesting only for building up test workflows. --> + <tool file="for_workflows/cat.xml" /> + <tool file="for_workflows/cat_list.xml" /> + <tool file="for_workflows/head.xml" /> + +</toolbox> https://bitbucket.org/galaxy/galaxy-central/commits/b7aea7640218/ Changeset: b7aea7640218 User: davebgx Date: 2014-08-28 20:43:55 Summary: Add externally referenced files to the tool tarball. Code cleanup and error checking. Affected #: 2 files diff -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 -r b7aea7640218779f0791730fdc3f37f96295b897 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -740,12 +740,17 @@ tarball_files = [] tool_tup = ( os.path.abspath( tool.config_file ), os.path.split( tool.config_file )[-1] ) tarball_files.append( tool_tup ) + # TODO: This feels hacky. tool_command = tool.command.split( ' ' )[0] tool_path = os.path.dirname( tool_tup[0] ) # Add the tool XML to the tuple that will be used to populate the tarball. if os.path.exists( os.path.join( tool_path, tool_command ) ): tarball_files.append( ( os.path.join( tool_path, tool_command ), tool_command ) ) tests = tool.tests + # Find and add macros and code files. + for external_file in tool.get_externally_referenced_paths( os.path.abspath( tool.config_file ) ): + external_file_abspath = os.path.abspath( os.path.join( tool_path, external_file ) ) + tarball_files.append( ( external_file_abspath, external_file ) ) # Find tests, and check them for test data. if tests is not None: for test in tests: @@ -766,24 +771,31 @@ # Check for tool data table definitions. if hasattr( param, 'options' ): if hasattr( param.options, 'tool_data_table' ): - for fnam in param.options.tool_data_table.filenames: - if not param.options.tool_data_table.filenames[ fnam ][ 'from_shed_config' ]: - tar_file = param.options.tool_data_table.filenames[ fnam ][ 'filename' ] + '.sample' - sample_file = os.path.join( param.options.tool_data_table.filenames[ fnam ][ 'tool_data_path' ], - tar_file ) - # Use the .sample file, if one exists. If not, skip this data table. - if os.path.exists( sample_file ): - tarfile_path, tarfile_name = os.path.split( tar_file ) - tarfile_path = os.path.join( 'tool-data', tarfile_name ) - sample_name = tarfile_path + '.sample' - tarball_files.append( ( sample_file, tarfile_path ) ) - # Put the data table definition XML in a temporary file. - table_definition = '<?xml version="1.0" encoding="utf-8"?>\n<tables>\n %s</tables>' - table_definition = table_definition % param.options.tool_data_table.xml_string - fd, table_conf = tempfile.mkstemp() - os.close( fd ) - file( table_conf, 'w' ).write( table_definition ) - tarball_files.append( ( table_conf, os.path.join( 'tool-data', 'tool_data_table_conf.xml.sample' ) ) ) + data_table = param.options.tool_data_table + if hasattr( data_table, 'filenames' ): + data_table_definitions = [] + for data_table_filename in data_table.filenames: + # FIXME: from_shed_config seems to always be False. + if not data_table.filenames[ data_table_filename ][ 'from_shed_config' ]: + tar_file = data_table.filenames[ data_table_filename ][ 'filename' ] + '.sample' + sample_file = os.path.join( data_table.filenames[ data_table_filename ][ 'tool_data_path' ], + tar_file ) + # Use the .sample file, if one exists. If not, skip this data table. + if os.path.exists( sample_file ): + tarfile_path, tarfile_name = os.path.split( tar_file ) + tarfile_path = os.path.join( 'tool-data', tarfile_name ) + sample_name = tarfile_path + '.sample' + tarball_files.append( ( sample_file, tarfile_path ) ) + data_table_definitions.append( data_table.xml_string ) + if len( data_table_definitions ) > 0: + # Put the data table definition XML in a temporary file. + table_definition = '<?xml version="1.0" encoding="utf-8"?>\n<tables>\n %s</tables>' + table_xml = [ data_table.xml_string for data_table in data_table_definitions ] + table_definition = table_definition % '\n'.join( table_xml ) + fd, table_conf = tempfile.mkstemp() + os.close( fd ) + file( table_conf, 'w' ).write( table_definition ) + tarball_files.append( ( table_conf, os.path.join( 'tool-data', 'tool_data_table_conf.xml.sample' ) ) ) # Create the tarball. fd, tarball_archive = tempfile.mkstemp( suffix='.tgz' ) os.close( fd ) diff -r a765d16b04f17af94ea7eafe5c8c05bb347036f9 -r b7aea7640218779f0791730fdc3f37f96295b897 lib/galaxy/web/base/controllers/admin.py --- a/lib/galaxy/web/base/controllers/admin.py +++ b/lib/galaxy/web/base/controllers/admin.py @@ -75,7 +75,6 @@ os.unlink( tool_tarball ) tarball_path, filename = os.path.split( tool_tarball ) trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s.tgz"' % ( tool_id ) - os.removedirs( tarball_path ) return download_file else: status = 'error' https://bitbucket.org/galaxy/galaxy-central/commits/bb4cfb25378a/ Changeset: bb4cfb25378a User: davebgx Date: 2014-08-28 20:44:29 Summary: Merge with -central tip. Affected #: 12 files diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/mvc/tools/tools-form.js --- a/static/scripts/mvc/tools/tools-form.js +++ b/static/scripts/mvc/tools/tools-form.js @@ -1,8 +1,8 @@ define(['mvc/ui/ui-portlet', 'mvc/ui/ui-misc', 'mvc/citation/citation-model', 'mvc/citation/citation-view', - 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-datasets', 'mvc/tools/tools-section'], + 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-datasets', 'mvc/tools/tools-section', 'mvc/tools/tools-tree'], function(Portlet, Ui, CitationModel, CitationView, - Tools, ToolTemplate, ToolDatasets, ToolSection) { + Tools, ToolTemplate, ToolDatasets, ToolSection, ToolTree) { // create tool model var Model = Backbone.Model.extend({ @@ -29,6 +29,18 @@ id : options.id }); + // creates a tree/json structure from the input form + this.tree = new ToolTree(this); + + // reset field list + this.field_list = {}; + + // reset sequential input definition list + this.inputs_sequential = {}; + + // create data model + this.data = new Backbone.Model(); + // initialize datasets this.datasets = new ToolDatasets({ success: function() { @@ -39,13 +51,6 @@ // initialize tool form _initializeToolForm: function() { - - // reset field list - this.field_list = {}; - - // reset sequential input definition list - this.inputs_sequential = {}; - // fetch model and render form var self = this; this.model.fetch({ @@ -67,6 +72,7 @@ title : 'Execute', floating : 'clear', onclick : function() { + console.log(self.tree.create(self)); } }) } @@ -107,8 +113,25 @@ // append tool section self.portlet.append(self.section.$el); + + // trigger refresh + self.refresh(); } }); + }, + + // refresh + refresh: function() { + // recreate tree structure + this.tree.refresh(); + + // trigger change + for (var id in this.field_list) { + this.field_list[id].trigger('change'); + } + + // log + console.debug('tools-form::refresh() - Recreated tree structure. Refresh.'); } }); diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/mvc/tools/tools-section.js --- a/static/scripts/mvc/tools/tools-section.js +++ b/static/scripts/mvc/tools/tools-section.js @@ -1,4 +1,5 @@ -define(['mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs'], function(Table, Ui, Tabs) { +define(['utils/utils', 'mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs'], + function(Utils, Table, Ui, Tabs) { // create form view var View = Backbone.View.extend({ @@ -13,6 +14,13 @@ // link datasets this.datasets = app.datasets; + // link data model + this.data = app.data; + + // add table class for tr tag + // this assist in transforming the form into a json structure + options.cls_tr = 'form-row'; + // create table this.table = new Table.View(options); @@ -28,98 +36,115 @@ // reset table this.table.delAll(); - // model - var data = new Backbone.Model(); - // load settings elements into table - for (var id in this.inputs) { - this._add(this.inputs[id], data); - } - - // trigger change - for (var id in this.app.field_list) { - this.app.field_list[id].trigger('change'); + for (var i in this.inputs) { + this._add(this.inputs[i], this.data); } }, // add table row - _add: function(inputs_def, data) { + _add: function(input, data) { // link this var self = this; + // clone definition + var input_def = jQuery.extend(true, {}, input); + + // create unique id + input_def.id = Utils.uuid(); + + // add to sequential list of inputs + this.app.inputs_sequential[input_def.id] = input_def; + // identify field type - var type = inputs_def.type; + var type = input_def.type; switch(type) { // conditional field case 'conditional': // add label to input definition root - inputs_def.label = inputs_def.test_param.label; + input_def.label = input_def.test_param.label; - // add id to input definition root - inputs_def.name = inputs_def.test_param.name; + // add value to input definition root + input_def.value = input_def.test_param.value; // build options field - this._addRow('conditional', inputs_def, data); + this._addRow('conditional', input_def, data); // add fields - for (var i in inputs_def.cases) { + for (var i in input_def.cases) { + // create id tag + var sub_section_id = input_def.id + '-section-' + i; + // create sub section var sub_section = new View(this.app, { - inputs : inputs_def.cases[i].inputs, + inputs : input_def.cases[i].inputs, cls : 'ui-table-plain' }); // append sub section this.table.add(''); this.table.add(sub_section.$el); - this.table.append(inputs_def.name + '_formsection_' + i); + this.table.append(sub_section_id); } break; // repeat block case 'repeat': // create tab field var tabs = new Tabs.View({ - title_new : 'Add Group', + title_new : 'Add ' + input_def.title, onnew : function() { + // create id tag + var sub_section_id = input_def.id + '-section-' + Utils.uuid(); + // create sub section var sub_section = new View(self.app, { - inputs : inputs_def.inputs, + inputs : input_def.inputs, cls : 'ui-table-plain' }); - // create id tag - var sub_section_id = inputs_def.name + '_formsection_' + tabs.size(); - // add new tab tabs.add({ id : sub_section_id, - title : 'Repeat', + title : input_def.title, $el : sub_section.$el, ondel : function() { + // delete tab tabs.del(sub_section_id); + + // retitle tabs + tabs.retitle(input_def.title); + + // trigger refresh + self.app.refresh(); } }); + // retitle tabs + tabs.retitle(input_def.title); + // show tab tabs.show(sub_section_id); + + // trigger refresh + self.app.refresh(); } }); // append sub section - this.table.add(inputs_def.title); + this.table.add(''); this.table.add(tabs.$el); - this.table.append(inputs_def.name); + this.table.append(input_def.id); break; // default single element row default: - this._addRow(type, inputs_def, data); + this._addRow(type, input_def, data); } }, // add table row - _addRow: function(field_type, inputs_def, data) { + _addRow: function(field_type, input_def, data) { // get id - var id = inputs_def.name; + var id = input_def.id; // field wrapper var field = null; @@ -128,37 +153,42 @@ switch(field_type) { // text input field case 'text' : - field = this._field_text(inputs_def, data); + field = this._field_text(input_def, data); break; // select field case 'select' : - field = this._field_select(inputs_def, data); + field = this._field_select(input_def, data); break; // radiobox field case 'radiobutton' : - field = this._field_radio(inputs_def, data); + field = this._field_radio(input_def, data); break; // dataset case 'data': - field = this._field_data(inputs_def, data); + field = this._field_data(input_def, data); break; // dataset column case 'data_column': - field = this._field_column(inputs_def, data); + field = this._field_column(input_def, data); break; // text area field case 'textarea' : - field = this._field_textarea(inputs_def, data); + field = this._field_textarea(input_def, data); break; // conditional select field case 'conditional': - field = this._field_conditional(inputs_def, data); + field = this._field_conditional(input_def, data); + break; + + // hidden field + case 'hidden': + field = this._field_hidden(input_def, data); break; } @@ -170,68 +200,37 @@ // set value if (!data.get(id)) { - data.set(id, inputs_def.value); + data.set(id, input_def.value); } field.value(data.get(id)); // add to field list this.app.field_list[id] = field; - // add to input definition into sequential list - this.app.inputs_sequential[id] = inputs_def; - // combine field and info var $input = $('<div/>'); $input.append(field.$el); - if (inputs_def.help) { - $input.append('<div class="ui-table-form-info">' + inputs_def.help + '</div>'); + if (input_def.help) { + $input.append('<div class="ui-table-form-info">' + input_def.help + '</div>'); } - // add row to table - this.table.add('<span class="ui-table-form-title">' + inputs_def.label + '</span>', '25%'); + // create table row + this.table.add('<span class="ui-table-form-title">' + input_def.label + '</span>', '25%'); this.table.add($input); - // add to table + // append to table this.table.append(id); - - // show/hide - if (inputs_def.hide) { - this.table.get(id).hide(); - } - }, - - // text input field - _field_text : function(inputs_def, data) { - var id = inputs_def.name; - return new Ui.Input({ - id : 'field-' + id, - value : data.get(id), - onchange : function(value) { - data.set(id, value); - } - }); - }, - - // text area - _field_textarea : function(inputs_def, data) { - var id = inputs_def.name; - return new Ui.Textarea({ - id : 'field-' + id, - onchange : function() { - data.set(id, field.value()); - } - }); }, // conditional input field - _field_conditional : function(inputs_def, data) { + _field_conditional : function(input_def, data) { // link this var self = this; // configure options fields var options = []; - for (var i in inputs_def.test_param.options) { - var option = inputs_def.test_param.options[i]; + for (var i in input_def.test_param.options) { + var option = input_def.test_param.options[i]; options.push({ label: option[0], value: option[1] @@ -239,7 +238,7 @@ } // select field - var id = inputs_def.name; + var id = input_def.id; return new Ui.Select.View({ id : 'field-' + id, data : options, @@ -249,19 +248,29 @@ data.set(id, value); // check value in order to hide/show options - for (var i in inputs_def.cases) { + for (var i in input_def.cases) { // get case - var case_def = inputs_def.cases[i]; + var case_def = input_def.cases[i]; // identify subsection name - var section_id = inputs_def.name + '_formsection_' + i; - + var section_id = input_def.id + '-section-' + i; + // identify row var section_row = self.table.get(section_id); - // check - if (case_def.value == value) { - section_row.show(); + // check if non-hidden elements exist + var nonhidden = false; + for (var j in case_def.inputs) { + var type = case_def.inputs[j].type; + if (type && type !== 'hidden') { + nonhidden = true; + break; + } + } + + // show/hide sub form + if (case_def.value == value && nonhidden) { + section_row.fadeIn('fast'); } else { section_row.hide(); } @@ -271,12 +280,12 @@ }, // data input field - _field_data : function(inputs_def, data) { + _field_data : function(input_def, data) { // link this var self = this; // get element id - var id = inputs_def.name; + var id = input_def.id; // get datasets var datasets = this.datasets.filterType(); @@ -299,11 +308,8 @@ // update value data.set(id, value); - // find referenced columns - var column_list = _.where(self.app.inputs_sequential, { - data_ref : id, - type : 'data_column' - }); + // get referenced columns + var column_list = self.app.tree.findReferences(id); // find selected dataset var dataset = self.datasets.filter(value); @@ -333,7 +339,7 @@ // update referenced columns for (var i in column_list) { - var column_field = self.app.field_list[column_list[i].name] + var column_field = self.app.field_list[column_list[i]] if (column_field) { column_field.update(columns); column_field.value(column_field.first()); @@ -348,8 +354,8 @@ }, // column selection field - _field_column : function (inputs_def, data) { - var id = inputs_def.name; + _field_column : function (input_def, data) { + var id = input_def.id; return new Ui.Select.View({ id : 'field-' + id, value : data.get(id), @@ -360,11 +366,11 @@ }, // select field - _field_select : function (inputs_def, data) { + _field_select : function (input_def, data) { // configure options fields var options = []; - for (var i in inputs_def.options) { - var option = inputs_def.options[i]; + for (var i in input_def.options) { + var option = input_def.options[i]; options.push({ label: option[0], value: option[1] @@ -373,12 +379,12 @@ // identify display type var SelectClass = Ui.Select; - if (inputs_def.display == 'checkboxes') { + if (input_def.display == 'checkboxes') { SelectClass = Ui.Checkbox; } // select field - var id = inputs_def.name; + var id = input_def.id; return new SelectClass.View({ id : 'field-' + id, data : options, @@ -389,17 +395,49 @@ }); }, - // radio field - _field_radio : function(inputs_def, data) { - var id = inputs_def.name; - return new Ui.RadioButton({ + // text input field + _field_text : function(input_def, data) { + var id = input_def.id; + return new Ui.Input({ id : 'field-' + id, - data : inputs_def.data, value : data.get(id), onchange : function(value) { data.set(id, value); } }); + }, + + // text area + _field_textarea : function(input_def, data) { + var id = input_def.id; + return new Ui.Textarea({ + id : 'field-' + id, + onchange : function() { + data.set(id, field.value()); + } + }); + }, + + // radio field + _field_radio : function(input_def, data) { + var id = input_def.id; + return new Ui.RadioButton({ + id : 'field-' + id, + data : input_def.data, + value : data.get(id), + onchange : function(value) { + data.set(id, value); + } + }); + }, + + // hidden field + _field_hidden : function(input_def, data) { + var id = input_def.id; + return new Ui.Hidden({ + id : 'field-' + id, + value : data.get(id) + }); } }); diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/mvc/tools/tools-tree.js --- /dev/null +++ b/static/scripts/mvc/tools/tools-tree.js @@ -0,0 +1,135 @@ +// dependencies +define([], function() { + +// tool form tree +return Backbone.Model.extend({ + // initialize + initialize: function(app) { + // link app + this.app = app; + }, + + // creates tree structure + refresh: function() { + // check if section is available + if (!this.app.section) { + return {}; + } + + // create dictionary + this.dict = {}; + + // create xml object + this.xml = $('<div/>'); + + // fill dictionary + this._iterate(this.app.section.$el, this.dict, this.xml); + }, + + // iterate + _iterate: function(parent, dict, xml) { + // get child nodes + var self = this; + var children = $(parent).children(); + children.each(function() { + // get child element + var child = this; + + // get id + var id = $(child).attr('id'); + + // create new branch + if ($(child).hasClass('form-row') || $(child).hasClass('tab-pane')) { + // create sub dictionary + dict[id] = {}; + + // add input element if it exists + var input = self.app.inputs_sequential[id]; + if (input) { + dict[id] = { + input : input + } + } + + // create xml element + var $el = $('<div id="' + id + '"/>'); + + // append xml + xml.append($el); + + // fill sub dictionary + self._iterate(child, dict[id], $el); + } else { + self._iterate(child, dict, xml); + } + }); + }, + + // find referenced elements + findReferences: function(identifier) { + // referenced elements + var referenced = []; + + // link this + var self = this; + + // iterate + function search (name, parent) { + // get child nodes + var children = $(parent).children(); + + // create sublist + var list = []; + + // verify that hierachy level is referenced to identifier + children.each(function() { + // get child element + var child = this; + + // get id + var id = $(child).attr('id'); + + // skip + if (id !== identifier) { + // get input element + var input = self.app.inputs_sequential[id]; + if (input) { + // check for new reference definition + if (input.name == name) { + // stop iteration + return; + } + + // check for referenced element + if (input.data_ref == name) { + list.push(id); + } + } + } + }); + + // merge temporary list with result + referenced = referenced.concat(list); + + // continue iteration + children.each(function() { + search(identifier, this); + }); + } + + // get initial node + var node = this.xml.find('#' + identifier); + if (node.length > 0) { + // get parent input element + var input = self.app.inputs_sequential[identifier]; + if (input) { + search(input.name, node.parent()); + } + } + + // return + return referenced; + } +}); + +}); \ No newline at end of file diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/mvc/ui/ui-misc.js --- a/static/scripts/mvc/ui/ui-misc.js +++ b/static/scripts/mvc/ui/ui-misc.js @@ -409,6 +409,35 @@ } }); +// plugin +var Hidden = Backbone.View.extend({ + // options + optionsDefault: { + value : '' + }, + + // initialize + initialize : function(options) { + // configure options + this.options = Utils.merge(options, this.optionsDefault); + + // create new element + this.setElement(this._template(this.options)); + }, + + // value + value : function (new_val) { + if (new_val !== undefined) { + this.$el.val(new_val); + } + return this.$el.val(); + }, + + // element + _template: function(options) { + return '<hidden id="' + options.id + '" value="' + options.value + '"/>'; + } +}); // return return { @@ -426,6 +455,7 @@ Checkbox : Checkbox, Searchbox : Searchbox, Select : Select, - Textarea : Textarea + Textarea : Textarea, + Hidden : Hidden } }); diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/mvc/ui/ui-table.js --- a/static/scripts/mvc/ui/ui-table.js +++ b/static/scripts/mvc/ui/ui-table.js @@ -17,7 +17,8 @@ onchange : null, ondblclick : null, onconfirm : null, - cls : 'ui-table' + cls : 'ui-table', + cls_tr : '' }, // events @@ -43,7 +44,7 @@ this.setElement($el); // initialize row - this.row = $('<tr></tr>'); + this.row = this._row(); }, // add header cell @@ -156,13 +157,18 @@ } // row - this.row = $('<tr></tr>'); + this.row = this._row(); // row count this.row_count++; this._refresh(); }, + // create new row + _row: function() { + return $('<tr class="' + this.options.cls_tr + '"></tr>'); + }, + // onclick _onclick: function(e) { // get values diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/mvc/ui/ui-tabs.js --- a/static/scripts/mvc/ui/ui-tabs.js +++ b/static/scripts/mvc/ui/ui-tabs.js @@ -132,7 +132,7 @@ del: function(id) { // delete tab from dom this.$el.find('#tab-' + id).remove(); - this.$el.find('#tab-content-' + id).remove(); + this.$el.find('#' + id).remove(); // check if first tab has been deleted if (this.first_tab == id) { @@ -143,14 +143,17 @@ if (this.first_tab != null) { this.show(this.first_tab); } + + // delete from list + if (this.list[id]) { + delete this.list[id]; + } }, // delete tab delRemovable: function() { for (var id in this.list) { - if (this.list[id]) { - this.del(id); - } + this.del(id); } }, @@ -165,7 +168,7 @@ this.$el.find('.tab-element').removeClass('active'); this.$el.find('.tab-pane').removeClass('active'); this.$el.find('#tab-' + id).addClass('active'); - this.$el.find('#tab-content-' + id).addClass('active'); + this.$el.find('#' + id).addClass('active'); } }, @@ -201,6 +204,14 @@ return $el.html(); }, + // retitle + retitle: function(new_title) { + var index = 0; + for (var id in this.list) { + this.title(id, ++index + ': ' + new_title); + } + }, + // fill template _template: function(options) { return '<div class="ui-tabs tabbable tabs-left">' + @@ -224,8 +235,8 @@ // fill template tab _template_tab: function(options) { var tmpl = '<li id="tab-' + options.id + '" class="tab-element">' + - '<a id="tab-title-link-' + options.id + '" title="" href="#tab-content-' + options.id + '" data-original-title="">' + - '<span id="tab-title-text-' + options.id + '">' + options.title + '</span>'; + '<a id="tab-title-link-' + options.id + '" title="" href="#' + options.id + '" data-original-title="">' + + '<span id="tab-title-text-' + options.id + '" class="tab-title-text">' + options.title + '</span>'; if (options.ondel) { tmpl += '<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'; @@ -239,7 +250,7 @@ // fill template tab content _template_tab_content: function(options) { - return '<div id="tab-content-' + options.id + '" class="tab-pane"/>'; + return '<div id="' + options.id + '" class="tab-pane"/>'; } }); diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/packed/mvc/tools/tools-form.js --- a/static/scripts/packed/mvc/tools/tools-form.js +++ b/static/scripts/packed/mvc/tools/tools-form.js @@ -1,1 +1,1 @@ -define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section"],function(f,j,h,a,e,c,g,i){var d=Backbone.Model.extend({initialize:function(k){this.url=galaxy_config.root+"api/tools/"+k.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(l){var k=this;this.options=l;this.model=new d({id:l.id});this.datasets=new g({success:function(){k._initializeToolForm()}})},_initializeToolForm:function(){this.field_list={};this.inputs_sequential={};var k=this;this.model.fetch({error:function(l){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){k.inputs=k.model.get("inputs");k.portlet=new f.View({icon:"fa-wrench",title:"<b>"+k.model.get("name")+"</b> "+k.model.get("description"),buttons:{execute:new j.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){}})}});k.message=new j.Message();k.portlet.append(k.message.$el);$(k.main_el).append(k.portlet.$el);if(k.options.help!=""){$(k.main_el).append(c.help(k.options.help))}if(k.options.citations){$(k.main_el).append(c.citations());var l=new h.ToolCitationCollection();l.tool_id=k.options.id;var m=new a.CitationListView({collection:l});m.render();l.fetch()}k.setElement(k.portlet.content());k.section=new i.View(k,{inputs:k.model.get("inputs")});k.portlet.append(k.section.$el)}})}});return{View:b}}); \ No newline at end of file +define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree"],function(g,k,i,a,f,d,h,j,c){var e=Backbone.Model.extend({initialize:function(l){this.url=galaxy_config.root+"api/tools/"+l.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(m){var l=this;this.options=m;this.model=new e({id:m.id});this.tree=new c(this);this.field_list={};this.inputs_sequential={};this.data=new Backbone.Model();this.datasets=new h({success:function(){l._initializeToolForm()}})},_initializeToolForm:function(){var l=this;this.model.fetch({error:function(m){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){l.inputs=l.model.get("inputs");l.portlet=new g.View({icon:"fa-wrench",title:"<b>"+l.model.get("name")+"</b> "+l.model.get("description"),buttons:{execute:new k.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){console.log(l.tree.create(l))}})}});l.message=new k.Message();l.portlet.append(l.message.$el);$(l.main_el).append(l.portlet.$el);if(l.options.help!=""){$(l.main_el).append(d.help(l.options.help))}if(l.options.citations){$(l.main_el).append(d.citations());var m=new i.ToolCitationCollection();m.tool_id=l.options.id;var n=new a.CitationListView({collection:m});n.render();m.fetch()}l.setElement(l.portlet.content());l.section=new j.View(l,{inputs:l.model.get("inputs")});l.portlet.append(l.section.$el);l.refresh()}})},refresh:function(){this.tree.refresh();for(var l in this.field_list){this.field_list[l].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")}});return{View:b}}); \ No newline at end of file diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/packed/mvc/tools/tools-section.js --- a/static/scripts/packed/mvc/tools/tools-section.js +++ b/static/scripts/packed/mvc/tools/tools-section.js @@ -1,1 +1,1 @@ -define(["mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-tabs"],function(b,d,a){var c=Backbone.View.extend({initialize:function(f,e){this.app=f;this.inputs=e.inputs;this.datasets=f.datasets;this.table=new b.View(e);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();var e=new Backbone.Model();for(var f in this.inputs){this._add(this.inputs[f],e)}for(var f in this.app.field_list){this.app.field_list[f].trigger("change")}},_add:function(f,k){var e=this;var j=f.type;switch(j){case"conditional":f.label=f.test_param.label;f.name=f.test_param.name;this._addRow("conditional",f,k);for(var h in f.cases){var l=new c(this.app,{inputs:f.cases[h].inputs,cls:"ui-table-plain"});this.table.add("");this.table.add(l.$el);this.table.append(f.name+"_formsection_"+h)}break;case"repeat":var g=new a.View({title_new:"Add Group",onnew:function(){var m=new c(e.app,{inputs:f.inputs,cls:"ui-table-plain"});var i=f.name+"_formsection_"+g.size();g.add({id:i,title:"Repeat",$el:m.$el,ondel:function(){g.del(i)}});g.show(i)}});this.table.add(f.title);this.table.add(g.$el);this.table.append(f.name);break;default:this._addRow(j,f,k)}},_addRow:function(h,e,f){var j=e.name;var g=null;switch(h){case"text":g=this._field_text(e,f);break;case"select":g=this._field_select(e,f);break;case"radiobutton":g=this._field_radio(e,f);break;case"data":g=this._field_data(e,f);break;case"data_column":g=this._field_column(e,f);break;case"textarea":g=this._field_textarea(e,f);break;case"conditional":g=this._field_conditional(e,f);break}if(!g){console.debug("tools-form::_addRow() : Unmatched field type ("+h+").");return}if(!f.get(j)){f.set(j,e.value)}g.value(f.get(j));this.app.field_list[j]=g;this.app.inputs_sequential[j]=e;var i=$("<div/>");i.append(g.$el);if(e.help){i.append('<div class="ui-table-form-info">'+e.help+"</div>")}this.table.add('<span class="ui-table-form-title">'+e.label+"</span>","25%");this.table.add(i);this.table.append(j);if(e.hide){this.table.get(j).hide()}},_field_text:function(e,f){var g=e.name;return new d.Input({id:"field-"+g,value:f.get(g),onchange:function(h){f.set(g,h)}})},_field_textarea:function(e,f){var g=e.name;return new d.Textarea({id:"field-"+g,onchange:function(){f.set(g,field.value())}})},_field_conditional:function(g,k){var e=this;var f=[];for(var h in g.test_param.options){var j=g.test_param.options[h];f.push({label:j[0],value:j[1]})}var l=g.name;return new d.Select.View({id:"field-"+l,data:f,value:k.get(l),onchange:function(q){k.set(l,q);for(var p in g.cases){var n=g.cases[p];var o=g.name+"_formsection_"+p;var m=e.table.get(o);if(n.value==q){m.show()}else{m.hide()}}}})},_field_data:function(g,k){var e=this;var l=g.name;var j=this.datasets.filterType();var f=[];for(var h in j){f.push({label:j[h].get("name"),value:j[h].get("id")})}return new d.Select.View({id:"field-"+l,data:f,value:f[0].value,onchange:function(r){k.set(l,r);var n=_.where(e.app.inputs_sequential,{data_ref:l,type:"data_column"});var t=e.datasets.filter(r);if(t&&n.length>0){console.debug("tool-form::field_data() - Selected dataset "+r+".");var s=t.get("metadata_column_types");if(!s){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+r+".")}var q=[];for(var p in s){q.push({label:"Column: "+(parseInt(p)+1)+" ["+s[p]+"]",value:p})}for(var o in n){var m=e.app.field_list[n[o].name];if(m){m.update(q);m.value(m.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+r+".")}}})},_field_column:function(e,f){var g=e.name;return new d.Select.View({id:"field-"+g,value:f.get(g),onchange:function(h){f.set(g,h)}})},_field_select:function(f,k){var e=[];for(var g in f.options){var h=f.options[g];e.push({label:h[0],value:h[1]})}var j=d.Select;if(f.display=="checkboxes"){j=d.Checkbox}var l=f.name;return new j.View({id:"field-"+l,data:e,value:k.get(l),onchange:function(i){k.set(l,i)}})},_field_radio:function(e,f){var g=e.name;return new d.RadioButton({id:"field-"+g,data:e.data,value:f.get(g),onchange:function(h){f.set(g,h)}})}});return{View:c}}); \ No newline at end of file +define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-tabs"],function(c,b,e,a){var d=Backbone.View.extend({initialize:function(g,f){this.app=g;this.inputs=f.inputs;this.datasets=g.datasets;this.data=g.data;f.cls_tr="form-row";this.table=new b.View(f);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var f in this.inputs){this._add(this.inputs[f],this.data)}},_add:function(n,h){var o=this;var k=jQuery.extend(true,{},n);k.id=c.uuid();this.app.inputs_sequential[k.id]=k;var l=k.type;switch(l){case"conditional":k.label=k.test_param.label;k.value=k.test_param.value;this._addRow("conditional",k,h);for(var j in k.cases){var g=k.id+"-section-"+j;var f=new d(this.app,{inputs:k.cases[j].inputs,cls:"ui-table-plain"});this.table.add("");this.table.add(f.$el);this.table.append(g)}break;case"repeat":var m=new a.View({title_new:"Add "+k.title,onnew:function(){var i=k.id+"-section-"+c.uuid();var p=new d(o.app,{inputs:k.inputs,cls:"ui-table-plain"});m.add({id:i,title:k.title,$el:p.$el,ondel:function(){m.del(i);m.retitle(k.title);o.app.refresh()}});m.retitle(k.title);m.show(i);o.app.refresh()}});this.table.add("");this.table.add(m.$el);this.table.append(k.id);break;default:this._addRow(l,k,h)}},_addRow:function(i,f,g){var k=f.id;var h=null;switch(i){case"text":h=this._field_text(f,g);break;case"select":h=this._field_select(f,g);break;case"radiobutton":h=this._field_radio(f,g);break;case"data":h=this._field_data(f,g);break;case"data_column":h=this._field_column(f,g);break;case"textarea":h=this._field_textarea(f,g);break;case"conditional":h=this._field_conditional(f,g);break;case"hidden":h=this._field_hidden(f,g);break}if(!h){console.debug("tools-form::_addRow() : Unmatched field type ("+i+").");return}if(!g.get(k)){g.set(k,f.value)}h.value(g.get(k));this.app.field_list[k]=h;var j=$("<div/>");j.append(h.$el);if(f.help){j.append('<div class="ui-table-form-info">'+f.help+"</div>")}this.table.add('<span class="ui-table-form-title">'+f.label+"</span>","25%");this.table.add(j);this.table.append(k)},_field_conditional:function(f,l){var g=this;var h=[];for(var j in f.test_param.options){var k=f.test_param.options[j];h.push({label:k[0],value:k[1]})}var m=f.id;return new e.Select.View({id:"field-"+m,data:h,value:l.get(m),onchange:function(u){l.set(m,u);for(var s in f.cases){var o=f.cases[s];var r=f.id+"-section-"+s;var n=g.table.get(r);var q=false;for(var p in o.inputs){var t=o.inputs[p].type;if(t&&t!=="hidden"){q=true;break}}if(o.value==u&&q){n.fadeIn("fast")}else{n.hide()}}}})},_field_data:function(f,l){var g=this;var m=f.id;var k=this.datasets.filterType();var h=[];for(var j in k){h.push({label:k[j].get("name"),value:k[j].get("id")})}return new e.Select.View({id:"field-"+m,data:h,value:h[0].value,onchange:function(s){l.set(m,s);var o=g.app.tree.findReferences(m);var u=g.datasets.filter(s);if(u&&o.length>0){console.debug("tool-form::field_data() - Selected dataset "+s+".");var t=u.get("metadata_column_types");if(!t){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+s+".")}var r=[];for(var q in t){r.push({label:"Column: "+(parseInt(q)+1)+" ["+t[q]+"]",value:q})}for(var p in o){var n=g.app.field_list[o[p]];if(n){n.update(r);n.value(n.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+s+".")}}})},_field_column:function(f,g){var h=f.id;return new e.Select.View({id:"field-"+h,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_select:function(f,l){var g=[];for(var h in f.options){var j=f.options[h];g.push({label:j[0],value:j[1]})}var k=e.Select;if(f.display=="checkboxes"){k=e.Checkbox}var m=f.id;return new k.View({id:"field-"+m,data:g,value:l.get(m),onchange:function(i){l.set(m,i)}})},_field_text:function(f,g){var h=f.id;return new e.Input({id:"field-"+h,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_textarea:function(f,g){var h=f.id;return new e.Textarea({id:"field-"+h,onchange:function(){g.set(h,field.value())}})},_field_radio:function(f,g){var h=f.id;return new e.RadioButton({id:"field-"+h,data:f.data,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_hidden:function(f,g){var h=f.id;return new e.Hidden({id:"field-"+h,value:g.get(h)})}});return{View:d}}); \ No newline at end of file diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/packed/mvc/tools/tools-tree.js --- /dev/null +++ b/static/scripts/packed/mvc/tools/tools-tree.js @@ -0,0 +1,1 @@ +define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){if(!this.app.section){return{}}this.dict={};this.xml=$("<div/>");this._iterate(this.app.section.$el,this.dict,this.xml)},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("form-row")||$(i).hasClass("tab-pane")){e[h]={};var f=a.app.inputs_sequential[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})},findReferences:function(c){var f=[];var b=this;function d(g,i){var h=$(i).children();var j=[];h.each(function(){var m=this;var l=$(m).attr("id");if(l!==c){var k=b.app.inputs_sequential[l];if(k){if(k.name==g){return}if(k.data_ref==g){j.push(l)}}}});f=f.concat(j);h.each(function(){d(c,this)})}var e=this.xml.find("#"+c);if(e.length>0){var a=b.app.inputs_sequential[c];if(a){d(a.name,e.parent())}}return f}})}); \ No newline at end of file diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/packed/mvc/ui/ui-misc.js --- a/static/scripts/packed/mvc/ui/ui-misc.js +++ b/static/scripts/packed/mvc/ui/ui-misc.js @@ -1,1 +1,1 @@ -define(["utils/utils","mvc/ui/ui-select-default","mvc/ui/ui-checkbox","mvc/ui/ui-radiobutton","mvc/ui/ui-button-menu","mvc/ui/ui-modal"],function(l,b,e,m,p,n){var d=Backbone.View.extend({optionsDefault:{url:"",cls:""},initialize:function(q){this.options=l.merge(q,this.optionsDefault);this.setElement(this._template(this.options))},_template:function(q){return'<img class="ui-image '+q.cls+'" src="'+q.url+'"/>'}});var k=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(q){this.options=l.merge(q,this.optionsDefault);this.setElement(this._template(this.options))},title:function(q){this.$el.html(q)},_template:function(q){return'<label class="ui-label '+q.cls+'">'+q.title+"</label>"},value:function(){return options.title}});var c=Backbone.View.extend({optionsDefault:{floating:"right",icon:"",tooltip:"",placement:"bottom",title:"",cls:""},initialize:function(q){this.options=l.merge(q,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).tooltip({title:q.tooltip,placement:"bottom"})},_template:function(q){return'<div><span class="fa '+q.icon+'" class="ui-icon"/> '+q.title+"</div>"}});var g=Backbone.View.extend({optionsDefault:{id:null,title:"",floating:"right",cls:"btn btn-default",icon:""},initialize:function(q){this.options=l.merge(q,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",q.onclick);$(this.el).tooltip({title:q.tooltip,placement:"bottom"})},_template:function(q){var r='<button id="'+q.id+'" type="submit" style="float: '+q.floating+';" type="button" class="ui-button '+q.cls+'">';if(q.icon){r+='<i class="icon fa '+q.icon+'"></i> '}r+=q.title+"</button>";return r}});var h=Backbone.View.extend({optionsDefault:{id:null,title:"",floating:"right",cls:"icon-btn",icon:"",tooltip:"",onclick:null},initialize:function(q){this.options=l.merge(q,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",q.onclick);$(this.el).tooltip({title:q.tooltip,placement:"bottom"})},_template:function(q){var r="";if(q.title){r="width: auto;"}var s='<div id="'+q.id+'" style="float: '+q.floating+"; "+r+'" class="ui-button-icon '+q.cls+'">';if(q.title){s+='<div class="button"><i class="icon fa '+q.icon+'"/> <span class="title">'+q.title+"</span></div>"}else{s+='<i class="icon fa '+q.icon+'"/>'}s+="</div>";return s}});var f=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(q){this.options=l.merge(q,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",q.onclick)},_template:function(q){return'<div><a href="javascript:void(0)" class="ui-anchor '+q.cls+'">'+q.title+"</a></div>"}});var o=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:false},initialize:function(q){this.options=l.merge(q,this.optionsDefault);this.setElement("<div></div>")},update:function(r){this.options=l.merge(r,this.optionsDefault);if(r.message!=""){this.$el.html(this._template(this.options));this.$el.find(".alert").append(r.message);this.$el.fadeIn();if(!r.persistent){var q=this;window.setTimeout(function(){if(q.$el.is(":visible")){q.$el.fadeOut()}else{q.$el.hide()}},3000)}}else{this.$el.fadeOut()}},_template:function(q){return'<div class="ui-message alert alert-'+q.status+'"/>'}});var a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options));var q=this;if(this.options.onclick){this.$el.on("submit",function(t){var s=q.$el.find("#search");q.options.onclick(s.val())})}},_template:function(q){return'<div class="ui-search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+q.searchword+'"><button type="submit" class="btn search-btn"><i class="fa fa-search"></i></button></form></div>'}});var j=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:false,visible:true,cls:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options));if(this.options.disabled){this.$el.prop("disabled",true)}if(!this.options.visible){this.$el.hide()}var q=this;this.$el.on("input",function(){if(q.options.onchange){q.options.onchange(q.$el.val())}})},value:function(q){if(q!==undefined){this.$el.val(q)}return this.$el.val()},_template:function(q){return'<input id="'+q.id+'" type="'+q.type+'" value="'+q.value+'" placeholder="'+q.placeholder+'" class="ui-input '+q.cls+'">'}});var i=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:false,visible:true,cls:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options));if(this.options.disabled){this.$el.prop("disabled",true)}if(!this.options.visible){this.$el.hide()}var q=this;this.$el.on("input",function(){if(q.options.onchange){q.options.onchange(q.$el.val())}})},value:function(q){if(q!==undefined){this.$el.val(q)}return this.$el.val()},_template:function(q){return'<textarea id="'+q.id+'" class="ui-textarea '+q.cls+'" rows="5"></textarea>'}});return{Anchor:f,Button:g,ButtonIcon:h,ButtonMenu:p,Icon:c,Image:d,Input:j,Label:k,Message:o,Modal:n,RadioButton:m,Checkbox:e,Searchbox:a,Select:b,Textarea:i}}); \ No newline at end of file +define(["utils/utils","mvc/ui/ui-select-default","mvc/ui/ui-checkbox","mvc/ui/ui-radiobutton","mvc/ui/ui-button-menu","mvc/ui/ui-modal"],function(l,b,e,m,q,n){var d=Backbone.View.extend({optionsDefault:{url:"",cls:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options))},_template:function(r){return'<img class="ui-image '+r.cls+'" src="'+r.url+'"/>'}});var k=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options))},title:function(r){this.$el.html(r)},_template:function(r){return'<label class="ui-label '+r.cls+'">'+r.title+"</label>"},value:function(){return options.title}});var c=Backbone.View.extend({optionsDefault:{floating:"right",icon:"",tooltip:"",placement:"bottom",title:"",cls:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).tooltip({title:r.tooltip,placement:"bottom"})},_template:function(r){return'<div><span class="fa '+r.icon+'" class="ui-icon"/> '+r.title+"</div>"}});var g=Backbone.View.extend({optionsDefault:{id:null,title:"",floating:"right",cls:"btn btn-default",icon:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",r.onclick);$(this.el).tooltip({title:r.tooltip,placement:"bottom"})},_template:function(r){var s='<button id="'+r.id+'" type="submit" style="float: '+r.floating+';" type="button" class="ui-button '+r.cls+'">';if(r.icon){s+='<i class="icon fa '+r.icon+'"></i> '}s+=r.title+"</button>";return s}});var h=Backbone.View.extend({optionsDefault:{id:null,title:"",floating:"right",cls:"icon-btn",icon:"",tooltip:"",onclick:null},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",r.onclick);$(this.el).tooltip({title:r.tooltip,placement:"bottom"})},_template:function(r){var s="";if(r.title){s="width: auto;"}var t='<div id="'+r.id+'" style="float: '+r.floating+"; "+s+'" class="ui-button-icon '+r.cls+'">';if(r.title){t+='<div class="button"><i class="icon fa '+r.icon+'"/> <span class="title">'+r.title+"</span></div>"}else{t+='<i class="icon fa '+r.icon+'"/>'}t+="</div>";return t}});var f=Backbone.View.extend({optionsDefault:{title:"",cls:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options));$(this.el).on("click",r.onclick)},_template:function(r){return'<div><a href="javascript:void(0)" class="ui-anchor '+r.cls+'">'+r.title+"</a></div>"}});var o=Backbone.View.extend({optionsDefault:{message:"",status:"info",persistent:false},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement("<div></div>")},update:function(s){this.options=l.merge(s,this.optionsDefault);if(s.message!=""){this.$el.html(this._template(this.options));this.$el.find(".alert").append(s.message);this.$el.fadeIn();if(!s.persistent){var r=this;window.setTimeout(function(){if(r.$el.is(":visible")){r.$el.fadeOut()}else{r.$el.hide()}},3000)}}else{this.$el.fadeOut()}},_template:function(r){return'<div class="ui-message alert alert-'+r.status+'"/>'}});var a=Backbone.View.extend({optionsDefault:{onclick:null,searchword:""},initialize:function(s){this.options=l.merge(s,this.optionsDefault);this.setElement(this._template(this.options));var r=this;if(this.options.onclick){this.$el.on("submit",function(u){var t=r.$el.find("#search");r.options.onclick(t.val())})}},_template:function(r){return'<div class="ui-search"><form onsubmit="return false;"><input id="search" class="form-control input-sm" type="text" name="search" placeholder="Search..." value="'+r.searchword+'"><button type="submit" class="btn search-btn"><i class="fa fa-search"></i></button></form></div>'}});var j=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:false,visible:true,cls:""},initialize:function(s){this.options=l.merge(s,this.optionsDefault);this.setElement(this._template(this.options));if(this.options.disabled){this.$el.prop("disabled",true)}if(!this.options.visible){this.$el.hide()}var r=this;this.$el.on("input",function(){if(r.options.onchange){r.options.onchange(r.$el.val())}})},value:function(r){if(r!==undefined){this.$el.val(r)}return this.$el.val()},_template:function(r){return'<input id="'+r.id+'" type="'+r.type+'" value="'+r.value+'" placeholder="'+r.placeholder+'" class="ui-input '+r.cls+'">'}});var i=Backbone.View.extend({optionsDefault:{value:"",type:"text",placeholder:"",disabled:false,visible:true,cls:""},initialize:function(s){this.options=l.merge(s,this.optionsDefault);this.setElement(this._template(this.options));if(this.options.disabled){this.$el.prop("disabled",true)}if(!this.options.visible){this.$el.hide()}var r=this;this.$el.on("input",function(){if(r.options.onchange){r.options.onchange(r.$el.val())}})},value:function(r){if(r!==undefined){this.$el.val(r)}return this.$el.val()},_template:function(r){return'<textarea id="'+r.id+'" class="ui-textarea '+r.cls+'" rows="5"></textarea>'}});var p=Backbone.View.extend({optionsDefault:{value:""},initialize:function(r){this.options=l.merge(r,this.optionsDefault);this.setElement(this._template(this.options))},value:function(r){if(r!==undefined){this.$el.val(r)}return this.$el.val()},_template:function(r){return'<hidden id="'+r.id+'" value="'+r.value+'"/>'}});return{Anchor:f,Button:g,ButtonIcon:h,ButtonMenu:q,Icon:c,Image:d,Input:j,Label:k,Message:o,Modal:n,RadioButton:m,Checkbox:e,Searchbox:a,Select:b,Textarea:i,Hidden:p}}); \ No newline at end of file diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/packed/mvc/ui/ui-table.js --- a/static/scripts/packed/mvc/ui/ui-table.js +++ b/static/scripts/packed/mvc/ui/ui-table.js @@ -1,1 +1,1 @@ -define(["utils/utils"],function(a){var b=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null,cls:"ui-table"},events:{click:"_onclick",dblclick:"_ondblclick"},initialize:function(c){this.options=a.merge(c,this.optionsDefault);var d=$(this._template(this.options));this.$thead=d.find("thead");this.$tbody=d.find("tbody");this.$tmessage=d.find("tmessage");this.setElement(d);this.row=$("<tr></tr>")},addHeader:function(c){var d=$("<th></th>");d.append(c);this.row.append(d)},appendHeader:function(){this.$thead.append(this.row);this.row=$("<tr></tr>")},add:function(c,d,f){var e=$("<td></td>");if(d){e.css("width",d)}if(f){e.css("text-align",f)}e.append(c);this.row.append(e)},append:function(c){this._commit(c)},prepend:function(c){this._commit(c,true)},get:function(c){return this.$el.find("#"+c)},del:function(d){var c=this.$tbody.find("#"+d);if(c.length>0){c.remove();this.row_count--;this._refresh()}},delAll:function(){this.$tbody.empty();this.row_count=0;this._refresh()},value:function(c){this.before=this.$tbody.find(".current").attr("id");if(c!==undefined){this.$tbody.find("tr").removeClass("current");if(c){this.$tbody.find("#"+c).addClass("current")}}var d=this.$tbody.find(".current").attr("id");if(d===undefined){return null}else{if(d!=this.before&&this.options.onchange){this.options.onchange(c)}return d}},size:function(){return this.$tbody.find("tr").length},_commit:function(d,c){this.del(d);this.row.attr("id",d);if(c){this.$tbody.prepend(this.row)}else{this.$tbody.append(this.row)}this.row=$("<tr></tr>");this.row_count++;this._refresh()},_onclick:function(f){var c=this.value();var d=$(f.target).closest("tr").attr("id");if(d!=""){if(d&&c!=d){if(this.options.onconfirm){this.options.onconfirm(d)}else{this.value(d)}}}},_ondblclick:function(d){var c=this.value();if(c&&this.options.ondblclick){this.options.ondblclick(c)}},_refresh:function(){if(this.row_count==0){this.$tmessage.show()}else{this.$tmessage.hide()}},_template:function(c){return'<div><table class="'+c.cls+'"><thead></thead><tbody></tbody></table><tmessage>'+c.content+"</tmessage><div>"}});return{View:b}}); \ No newline at end of file +define(["utils/utils"],function(a){var b=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null,cls:"ui-table",cls_tr:""},events:{click:"_onclick",dblclick:"_ondblclick"},initialize:function(c){this.options=a.merge(c,this.optionsDefault);var d=$(this._template(this.options));this.$thead=d.find("thead");this.$tbody=d.find("tbody");this.$tmessage=d.find("tmessage");this.setElement(d);this.row=this._row()},addHeader:function(c){var d=$("<th></th>");d.append(c);this.row.append(d)},appendHeader:function(){this.$thead.append(this.row);this.row=$("<tr></tr>")},add:function(c,d,f){var e=$("<td></td>");if(d){e.css("width",d)}if(f){e.css("text-align",f)}e.append(c);this.row.append(e)},append:function(c){this._commit(c)},prepend:function(c){this._commit(c,true)},get:function(c){return this.$el.find("#"+c)},del:function(d){var c=this.$tbody.find("#"+d);if(c.length>0){c.remove();this.row_count--;this._refresh()}},delAll:function(){this.$tbody.empty();this.row_count=0;this._refresh()},value:function(c){this.before=this.$tbody.find(".current").attr("id");if(c!==undefined){this.$tbody.find("tr").removeClass("current");if(c){this.$tbody.find("#"+c).addClass("current")}}var d=this.$tbody.find(".current").attr("id");if(d===undefined){return null}else{if(d!=this.before&&this.options.onchange){this.options.onchange(c)}return d}},size:function(){return this.$tbody.find("tr").length},_commit:function(d,c){this.del(d);this.row.attr("id",d);if(c){this.$tbody.prepend(this.row)}else{this.$tbody.append(this.row)}this.row=this._row();this.row_count++;this._refresh()},_row:function(){return $('<tr class="'+this.options.cls_tr+'"></tr>')},_onclick:function(f){var c=this.value();var d=$(f.target).closest("tr").attr("id");if(d!=""){if(d&&c!=d){if(this.options.onconfirm){this.options.onconfirm(d)}else{this.value(d)}}}},_ondblclick:function(d){var c=this.value();if(c&&this.options.ondblclick){this.options.ondblclick(c)}},_refresh:function(){if(this.row_count==0){this.$tmessage.show()}else{this.$tmessage.hide()}},_template:function(c){return'<div><table class="'+c.cls+'"><thead></thead><tbody></tbody></table><tmessage>'+c.content+"</tmessage><div>"}});return{View:b}}); \ No newline at end of file diff -r b7aea7640218779f0791730fdc3f37f96295b897 -r bb4cfb25378acec366e98a630dc508dccc5a6df6 static/scripts/packed/mvc/ui/ui-tabs.js --- a/static/scripts/packed/mvc/ui/ui-tabs.js +++ b/static/scripts/packed/mvc/ui/ui-tabs.js @@ -1,1 +1,1 @@ -define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},size:function(){return _.size(this.list)},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(_.size(this.list)==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#tab-content-"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}},delRemovable:function(){for(var c in this.list){if(this.list[c]){this.del(c)}}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#tab-content-"+c).addClass("active")}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#tab-content-'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="tab-content-'+c.id+'" class="tab-pane"/>'}});return{View:b}}); \ No newline at end of file +define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},size:function(){return _.size(this.list)},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(_.size(this.list)==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}if(this.list[c]){delete this.list[c]}},delRemovable:function(){for(var c in this.list){this.del(c)}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#"+c).addClass("active")}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},retitle:function(d){var c=0;for(var e in this.list){this.title(e,++c+": "+d)}},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'" class="tab-title-text">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="'+c.id+'" class="tab-pane"/>'}});return{View:b}}); \ No newline at end of file https://bitbucket.org/galaxy/galaxy-central/commits/993bdd055f70/ Changeset: 993bdd055f70 User: davebgx Date: 2014-08-29 21:21:30 Summary: Find and add tool help images to the tarball. Delete any temporary files that were generated. Affected #: 1 file diff -r bb4cfb25378acec366e98a630dc508dccc5a6df6 -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -738,7 +738,34 @@ else: tool = self.tools_by_id[ tool_id ] tarball_files = [] - tool_tup = ( os.path.abspath( tool.config_file ), os.path.split( tool.config_file )[-1] ) + temp_files = [] + tool_xml = file( os.path.abspath( tool.config_file ), 'r' ).read() + # Retrieve tool help images and rewrite the tool's xml into a temporary file with the path + # modified to be relative to the repository root. + tool_help = tool.help._source + image_found = False + # Check each line of the rendered tool help for an image tag that points to a location under static/ + for help_line in tool_help.split( '\n' ): + image_regex = re.compile( 'img alt="[^"]+" src="\${static_path}/([^"]+)"' ) + matches = re.search( image_regex, help_line ) + if matches is not None: + tool_help_image = matches.group(1) + tarball_path = tool_help_image + filesystem_path = os.path.abspath( os.path.join( trans.app.config.root, 'static', tool_help_image ) ) + if os.path.exists( filesystem_path ): + tarball_files.append( ( filesystem_path, tarball_path ) ) + image_found = True + tool_xml = tool_xml.replace( '${static_path}/%s' % tarball_path, tarball_path ) + log.debug( tarball_files ) + # If one or more tool help images were found, add the modified tool XML to the tarball instead of the original. + if image_found: + fd, new_tool_config = tempfile.mkstemp( suffix='.xml' ) + os.close( fd ) + file( new_tool_config, 'w' ).write( tool_xml ) + tool_tup = ( os.path.abspath( new_tool_config ), os.path.split( tool.config_file )[-1] ) + temp_files.append( os.path.abspath( new_tool_config ) ) + else: + tool_tup = ( os.path.abspath( tool.config_file ), os.path.split( tool.config_file )[-1] ) tarball_files.append( tool_tup ) # TODO: This feels hacky. tool_command = tool.command.split( ' ' )[0] @@ -796,6 +823,7 @@ os.close( fd ) file( table_conf, 'w' ).write( table_definition ) tarball_files.append( ( table_conf, os.path.join( 'tool-data', 'tool_data_table_conf.xml.sample' ) ) ) + temp_files.append( table_conf ) # Create the tarball. fd, tarball_archive = tempfile.mkstemp( suffix='.tgz' ) os.close( fd ) @@ -804,6 +832,9 @@ for fspath, tarpath in tarball_files: tarball.add( fspath, arcname=tarpath ) tarball.close() + # Delete any temporary files that were generated. + for temp_file in temp_files: + os.remove( temp_file ) return tarball_archive, True, None return None, False, "An unknown error occurred." https://bitbucket.org/galaxy/galaxy-central/commits/59032da981d8/ Changeset: 59032da981d8 User: davebgx Date: 2014-08-29 21:22:08 Summary: Merge with -central. Affected #: 14 files diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/mvc/dataset/list-panel.js --- a/static/scripts/mvc/dataset/list-panel.js +++ b/static/scripts/mvc/dataset/list-panel.js @@ -408,7 +408,7 @@ return view; }, - /** get views based on model properties + /** get views based on model */ viewFromModel : function( model ){ for( var i=0; i<this.views.length; i++ ){ diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/mvc/history/history-contents.js --- a/static/scripts/mvc/history/history-contents.js +++ b/static/scripts/mvc/history/history-contents.js @@ -21,11 +21,11 @@ //TODO: can we decorate the mixed models using the model fn below (instead of having them build their own type_id)? /** logger used to record this.log messages, commonly set to console */ - // comment this out to suppress log output //logger : console, /** since history content is a mix, override model fn into a factory, creating based on history_content_type */ model : function( attrs, options ) { + //console.debug( 'HistoryContents.model:', attrs, options ); //TODO: can we move the type_id stuff here? //attrs.type_id = typeIdStr( attrs ); @@ -184,6 +184,23 @@ return deferred; }, + /** copy an existing, accessible hda into this collection */ + copy : function( id ){ + var collection = this, + xhr = jQuery.post( this.url(), { + source : 'hda', + content : id + }); + xhr.done( function( json ){ + collection.add([ json ]); + }); + xhr.fail( function( error, status, message ){ +//TODO: better distinction btwn not-allowed and actual ajax error + collection.trigger( 'error', collection, xhr, {}, 'Error copying dataset' ); + }); + return xhr; + }, + // ........................................................................ sorting/filtering /** return a new collection of contents whose attributes contain the substring matchesWhat */ matches : function( matchesWhat ){ @@ -195,6 +212,7 @@ // ........................................................................ misc /** override to get a correct/smarter merge when incoming data is partial */ set : function( models, options ){ + this.debug( 'set:', models ); // arrrrrrrrrrrrrrrrrg... // (e.g. stupid backbone) // w/o this partial models from the server will fill in missing data with model defaults diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/mvc/tools/tools-form.js --- a/static/scripts/mvc/tools/tools-form.js +++ b/static/scripts/mvc/tools/tools-form.js @@ -36,7 +36,7 @@ this.field_list = {}; // reset sequential input definition list - this.inputs_sequential = {}; + this.input_list = {}; // create data model this.data = new Backbone.Model(); diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/mvc/tools/tools-section.js --- a/static/scripts/mvc/tools/tools-section.js +++ b/static/scripts/mvc/tools/tools-section.js @@ -54,91 +54,131 @@ input_def.id = Utils.uuid(); // add to sequential list of inputs - this.app.inputs_sequential[input_def.id] = input_def; + this.app.input_list[input_def.id] = input_def; // identify field type var type = input_def.type; switch(type) { // conditional field case 'conditional': - // add label to input definition root - input_def.label = input_def.test_param.label; - - // add value to input definition root - input_def.value = input_def.test_param.value; - - // build options field - this._addRow('conditional', input_def, data); - - // add fields - for (var i in input_def.cases) { - // create id tag - var sub_section_id = input_def.id + '-section-' + i; - - // create sub section - var sub_section = new View(this.app, { - inputs : input_def.cases[i].inputs, - cls : 'ui-table-plain' - }); - - // append sub section - this.table.add(''); - this.table.add(sub_section.$el); - this.table.append(sub_section_id); - } + this._addConditional(input_def, data); break; // repeat block case 'repeat': - // create tab field - var tabs = new Tabs.View({ - title_new : 'Add ' + input_def.title, - onnew : function() { - // create id tag - var sub_section_id = input_def.id + '-section-' + Utils.uuid(); - - // create sub section - var sub_section = new View(self.app, { - inputs : input_def.inputs, - cls : 'ui-table-plain' - }); - - // add new tab - tabs.add({ - id : sub_section_id, - title : input_def.title, - $el : sub_section.$el, - ondel : function() { - // delete tab - tabs.del(sub_section_id); - - // retitle tabs - tabs.retitle(input_def.title); - - // trigger refresh - self.app.refresh(); - } - }); + this._addRepeat(input_def); + break; + // default single element row + default: + this._addRow(type, input_def, data); + } + }, + + // add conditional block + _addConditional: function(input_def, data) { + // add label to input definition root + input_def.label = input_def.test_param.label; + + // add value to input definition root + input_def.value = input_def.test_param.value; + + // build options field + this._addRow('conditional', input_def, data); + + // add fields + for (var i in input_def.cases) { + // create id tag + var sub_section_id = input_def.id + '-section-' + i; + + // create sub section + var sub_section = new View(this.app, { + inputs : input_def.cases[i].inputs, + cls : 'ui-table-plain' + }); + + // append sub section + this.table.add(''); + this.table.add(sub_section.$el); + this.table.append(sub_section_id); + } + }, + + // add repeat block + _addRepeat: function(input_def) { + // link this + var self = this; + + // + // create tab field + // + var tabs = new Tabs.View({ + title_new : 'Add ' + input_def.title, + max : input_def.max, + onnew : function() { + // create id tag + var sub_section_id = input_def.id + '-section-' + Utils.uuid(); + + // create sub section + var sub_section = new View(self.app, { + inputs : input_def.inputs, + cls : 'ui-table-plain' + }); + + // add new tab + tabs.add({ + id : sub_section_id, + title : input_def.title, + $el : sub_section.$el, + ondel : function() { + // delete tab + tabs.del(sub_section_id); // retitle tabs tabs.retitle(input_def.title); - - // show tab - tabs.show(sub_section_id); - + // trigger refresh self.app.refresh(); } }); - // append sub section - this.table.add(''); - this.table.add(tabs.$el); - this.table.append(input_def.id); - break; - // default single element row - default: - this._addRow(type, input_def, data); + // retitle tabs + tabs.retitle(input_def.title); + + // show tab + tabs.show(sub_section_id); + + // trigger refresh + self.app.refresh(); + } + }); + + // + // add min number of tabs + // + for (var i = 0; i < input_def.min; i++) { + // create id tag + var sub_section_id = input_def.id + '-section-' + Utils.uuid(); + + // create sub section + var sub_section = new View(self.app, { + inputs : input_def.inputs, + cls : 'ui-table-plain' + }); + + // add tab + tabs.add({ + id : sub_section_id, + title : input_def.title, + $el : sub_section.$el + }); } + + // retitle tabs + tabs.retitle(input_def.title); + + // append sub section + this.table.add(''); + this.table.add(tabs.$el); + this.table.append(input_def.id); }, // add table row @@ -215,7 +255,7 @@ } // create table row - this.table.add('<span class="ui-table-form-title">' + input_def.label + '</span>', '25%'); + this.table.add('<span class="ui-table-form-title">' + input_def.label + '</span>', '20%'); this.table.add($input); // append to table @@ -342,7 +382,9 @@ var column_field = self.app.field_list[column_list[i]] if (column_field) { column_field.update(columns); - column_field.value(column_field.first()); + if (!column_field.exists(column_field.value())) { + column_field.value(column_field.first()); + } } } } else { diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/mvc/tools/tools-tree.js --- a/static/scripts/mvc/tools/tools-tree.js +++ b/static/scripts/mvc/tools/tools-tree.js @@ -44,7 +44,7 @@ dict[id] = {}; // add input element if it exists - var input = self.app.inputs_sequential[id]; + var input = self.app.input_list[id]; if (input) { dict[id] = { input : input @@ -78,10 +78,13 @@ // get child nodes var children = $(parent).children(); - // create sublist + // create list of referenced elements var list = []; - // verify that hierachy level is referenced to identifier + // a node level is skipped if a reference of higher priority was found + var skip = false; + + // verify that hierarchy level is referenced by target identifier children.each(function() { // get child element var child = this; @@ -89,15 +92,16 @@ // get id var id = $(child).attr('id'); - // skip + // skip target element if (id !== identifier) { // get input element - var input = self.app.inputs_sequential[id]; + var input = self.app.input_list[id]; if (input) { - // check for new reference definition + // check for new reference definition with higher priority if (input.name == name) { - // stop iteration - return; + // skip iteration for this branch + skip = true; + return false; } // check for referenced element @@ -108,20 +112,23 @@ } }); - // merge temporary list with result - referenced = referenced.concat(list); - - // continue iteration - children.each(function() { - search(identifier, this); - }); + // skip iteration + if (!skip) { + // merge temporary list with result + referenced = referenced.concat(list); + + // continue iteration + children.each(function() { + search(name, this); + }); + } } // get initial node var node = this.xml.find('#' + identifier); if (node.length > 0) { // get parent input element - var input = self.app.inputs_sequential[identifier]; + var input = this.app.input_list[identifier]; if (input) { search(input.name, node.parent()); } diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/mvc/ui.js --- a/static/scripts/mvc/ui.js +++ b/static/scripts/mvc/ui.js @@ -574,6 +574,8 @@ self.show = function( msg, speed, callback ){ msg = msg || 'loading...'; speed = speed || 'fast'; + // remove previous + $where.parent().find( '.loading-indicator' ).remove(); // since position is fixed - we insert as sibling self.$indicator = render().insertBefore( $where ); self.message( msg ); diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/mvc/ui/ui-tabs.js --- a/static/scripts/mvc/ui/ui-tabs.js +++ b/static/scripts/mvc/ui/ui-tabs.js @@ -7,7 +7,9 @@ optionsDefault: { title_new : '', operations : null, - onnew : null + onnew : null, + min : null, + max : null }, // initialize @@ -96,12 +98,17 @@ this.$content.append($tab_content); // activate this tab if this is the first tab - if (_.size(this.list) == 1) { + if (this.size() == 1) { $tab_title.addClass('active'); $tab_content.addClass('active'); this.first_tab = id; } + // hide add tab + if (this.options.max && this.size() >= this.options.max) { + this.$el.find('#new-tab').hide(); + } + // add click event to remove tab if (options.ondel) { var $del_icon = $tab_title.find('#delete'); @@ -148,6 +155,11 @@ if (this.list[id]) { delete this.list[id]; } + + // show add tab + if (this.size() < this.options.max) { + this.$el.find('#new-tab').show(); + } }, // delete tab diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/packed/mvc/history/history-contents.js --- a/static/scripts/packed/mvc/history/history-contents.js +++ b/static/scripts/packed/mvc/history/history-contents.js @@ -1,1 +1,1 @@ -define(["mvc/history/history-content-model","mvc/history/hda-model","mvc/history/hdca-model","mvc/base-mvc","utils/localization"],function(g,e,b,a,c){var f=Backbone.Collection.extend(a.LoggableMixin).extend({model:function(i,h){if(i.history_content_type==="dataset"){return new e.HistoryDatasetAssociation(i,h)}else{if(i.history_content_type==="dataset_collection"){switch(i.collection_type){case"list":return new b.HistoryListDatasetCollection(i,h);case"paired":return new b.HistoryPairDatasetCollection(i,h);case"list:paired":return new b.HistoryListPairedDatasetCollection(i,h)}throw new TypeError("Unknown collection_type: "+i.collection_type)}}throw new TypeError("Unknown history_content_type: "+i.history_content_type)},initialize:function(i,h){h=h||{};this.historyId=h.historyId;this.on("all",function(){this.debug(this+".event:",arguments)})},urlRoot:galaxy_config.root+"api/histories",url:function(){return this.urlRoot+"/"+this.historyId+"/contents"},ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},running:function(){var h=[];this.each(function(j){var i=!j.inReadyState();if(i){h.push(j.get("id"))}});return h},getByHid:function(h){return _.first(this.filter(function(i){return i.get("hid")===h}))},getVisible:function(h,k,j){j=j||[];this.debug("checking isVisible");var i=new f(this.filter(function(l){return l.isVisible(h,k)}));_.each(j,function(l){if(!_.isFunction(l)){return}i=new f(i.filter(l))});return i},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},fetchAllDetails:function(i){i=i||{};var h={details:"all"};i.data=(i.data)?(_.extend(i.data,h)):(h);return this.fetch(i)},ajaxQueue:function(m,j){var i=jQuery.Deferred(),h=this.length,l=[];if(!h){i.resolve([]);return i}var k=this.chain().reverse().map(function(o,n){return function(){var p=m.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){l.push(q);if(k.length){k.shift()()}else{i.resolve(l)}})}}).value();k.shift()();return i},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){var i=this;j=_.map(j,function(m){var l=m.attributes||m,n=g.typeIdStr(l.history_content_type,l.id),o=i.get(n);if(!o){return m}var k=o.toJSON();_.extend(k,m);return k});Backbone.Collection.prototype.set.call(this,j,h)},promoteToHistoryDatasetCollection:function d(m,k,i){i=i||{};i.url=this.url();i.type="POST";var o=k;var l=[],h=null;if(k==="list"){this.chain().each(function(r){var p=r.attributes.name;var s=r.get("id");var q=r.attributes.history_content_type;if(q==="dataset"){if(o!=="list"){this.log("Invalid collection type")}l.push({name:p,src:"hda",id:s})}else{if(o==="list"){o="list:"+r.attributes.collection_type}else{if(o!=="list:"+r.attributes.collection_type){this.log("Invalid collection type")}}l.push({name:p,src:"hdca",id:s})}});h="New Dataset List"}else{if(k==="paired"){var j=this.ids();if(j.length!==2){}l.push({name:"forward",src:"hda",id:j[0]});l.push({name:"reverse",src:"hda",id:j[1]});h="New Dataset Pair"}}i.data={type:"dataset_collection",name:h,collection_type:o,element_identifiers:JSON.stringify(l)};var n=jQuery.ajax(i);n.done(function(r,p,q){m.refresh()});n.fail(function(r,p,q){if(r.responseJSON&&r.responseJSON.error){error=r.responseJSON.error}else{error=r.responseJSON}r.responseText=error});return n},print:function(){var h=this;h.each(function(i){h.debug(i);if(i.elements){h.debug("\t elements:",i.elements)}})},toString:function(){return(["HistoryContents(",[this.historyId,this.length].join(),")"].join(""))}});return{HistoryContents:f}}); \ No newline at end of file +define(["mvc/history/history-content-model","mvc/history/hda-model","mvc/history/hdca-model","mvc/base-mvc","utils/localization"],function(g,e,b,a,c){var f=Backbone.Collection.extend(a.LoggableMixin).extend({model:function(i,h){if(i.history_content_type==="dataset"){return new e.HistoryDatasetAssociation(i,h)}else{if(i.history_content_type==="dataset_collection"){switch(i.collection_type){case"list":return new b.HistoryListDatasetCollection(i,h);case"paired":return new b.HistoryPairDatasetCollection(i,h);case"list:paired":return new b.HistoryListPairedDatasetCollection(i,h)}throw new TypeError("Unknown collection_type: "+i.collection_type)}}throw new TypeError("Unknown history_content_type: "+i.history_content_type)},initialize:function(i,h){h=h||{};this.historyId=h.historyId;this.on("all",function(){this.debug(this+".event:",arguments)})},urlRoot:galaxy_config.root+"api/histories",url:function(){return this.urlRoot+"/"+this.historyId+"/contents"},ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},running:function(){var h=[];this.each(function(j){var i=!j.inReadyState();if(i){h.push(j.get("id"))}});return h},getByHid:function(h){return _.first(this.filter(function(i){return i.get("hid")===h}))},getVisible:function(h,k,j){j=j||[];this.debug("checking isVisible");var i=new f(this.filter(function(l){return l.isVisible(h,k)}));_.each(j,function(l){if(!_.isFunction(l)){return}i=new f(i.filter(l))});return i},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},fetchAllDetails:function(i){i=i||{};var h={details:"all"};i.data=(i.data)?(_.extend(i.data,h)):(h);return this.fetch(i)},ajaxQueue:function(m,j){var i=jQuery.Deferred(),h=this.length,l=[];if(!h){i.resolve([]);return i}var k=this.chain().reverse().map(function(o,n){return function(){var p=m.call(o,j);p.done(function(q){i.notify({curr:n,total:h,response:q,model:o})});p.always(function(q){l.push(q);if(k.length){k.shift()()}else{i.resolve(l)}})}}).value();k.shift()();return i},copy:function(j){var i=this,h=jQuery.post(this.url(),{source:"hda",content:j});h.done(function(k){i.add([k])});h.fail(function(l,k,m){i.trigger("error",i,h,{},"Error copying dataset")});return h},matches:function(h){return this.filter(function(i){return i.matches(h)})},set:function(j,h){this.debug("set:",j);var i=this;j=_.map(j,function(m){var l=m.attributes||m,n=g.typeIdStr(l.history_content_type,l.id),o=i.get(n);if(!o){return m}var k=o.toJSON();_.extend(k,m);return k});Backbone.Collection.prototype.set.call(this,j,h)},promoteToHistoryDatasetCollection:function d(m,k,i){i=i||{};i.url=this.url();i.type="POST";var o=k;var l=[],h=null;if(k==="list"){this.chain().each(function(r){var p=r.attributes.name;var s=r.get("id");var q=r.attributes.history_content_type;if(q==="dataset"){if(o!=="list"){this.log("Invalid collection type")}l.push({name:p,src:"hda",id:s})}else{if(o==="list"){o="list:"+r.attributes.collection_type}else{if(o!=="list:"+r.attributes.collection_type){this.log("Invalid collection type")}}l.push({name:p,src:"hdca",id:s})}});h="New Dataset List"}else{if(k==="paired"){var j=this.ids();if(j.length!==2){}l.push({name:"forward",src:"hda",id:j[0]});l.push({name:"reverse",src:"hda",id:j[1]});h="New Dataset Pair"}}i.data={type:"dataset_collection",name:h,collection_type:o,element_identifiers:JSON.stringify(l)};var n=jQuery.ajax(i);n.done(function(r,p,q){m.refresh()});n.fail(function(r,p,q){if(r.responseJSON&&r.responseJSON.error){error=r.responseJSON.error}else{error=r.responseJSON}r.responseText=error});return n},print:function(){var h=this;h.each(function(i){h.debug(i);if(i.elements){h.debug("\t elements:",i.elements)}})},toString:function(){return(["HistoryContents(",[this.historyId,this.length].join(),")"].join(""))}});return{HistoryContents:f}}); \ No newline at end of file diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/packed/mvc/tools/tools-form.js --- a/static/scripts/packed/mvc/tools/tools-form.js +++ b/static/scripts/packed/mvc/tools/tools-form.js @@ -1,1 +1,1 @@ -define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree"],function(g,k,i,a,f,d,h,j,c){var e=Backbone.Model.extend({initialize:function(l){this.url=galaxy_config.root+"api/tools/"+l.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(m){var l=this;this.options=m;this.model=new e({id:m.id});this.tree=new c(this);this.field_list={};this.inputs_sequential={};this.data=new Backbone.Model();this.datasets=new h({success:function(){l._initializeToolForm()}})},_initializeToolForm:function(){var l=this;this.model.fetch({error:function(m){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){l.inputs=l.model.get("inputs");l.portlet=new g.View({icon:"fa-wrench",title:"<b>"+l.model.get("name")+"</b> "+l.model.get("description"),buttons:{execute:new k.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){console.log(l.tree.create(l))}})}});l.message=new k.Message();l.portlet.append(l.message.$el);$(l.main_el).append(l.portlet.$el);if(l.options.help!=""){$(l.main_el).append(d.help(l.options.help))}if(l.options.citations){$(l.main_el).append(d.citations());var m=new i.ToolCitationCollection();m.tool_id=l.options.id;var n=new a.CitationListView({collection:m});n.render();m.fetch()}l.setElement(l.portlet.content());l.section=new j.View(l,{inputs:l.model.get("inputs")});l.portlet.append(l.section.$el);l.refresh()}})},refresh:function(){this.tree.refresh();for(var l in this.field_list){this.field_list[l].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")}});return{View:b}}); \ No newline at end of file +define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section","mvc/tools/tools-tree"],function(g,k,i,a,f,d,h,j,c){var e=Backbone.Model.extend({initialize:function(l){this.url=galaxy_config.root+"api/tools/"+l.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(m){var l=this;this.options=m;this.model=new e({id:m.id});this.tree=new c(this);this.field_list={};this.input_list={};this.data=new Backbone.Model();this.datasets=new h({success:function(){l._initializeToolForm()}})},_initializeToolForm:function(){var l=this;this.model.fetch({error:function(m){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){l.inputs=l.model.get("inputs");l.portlet=new g.View({icon:"fa-wrench",title:"<b>"+l.model.get("name")+"</b> "+l.model.get("description"),buttons:{execute:new k.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){console.log(l.tree.create(l))}})}});l.message=new k.Message();l.portlet.append(l.message.$el);$(l.main_el).append(l.portlet.$el);if(l.options.help!=""){$(l.main_el).append(d.help(l.options.help))}if(l.options.citations){$(l.main_el).append(d.citations());var m=new i.ToolCitationCollection();m.tool_id=l.options.id;var n=new a.CitationListView({collection:m});n.render();m.fetch()}l.setElement(l.portlet.content());l.section=new j.View(l,{inputs:l.model.get("inputs")});l.portlet.append(l.section.$el);l.refresh()}})},refresh:function(){this.tree.refresh();for(var l in this.field_list){this.field_list[l].trigger("change")}console.debug("tools-form::refresh() - Recreated tree structure. Refresh.")}});return{View:b}}); \ No newline at end of file diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/packed/mvc/tools/tools-section.js --- a/static/scripts/packed/mvc/tools/tools-section.js +++ b/static/scripts/packed/mvc/tools/tools-section.js @@ -1,1 +1,1 @@ -define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-tabs"],function(c,b,e,a){var d=Backbone.View.extend({initialize:function(g,f){this.app=g;this.inputs=f.inputs;this.datasets=g.datasets;this.data=g.data;f.cls_tr="form-row";this.table=new b.View(f);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var f in this.inputs){this._add(this.inputs[f],this.data)}},_add:function(n,h){var o=this;var k=jQuery.extend(true,{},n);k.id=c.uuid();this.app.inputs_sequential[k.id]=k;var l=k.type;switch(l){case"conditional":k.label=k.test_param.label;k.value=k.test_param.value;this._addRow("conditional",k,h);for(var j in k.cases){var g=k.id+"-section-"+j;var f=new d(this.app,{inputs:k.cases[j].inputs,cls:"ui-table-plain"});this.table.add("");this.table.add(f.$el);this.table.append(g)}break;case"repeat":var m=new a.View({title_new:"Add "+k.title,onnew:function(){var i=k.id+"-section-"+c.uuid();var p=new d(o.app,{inputs:k.inputs,cls:"ui-table-plain"});m.add({id:i,title:k.title,$el:p.$el,ondel:function(){m.del(i);m.retitle(k.title);o.app.refresh()}});m.retitle(k.title);m.show(i);o.app.refresh()}});this.table.add("");this.table.add(m.$el);this.table.append(k.id);break;default:this._addRow(l,k,h)}},_addRow:function(i,f,g){var k=f.id;var h=null;switch(i){case"text":h=this._field_text(f,g);break;case"select":h=this._field_select(f,g);break;case"radiobutton":h=this._field_radio(f,g);break;case"data":h=this._field_data(f,g);break;case"data_column":h=this._field_column(f,g);break;case"textarea":h=this._field_textarea(f,g);break;case"conditional":h=this._field_conditional(f,g);break;case"hidden":h=this._field_hidden(f,g);break}if(!h){console.debug("tools-form::_addRow() : Unmatched field type ("+i+").");return}if(!g.get(k)){g.set(k,f.value)}h.value(g.get(k));this.app.field_list[k]=h;var j=$("<div/>");j.append(h.$el);if(f.help){j.append('<div class="ui-table-form-info">'+f.help+"</div>")}this.table.add('<span class="ui-table-form-title">'+f.label+"</span>","25%");this.table.add(j);this.table.append(k)},_field_conditional:function(f,l){var g=this;var h=[];for(var j in f.test_param.options){var k=f.test_param.options[j];h.push({label:k[0],value:k[1]})}var m=f.id;return new e.Select.View({id:"field-"+m,data:h,value:l.get(m),onchange:function(u){l.set(m,u);for(var s in f.cases){var o=f.cases[s];var r=f.id+"-section-"+s;var n=g.table.get(r);var q=false;for(var p in o.inputs){var t=o.inputs[p].type;if(t&&t!=="hidden"){q=true;break}}if(o.value==u&&q){n.fadeIn("fast")}else{n.hide()}}}})},_field_data:function(f,l){var g=this;var m=f.id;var k=this.datasets.filterType();var h=[];for(var j in k){h.push({label:k[j].get("name"),value:k[j].get("id")})}return new e.Select.View({id:"field-"+m,data:h,value:h[0].value,onchange:function(s){l.set(m,s);var o=g.app.tree.findReferences(m);var u=g.datasets.filter(s);if(u&&o.length>0){console.debug("tool-form::field_data() - Selected dataset "+s+".");var t=u.get("metadata_column_types");if(!t){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+s+".")}var r=[];for(var q in t){r.push({label:"Column: "+(parseInt(q)+1)+" ["+t[q]+"]",value:q})}for(var p in o){var n=g.app.field_list[o[p]];if(n){n.update(r);n.value(n.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+s+".")}}})},_field_column:function(f,g){var h=f.id;return new e.Select.View({id:"field-"+h,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_select:function(f,l){var g=[];for(var h in f.options){var j=f.options[h];g.push({label:j[0],value:j[1]})}var k=e.Select;if(f.display=="checkboxes"){k=e.Checkbox}var m=f.id;return new k.View({id:"field-"+m,data:g,value:l.get(m),onchange:function(i){l.set(m,i)}})},_field_text:function(f,g){var h=f.id;return new e.Input({id:"field-"+h,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_textarea:function(f,g){var h=f.id;return new e.Textarea({id:"field-"+h,onchange:function(){g.set(h,field.value())}})},_field_radio:function(f,g){var h=f.id;return new e.RadioButton({id:"field-"+h,data:f.data,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_hidden:function(f,g){var h=f.id;return new e.Hidden({id:"field-"+h,value:g.get(h)})}});return{View:d}}); \ No newline at end of file +define(["utils/utils","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-tabs"],function(c,b,e,a){var d=Backbone.View.extend({initialize:function(g,f){this.app=g;this.inputs=f.inputs;this.datasets=g.datasets;this.data=g.data;f.cls_tr="form-row";this.table=new b.View(f);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();for(var f in this.inputs){this._add(this.inputs[f],this.data)}},_add:function(h,j){var g=this;var f=jQuery.extend(true,{},h);f.id=c.uuid();this.app.input_list[f.id]=f;var i=f.type;switch(i){case"conditional":this._addConditional(f,j);break;case"repeat":this._addRepeat(f);break;default:this._addRow(i,f,j)}},_addConditional:function(f,j){f.label=f.test_param.label;f.value=f.test_param.value;this._addRow("conditional",f,j);for(var h in f.cases){var g=f.id+"-section-"+h;var k=new d(this.app,{inputs:f.cases[h].inputs,cls:"ui-table-plain"});this.table.add("");this.table.add(k.$el);this.table.append(g)}},_addRepeat:function(f){var g=this;var k=new a.View({title_new:"Add "+f.title,max:f.max,onnew:function(){var i=f.id+"-section-"+c.uuid();var m=new d(g.app,{inputs:f.inputs,cls:"ui-table-plain"});k.add({id:i,title:f.title,$el:m.$el,ondel:function(){k.del(i);k.retitle(f.title);g.app.refresh()}});k.retitle(f.title);k.show(i);g.app.refresh()}});for(var j=0;j<f.min;j++){var h=f.id+"-section-"+c.uuid();var l=new d(g.app,{inputs:f.inputs,cls:"ui-table-plain"});k.add({id:h,title:f.title,$el:l.$el})}k.retitle(f.title);this.table.add("");this.table.add(k.$el);this.table.append(f.id)},_addRow:function(i,f,g){var k=f.id;var h=null;switch(i){case"text":h=this._field_text(f,g);break;case"select":h=this._field_select(f,g);break;case"radiobutton":h=this._field_radio(f,g);break;case"data":h=this._field_data(f,g);break;case"data_column":h=this._field_column(f,g);break;case"textarea":h=this._field_textarea(f,g);break;case"conditional":h=this._field_conditional(f,g);break;case"hidden":h=this._field_hidden(f,g);break}if(!h){console.debug("tools-form::_addRow() : Unmatched field type ("+i+").");return}if(!g.get(k)){g.set(k,f.value)}h.value(g.get(k));this.app.field_list[k]=h;var j=$("<div/>");j.append(h.$el);if(f.help){j.append('<div class="ui-table-form-info">'+f.help+"</div>")}this.table.add('<span class="ui-table-form-title">'+f.label+"</span>","20%");this.table.add(j);this.table.append(k)},_field_conditional:function(f,l){var g=this;var h=[];for(var j in f.test_param.options){var k=f.test_param.options[j];h.push({label:k[0],value:k[1]})}var m=f.id;return new e.Select.View({id:"field-"+m,data:h,value:l.get(m),onchange:function(u){l.set(m,u);for(var s in f.cases){var o=f.cases[s];var r=f.id+"-section-"+s;var n=g.table.get(r);var q=false;for(var p in o.inputs){var t=o.inputs[p].type;if(t&&t!=="hidden"){q=true;break}}if(o.value==u&&q){n.fadeIn("fast")}else{n.hide()}}}})},_field_data:function(f,l){var g=this;var m=f.id;var k=this.datasets.filterType();var h=[];for(var j in k){h.push({label:k[j].get("name"),value:k[j].get("id")})}return new e.Select.View({id:"field-"+m,data:h,value:h[0].value,onchange:function(s){l.set(m,s);var o=g.app.tree.findReferences(m);var u=g.datasets.filter(s);if(u&&o.length>0){console.debug("tool-form::field_data() - Selected dataset "+s+".");var t=u.get("metadata_column_types");if(!t){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+s+".")}var r=[];for(var q in t){r.push({label:"Column: "+(parseInt(q)+1)+" ["+t[q]+"]",value:q})}for(var p in o){var n=g.app.field_list[o[p]];if(n){n.update(r);if(!n.exists(n.value())){n.value(n.first())}}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+s+".")}}})},_field_column:function(f,g){var h=f.id;return new e.Select.View({id:"field-"+h,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_select:function(f,l){var g=[];for(var h in f.options){var j=f.options[h];g.push({label:j[0],value:j[1]})}var k=e.Select;if(f.display=="checkboxes"){k=e.Checkbox}var m=f.id;return new k.View({id:"field-"+m,data:g,value:l.get(m),onchange:function(i){l.set(m,i)}})},_field_text:function(f,g){var h=f.id;return new e.Input({id:"field-"+h,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_textarea:function(f,g){var h=f.id;return new e.Textarea({id:"field-"+h,onchange:function(){g.set(h,field.value())}})},_field_radio:function(f,g){var h=f.id;return new e.RadioButton({id:"field-"+h,data:f.data,value:g.get(h),onchange:function(i){g.set(h,i)}})},_field_hidden:function(f,g){var h=f.id;return new e.Hidden({id:"field-"+h,value:g.get(h)})}});return{View:d}}); \ No newline at end of file diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/packed/mvc/tools/tools-tree.js --- a/static/scripts/packed/mvc/tools/tools-tree.js +++ b/static/scripts/packed/mvc/tools/tools-tree.js @@ -1,1 +1,1 @@ -define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){if(!this.app.section){return{}}this.dict={};this.xml=$("<div/>");this._iterate(this.app.section.$el,this.dict,this.xml)},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("form-row")||$(i).hasClass("tab-pane")){e[h]={};var f=a.app.inputs_sequential[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})},findReferences:function(c){var f=[];var b=this;function d(g,i){var h=$(i).children();var j=[];h.each(function(){var m=this;var l=$(m).attr("id");if(l!==c){var k=b.app.inputs_sequential[l];if(k){if(k.name==g){return}if(k.data_ref==g){j.push(l)}}}});f=f.concat(j);h.each(function(){d(c,this)})}var e=this.xml.find("#"+c);if(e.length>0){var a=b.app.inputs_sequential[c];if(a){d(a.name,e.parent())}}return f}})}); \ No newline at end of file +define([],function(){return Backbone.Model.extend({initialize:function(a){this.app=a},refresh:function(){if(!this.app.section){return{}}this.dict={};this.xml=$("<div/>");this._iterate(this.app.section.$el,this.dict,this.xml)},_iterate:function(d,e,b){var a=this;var c=$(d).children();c.each(function(){var i=this;var h=$(i).attr("id");if($(i).hasClass("form-row")||$(i).hasClass("tab-pane")){e[h]={};var f=a.app.input_list[h];if(f){e[h]={input:f}}var g=$('<div id="'+h+'"/>');b.append(g);a._iterate(i,e[h],g)}else{a._iterate(i,e,b)}})},findReferences:function(c){var f=[];var b=this;function d(g,i){var h=$(i).children();var k=[];var j=false;h.each(function(){var n=this;var m=$(n).attr("id");if(m!==c){var l=b.app.input_list[m];if(l){if(l.name==g){j=true;return false}if(l.data_ref==g){k.push(m)}}}});if(!j){f=f.concat(k);h.each(function(){d(g,this)})}}var e=this.xml.find("#"+c);if(e.length>0){var a=this.app.input_list[c];if(a){d(a.name,e.parent())}}return f}})}); \ No newline at end of file diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 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(){var b=window._l||function(d){return d};function a(k,q){var e=27,n=13,d=$(k),f=true,h={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(r){},minSearchLen:0,escWillClear:true,oninit:function(){}};function j(r){var s=$(this).parent().children("input");s.val("");s.trigger("clear:searchInput");q.onclear()}function p(s,r){$(this).trigger("search:searchInput",r);if(typeof q.onfirstsearch==="function"&&f){f=false;q.onfirstsearch(r)}else{q.onsearch(r)}}function g(){return['<input type="text" name="',q.name,'" placeholder="',q.placeholder,'" ','class="search-query ',q.classes,'" ',"/>"].join("")}function m(){return $(g()).focus(function(r){$(this).select()}).keyup(function(s){s.preventDefault();s.stopPropagation();if(!$(this).val()){$(this).blur()}if(s.which===e&&q.escWillClear){j.call(this,s)}else{var r=$(this).val();if((s.which===n)||(q.minSearchLen&&r.length>=q.minSearchLen)){p.call(this,s,r)}else{if(!r.length){j.call(this,s)}}}}).val(q.initialVal)}function l(){return $(['<span class="search-clear fa fa-times-circle" ','title="',b("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(r){j.call(this,r)})}function o(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',b("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function i(){d.find(".search-loading").toggle();d.find(".search-clear").toggle()}if(jQuery.type(q)==="string"){if(q==="toggle-loading"){i()}return d}if(jQuery.type(q)==="object"){q=jQuery.extend(true,{},h,q)}return d.addClass("search-input").prepend([m(),l(),o()])}jQuery.fn.extend({searchInput:function c(d){return this.each(function(){return a(this,d)})}})}());(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")){return o.call(this.$element.get(0))}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");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 +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";a.parent().find(".loading-indicator").remove();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(){var b=window._l||function(d){return d};function a(k,q){var e=27,n=13,d=$(k),f=true,h={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(r){},minSearchLen:0,escWillClear:true,oninit:function(){}};function j(r){var s=$(this).parent().children("input");s.val("");s.trigger("clear:searchInput");q.onclear()}function p(s,r){$(this).trigger("search:searchInput",r);if(typeof q.onfirstsearch==="function"&&f){f=false;q.onfirstsearch(r)}else{q.onsearch(r)}}function g(){return['<input type="text" name="',q.name,'" placeholder="',q.placeholder,'" ','class="search-query ',q.classes,'" ',"/>"].join("")}function m(){return $(g()).focus(function(r){$(this).select()}).keyup(function(s){s.preventDefault();s.stopPropagation();if(!$(this).val()){$(this).blur()}if(s.which===e&&q.escWillClear){j.call(this,s)}else{var r=$(this).val();if((s.which===n)||(q.minSearchLen&&r.length>=q.minSearchLen)){p.call(this,s,r)}else{if(!r.length){j.call(this,s)}}}}).val(q.initialVal)}function l(){return $(['<span class="search-clear fa fa-times-circle" ','title="',b("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(r){j.call(this,r)})}function o(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',b("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function i(){d.find(".search-loading").toggle();d.find(".search-clear").toggle()}if(jQuery.type(q)==="string"){if(q==="toggle-loading"){i()}return d}if(jQuery.type(q)==="object"){q=jQuery.extend(true,{},h,q)}return d.addClass("search-input").prepend([m(),l(),o()])}jQuery.fn.extend({searchInput:function c(d){return this.each(function(){return a(this,d)})}})}());(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")){return o.call(this.$element.get(0))}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");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 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 static/scripts/packed/mvc/ui/ui-tabs.js --- a/static/scripts/packed/mvc/ui/ui-tabs.js +++ b/static/scripts/packed/mvc/ui/ui-tabs.js @@ -1,1 +1,1 @@ -define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},size:function(){return _.size(this.list)},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(_.size(this.list)==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}if(this.list[c]){delete this.list[c]}},delRemovable:function(){for(var c in this.list){this.del(c)}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#"+c).addClass("active")}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},retitle:function(d){var c=0;for(var e in this.list){this.title(e,++c+": "+d)}},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'" class="tab-title-text">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="'+c.id+'" class="tab-pane"/>'}});return{View:b}}); \ No newline at end of file +define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null,min:null,max:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},size:function(){return _.size(this.list)},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(this.size()==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(this.options.max&&this.size()>=this.options.max){this.$el.find("#new-tab").hide()}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}if(this.list[c]){delete this.list[c]}if(this.size()<this.options.max){this.$el.find("#new-tab").show()}},delRemovable:function(){for(var c in this.list){this.del(c)}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#"+c).addClass("active")}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},retitle:function(d){var c=0;for(var e in this.list){this.title(e,++c+": "+d)}},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'" class="tab-title-text">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="'+c.id+'" class="tab-pane"/>'}});return{View:b}}); \ No newline at end of file diff -r 993bdd055f705289d6dc4ad536a66d0bc6a3cdc3 -r 59032da981d818a1937b4dc637ddb948c953ac38 templates/webapps/galaxy/admin/index.mako --- a/templates/webapps/galaxy/admin/index.mako +++ b/templates/webapps/galaxy/admin/index.mako @@ -66,9 +66,6 @@ <div class="toolTitle"><a href="${h.url_for( controller='admin', action='quotas' )}" target="galaxy_main">Manage quotas</a></div> %endif <div class="toolTitle"><a href="${h.url_for( controller='library_admin', action='browse_libraries' )}" target="galaxy_main">Manage data libraries</a></div> - %if trans.app.config.enable_beta_job_managers: - <div class="toolTitle"><a href="${h.url_for( controller='data_admin', action='manage_data' )}" target="galaxy_main">Manage local data</a></div> - %endif <div class="toolTitle"><a href="${h.url_for( controller='data_manager' )}" target="galaxy_main">Manage local data (beta)</a></div></div></div> https://bitbucket.org/galaxy/galaxy-central/commits/d44794f40ca5/ Changeset: d44794f40ca5 User: davebgx Date: 2014-08-29 21:29:46 Summary: Correct path to original tool XML file in the event a temporary XML file had been generated. Affected #: 1 file diff -r 59032da981d818a1937b4dc637ddb948c953ac38 -r d44794f40ca5c4cb265f0c648b2a11622cf4c144 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -769,16 +769,16 @@ tarball_files.append( tool_tup ) # TODO: This feels hacky. tool_command = tool.command.split( ' ' )[0] - tool_path = os.path.dirname( tool_tup[0] ) + tool_path = os.path.dirname( os.path.abspath( tool.config_file ) ) # Add the tool XML to the tuple that will be used to populate the tarball. if os.path.exists( os.path.join( tool_path, tool_command ) ): tarball_files.append( ( os.path.join( tool_path, tool_command ), tool_command ) ) - tests = tool.tests # Find and add macros and code files. for external_file in tool.get_externally_referenced_paths( os.path.abspath( tool.config_file ) ): external_file_abspath = os.path.abspath( os.path.join( tool_path, external_file ) ) tarball_files.append( ( external_file_abspath, external_file ) ) # Find tests, and check them for test data. + tests = tool.tests if tests is not None: for test in tests: # Add input file tuples to the list. 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