galaxy-commits
Threads by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
commit/galaxy-central: carlfeberhard: Vis registry: add two tests (has_attribute, not_eq); add see also for test types in visualization.dtd; correct applicability tests for trackster and circster using not_eq on datatype.track_type
by commits-noreply@bitbucket.org 28 Aug '14
by commits-noreply@bitbucket.org 28 Aug '14
28 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/df2a99433e85/
Changeset: df2a99433e85
User: carlfeberhard
Date: 2014-08-28 15:44:56
Summary: Vis registry: add two tests (has_attribute, not_eq); add see also for test types in visualization.dtd; correct applicability tests for trackster and circster using not_eq on datatype.track_type
Affected #: 4 files
diff -r f36c6fc80e8cd2bc6a5c6f77f0806aa7271e65f0 -r df2a99433e850b7ba594994fece91fdc87c24181 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 f36c6fc80e8cd2bc6a5c6f77f0806aa7271e65f0 -r df2a99433e850b7ba594994fece91fdc87c24181 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 f36c6fc80e8cd2bc6a5c6f77f0806aa7271e65f0 -r df2a99433e850b7ba594994fece91fdc87c24181 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 f36c6fc80e8cd2bc6a5c6f77f0806aa7271e65f0 -r df2a99433e850b7ba594994fece91fdc87c24181 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
@@ -228,14 +229,14 @@
Run a visualization's data_source tests to find out if
it can be applied to the target_object.
"""
- #log.debug( 'is_object_applicable( self, trans, %s, %s )', target_object, data_source_tests )
+ log.debug( 'is_object_applicable( self, trans, %s, %s )', target_object, data_source_tests )
for test in data_source_tests:
test_type = test[ 'type' ]
result_type = test[ 'result_type' ]
test_result = test[ 'result' ]
test_fn = test[ 'fn' ]
- #log.debug( '%s %s: %s, %s, %s, %s', str( target_object ), 'is_object_applicable',
- # test_type, result_type, test_result, test_fn )
+ log.debug( '%s %s: %s, %s, %s, %s', str( target_object ), 'is_object_applicable',
+ test_type, result_type, test_result, test_fn )
if test_type == 'isinstance':
# parse test_result based on result_type (curr: only datatype has to do this)
@@ -253,7 +254,7 @@
#NOTE: tests are OR'd, if any test passes - the visualization can be applied
if test_fn( target_object, test_result ):
- #log.debug( '\t test passed' )
+ log.debug( '\t test passed' )
return True
return False
@@ -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
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Update tag latest_2014.08.11 for changeset 109b170188e9
by commits-noreply@bitbucket.org 28 Aug '14
by commits-noreply@bitbucket.org 28 Aug '14
28 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/57d1b775b0ca/
Changeset: 57d1b775b0ca
Branch: stable
User: natefoo
Date: 2014-08-28 15:00:13
Summary: Update tag latest_2014.08.11 for changeset 109b170188e9
Affected #: 1 file
diff -r 109b170188e97fbfc2c998ec174aff9546dd1bd8 -r 57d1b775b0ca8515fd1fc71cee91e5db41cd9ec1 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -18,4 +18,4 @@
81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04
2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
-9a4b43021fd1c5808c17329da7b6acbfd9ae27ed latest_2014.08.11
+109b170188e97fbfc2c998ec174aff9546dd1bd8 latest_2014.08.11
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Fix using multiple list collections with different identifiers in workflows.
by commits-noreply@bitbucket.org 28 Aug '14
by commits-noreply@bitbucket.org 28 Aug '14
28 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/109b170188e9/
Changeset: 109b170188e9
Branch: stable
User: jmchilton
Date: 2014-08-27 20:39:43
Summary: Fix using multiple list collections with different identifiers in workflows.
Tools will pair off (or triplize, quadraplate, quintukify, etc...) based only on the index of the elements in the collection (so any N element list can be used in the same tool execution as any other N element list). Originally, I had decided to require the element identifiers to be the same in both collections (allows mixing a matching fewer collections in tools - but probably less likely to mismatch in a way the user did not intend). At any rate - I changed that decision and updated tool execution appropriately but not every aspect workflow collection 'pairing' - this fixes that and closes out this card https://trello.com/c/m5PiF1lR.
In very partical terms tools would ideally be consuming collection pairs - but for those that are still consuming two separate files (i.e. all of them) one can use two lists of datasets with pairs at matching indices and feed them into these tools - for workflows this doesn't work without this patch unless the identifiers and the indices match on these collections.
Thanks for Michael Crusoe and takadonet for the bug reports.
Affected #: 1 file
diff -r 51de5214e6f9e59b9bad5a05ae6a79d6e8944a9e -r 109b170188e97fbfc2c998ec174aff9546dd1bd8 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 )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
4 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e032250c3f2e/
Changeset: e032250c3f2e
User: jmchilton
Date: 2014-08-27 22:32:26
Summary: Update readme for functional test tools directory.
Affected #: 1 file
diff -r a66a80701913bb99e8abd12235c1ca82dc508f57 -r e032250c3f2eef09002a00d6d1035de0928e58dd 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
https://bitbucket.org/galaxy/galaxy-central/commits/14230488f497/
Changeset: 14230488f497
User: jmchilton
Date: 2014-08-27 22:32:26
Summary: Add some more basic test tools for building simple workflows for testing.
Affected #: 4 files
diff -r e032250c3f2eef09002a00d6d1035de0928e58dd -r 14230488f49758d1abe748cd7500f9719a3390b6 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 e032250c3f2eef09002a00d6d1035de0928e58dd -r 14230488f49758d1abe748cd7500f9719a3390b6 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 e032250c3f2eef09002a00d6d1035de0928e58dd -r 14230488f49758d1abe748cd7500f9719a3390b6 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 e032250c3f2eef09002a00d6d1035de0928e58dd -r 14230488f49758d1abe748cd7500f9719a3390b6 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/c692332612dd/
Changeset: c692332612dd
User: jmchilton
Date: 2014-08-27 22:32:26
Summary: Remove workflow test that accidently depended on tool not in -central.
Opps.
Affected #: 3 files
diff -r 14230488f49758d1abe748cd7500f9719a3390b6 -r c692332612dd5c8d7eff798cdba4f2e91d4ff5a1 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,9 +160,6 @@
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 simple_workflow( self, name, **create_kwds ):
workflow = self.load_workflow( name )
return self.create_workflow( workflow, **create_kwds )
diff -r 14230488f49758d1abe748cd7500f9719a3390b6 -r c692332612dd5c8d7eff798cdba4f2e91d4ff5a1 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 14230488f49758d1abe748cd7500f9719a3390b6 -r c692332612dd5c8d7eff798cdba4f2e91d4ff5a1 test/api/test_workflows.py
--- a/test/api/test_workflows.py
+++ b/test/api/test_workflows.py
@@ -149,26 +149,6 @@
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" )
- 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()
- self.dataset_populator.wait_for_history( history_id, assert_ok=True )
- label_map = { "f1": self._ds_entry( hdca1 ), "f2": self._ds_entry( hdca2 ) }
- workflow_request = dict(
- history="hist_id=%s" % history_id,
- workflow_id=workflow_id,
- ds_map=self._build_ds_map( workflow_id, label_map ),
- )
- run_workflow_response = self._post( "workflows", data=workflow_request )
- self._assert_status_code_is( run_workflow_response, 200 )
- self.dataset_populator.wait_for_history( history_id, assert_ok=True )
- self.assertEquals("1 2 3\n4 5 6\n7 8 9\n0 a b\n", self.dataset_populator.get_history_dataset_content( history_id ) )
-
def test_workflow_stability( self ):
# Run this index stability test with following command:
# ./run_tests.sh test/api/test_workflows.py:WorkflowsApiTestCase.test_workflow_stability
https://bitbucket.org/galaxy/galaxy-central/commits/f36c6fc80e8c/
Changeset: f36c6fc80e8c
User: jmchilton
Date: 2014-08-27 22:32:26
Summary: Add workflow test demonstrating failure when multiple lists with different identifiers are using in workflows.
Affected #: 3 files
diff -r c692332612dd5c8d7eff798cdba4f2e91d4ff5a1 -r f36c6fc80e8cd2bc6a5c6f77f0806aa7271e65f0 test/api/helpers.py
--- a/test/api/helpers.py
+++ b/test/api/helpers.py
@@ -160,6 +160,12 @@
def load_random_x2_workflow( self, name ):
return self.load_workflow( name, content=workflow_random_x2_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 )
return self.create_workflow( workflow, **create_kwds )
@@ -319,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 c692332612dd5c8d7eff798cdba4f2e91d4ff5a1 -r f36c6fc80e8cd2bc6a5c6f77f0806aa7271e65f0 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 c692332612dd5c8d7eff798cdba4f2e91d4ff5a1 -r f36c6fc80e8cd2bc6a5c6f77f0806aa7271e65f0 test/api/test_workflows.py
--- a/test/api/test_workflows.py
+++ b/test/api/test_workflows.py
@@ -149,6 +149,26 @@
run_workflow_response = self._post( "workflows", data=workflow_request )
self._assert_status_code_is( run_workflow_response, 403 )
+ @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_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 = { "list1": self._ds_entry( hdca1 ), "list2": self._ds_entry( hdca2 ) }
+ workflow_request = dict(
+ history="hist_id=%s" % history_id,
+ workflow_id=workflow_id,
+ ds_map=self._build_ds_map( workflow_id, label_map ),
+ )
+ run_workflow_response = self._post( "workflows", data=workflow_request )
+ self._assert_status_code_is( run_workflow_response, 200 )
+ self.dataset_populator.wait_for_history( history_id, assert_ok=True )
+ self.assertEquals("1 2 3\n4 5 6\n7 8 9\n0 a b\n", self.dataset_populator.get_history_dataset_content( history_id ) )
+
def test_workflow_stability( self ):
# Run this index stability test with following command:
# ./run_tests.sh test/api/test_workflows.py:WorkflowsApiTestCase.test_workflow_stability
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: UI, Paired collection creator: fixes and refactoring, allow pairs to be selected
by commits-noreply@bitbucket.org 28 Aug '14
by commits-noreply@bitbucket.org 28 Aug '14
28 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a66a80701913/
Changeset: a66a80701913
User: carlfeberhard
Date: 2014-08-27 20:47:54
Summary: UI, Paired collection creator: fixes and refactoring, allow pairs to be selected
Affected #: 4 files
diff -r 5a7a7003fbc3bc8f9d56f18a8d4b8f2d5b28fe42 -r a66a80701913bb99e8abd12235c1ca82dc508f57 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
@@ -5,10 +5,18 @@
], function( levelshteinDistance, baseMVC, _l ){
/* ============================================================================
TODO:
+ _adjPairedOnScrollBar
+ parition drag now doesn't stop when dragging down
+ can push footer out of modal
+ only *after* partition is all the way down once?
PROGRAMMATICALLY:
-h = Galaxy.currHistoryPanel; h.showSelectors(); h.selectAllDatasets(); _.last( h.actionsPopup.options ).func()
+currPanel.once( 'rendered', function(){
+ currPanel.showSelectors();
+ currPanel.selectAllDatasets();
+ _.last( currPanel.actionsPopup.options ).func();
+});
============================================================================ */
/** A view for paired datasets in the collections creator.
@@ -26,7 +34,9 @@
this.$el.attr( 'draggable', true )
.html( _.template([
'<span class="forward-dataset-name flex-column"><%= pair.forward.name %></span>',
- '<span class="pair-name flex-column"><%= pair.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' );
@@ -661,8 +671,6 @@
return;
}
- //this.$( '.unpaired-columns .forward-column' ).lassoable({});
-
// create the dataset dom arrays
$rev = split[1].map( function( dataset, i ){
// if there'll be a fwd dataset across the way, add a button to pair the row
@@ -685,6 +693,7 @@
this.$( '.unpaired-columns .forward-column .column-datasets' ).append( $fwd )
.add( this.$( '.unpaired-columns .paired-column .column-datasets' ).append( $prd ) )
.add( this.$( '.unpaired-columns .reverse-column .column-datasets' ).append( $rev ) );
+ this._adjUnpairedOnScrollbar();
},
/** return a string to display the count of filtered out datasets */
_renderUnpairedDisplayStr : function( numFiltered ){
@@ -724,6 +733,18 @@
this.$( '.unpaired-columns .paired-column .column-datasets' ).empty().prepend( $msg );
return $msg;
},
+ /** try to detect if the unpaired section has a scrollbar and adjust left column for better centering of all */
+ _adjUnpairedOnScrollbar : function(){
+ var $unpairedColumns = this.$( '.unpaired-columns' ).last(),
+ $firstDataset = this.$( '.unpaired-columns .reverse-column .dataset' ).first();
+ if( !$firstDataset.size() ){ return; }
+ var ucRight = $unpairedColumns.offset().left + $unpairedColumns.outerWidth(),
+ dsRight = $firstDataset.offset().left + $firstDataset.outerWidth(),
+ rightDiff = Math.floor( ucRight ) - Math.floor( dsRight );
+ //this.debug( 'rightDiff:', ucRight, '-', dsRight, '=', rightDiff );
+ this.$( '.unpaired-columns .forward-column' )
+ .css( 'margin-left', ( rightDiff > 0 )? rightDiff: 0 );
+ },
/** render the paired section and update counts of paired datasets */
_renderPaired : function( speed, callback ){
@@ -907,6 +928,7 @@
'click .paired-column-title' : '_clickShowOnlyPaired',
'mousedown .flexible-partition-drag' : '_startPartitionDrag',
// paired
+ 'click .paired-columns .dataset.paired' : 'selectPair',
'click .paired-columns .pair-name' : '_clickPairName',
'click .unpair-btn' : '_clickUnpair',
@@ -965,28 +987,23 @@
this.splitView();
}
},
+
/** hide unpaired, show paired */
hideUnpaired : function( speed, callback ){
- speed = speed || 0;
- this.$( '.unpaired-columns' ).hide( speed, callback );
- //this.$( '.unpaired-filter' ).hide( speed );
- this.$( '.paired-columns' ).show( speed ).css( 'flex', '1 0 auto' );
this.unpairedPanelHidden = true;
+ this.pairedPanelHidden = false;
+ this._renderMiddle( speed, callback );
},
/** hide paired, show unpaired */
hidePaired : function( speed, callback ){
- speed = speed || 0;
- this.$( '.unpaired-columns' ).show( speed ).css( 'flex', '1 0 auto' );
- //this.$( '.unpaired-filter' ).show( speed );
- this.$( '.paired-columns' ).hide( speed, callback );
+ this.unpairedPanelHidden = false;
this.pairedPanelHidden = true;
+ this._renderMiddle( speed, callback );
},
/** show both paired and unpaired (splitting evenly) */
splitView : function( speed, callback ){
- speed = speed || 0;
this.unpairedPanelHidden = this.pairedPanelHidden = false;
- //this.$( '.unpaired-filter' ).show( speed );
- this._renderMiddle( speed );
+ this._renderMiddle( speed, callback );
return this;
},
@@ -1148,6 +1165,7 @@
//creator.debug( 'mouseup triggered' );
$( 'body' ).trigger( 'mouseup' );
}
+ creator._adjUnpairedOnScrollbar();
startingY += offset;
}
$( 'body' ).mousemove( trackMouse );
@@ -1165,29 +1183,37 @@
unpairedHi = Math.max( 10, unpairedHi + adj );
pairedHi = pairedHi - adj;
- //TODO: seems like shouldn't need this (it should be part of the hide/show/splitView)
- if( unpairedHi <= 10 ){
- if( !this.unpairedPanelHidden ){
+//TODO: seems like shouldn't need this (it should be part of the hide/show/splitView)
+ var movingUpwards = adj < 0;
+ // when the divider gets close to the top - lock into hiding the unpaired section
+ if( movingUpwards ){
+ if( this.unpairedPanelHidden ){
+ return false;
+ } else if( unpairedHi <= 10 ){
this.hideUnpaired();
return false;
}
-
- } else if( this.unpairedPanelHidden ){
- $unpaired.show();
- this.unpairedPanelHidden = false;
+ } else {
+ if( this.unpairedPanelHidden ){
+ $unpaired.show();
+ this.unpairedPanelHidden = false;
+ }
}
// when the divider gets close to the bottom - lock into hiding the paired section
- if( pairedHi <= 15 ){
- if( !this.pairedPanelHidden ){
+ if( !movingUpwards ){
+ if( this.pairedPanelHidden ){
+ return false;
+ } else if( pairedHi <= 15 ){
this.hidePaired();
- if( pairedHi < 5 ){ return false; }
+ return false;
}
- // when the divider gets close to the bottom and the paired section is hidden
- } else if( this.pairedPanelHidden ){
- $paired.show();
- this.pairedPanelHidden = false;
+ } else {
+ if( this.pairedPanelHidden ){
+ $paired.show();
+ this.pairedPanelHidden = false;
+ }
}
$unpaired.css({
@@ -1198,8 +1224,14 @@
},
// ........................................................................ paired
+ /** select a pair when clicked */
+ selectPair : function( ev ){
+ $( ev.currentTarget ).toggleClass( 'selected' );
+ },
+
/** rename a pair when the pair name is clicked */
_clickPairName : function( ev ){
+ ev.stopPropagation();
var $control = $( ev.currentTarget ),
pair = this.paired[ $control.parent().index() ],
response = prompt( 'Enter a new name for the pair:', pair.name );
diff -r 5a7a7003fbc3bc8f9d56f18a8d4b8f2d5b28fe42 -r a66a80701913bb99e8abd12235c1ca82dc508f57 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 flex-column"><%= pair.name %></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))},_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},_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 .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){h=h||0;this.$(".unpaired-columns").hide(h,i);this.$(".paired-columns").show(h).css("flex","1 0 auto");this.unpairedPanelHidden=true},hidePaired:function(h,i){h=h||0;this.$(".unpaired-columns").show(h).css("flex","1 0 auto");this.$(".paired-columns").hide(h,i);this.pairedPanelHidden=true},splitView:function(h,i){h=h||0;this.unpairedPanelHidden=this.pairedPanelHidden=false;this._renderMiddle(h);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")}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;if(k<=10){if(!this.unpairedPanelHidden){this.hideUnpaired();return false}}else{if(this.unpairedPanelHidden){h.show();this.unpairedPanelHidden=false}}if(l<=15){if(!this.pairedPanelHidden){this.hidePaired();if(l<5){return false}}}else{if(this.pairedPanelHidden){j.show();this.pairedPanelHidden=false}}h.css({height:k+"px",flex:"0 0 auto"});return true},_clickPairName:function(j){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_Expre…"',' 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).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_Expre…"',' 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 5a7a7003fbc3bc8f9d56f18a8d4b8f2d5b28fe42 -r a66a80701913bb99e8abd12235c1ca82dc508f57 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1851,12 +1851,16 @@
.collection-creator .header .column-headers .column-header .unpaired-filter{width:100%}.collection-creator .header .column-headers .column-header .unpaired-filter .search-query{width:100%;height:22px}
.collection-creator .header .paired-column a:not(:last-child){margin-right:8px}
.collection-creator .header .reverse-column .column-title{text-align:right}
-.collection-creator .unpaired-columns,.collection-creator .paired-columns{height:0;border:1px solid lightgrey;border-width:1px 0 1px 0}
-.collection-creator .paired-columns{margin-bottom:8px}
-.collection-creator .column-datasets{list-style:none;overflow:hidden}.collection-creator .column-datasets .dataset{height:32px;margin-bottom:2px;border:1px solid lightgrey;border-radius:3px;padding:0 8px 0 8px;line-height:28px;cursor:pointer}.collection-creator .column-datasets .dataset:last-child{margin-bottom:4px}
-.collection-creator .unpaired-columns .dataset.unpaired{margin-top:2px;border-color:grey}.collection-creator .unpaired-columns .dataset.unpaired:hover{border-color:black}
-.collection-creator .unpaired-columns .dataset.unpaired.selected{border-color:black;background:black;color:white}
-.collection-creator .unpaired-columns .forward-column .dataset.unpaired{margin-right:32px}
+.collection-creator .flex-bordered-vertically{height:0;border:1px solid lightgrey;border-width:1px 0 1px 0}
+.collection-creator .column-datasets{list-style:none;overflow:hidden}.collection-creator .column-datasets .dataset{height:32px;margin-top:2px;border:1px solid lightgrey;border-radius:3px;padding:0 8px 0 8px;line-height:28px;cursor:pointer}.collection-creator .column-datasets .dataset:last-of-type{margin-bottom:2px}
+.collection-creator .column-datasets .dataset.unpaired{border-color:grey}
+.collection-creator .column-datasets .dataset.paired{margin-left:34px;margin-right:34px;border:2px solid grey;background:#AFF1AF}.collection-creator .column-datasets .dataset.paired span{display:inline-block;overflow:hidden}
+.collection-creator .column-datasets .dataset.paired .forward-dataset-name{text-align:right;border-right:1px solid grey;padding-right:8px}.collection-creator .column-datasets .dataset.paired .forward-dataset-name:after{margin-left:8px;font-family:FontAwesome;content:'\f061'}
+.collection-creator .column-datasets .dataset.paired .pair-name-column{text-align:center}.collection-creator .column-datasets .dataset.paired .pair-name-column .pair-name:hover{text-decoration:underline}
+.collection-creator .column-datasets .dataset.paired .reverse-dataset-name{border-left:1px solid grey;padding-left:8px}.collection-creator .column-datasets .dataset.paired .reverse-dataset-name:before{margin-right:8px;font-family:FontAwesome;content:'\f060'}
+.collection-creator .column-datasets .dataset:hover{border-color:black}
+.collection-creator .column-datasets .dataset.selected{border-color:black;background:black;color:white}
+.collection-creator .unpaired-columns{height:0;border:1px solid lightgrey;border-width:1px 0 1px 0}.collection-creator .unpaired-columns .forward-column .dataset.unpaired{margin-right:32px}
.collection-creator .unpaired-columns .paired-column .dataset.unpaired{border-color:lightgrey;color:lightgrey}.collection-creator .unpaired-columns .paired-column .dataset.unpaired:hover{border-color:black;color:black}
.collection-creator .unpaired-columns .reverse-column .dataset.unpaired{text-align:right;margin-left:32px}
.collection-creator .flexible-partition .flexible-partition-drag{width:100%;height:8px;cursor:ns-resize;line-height:2px;text-align:center;color:lightgrey}.collection-creator .flexible-partition .flexible-partition-drag:before{content:'...'}
@@ -1864,13 +1868,8 @@
.collection-creator .flexible-partition .column-header{width:100%;text-align:center}.collection-creator .flexible-partition .column-header .column-title{display:inline}
.collection-creator .flexible-partition .column-header>*:not(:last-child){margin-right:8px}
.collection-creator .flexible-partition .column-header .remove-extensions-link{display:none}
-.collection-creator .paired-columns .column-datasets{width:100%;overflow:auto}.collection-creator .paired-columns .column-datasets .dataset.paired{margin:0px 34px 2px 34px;border-radius:3px;border:2px solid grey;background:#AFF1AF}.collection-creator .paired-columns .column-datasets .dataset.paired:first-child{margin-top:2px}
-.collection-creator .paired-columns .column-datasets .dataset.paired:hover,.collection-creator .paired-columns .column-datasets .dataset.paired.emphasized{border-color:black}
-.collection-creator .paired-columns .column-datasets .dataset.paired span{display:inline-block;overflow:hidden}
-.collection-creator .paired-columns .column-datasets .dataset.paired .forward-dataset-name{text-align:right;border-right:1px solid grey;padding-right:8px}.collection-creator .paired-columns .column-datasets .dataset.paired .forward-dataset-name:after{margin-left:8px;font-family:FontAwesome;content:'\f061'}
-.collection-creator .paired-columns .column-datasets .dataset.paired .pair-name{display:inline-block;text-align:center}.collection-creator .paired-columns .column-datasets .dataset.paired .pair-name:hover{text-decoration:underline}
-.collection-creator .paired-columns .column-datasets .dataset.paired .reverse-dataset-name{display:inline-block;border-left:1px solid grey;padding-left:8px}.collection-creator .paired-columns .column-datasets .dataset.paired .reverse-dataset-name:before{margin-right:8px;font-family:FontAwesome;content:'\f060'}
-.collection-creator .paired-columns .unpair-btn{float:right;margin-top:-34px;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{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 .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 5a7a7003fbc3bc8f9d56f18a8d4b8f2d5b28fe42 -r a66a80701913bb99e8abd12235c1ca82dc508f57 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
@@ -211,10 +211,9 @@
}
// ------------------------------------------------------------------------ middle
- .middle {
- }
- .unpaired-columns,
- .paired-columns {
+ // ---- all
+ // macro
+ .flex-bordered-vertically {
// huh! - giving these any static height will pull them in
height: 0;
// NOT setting the above will give a full-height page
@@ -222,46 +221,80 @@
border: 1px solid lightgrey;
border-width: 1px 0 1px 0;
}
- // ------------------------------------------------------------------------ unpaired
- .paired-columns {
- margin-bottom: 8px;
- }
- // ------------------------------------------------------------------------ middle
- // ---- all
.column-datasets {
list-style: none;
overflow: hidden;
.dataset {
height: 32px;
- margin-bottom: 2px;
+ margin-top: 2px;
+ &:last-of-type {
+ margin-bottom: 2px;
+ }
border: 1px solid lightgrey;
border-radius: 3px;
padding: 0 8px 0 8px;
line-height: 28px;
cursor: pointer;
- //overflow: hidden;
- &:last-child {
- margin-bottom: 4px;
+
+ &.unpaired {
+ border-color: grey;
+ }
+
+ &.paired {
+ margin-left: 34px;
+ margin-right: 34px;
+ border: 2px solid grey;
+ background: #AFF1AF;
+
+ span {
+ display: inline-block;
+ overflow: hidden;
+ }
+ .forward-dataset-name {
+ text-align: right;
+ border-right: 1px solid grey;
+ padding-right: 8px;
+ &:after {
+ margin-left: 8px;
+ font-family: FontAwesome;
+ content: '\f061';
+ }
+ }
+ .pair-name-column {
+ text-align: center;
+ .pair-name:hover {
+ text-decoration: underline;
+ }
+ }
+ .reverse-dataset-name {
+ border-left: 1px solid grey;
+ padding-left: 8px;
+ &:before {
+ margin-right: 8px;
+ font-family: FontAwesome;
+ content: '\f060';
+ }
+ }
+ }
+
+ &:hover {
+ border-color: black;
+ }
+
+ &.selected {
+ border-color: black;
+ background: black;
+ color: white;
}
}
}
// ---- unpaired
.unpaired-columns {
- .dataset.unpaired {
- margin-top: 2px;
- border-color: grey;
- &:hover {
- border-color: black;
- }
- &.selected {
- border-color: black;
- background: black;
- color: white;
- }
- }
+ .flex-bordered-vertically;
+
.forward-column {
.dataset.unpaired {
margin-right: 32px;
@@ -319,62 +352,16 @@
// ---- paired datasets
.paired-columns {
+ .flex-bordered-vertically;
+ margin-bottom: 8px;
+
.column-datasets {
width: 100%;
overflow: auto;
-
- .dataset.paired {
- &:first-child {
- margin-top: 2px;
- }
- margin: 0px 34px 2px 34px;
-
- border-radius: 3px;
- border: 2px solid grey;
-
- background: #AFF1AF;
-
- &:hover,
- &.emphasized {
- border-color: black;
- }
-
- span {
- display: inline-block;
- overflow: hidden;
- }
- .forward-dataset-name {
- text-align: right;
- border-right: 1px solid grey;
- padding-right: 8px;
- &:after {
- margin-left: 8px;
- font-family: FontAwesome;
- content: '\f061';
- }
- }
- .pair-name {
- display: inline-block;
- text-align: center;
- &:hover {
- text-decoration: underline;
- }
- }
- .reverse-dataset-name {
- display: inline-block;
- border-left: 1px solid grey;
- padding-left: 8px;
- &:before {
- margin-right: 8px;
- font-family: FontAwesome;
- content: '\f060';
- }
- }
- }
}
.unpair-btn {
float: right;
- margin-top: -34px;
+ margin-top: -32px;
width: 31px;
height: 32px;
//z-index: 1;
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: martenson: initial implementation of library folder manager
by commits-noreply@bitbucket.org 27 Aug '14
by commits-noreply@bitbucket.org 27 Aug '14
27 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5a7a7003fbc3/
Changeset: 5a7a7003fbc3
User: martenson
Date: 2014-08-27 19:26:36
Summary: initial implementation of library folder manager
Affected #: 2 files
diff -r 8c0b86881425de9ba43c6aa604e868236cb7a9c9 -r 5a7a7003fbc3bc8f9d56f18a8d4b8f2d5b28fe42 lib/galaxy/managers/folders.py
--- /dev/null
+++ b/lib/galaxy/managers/folders.py
@@ -0,0 +1,160 @@
+"""
+Manager and Serializer for Library Folders.
+"""
+
+import galaxy.web
+from galaxy import exceptions
+from galaxy.model import orm
+
+import logging
+log = logging.getLogger( __name__ )
+
+
+# =============================================================================
+class FolderManager( object ):
+ """
+ Interface/service object for interacting with folders.
+ """
+
+ def get( self, trans, decoded_folder_id, check_ownership=False, check_accessible=True):
+ """
+ Get the folder from the DB.
+
+ :param decoded_folder_id: decoded folder id
+ :type decoded_folder_id: int
+ :param check_ownership: flag whether the check that user is owner
+ :type check_ownership: bool
+ :param check_accessible: flag whether to check that user can access item
+ :type check_accessible: bool
+
+ :returns: the requested folder
+ :rtype: LibraryFolder
+ """
+ try:
+ folder = trans.sa_session.query( trans.app.model.LibraryFolder ).filter( trans.app.model.LibraryFolder.table.c.id == decoded_folder_id ).one()
+ except MultipleResultsFound:
+ raise exceptions.InconsistentDatabase( 'Multiple folders found with the same id.' )
+ except NoResultFound:
+ raise exceptions.RequestParameterInvalidException( 'No folder found with the id provided.' )
+ except Exception, e:
+ raise exceptions.InternalServerError( 'Error loading from the database.' + str( e ) )
+
+ folder = self.secure( trans, folder, check_ownership, check_accessible )
+
+ return folder
+
+ def secure( self, trans, folder, check_ownership=True, check_accessible=True ):
+ """
+ Check if (a) user owns folder or (b) folder is accessible to user.
+
+ :param folder: folder item
+ :type folder: LibraryFolder
+ :param check_ownership: flag whether the check that user is owner
+ :type check_ownership: bool
+ :param check_accessible: flag whether to check that user can access item
+ :type check_accessible: bool
+
+ :returns: the original folder
+ :rtype: LibraryFolder
+ """
+ # all folders are accessible to an admin
+ if trans.user_is_admin():
+ return folder
+ if check_ownership:
+ folder = self.check_ownership( trans, folder )
+ if check_accessible:
+ folder = self.check_accessible( trans, folder )
+ return folder
+
+ def check_ownership( self, trans, folder ):
+ """
+ Check whether the user is owner of the folder.
+
+ :returns: the original folder
+ :rtype: LibraryFolder
+ """
+ if not trans.user:
+ raise exceptions.AuthenticationRequired( "Must be logged in to manage Galaxy items", type='error' )
+ if folder.user != trans.user:
+ raise exceptions.ItemOwnershipException( "Folder is not owned by the current user", type='error' )
+ else:
+ return folder
+
+ def check_accessible( self, trans, folder ):
+ """
+ Check whether the folder is accessible to current user.
+ By default every folder is accessible (contents have their own permissions).
+ """
+ return True
+
+ def get_folder_dict( self, trans, folder ):
+ """
+ Return folder data in the form of a dictionary.
+
+ :param folder: folder item
+ :type folder: LibraryFolder
+
+ :returns: dict with data about the new folder
+ :rtype: dictionary
+
+ """
+ folder_dict = folder.to_dict( view='element' )
+ folder_dict = trans.security.encode_all_ids( folder_dict, True )
+ folder_dict[ 'id' ] = 'F' + folder_dict[ 'id' ]
+ if folder_dict[ 'parent_id' ] is not None:
+ folder_dict[ 'parent_id' ] = 'F' + folder_dict[ 'parent_id' ]
+ return folder_dict
+
+ def create( self, trans, parent_folder_id, new_folder_name, new_folder_description='' ):
+ """
+ Create a new folder under the given folder.
+
+ :param parent_folder_id: decoded id
+ :type parent_folder_id: int
+ :param new_folder_name: name of the new folder
+ :type new_folder_name: str
+ :param new_folder_description: description of the folder (optional, defaults to empty string)
+ :type new_folder_description: str
+
+ :returns: the new folder
+ :rtype: LibraryFolder
+
+ :raises: InsufficientPermissionsException
+ """
+ parent_folder = self.get( trans, parent_folder_id )
+ current_user_roles = trans.get_current_user_roles()
+ if not ( trans.user_is_admin or trans.app.security_agent.can_add_library_item( current_user_roles, parent_folder ) ):
+ raise exceptions.InsufficientPermissionsException( 'You do not have proper permission to create folders under given folder.' )
+ new_folder = trans.app.model.LibraryFolder( name=new_folder_name, description=new_folder_description )
+ # We are associating the last used genome build with folders, so we will always
+ # initialize a new folder with the first dbkey in genome builds list which is currently
+ # ? unspecified (?)
+ new_folder.genome_build = trans.app.genome_builds.default_value
+ parent_folder.add_folder( new_folder )
+ trans.sa_session.add( new_folder )
+ trans.sa_session.flush()
+ # New folders default to having the same permissions as their parent folder
+ trans.app.security_agent.copy_library_permissions( trans, parent_folder, new_folder )
+ return new_folder
+
+ def get_current_roles( self, trans, folder ):
+ """
+ Find all roles currently connected to relevant permissions
+ on the folder.
+
+ :param folder: the model object
+ :type folder: LibraryFolder
+
+ :returns: dict of current roles for all available permission types
+ :rtype: dictionary
+ """
+ # Omit duplicated roles by converting to set
+ modify_roles = set( trans.app.security_agent.get_roles_for_action( folder, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY ) )
+ manage_roles = set( trans.app.security_agent.get_roles_for_action( folder, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE ) )
+ add_roles = set( trans.app.security_agent.get_roles_for_action( folder, trans.app.security_agent.permitted_actions.LIBRARY_ADD ) )
+
+ modify_folder_role_list = [ modify_role.name for modify_role in modify_roles ]
+ manage_folder_role_list = [ manage_role.name for manage_role in manage_roles ]
+ add_library_item_role_list = [ add_role.name for add_role in add_roles ]
+
+ return dict( modify_folder_role_list=modify_folder_role_list, manage_folder_role_list=manage_folder_role_list, add_library_item_role_list=add_library_item_role_list )
diff -r 8c0b86881425de9ba43c6aa604e868236cb7a9c9 -r 5a7a7003fbc3bc8f9d56f18a8d4b8f2d5b28fe42 lib/galaxy/webapps/galaxy/api/folders.py
--- a/lib/galaxy/webapps/galaxy/api/folders.py
+++ b/lib/galaxy/webapps/galaxy/api/folders.py
@@ -1,16 +1,10 @@
"""
API operations on library folders
"""
-# import os
-# import shutil
-# import urllib
-# import re
-# import socket
-# import traceback
-# import string
from galaxy import util
from galaxy import web
from galaxy import exceptions
+from galaxy.managers import folders
from galaxy.web import _future_expose_api as expose_api
from galaxy.web.base.controller import BaseAPIController, UsesLibraryMixin, UsesLibraryMixinItems
from sqlalchemy.orm.exc import MultipleResultsFound
@@ -22,10 +16,14 @@
class FoldersController( BaseAPIController, UsesLibraryMixin, UsesLibraryMixinItems ):
+ def __init__( self, app ):
+ super( FoldersController, self ).__init__( app )
+ self.folder_manager = folders.FolderManager()
+
@web.expose_api
def index( self, trans, **kwd ):
"""
- GET /api/folders/
+ *GET /api/folders/
This would normally display a list of folders. However, that would
be across multiple libraries, so it's not implemented.
"""
@@ -45,12 +43,8 @@
:returns: dictionary including details of the folder
:rtype: dict
"""
- folder_id_without_prefix = self.__cut_the_prefix( id )
- content = self.get_library_folder( trans, folder_id_without_prefix, check_ownership=False, check_accessible=True )
- return_dict = self.encode_all_ids( trans, content.to_dict( view='element' ) )
- return_dict[ 'id' ] = 'F' + return_dict[ 'id' ]
- if return_dict[ 'parent_id' ] is not None:
- return_dict[ 'parent_id' ] = 'F' + return_dict[ 'parent_id' ]
+ folder = self.folder_manager.get( trans, self.__cut_and_decode( trans, id ), check_ownership=False, check_accessible=True )
+ return_dict = self.folder_manager.get_folder_dict( trans, folder )
return return_dict
@expose_api
@@ -74,47 +68,20 @@
:returns: information about newly created folder, notably including ID
:rtype: dictionary
- :raises: RequestParameterMissingException, MalformedId, InternalServerError
+ :raises: RequestParameterMissingException
"""
-
payload = kwd.get( 'payload', None )
if payload is None:
- raise exceptions.RequestParameterMissingException( "Missing required parameters 'encoded_parent_folder_id' and 'name'." )
+ raise exceptions.RequestParameterMissingException( "Missing required parameter 'name'." )
name = payload.get( 'name', None )
+ if name is None:
+ raise exceptions.RequestParameterMissingException( "Missing required parameter 'name'." )
description = payload.get( 'description', '' )
- if encoded_parent_folder_id is None:
- raise exceptions.RequestParameterMissingException( "Missing required parameter 'encoded_parent_folder_id'." )
- elif name is None:
- raise exceptions.RequestParameterMissingException( "Missing required parameter 'name'." )
-
- encoded_parent_folder_id = self.__cut_the_prefix( encoded_parent_folder_id )
- decoded_parent_folder_id = self.__decode_folder_id( trans, encoded_parent_folder_id )
- parent_folder = self.__load_folder( trans, decoded_parent_folder_id )
+ decoded_parent_folder_id = self.__cut_and_decode( trans, encoded_parent_folder_id )
+ parent_folder = self.folder_manager.get( trans, decoded_parent_folder_id )
+ new_folder = self.folder_manager.create( trans, parent_folder.id, name, description )
+ return self.folder_manager.get_folder_dict( trans, new_folder )
- library = parent_folder.parent_library
- if library.deleted:
- raise exceptions.ObjectAttributeInvalidException( 'You cannot create folder within a deleted library. Undelete it first.' )
-
- # TODO: refactor the functionality for use in manager instead of calling another controller
- params = dict( [ ( "name", name ), ( "description", description ) ] )
- status, output = trans.webapp.controllers['library_common'].create_folder( trans, 'api', encoded_parent_folder_id, '', **params )
-
- if 200 == status and len( output.items() ) == 1:
- for k, v in output.items():
- try:
- folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( v.id )
- except Exception, e:
- raise exceptions.InternalServerError( 'Error loading from the database.' + str( e ))
- if folder:
- update_time = folder.update_time.strftime( "%Y-%m-%d %I:%M %p" )
- return_dict = self.encode_all_ids( trans, folder.to_dict( view='element' ) )
- return_dict[ 'update_time' ] = update_time
- return_dict[ 'parent_id' ] = 'F' + return_dict[ 'parent_id' ]
- return_dict[ 'id' ] = 'F' + return_dict[ 'id' ]
- return return_dict
- else:
- raise exceptions.InternalServerError( 'Error while creating a folder.' + str( e ) )
-
@expose_api
def get_permissions( self, trans, encoded_folder_id, **kwd ):
"""
@@ -135,19 +102,16 @@
"""
current_user_roles = trans.get_current_user_roles()
is_admin = trans.user_is_admin()
-
encoded_folder_id = self.__cut_the_prefix( encoded_folder_id )
decoded_folder_id = self.__decode_folder_id( trans, encoded_folder_id )
- folder = self.__load_folder( trans, decoded_folder_id )
+ folder = self.folder_manager.get( trans, decoded_folder_id )
- if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, library ) ):
+ if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, folder ) ):
raise exceptions.InsufficientPermissionsException( 'You do not have proper permission to access permissions of this folder.' )
scope = kwd.get( 'scope', None )
-
if scope == 'current' or scope is None:
- return self._get_current_roles( trans, folder )
-
+ return self.folder_manager.get_current_roles( trans, folder )
# Return roles that are available to select.
elif scope == 'available':
page = kwd.get( 'page', None )
@@ -155,17 +119,13 @@
page = int( page )
else:
page = 1
-
page_limit = kwd.get( 'page_limit', None )
if page_limit is not None:
page_limit = int( page_limit )
else:
page_limit = 10
-
query = kwd.get( 'q', None )
-
roles, total_roles = trans.app.security_agent.get_valid_roles( trans, folder, query, page, page_limit )
-
return_roles = []
for role in roles:
return_roles.append( dict( id=role.name, name=role.name, type=role.type ) )
@@ -203,7 +163,7 @@
current_user_roles = trans.get_current_user_roles()
decoded_folder_id = self.__decode_folder_id( trans, self.__cut_the_prefix( encoded_folder_id ) )
- folder = self.__load_folder( trans, decoded_folder_id )
+ folder = self.folder_manager.get( trans, decoded_folder_id )
if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, folder ) ):
raise exceptions.InsufficientPermissionsException( 'You do not have proper permission to modify permissions of this folder.' )
@@ -266,8 +226,7 @@
else:
raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value.'
'Allowed values are: "set_permissions"' )
-
- return self._get_current_roles( trans, folder )
+ return self.folder_manager.get_current_roles( trans, folder )
@web.expose_api
def update( self, trans, id, library_id, payload, **kwd ):
@@ -297,42 +256,11 @@
raise exceptions.MalformedId( "Malformed folder id ( %s ) specified, unable to decode" % ( str( encoded_id ) ) )
return decoded_id
- def __load_folder( self, trans, folder_id ):
+ def __cut_and_decode( self, trans, encoded_folder_id ):
"""
- Load the folder from the DB.
+ Cuts the prefix (the prepended 'F') and returns the decoded id.
"""
- try:
- folder = trans.sa_session.query( trans.app.model.LibraryFolder ).filter( trans.app.model.LibraryFolder.table.c.id == folder_id ).one()
- except MultipleResultsFound:
- raise exceptions.InconsistentDatabase( 'Multiple folders found with the same id.' )
- except NoResultFound:
- raise exceptions.RequestParameterInvalidException( 'No folder found with the id provided.' )
- except Exception, e:
- raise exceptions.InternalServerError( 'Error loading from the database.' + str( e ) )
- return folder
-
-
- def _get_current_roles( self, trans, folder ):
- """
- Find all roles currently connected to relevant permissions
- on the folder.
-
- :param folder: the model object
- :type folder: LibraryFolder
-
- :rtype: dictionary
- :returns: dict of current roles for all available permission types
- """
- # Omit duplicated roles by converting to set
- modify_roles = set( trans.app.security_agent.get_roles_for_action( folder, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY ) )
- manage_roles = set( trans.app.security_agent.get_roles_for_action( folder, trans.app.security_agent.permitted_actions.LIBRARY_MANAGE ) )
- add_roles = set( trans.app.security_agent.get_roles_for_action( folder, trans.app.security_agent.permitted_actions.LIBRARY_ADD ) )
-
- modify_folder_role_list = [ modify_role.name for modify_role in modify_roles ]
- manage_folder_role_list = [ manage_role.name for manage_role in manage_roles ]
- add_library_item_role_list = [ add_role.name for add_role in add_roles ]
-
- return dict( modify_folder_role_list=modify_folder_role_list, manage_folder_role_list=manage_folder_role_list, add_library_item_role_list=add_library_item_role_list )
+ return self.__decode_folder_id( trans, self.__cut_the_prefix( encoded_folder_id ) )
def _load_role( self, trans, role_name ):
"""
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Fix upload tool for 6cb895d.
by commits-noreply@bitbucket.org 27 Aug '14
by commits-noreply@bitbucket.org 27 Aug '14
27 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8c0b86881425/
Changeset: 8c0b86881425
User: jmchilton
Date: 2014-08-27 19:06:26
Summary: Fix upload tool for 6cb895d.
Web form (at least for older style upload tool) was passing in '' and the UUID custom datatype treats this as an invalid UUID (probably correct) instead of a None. This changeset fixes that by ensuring these values coming in through the controllers are transformed into None-s.
Affected #: 1 file
diff -r 3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff -r 8c0b86881425de9ba43c6aa604e868236cb7a9c9 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -278,7 +278,7 @@
ftp_files = context['ftp_files']
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
- uuid = context.get( 'uuid', None )
+ uuid = context.get( 'uuid', None ) or None # Turn '' to None
warnings = []
to_posix_lines = False
if context.get( 'to_posix_lines', None ) not in [ "None", None, False ]:
@@ -324,7 +324,7 @@
data_file = context['file_data']
url_paste = context['url_paste']
ftp_files = context['ftp_files']
- uuid = context.get( 'uuid', None )
+ uuid = context.get( 'uuid', None ) or None # Turn '' to None
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
to_posix_lines = False
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Reduce workflow step state and module population duplication.
by commits-noreply@bitbucket.org 27 Aug '14
by commits-noreply@bitbucket.org 27 Aug '14
27 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/3e00d002e7ba/
Changeset: 3e00d002e7ba
User: jmchilton
Date: 2014-08-27 16:49:15
Summary: Reduce workflow step state and module population duplication.
Move all operations prior to workflow invocation (and a few other places state and modules are used) relating to populating the non-persistent attributes of `WorkflowStep`s (e.g. module, state, upgrade_messages, and input_connections_by_name) into a single function on a new class.
This should fix a couple of small errors as well - input_connections_by_name was being mis-calculated in a few places (though potentially never used down those roads) and some error handling code in the workflow editor template was expecting step.module to be populated with something (even if None) and it was not always.
Affected #: 4 files
diff -r 7c566a68d2d07375c53006191671dfed04332f55 -r 3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -26,7 +26,7 @@
from galaxy.web import error, url_for
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
+from galaxy.workflow.modules import module_factory, WorkflowModuleInjector, MissingToolException
from galaxy.model.orm import eagerload, eagerload_all, desc
from galaxy.security.validate_user_input import validate_publicname
from galaxy.util.sanitize_html import sanitize_html
@@ -1625,30 +1625,13 @@
def get_stored_workflow_steps( self, trans, stored_workflow ):
""" Restores states for a stored workflow's steps. """
+ module_injector = WorkflowModuleInjector( trans )
for step in stored_workflow.latest_workflow.steps:
- step.upgrade_messages = {}
- if step.type == 'tool' or step.type is None:
- # Restore the tool state for the step
- module = module_factory.from_workflow_step( trans, step )
- if module:
- #Check if tool was upgraded
- step.upgrade_messages = module.check_and_update_state()
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- module.add_dummy_datasets( connections=step.input_connections )
- # Store state with the step
- step.module = module
- step.state = module.state
- else:
- step.upgrade_messages = "Unknown Tool ID"
- step.module = None
- step.state = None
- else:
- ## Non-tool specific stuff?
- step.module = module_factory.from_workflow_step( trans, step )
- step.state = step.module.get_runtime_state()
- # Connections by input name
- step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in step.input_connections )
+ try:
+ module_injector.inject( step )
+ except MissingToolException:
+ # Now upgrade_messages is a string instead of a dict, why?
+ step.upgrade_messages = "Unknown Tool ID"
def _import_shared_workflow( self, trans, stored):
""" """
diff -r 7c566a68d2d07375c53006191671dfed04332f55 -r 3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -24,6 +24,8 @@
from galaxy.web.framework import form
from galaxy.web.framework.helpers import grids, time_ago
from galaxy.web.framework.helpers import to_unicode
+from galaxy.workflow.modules import WorkflowModuleInjector
+from galaxy.workflow.modules import MissingToolException
from galaxy.workflow.modules import module_factory, is_tool_module_type
from galaxy.workflow.run import invoke
from galaxy.workflow.run import WorkflowRunConfig
@@ -1269,6 +1271,7 @@
error("That history does not exist.")
try: # use a try/finally block to restore the user's current history
default_target_history = trans.get_history()
+ module_injector = WorkflowModuleInjector( trans )
if kwargs:
# If kwargs were provided, the states for each step should have
# been POSTed
@@ -1276,45 +1279,15 @@
invocations = []
for (kwargs, multi_input_keys) in _expand_multiple_inputs(kwargs):
for step in workflow.steps:
- step.upgrade_messages = {}
- # Connections by input name
- input_connections_by_name = {}
- for conn in step.input_connections:
- input_name = conn.input_name
- if not input_name in input_connections_by_name:
- input_connections_by_name[input_name] = []
- input_connections_by_name[input_name].append(conn)
- step.input_connections_by_name = input_connections_by_name
# Extract just the arguments for this step by prefix
p = "%s|" % step.id
l = len(p)
step_args = dict( ( k[l:], v ) for ( k, v ) in kwargs.iteritems() if k.startswith( p ) )
- step_errors = None
- if step.type == 'tool' or step.type is None:
- module = module_factory.from_workflow_step( trans, step )
- # Fix any missing parameters
- step.upgrade_messages = module.check_and_update_state()
- if step.upgrade_messages:
- has_upgrade_messages = True
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- module.add_dummy_datasets( connections=step.input_connections )
- # Get the tool
- tool = module.tool
- # Get the state
- step.state = state = module.state
- # Get old errors
- old_errors = state.inputs.pop( "__errors__", {} )
- # Update the state
- step_errors = tool.update_state( trans, tool.inputs, step.state.inputs, step_args,
- update_only=True, old_errors=old_errors )
- else:
- # Fix this for multiple inputs
- module = step.module = module_factory.from_workflow_step( trans, step )
- state = step.state = module.decode_runtime_state( trans, step_args.pop( "tool_state" ) )
- step_errors = module.update_runtime_state( trans, state, step_args )
+ step_errors = module_injector.inject( step, step_args )
+ if step.upgrade_messages:
+ has_upgrade_messages = True
if step_errors:
- errors[step.id] = state.inputs["__errors__"] = step_errors
+ errors[step.id] = step.state.inputs["__errors__"] = step_errors
if 'run_workflow' in kwargs and not errors:
new_history = None
if 'new_history' in kwargs:
@@ -1361,36 +1334,20 @@
# Prepare each step
missing_tools = []
for step in workflow.steps:
- step.upgrade_messages = {}
- # Contruct modules
+ try:
+ module_injector.inject( step )
+ except MissingToolException:
+ if step.tool_id not in missing_tools:
+ missing_tools.append(step.tool_id)
+ continue
+ if step.upgrade_messages:
+ has_upgrade_messages = True
if step.type == 'tool' or step.type is None:
- # Restore the tool state for the step
- step.module = module_factory.from_workflow_step( trans, step )
- if not step.module:
- if step.tool_id not in missing_tools:
- missing_tools.append(step.tool_id)
- continue
- step.upgrade_messages = step.module.check_and_update_state()
- if step.upgrade_messages:
- has_upgrade_messages = True
- if step.type == 'tool' and step.module.version_changes:
+ if step.module.version_changes:
step_version_changes.extend(step.module.version_changes)
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- step.module.add_dummy_datasets( connections=step.input_connections )
- # Store state with the step
- step.state = step.module.state
# Error dict
if step.tool_errors:
- # has_errors is never used.
- # has_errors = True
errors[step.id] = step.tool_errors
- else:
- ## Non-tool specific stuff?
- step.module = module_factory.from_workflow_step( trans, step )
- step.state = step.module.get_runtime_state()
- # Connections by input name
- step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in step.input_connections )
if missing_tools:
stored.annotation = self.get_item_annotation_str( trans.sa_session, trans.user, stored )
return trans.fill_template(
@@ -1464,32 +1421,17 @@
trans.sa_session.add(m)
# Prepare each step
trans.sa_session.flush()
+ module_injector = WorkflowModuleInjector( trans )
for step in workflow.steps:
step.upgrade_messages = {}
# Contruct modules
+ module_injector.inject( step )
+ if step.upgrade_messages:
+ has_upgrade_messages = True
if step.type == 'tool' or step.type is None:
- # Restore the tool state for the step
- step.module = module_factory.from_workflow_step( trans, step )
- # Fix any missing parameters
- step.upgrade_messages = step.module.check_and_update_state()
- if step.upgrade_messages:
- has_upgrade_messages = True
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- step.module.add_dummy_datasets( connections=step.input_connections )
- # Store state with the step
- step.state = step.module.state
# Error dict
if step.tool_errors:
- # has_errors is never used
- # has_errors = True
errors[step.id] = step.tool_errors
- else:
- ## Non-tool specific stuff?
- step.module = module_factory.from_workflow_step( trans, step )
- step.state = step.module.get_runtime_state()
- # Connections by input name
- step.input_connections_by_name = dict( ( conn.input_name, conn ) for conn in step.input_connections )
# Render the form
return trans.fill_template(
"workflow/tag_outputs.mako",
diff -r 7c566a68d2d07375c53006191671dfed04332f55 -r 3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -559,3 +559,81 @@
tool=ToolModule,
)
module_factory = WorkflowModuleFactory( module_types )
+
+
+class MissingToolException( Exception ):
+ """ WorkflowModuleInjector will raise this if the tool corresponding to the
+ module is missing. """
+
+
+class WorkflowModuleInjector(object):
+ """ Injects workflow step objects from the ORM with appropriate module and
+ module generated/influenced state. """
+
+ def __init__( self, trans ):
+ self.trans = trans
+
+ def inject( self, step, step_args=None ):
+ """ Pre-condition: `step` is an ORM object coming from the database, if
+ supplied `step_args` is the representation of the inputs for that step
+ supplied via web form.
+
+ Post-condition: The supplied `step` has new non-persistent attributes
+ useful during workflow invocation. These include 'upgrade_messages',
+ 'state', 'input_connections_by_name', and 'module'.
+
+ If step_args is provided from a web form this is applied to generate
+ 'state' else it is just obtained from the database.
+ """
+ trans = self.trans
+
+ step_errors = None
+
+ step.upgrade_messages = {}
+
+ # Make connection information available on each step by input name.
+ input_connections_by_name = {}
+ for conn in step.input_connections:
+ input_name = conn.input_name
+ if not input_name in input_connections_by_name:
+ input_connections_by_name[input_name] = []
+ input_connections_by_name[input_name].append(conn)
+ step.input_connections_by_name = input_connections_by_name
+
+ # Populate module.
+ module = step.module = module_factory.from_workflow_step( trans, step )
+
+ # Calculating step errors and state depends on whether step is a tool step or not.
+ if step.type == 'tool' or step.type is None:
+ if not module:
+ step.module = None
+ step.state = None
+ raise MissingToolException()
+
+ # Fix any missing parameters
+ step.upgrade_messages = module.check_and_update_state()
+
+ # Any connected input needs to have value DummyDataset (these
+ # are not persisted so we need to do it every time)
+ module.add_dummy_datasets( connections=step.input_connections )
+
+ state = module.state
+ step.state = state
+ if step_args is not None:
+ # Get the tool
+ tool = module.tool
+ # Get old errors
+ old_errors = state.inputs.pop( "__errors__", {} )
+ # Update the state
+ step_errors = tool.update_state( trans, tool.inputs, step.state.inputs, step_args,
+ update_only=True, old_errors=old_errors )
+
+ else:
+ if step_args:
+ # Fix this for multiple inputs
+ state = step.state = module.decode_runtime_state( trans, step_args.pop( "tool_state" ) )
+ step_errors = module.update_runtime_state( trans, state, step_args )
+ else:
+ step.state = step.module.get_runtime_state()
+
+ return step_errors
diff -r 7c566a68d2d07375c53006191671dfed04332f55 -r 3e00d002e7ba1fdd9d914bcd68589aad5c1e21ff lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -229,24 +229,10 @@
def _populate_state( self ):
# Build the state for each step
+ module_injector = modules.WorkflowModuleInjector( self.trans )
for step in self.workflow.steps:
- step_errors = None
- input_connections_by_name = {}
- for conn in step.input_connections:
- input_name = conn.input_name
- if not input_name in input_connections_by_name:
- input_connections_by_name[input_name] = []
- input_connections_by_name[input_name].append(conn)
- step.input_connections_by_name = input_connections_by_name
-
+ step_errors = module_injector.inject( step )
if step.type == 'tool' or step.type is None:
- step.module = modules.module_factory.from_workflow_step( self.trans, step )
- # Check for missing parameters
- step.upgrade_messages = step.module.check_and_update_state()
- # Any connected input needs to have value DummyDataset (these
- # are not persisted so we need to do it every time)
- step.module.add_dummy_datasets( connections=step.input_connections )
- step.state = step.module.state
_update_step_parameters( step, self.param_map )
if step.tool_errors:
message = "Workflow cannot be run because of validation errors in some steps: %s" % step_errors
@@ -254,9 +240,6 @@
if step.upgrade_messages:
message = "Workflow cannot be run because of step upgrade messages: %s" % step.upgrade_messages
raise exceptions.MessageException( message )
- else:
- step.module = modules.module_factory.from_workflow_step( self.trans, step )
- step.state = step.module.get_runtime_state()
def _update_step_parameters(step, normalized_param_map):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: UI, Paired collection creator: refactoring of paired HTML and fixes to draggable partition, add brush selection to unpaired
by commits-noreply@bitbucket.org 27 Aug '14
by commits-noreply@bitbucket.org 27 Aug '14
27 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7c566a68d2d0/
Changeset: 7c566a68d2d0
User: carlfeberhard
Date: 2014-08-26 22:30:46
Summary: UI, Paired collection creator: refactoring of paired HTML and fixes to draggable partition, add brush selection to unpaired
Affected #: 6 files
diff -r ece8ef90a8289399bf9faca6a3265696da7e0beb -r 7c566a68d2d07375c53006191671dfed04332f55 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
@@ -3,7 +3,38 @@
"mvc/base-mvc",
"utils/localization"
], function( levelshteinDistance, baseMVC, _l ){
-//=============================================================================
+/* ============================================================================
+TODO:
+
+
+PROGRAMMATICALLY:
+h = Galaxy.currHistoryPanel; h.showSelectors(); h.selectAllDatasets(); _.last( h.actionsPopup.options ).func()
+
+============================================================================ */
+/** A view for paired datasets in the collections creator.
+ */
+var PairView = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
+
+ tagName : 'li',
+ className : 'dataset paired',
+
+ initialize : function( attributes ){
+ this.pair = attributes.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 flex-column"><%= pair.name %></span>',
+ '<span class="reverse-dataset-name flex-column"><%= pair.reverse.name %></span>'
+ ].join(''), { pair: this.pair }))
+ .addClass( 'flex-column-container' );
+ return this;
+ }
+
+});
+
/** An interface for building collections of paired datasets.
*/
var PairedCollectionCreator = Backbone.View.extend( baseMVC.LoggableMixin ).extend({
@@ -12,11 +43,12 @@
/** set up initial options, instance vars, behaviors, and autopair (if set to do so) */
initialize : function( attributes ){
- //console.debug( '-- PairedCollectionCreator:', attributes );
+ //this.debug( '-- PairedCollectionCreator:', attributes );
attributes = _.defaults( attributes, {
datasets : [],
filters : this.DEFAULT_FILTERS,
+ //automaticallyPair : false,
automaticallyPair : true,
matchPercentage : 1.0,
//matchPercentage : 0.9,
@@ -24,7 +56,7 @@
//strategy : 'levenshtein'
strategy : 'lcs'
});
- //console.debug( 'attributes now:', attributes );
+ //this.debug( 'attributes now:', attributes );
/** unordered, original list */
this.initialList = attributes.datasets;
@@ -89,7 +121,7 @@
// ------------------------------------------------------------------------ process raw list
/** set up main data: cache initialList, sort, and autopair */
_dataSetUp : function(){
- //console.debug( '-- _dataSetUp' );
+ //this.debug( '-- _dataSetUp' );
this.paired = [];
this.unpaired = [];
@@ -110,7 +142,7 @@
/** sort initial list */
_sortInitialList : function(){
- //console.debug( '-- _sortInitialList' );
+ //this.debug( '-- _sortInitialList' );
this._sortDatasetList( this.initialList );
//this._printList( this.unpaired );
},
@@ -192,14 +224,14 @@
*/
autoPair : function( strategy ){
strategy = strategy || this.strategy;
- //console.debug( '-- autoPair', strategy );
+ //this.debug( '-- autoPair', strategy );
this.simpleAutoPair();
return this[ strategy ].call( this );
},
/** attempts to pair forward with reverse when names exactly match (after removing filters) */
simpleAutoPair : function(){
- //console.debug( '-- simpleAutoPair' );
+ //this.debug( '-- simpleAutoPair' );
// simplified auto pair that moves down unpaired lists *in order*,
// removes filters' strings from fwd and rev,
// and, if names w/o filters *exactly* match, creates a pair
@@ -215,18 +247,18 @@
var fwd = fwdList[ i ];
//TODO: go through the filterFwdFn
fwdName = fwd.name.replace( this.filters[0], '' );
- //console.debug( i, 'fwd:', fwdName );
+ //this.debug( i, 'fwd:', fwdName );
matchFound = false;
for( j=0; j<revList.length; j++ ){
var rev = revList[ j ];
revName = rev.name.replace( this.filters[1], '' );
- //console.debug( '\t ', j, 'rev:', revName );
+ //this.debug( '\t ', j, 'rev:', revName );
if( fwd !== rev && fwdName === revName ){
matchFound = true;
// if it is a match, keep i at current, pop fwd, pop rev and break
- //console.debug( '---->', fwdName, revName );
+ //this.debug( '---->', fwdName, revName );
this._pair(
fwdList.splice( i, 1 )[0],
revList.splice( j, 1 )[0],
@@ -237,17 +269,17 @@
}
if( !matchFound ){ i += 1; }
}
- //console.debug( 'remaining Forward:' );
+ //this.debug( 'remaining Forward:' );
//this._printList( this.unpairedForward );
- //console.debug( 'remaining Reverse:' );
+ //this.debug( 'remaining Reverse:' );
//this._printList( this.unpairedReverse );
- //console.debug( '' );
+ //this.debug( '' );
},
/** attempt to autopair using edit distance between forward and reverse (after removing filters) */
autoPairLevenshtein : function(){
//precondition: filters are set, both lists are not empty, and all filenames.length > filters[?].length
- //console.debug( '-- autoPairLevenshtein' );
+ //this.debug( '-- autoPairLevenshtein' );
var i = 0, j,
split = this._splitByFilters(),
fwdList = split[0],
@@ -259,34 +291,34 @@
var fwd = fwdList[ i ];
//TODO: go through the filterFwdFn
fwdName = fwd.name.replace( this.filters[0], '' );
- //console.debug( i, 'fwd:', fwdName );
+ //this.debug( i, 'fwd:', fwdName );
bestDist = Number.MAX_VALUE;
for( j=0; j<revList.length; j++ ){
var rev = revList[ j ];
revName = rev.name.replace( this.filters[1], '' );
- //console.debug( '\t ', j, 'rev:', revName );
+ //this.debug( '\t ', j, 'rev:', revName );
if( fwd !== rev ){
if( fwdName === revName ){
- //console.debug( '\t\t exactmatch:', fwdName, revName );
+ //this.debug( '\t\t exactmatch:', fwdName, revName );
bestIndex = j;
bestDist = 0;
break;
}
distance = levenshteinDistance( fwdName, revName );
- //console.debug( '\t\t distance:', distance, 'bestDist:', bestDist );
+ //this.debug( '\t\t distance:', distance, 'bestDist:', bestDist );
if( distance < bestDist ){
bestIndex = j;
bestDist = distance;
}
}
}
- //console.debug( '---->', fwd.name, bestIndex, bestDist );
- //console.debug( '---->', fwd.name, revList[ bestIndex ].name, bestDist );
+ //this.debug( '---->', fwd.name, bestIndex, bestDist );
+ //this.debug( '---->', fwd.name, revList[ bestIndex ].name, bestDist );
var percentage = 1.0 - ( bestDist / ( Math.max( fwdName.length, revName.length ) ) );
- //console.debug( '----> %', percentage * 100 );
+ //this.debug( '----> %', percentage * 100 );
if( percentage >= this.matchPercentage ){
this._pair(
@@ -301,17 +333,17 @@
i += 1;
}
}
- //console.debug( 'remaining Forward:' );
+ //this.debug( 'remaining Forward:' );
//this._printList( this.unpairedForward );
- //console.debug( 'remaining Reverse:' );
+ //this.debug( 'remaining Reverse:' );
//this._printList( this.unpairedReverse );
- //console.debug( '' );
+ //this.debug( '' );
},
/** attempt to auto pair using common substrings from both front and back (after removing filters) */
autoPairLCSs : function(){
//precondition: filters are set, both lists are not empty
- //console.debug( '-- autoPairLCSs' );
+ //this.debug( '-- autoPairLCSs' );
var i = 0, j,
split = this._splitByFilters(),
fwdList = split[0],
@@ -319,39 +351,39 @@
fwdName, revName,
currMatch, bestIndex, bestMatch;
if( !fwdList.length || !revList.length ){ return; }
- //console.debug( fwdList, revList );
+ //this.debug( fwdList, revList );
while( i<fwdList.length ){
var fwd = fwdList[ i ];
fwdName = fwd.name.replace( this.filters[0], '' );
- //console.debug( i, 'fwd:', fwdName );
+ //this.debug( i, 'fwd:', fwdName );
bestMatch = 0;
for( j=0; j<revList.length; j++ ){
var rev = revList[ j ];
revName = rev.name.replace( this.filters[1], '' );
- //console.debug( '\t ', j, 'rev:', revName );
+ //this.debug( '\t ', j, 'rev:', revName );
if( fwd !== rev ){
if( fwdName === revName ){
- //console.debug( '\t\t exactmatch:', fwdName, revName );
+ //this.debug( '\t\t exactmatch:', fwdName, revName );
bestIndex = j;
bestMatch = fwdName.length;
break;
}
var match = this._naiveStartingAndEndingLCS( fwdName, revName );
currMatch = match.length;
- //console.debug( '\t\t match:', match, 'currMatch:', currMatch, 'bestMatch:', bestMatch );
+ //this.debug( '\t\t match:', match, 'currMatch:', currMatch, 'bestMatch:', bestMatch );
if( currMatch > bestMatch ){
bestIndex = j;
bestMatch = currMatch;
}
}
}
- //console.debug( '---->', i, fwd.name, bestIndex, revList[ bestIndex ].name, bestMatch );
+ //this.debug( '---->', i, fwd.name, bestIndex, revList[ bestIndex ].name, bestMatch );
var percentage = bestMatch / ( Math.min( fwdName.length, revName.length ) );
- //console.debug( '----> %', percentage * 100 );
+ //this.debug( '----> %', percentage * 100 );
if( percentage >= this.matchPercentage ){
this._pair(
@@ -366,11 +398,11 @@
i += 1;
}
}
- //console.debug( 'remaining Forward:' );
+ //this.debug( 'remaining Forward:' );
//this._printList( this.unpairedForward );
- //console.debug( 'remaining Reverse:' );
+ //this.debug( 'remaining Reverse:' );
//this._printList( this.unpairedReverse );
- //console.debug( '' );
+ //this.debug( '' );
},
/** return the concat'd longest common prefix and suffix from two strings */
@@ -406,7 +438,7 @@
_pair : function( fwd, rev, options ){
options = options || {};
//TODO: eventing, options
- //console.debug( '_pair:', fwd, rev );
+ //this.debug( '_pair:', fwd, rev );
var pair = this._createPair( fwd, rev, options.name );
this.paired.push( pair );
this.unpaired = _.without( this.unpaired, fwd, rev );
@@ -524,7 +556,7 @@
return creator._pairToJSON( pair );
})
};
- //console.debug( JSON.stringify( ajaxData ) );
+ //this.debug( JSON.stringify( ajaxData ) );
return jQuery.ajax( url, {
type : 'POST',
contentType : 'application/json',
@@ -535,7 +567,7 @@
creator._ajaxErrHandler( xhr, status, message );
})
.done( function( response, message, xhr ){
- //console.info( 'ok', response, message, xhr );
+ //this.info( 'ok', response, message, xhr );
creator.trigger( 'collection:created', response, message, xhr );
if( typeof creator.oncreate === 'function' ){
creator.oncreate.call( this, response, message, xhr );
@@ -545,7 +577,7 @@
/** handle ajax errors with feedback and details to the user (if available) */
_ajaxErrHandler : function( xhr, status, message ){
- console.error( xhr, status, message );
+ this.error( xhr, status, message );
var content = _l( 'An error occurred while creating this collection' );
if( xhr ){
if( xhr.readyState === 0 && xhr.status === 0 ){
@@ -563,7 +595,7 @@
// ------------------------------------------------------------------------ rendering
/** render the entire interface */
render : function( speed, callback ){
- //console.debug( '-- _render' );
+ //this.debug( '-- _render' );
//this.$el.empty().html( PairedCollectionCreator.templates.main() );
this.$el.empty().html( PairedCollectionCreator.templates.main() );
this._renderHeader( speed );
@@ -575,7 +607,7 @@
/** render the header section */
_renderHeader : function( speed, callback ){
- //console.debug( '-- _renderHeader' );
+ //this.debug( '-- _renderHeader' );
var $header = this.$( '.header' ).empty().html( PairedCollectionCreator.templates.header() )
.find( '.help-content' ).prepend( $( PairedCollectionCreator.templates.helpContent() ) );
@@ -606,7 +638,7 @@
},
/** render the unpaired section, showing datasets accrd. to filters, update the unpaired counts */
_renderUnpaired : function( speed, callback ){
- //console.debug( '-- _renderUnpaired' );
+ //this.debug( '-- _renderUnpaired' );
var creator = this,
$fwd, $rev, $prd = [],
split = this._splitByFilters();
@@ -620,16 +652,17 @@
this.$( '.reverse-column .unpaired-info' )
.text( this._renderUnpairedDisplayStr( this.unpaired.length - split[1].length ) );
+ this.$( '.unpaired-columns .column-datasets' ).empty();
+
// show/hide the auto pair button if any unpaired are left
this.$( '.autopair-link' ).toggle( this.unpaired.length !== 0 );
if( this.unpaired.length === 0 ){
this._renderUnpairedEmpty();
- //this.$( '.unpaired-columns .paired-column .column-datasets' )
- // .append( this._renderUnpairedEmpty() );
- //TODO: would be best to return here (the $columns)
return;
}
+ //this.$( '.unpaired-columns .forward-column' ).lassoable({});
+
// create the dataset dom arrays
$rev = split[1].map( function( dataset, i ){
// if there'll be a fwd dataset across the way, add a button to pair the row
@@ -649,7 +682,6 @@
}
// add to appropo cols
//TODO: not the best way to render
- this.$( '.unpaired-columns .column-datasets' ).empty();
this.$( '.unpaired-columns .forward-column .column-datasets' ).append( $fwd )
.add( this.$( '.unpaired-columns .paired-column .column-datasets' ).append( $prd ) )
.add( this.$( '.unpaired-columns .reverse-column .column-datasets' ).append( $rev ) );
@@ -678,7 +710,7 @@
},
/** a message to display when no unpaired left */
_renderUnpairedEmpty : function(){
- //console.debug( '-- renderUnpairedEmpty' );
+ //this.debug( '-- renderUnpairedEmpty' );
var $msg = $( '<div class="empty-message"></div>' )
.text( '(' + _l( 'no remaining unpaired datasets' ) + ')' );
this.$( '.unpaired-columns .paired-column .column-datasets' ).empty().prepend( $msg );
@@ -686,7 +718,7 @@
},
/** a message to display when no unpaired can be shown with the current filters */
_renderUnpairedNotShown : function(){
- //console.debug( '-- renderUnpairedEmpty' );
+ //this.debug( '-- renderUnpairedEmpty' );
var $msg = $( '<div class="empty-message"></div>' )
.text( '(' + _l( 'no datasets were found matching the current filters' ) + ')' );
this.$( '.unpaired-columns .paired-column .column-datasets' ).empty().prepend( $msg );
@@ -695,44 +727,39 @@
/** render the paired section and update counts of paired datasets */
_renderPaired : function( speed, callback ){
- //console.debug( '-- _renderPaired' );
- var $fwd = [],
- $prd = [],
- $rev = [];
-
+ //this.debug( '-- _renderPaired' );
this.$( '.paired-column-title .title' ).text([ this.paired.length, _l( 'paired' ) ].join( ' ' ) );
// show/hide the unpair all link
this.$( '.unpair-all-link' ).toggle( this.paired.length !== 0 );
if( this.paired.length === 0 ){
this._renderPairedEmpty();
+ return;
//TODO: would be best to return here (the $columns)
} else {
// show/hide 'remove extensions link' when any paired and they seem to have extensions
this.$( '.remove-extensions-link' ).show();
}
+ this.$( '.paired-columns .column-datasets' ).empty();
+ var creator = this;
this.paired.forEach( function( pair, i ){
- $fwd.push( $( '<li/>').addClass( 'dataset paired' )
- .append( $( '<span/>' ).addClass( 'dataset-name' ).text( pair.forward.name ) ) );
- $prd.push( $( '<li/>').addClass( 'dataset paired' )
- .append( $( '<span/>' ).addClass( 'dataset-name' ).text( pair.name ) ) );
- $rev.push( $( '<li/>').addClass( 'dataset paired' )
- .append( $( '<span/>' ).addClass( 'dataset-name' ).text( pair.reverse.name ) ) );
- $rev.push( $( '<button/>' ).addClass( 'unpair-btn' )
- .append( $( '<span/>' ).addClass( 'fa fa-unlink' ).attr( 'title', _l( 'Unpair' ) ) ) );
+//TODO: cache these?
+ var pairView = new PairView({ pair: pair });
+ creator.$( '.paired-columns .column-datasets' )
+ .append( pairView.render().$el )
+ .append([
+//TODO: data-index="i"
+ '<button class="unpair-btn">',
+ '<span class="fa fa-unlink" title="', _l( 'Unpair' ), '"></span>',
+ '</button>'
+ ].join( '' ));
});
-
- //TODO: better as one swell foop (instead of 4 repaints)
- this.$( '.paired-columns .column-datasets' ).empty();
- return this.$( '.paired-columns .forward-column .column-datasets' ).prepend( $fwd )
- .add( this.$( '.paired-columns .paired-column .column-datasets' ).prepend( $prd ) )
- .add( this.$( '.paired-columns .reverse-column .column-datasets' ).prepend( $rev ) );
},
/** a message to display when none paired */
_renderPairedEmpty : function(){
var $msg = $( '<div class="empty-message"></div>' )
.text( '(' + _l( 'no paired datasets yet' ) + ')' );
- this.$( '.paired-columns .paired-column .column-datasets' ).prepend( $msg );
+ this.$( '.paired-columns .column-datasets' ).empty().prepend( $msg );
return $msg;
},
@@ -749,7 +776,7 @@
/** add any jQuery/bootstrap/custom plugins to elements rendered */
_addPluginComponents : function(){
this._chooseFiltersPopover( '.choose-filters-link' );
- this.$( '.help-content i' ).hoverhighlight( '.collection-creator', 'rgba( 192, 255, 255, 1.0 )' );
+ this.$( '.help-content i' ).hoverhighlight( '.collection-creator', 'rgba( 64, 255, 255, 1.0 )' );
},
/** build a filter selection popover allowing selection of common filter pairs */
@@ -811,7 +838,7 @@
// may have to do with improper flex columns
//var $pairedView = this.$( '.paired-columns' );
//$pairedView.scrollTop( $pairedView.innerHeight() );
- //console.debug( $pairedView.height() )
+ //this.debug( $pairedView.height() )
this.$( '.paired-columns' ).scrollTop( 8000000 );
});
this.on( 'pair:unpair', function( pairs ){
@@ -849,7 +876,7 @@
});
//this.on( 'all', function(){
- // console.info( arguments );
+ // this.info( arguments );
//});
return this;
},
@@ -875,13 +902,12 @@
'click .reverse-column .dataset.unpaired' : '_clickUnpairedDataset',
'click .paired-column .dataset.unpaired' : '_clickPairRow',
'click .unpaired-columns' : 'clearSelectedUnpaired',
+ 'mousedown .unpaired-columns .dataset' : '_mousedownUnpaired',
// divider
'click .paired-column-title' : '_clickShowOnlyPaired',
'mousedown .flexible-partition-drag' : '_startPartitionDrag',
// paired
- 'click .paired-columns .paired-column .dataset-name' : '_clickPairName',
- 'mouseover .dataset.paired' : '_hoverPaired',
- 'mouseout .dataset.paired' : '_hoverOutPaired',
+ 'click .paired-columns .pair-name' : '_clickPairName',
'click .unpair-btn' : '_clickUnpair',
// footer
@@ -892,7 +918,7 @@
this.oncancel.call( this );
}
},
- 'click .create-collection' : '_clickCreate'
+ 'click .create-collection' : '_clickCreate'//,
},
// ........................................................................ header
@@ -923,7 +949,7 @@
//TODO: consolidate these
/** toggle between showing only unpaired and split view */
_clickShowOnlyUnpaired : function( ev ){
- //console.debug( 'click unpaired', ev.currentTarget );
+ //this.debug( 'click unpaired', ev.currentTarget );
if( this.$( '.paired-columns' ).is( ':visible' ) ){
this.hidePaired();
} else {
@@ -932,7 +958,7 @@
},
/** toggle between showing only paired and split view */
_clickShowOnlyPaired : function( ev ){
- //console.debug( 'click paired' );
+ //this.debug( 'click paired' );
if( this.$( '.unpaired-columns' ).is( ':visible' ) ){
this.hideUnpaired();
} else {
@@ -972,7 +998,7 @@
/** attempt to autopair */
_clickAutopair : function( ev ){
var paired = this.autoPair();
- //console.debug( 'autopaired', paired );
+ //this.debug( 'autopaired', paired );
//TODO: an indication of how many pairs were found - if 0, assist
this.trigger( 'autopair', paired );
},
@@ -1016,7 +1042,7 @@
options = options || {};
var dataset = $dataset.data( 'dataset' ),
select = options.force !== undefined? options.force: !$dataset.hasClass( 'selected' );
- //console.debug( id, options.force, $dataset, dataset );
+ //this.debug( id, options.force, $dataset, dataset );
if( !$dataset.size() || dataset === undefined ){ return $dataset; }
if( select ){
@@ -1047,8 +1073,8 @@
revs.push( $( this ).data( 'dataset' ) );
});
fwds.length = revs.length = Math.min( fwds.length, revs.length );
- //console.debug( fwds );
- //console.debug( revs );
+ //this.debug( fwds );
+ //this.debug( revs );
fwds.forEach( function( fwd, i ){
try {
pairs.push( creator._pair( fwd, revs[i], { silent: true }) );
@@ -1056,7 +1082,7 @@
} catch( err ){
//TODO: preserve selected state of those that couldn't be paired
//TODO: warn that some could not be paired
- console.error( err );
+ creator.error( err );
}
});
if( pairs.length && !options.silent ){
@@ -1070,35 +1096,56 @@
this.$( '.unpaired-columns .dataset.selected' ).removeClass( 'selected' );
},
+ /** when holding down the shift key on a click, 'paint' the moused over datasets as selected */
+ _mousedownUnpaired : function( ev ){
+ if( ev.shiftKey ){
+ var creator = this,
+ $startTarget = $( ev.target ).addClass( 'selected' ),
+ moveListener = function( ev ){
+ creator.$( ev.target ).filter( '.dataset' ).addClass( 'selected' );
+ };
+ $startTarget.parent().on( 'mousemove', moveListener );
+
+ // on any mouseup, stop listening to the move and try to pair any selected
+ $( document ).one( 'mouseup', function( ev ){
+ $startTarget.parent().off( 'mousemove', moveListener );
+ creator.pairAllSelected();
+ });
+ }
+ },
+
/** attempt to pair two datasets directly across from one another */
_clickPairRow : function( ev ){
//if( !ev.currentTarget ){ return true; }
var rowIndex = $( ev.currentTarget ).index(),
fwd = $( '.unpaired-columns .forward-column .dataset' ).eq( rowIndex ).data( 'dataset' ),
rev = $( '.unpaired-columns .reverse-column .dataset' ).eq( rowIndex ).data( 'dataset' );
- //console.debug( 'row:', rowIndex, fwd, rev );
+ //this.debug( 'row:', rowIndex, fwd, rev );
//TODO: animate
this._pair( fwd, rev );
},
// ........................................................................ divider/partition
+//TODO: simplify
/** start dragging the visible divider/partition between unpaired and paired panes */
_startPartitionDrag : function( ev ){
var creator = this,
startingY = ev.pageY;
- //console.debug( 'partition drag START:', ev );
+ //this.debug( 'partition drag START:', ev );
$( 'body' ).css( 'cursor', 'ns-resize' );
creator.$( '.flexible-partition-drag' ).css( 'color', 'black' );
function endDrag( ev ){
- //console.debug( 'partition drag STOP:', ev );
+ //creator.debug( 'partition drag STOP:', ev );
// doing this by an added class didn't really work well - kept flashing still
creator.$( '.flexible-partition-drag' ).css( 'color', '' );
$( 'body' ).css( 'cursor', '' ).unbind( 'mousemove', trackMouse );
}
function trackMouse( ev ){
var offset = ev.pageY - startingY;
+ //creator.debug( 'partition:', startingY, offset );
if( !creator.adjPartition( offset ) ){
+ //creator.debug( 'mouseup triggered' );
$( 'body' ).trigger( 'mouseup' );
}
startingY += offset;
@@ -1113,25 +1160,34 @@
$paired = this.$( '.paired-columns' ),
unpairedHi = parseInt( $unpaired.css( 'height' ), 10 ),
pairedHi = parseInt( $paired.css( 'height' ), 10 );
- //console.debug( adj, 'hi\'s:', unpairedHi, pairedHi, unpairedHi + adj, pairedHi - adj );
+ //this.debug( adj, 'hi\'s:', unpairedHi, pairedHi, unpairedHi + adj, pairedHi - adj );
unpairedHi = Math.max( 10, unpairedHi + adj );
pairedHi = pairedHi - adj;
+ //TODO: seems like shouldn't need this (it should be part of the hide/show/splitView)
if( unpairedHi <= 10 ){
- this.hideUnpaired();
- return false;
- } else if( !$unpaired.is( 'visible' ) ){
+ if( !this.unpairedPanelHidden ){
+ this.hideUnpaired();
+ return false;
+ }
+
+ } else if( this.unpairedPanelHidden ){
$unpaired.show();
- //this.$( '.unpaired-filter' ).show();
+ this.unpairedPanelHidden = false;
}
+ // when the divider gets close to the bottom - lock into hiding the paired section
if( pairedHi <= 15 ){
- this.hidePaired();
- if( pairedHi < 10 ){ return false; }
+ if( !this.pairedPanelHidden ){
+ this.hidePaired();
+ if( pairedHi < 5 ){ return false; }
+ }
- } else if( !$paired.is( 'visible' ) ){
+ // when the divider gets close to the bottom and the paired section is hidden
+ } else if( this.pairedPanelHidden ){
$paired.show();
+ this.pairedPanelHidden = false;
}
$unpaired.css({
@@ -1162,47 +1218,11 @@
//if( !ev.currentTarget ){ return true; }
//TODO: this is a hack bc each paired rev now has two elems (dataset, button)
var pairIndex = Math.floor( $( ev.currentTarget ).index() / 2 );
- //console.debug( 'pair:', pairIndex );
+ //this.debug( 'pair:', pairIndex );
//TODO: animate
this._unpair( this.paired[ pairIndex ] );
},
- //TODO: the following is ridiculous
- _hoverPaired : function( ev ){
- var $target = $( ev.currentTarget ),
- index = $target.index();
- //TODO: this is a hack bc each paired rev now has two elems (dataset, button)
- if( $target.parents( '.reverse-column' ).size() ){
- index = Math.floor( index / 2 );
- }
- //console.debug( 'index:', index );
- this.emphasizePair( index );
- },
- _hoverOutPaired : function( ev ){
- var $target = $( ev.currentTarget ),
- index = $target.index();
- //TODO: this is a hack bc each paired rev now has two elems (dataset, button)
- if( $target.parents( '.reverse-column' ).size() ){
- index = Math.floor( index / 2 );
- }
- //console.debug( 'index:', index );
- this.deemphasizePair( index );
- },
- emphasizePair : function( index ){
- //console.debug( 'emphasizePairedBorder:', index );
- this.$( '.paired-columns .forward-column .dataset.paired' ).eq( index )
- .add( this.$( '.paired-columns .paired-column .dataset.paired' ).eq( index ) )
- .add( this.$( '.paired-columns .reverse-column .dataset.paired' ).eq( index ) )
- .addClass( 'emphasized' );
- },
- deemphasizePair : function( index ){
- //console.debug( 'deemphasizePairedBorder:', index );
- this.$( '.paired-columns .forward-column .dataset.paired' ).eq( index )
- .add( this.$( '.paired-columns .paired-column .dataset.paired' ).eq( index ) )
- .add( this.$( '.paired-columns .reverse-column .dataset.paired' ).eq( index ) )
- .removeClass( 'emphasized' );
- },
-
// ........................................................................ footer
toggleExtensions : function( force ){
var creator = this;
@@ -1246,14 +1266,14 @@
if( list === creator.paired ){
creator._printPair( e );
} else {
- //console.debug( e );
+ //creator.debug( e );
}
});
},
/** print a pair Object */
_printPair : function( pair ){
- console.debug( pair.forward.name, pair.reverse.name, ': ->', pair.name );
+ this.debug( pair.forward.name, pair.reverse.name, ': ->', pair.name );
},
/** string rep */
@@ -1341,7 +1361,7 @@
'</div>',
'</div>',
'<div class="flexible-partition">',
- '<div class="flexible-partition-drag"></div>',
+ '<div class="flexible-partition-drag" title="', _l( 'Drag to change' ), '"></div>',
'<div class="column-header">',
'<div class="column-title paired-column-title">',
'<span class="title"></span>',
@@ -1352,15 +1372,7 @@
'</div>',
'</div>',
'<div class="paired-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>',
+ '<ol class="column-datasets"></ol>',
'</div>'
].join('')),
@@ -1405,7 +1417,7 @@
helpContent : _.template([
'<p>', _l([
'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 each member of ',
+ '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>',
@@ -1520,7 +1532,7 @@
title : 'Create a collection of paired datasets',
body : creator.$el,
width : '80%',
- height : '700px',
+ height : '800px',
closing_events: true
});
//TODO: remove modal header
diff -r ece8ef90a8289399bf9faca6a3265696da7e0beb -r 7c566a68d2d07375c53006191671dfed04332f55 static/scripts/mvc/history/history-panel-edit.js
--- a/static/scripts/mvc/history/history-panel-edit.js
+++ b/static/scripts/mvc/history/history-panel-edit.js
@@ -187,7 +187,7 @@
}
// set up the pupup for actions available when multi selecting
- this._setUpDatasetActionsPopup( $where );
+ this.actionsPopup = this._setUpDatasetActionsPopup( $where );
// anon users shouldn't have access to any of the following
if( ( !Galaxy.currUser || Galaxy.currUser.isAnonymous() )
diff -r ece8ef90a8289399bf9faca6a3265696da7e0beb -r 7c566a68d2d07375c53006191671dfed04332f55 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(f,a,d){var e=Backbone.View.extend(a.LoggableMixin).extend({className:"collection-creator flex-row-container",initialize:function(g){g=_.defaults(g,{datasets:[],filters:this.DEFAULT_FILTERS,automaticallyPair:true,matchPercentage:1,strategy:"lcs"});this.initialList=g.datasets;this.historyId=g.historyId;this.filters=this.commonFilters[g.filters]||this.commonFilters[this.DEFAULT_FILTERS];if(_.isArray(g.filters)){this.filters=g.filters}this.automaticallyPair=g.automaticallyPair;this.matchPercentage=g.matchPercentage;this.strategy=this.strategies[g.strategy]||this.strategies[this.DEFAULT_STRATEGY];if(_.isFunction(g.strategy)){this.strategy=g.strategy}this.removeExtensions=true;this.oncancel=g.oncancel;this.oncreate=g.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(g){g.sort(function(i,h){return naturalSort(i.name,h.name)});return g},_ensureIds:function(){this.initialList.forEach(function(g){if(!g.hasOwnProperty("id")){g.id=_.uniqueId()}});return this.initialList},_splitByFilters:function(i){var h=[],g=[];this.unpaired.forEach(function(j){if(this._filterFwdFn(j)){h.push(j)}if(this._filterRevFn(j)){g.push(j)}}.bind(this));return[h,g]},_filterFwdFn:function(h){var g=new RegExp(this.filters[0]);return g.test(h.name)},_filterRevFn:function(h){var g=new RegExp(this.filters[1]);return g.test(h.name)},_addToUnpaired:function(h){var g=function(i,k){if(i===k){return i}var j=Math.floor((k-i)/2)+i,l=naturalSort(h.name,this.unpaired[j].name);if(l<0){return g(i,j)}else{if(l>0){return g(j+1,k)}}while(this.unpaired[j]&&this.unpaired[j].name===h.name){j++}return j}.bind(this);this.unpaired.splice(g(0,this.unpaired.length),0,h)},autoPair:function(g){g=g||this.strategy;this.simpleAutoPair();return this[g].call(this)},simpleAutoPair:function(){var m=0,k,q=this._splitByFilters(),g=q[0],p=q[1],o,r,h=false;while(m<g.length){var l=g[m];o=l.name.replace(this.filters[0],"");h=false;for(k=0;k<p.length;k++){var n=p[k];r=n.name.replace(this.filters[1],"");if(l!==n&&o===r){h=true;this._pair(g.splice(m,1)[0],p.splice(k,1)[0],{silent:true});break}}if(!h){m+=1}}},autoPairLevenshtein:function(){var n=0,l,s=this._splitByFilters(),g=s[0],q=s[1],p,u,h,r,k;while(n<g.length){var m=g[n];p=m.name.replace(this.filters[0],"");k=Number.MAX_VALUE;for(l=0;l<q.length;l++){var o=q[l];u=o.name.replace(this.filters[1],"");if(m!==o){if(p===u){r=l;k=0;break}h=levenshteinDistance(p,u);if(h<k){r=l;k=h}}}var t=1-(k/(Math.max(p.length,u.length)));if(t>=this.matchPercentage){this._pair(g.splice(n,1)[0],q.splice(r,1)[0],{silent:true});if(g.length<=0||q.length<=0){return}}else{n+=1}}},autoPairLCSs:function(){var l=0,h,s=this._splitByFilters(),g=s[0],q=s[1],p,v,u,r,n;if(!g.length||!q.length){return}while(l<g.length){var k=g[l];p=k.name.replace(this.filters[0],"");n=0;for(h=0;h<q.length;h++){var o=q[h];v=o.name.replace(this.filters[1],"");if(k!==o){if(p===v){r=h;n=p.length;break}var m=this._naiveStartingAndEndingLCS(p,v);u=m.length;if(u>n){r=h;n=u}}}var t=n/(Math.min(p.length,v.length));if(t>=this.matchPercentage){this._pair(g.splice(l,1)[0],q.splice(r,1)[0],{silent:true});if(g.length<=0||q.length<=0){return}}else{l+=1}}},_naiveStartingAndEndingLCS:function(l,h){var m="",n="",k=0,g=0;while(k<l.length&&k<h.length){if(l[k]!==h[k]){break}m+=l[k];k+=1}if(k===l.length){return l}if(k===h.length){return h}k=(l.length-1);g=(h.length-1);while(k>=0&&g>=0){if(l[k]!==h[g]){break}n=[l[k],n].join("");k-=1;g-=1}return m+n},_pair:function(i,g,h){h=h||{};var j=this._createPair(i,g,h.name);this.paired.push(j);this.unpaired=_.without(this.unpaired,i,g);if(!h.silent){this.trigger("pair:new",j)}return j},_createPair:function(i,g,h){if(!(i&&g)||(i===g)){throw new Error("Bad pairing: "+[JSON.stringify(i),JSON.stringify(g)])}h=h||this._guessNameForPair(i,g);return{forward:i,name:h,reverse:g}},_guessNameForPair:function(i,g,j){j=(j!==undefined)?(j):(this.removeExtensions);var h=this._naiveStartingAndEndingLCS(i.name.replace(this.filters[0],""),g.name.replace(this.filters[1],""));if(j){var k=h.lastIndexOf(".");if(k>0){h=h.slice(0,k)}}return h||(i.name+" & "+g.name)},_unpair:function(h,g){g=g||{};if(!h){throw new Error("Bad pair: "+JSON.stringify(h))}this.paired=_.without(this.paired,h);this._addToUnpaired(h.forward);this._addToUnpaired(h.reverse);if(!g.silent){this.trigger("pair:unpair",[h])}return h},unpairAll:function(){var g=[];while(this.paired.length){g.push(this._unpair(this.paired[0],{silent:true}))}this.trigger("pair:unpair",g)},_pairToJSON:function(g){return{collection_type:"paired",src:"new_collection",name:g.name,element_identifiers:[{name:"forward",id:g.forward.id,src:"hda"},{name:"reverse",id:g.reverse.id,src:"hda"}]}},createList:function(){var i=this,h;if(i.historyId){h="/api/histories/"+this.historyId+"/contents/dataset_collections"}var g={type:"dataset_collection",collection_type:"list:paired",name:_.escape(i.$(".collection-name").val()),element_identifiers:i.paired.map(function(j){return i._pairToJSON(j)})};return jQuery.ajax(h,{type:"POST",contentType:"application/json",dataType:"json",data:JSON.stringify(g)}).fail(function(l,j,k){i._ajaxErrHandler(l,j,k)}).done(function(j,k,l){i.trigger("collection:created",j,k,l);if(typeof i.oncreate==="function"){i.oncreate.call(this,j,k,l)}})},_ajaxErrHandler:function(j,g,i){console.error(j,g,i);var h=d("An error occurred while creating this collection");if(j){if(j.readyState===0&&j.status===0){h+=": "+d("Galaxy could not be reached and may be updating.")+d(" Try again in a few minutes.")}else{if(j.responseJSON){h+="<br /><pre>"+JSON.stringify(j.responseJSON)+"</pre>"}else{h+=": "+i}}}creator._showAlert(h,"alert-danger")},render:function(g,h){this.$el.empty().html(e.templates.main());this._renderHeader(g);this._renderMiddle(g);this._renderFooter(g);this._addPluginComponents();return this},_renderHeader:function(h,i){var g=this.$(".header").empty().html(e.templates.header()).find(".help-content").prepend($(e.templates.helpContent()));this._renderFilters();return g},_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(h,i){var g=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 g},_renderUnpaired:function(l,m){var j=this,k,h,g=[],i=this._splitByFilters();this.$(".forward-column .title").text([i[0].length,d("unpaired forward")].join(" "));this.$(".forward-column .unpaired-info").text(this._renderUnpairedDisplayStr(this.unpaired.length-i[0].length));this.$(".reverse-column .title").text([i[1].length,d("unpaired reverse")].join(" "));this.$(".reverse-column .unpaired-info").text(this._renderUnpairedDisplayStr(this.unpaired.length-i[1].length));this.$(".autopair-link").toggle(this.unpaired.length!==0);if(this.unpaired.length===0){this._renderUnpairedEmpty();return}h=i[1].map(function(o,n){if((i[0][n]!==undefined)&&(i[0][n]!==o)){g.push(j._renderPairButton())}return j._renderUnpairedDataset(o)});k=i[0].map(function(n){return j._renderUnpairedDataset(n)});if(!k.length&&!h.length){this._renderUnpairedNotShown();return}this.$(".unpaired-columns .column-datasets").empty();this.$(".unpaired-columns .forward-column .column-datasets").append(k).add(this.$(".unpaired-columns .paired-column .column-datasets").append(g)).add(this.$(".unpaired-columns .reverse-column .column-datasets").append(h))},_renderUnpairedDisplayStr:function(g){return["(",g," ",d("filtered out"),")"].join("")},_renderUnpairedDataset:function(g){return $("<li/>").attr("id","dataset-"+g.id).addClass("dataset unpaired").attr("draggable",true).addClass(g.selected?"selected":"").append($("<span/>").addClass("dataset-name").text(g.name)).data("dataset",g)},_renderPairButton:function(){return $("<li/>").addClass("dataset unpaired").append($("<span/>").addClass("dataset-name").text(d("Pair these datasets")))},_renderUnpairedEmpty:function(){var g=$('<div class="empty-message"></div>').text("("+d("no remaining unpaired datasets")+")");this.$(".unpaired-columns .paired-column .column-datasets").empty().prepend(g);return g},_renderUnpairedNotShown:function(){var g=$('<div class="empty-message"></div>').text("("+d("no datasets were found matching the current filters")+")");this.$(".unpaired-columns .paired-column .column-datasets").empty().prepend(g);return g},_renderPaired:function(j,k){var i=[],g=[],h=[];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()}else{this.$(".remove-extensions-link").show()}this.paired.forEach(function(m,l){i.push($("<li/>").addClass("dataset paired").append($("<span/>").addClass("dataset-name").text(m.forward.name)));g.push($("<li/>").addClass("dataset paired").append($("<span/>").addClass("dataset-name").text(m.name)));h.push($("<li/>").addClass("dataset paired").append($("<span/>").addClass("dataset-name").text(m.reverse.name)));h.push($("<button/>").addClass("unpair-btn").append($("<span/>").addClass("fa fa-unlink").attr("title",d("Unpair"))))});this.$(".paired-columns .column-datasets").empty();return this.$(".paired-columns .forward-column .column-datasets").prepend(i).add(this.$(".paired-columns .paired-column .column-datasets").prepend(g)).add(this.$(".paired-columns .reverse-column .column-datasets").prepend(h))},_renderPairedEmpty:function(){var g=$('<div class="empty-message"></div>').text("("+d("no paired datasets yet")+")");this.$(".paired-columns .paired-column .column-datasets").prepend(g);return g},_renderFooter:function(h,i){var g=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 g},_addPluginComponents:function(){this._chooseFiltersPopover(".choose-filters-link");this.$(".help-content i").hoverhighlight(".collection-creator","rgba( 192, 255, 255, 1.0 )")},_chooseFiltersPopover:function(g){function h(k,j){return['<button class="filter-choice btn" ','data-forward="',k,'" data-reverse="',j,'">',d("Forward"),": ",k,", ",d("Reverse"),": ",j,"</button>"].join("")}var i=$(_.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>",h("_1","_2"),h("_R1","_R2"),"</div>"].join(""),{}));return this.$(g).popover({container:".collection-creator",placement:"bottom",html:true,content:i})},_validationWarning:function(h,g){var i="validation-warning";if(h==="name"){h=this.$(".collection-name").add(this.$(".collection-name-prompt"));this.$(".collection-name").focus().select()}if(g){h=h||this.$("."+i);h.removeClass(i)}else{h.addClass(i)}},_setUpBehaviors:function(){this.on("pair:new",function(){this._renderUnpaired();this._renderPaired();this.$(".paired-columns").scrollTop(8000000)});this.on("pair:unpair",function(g){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 g,h=null;if(this.paired.length){h="alert-success";g=this.paired.length+" "+d("pairs created");if(!this.unpaired.length){g+=": "+d("all datasets have been successfully paired");this.hideUnpaired()}}else{g=d("Could not automatically create any pairs from the given dataset names")}this._showAlert(g,h)});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(g){this.trigger("filter-change")},"focus .forward-unpaired-filter input":function(g){$(g.currentTarget).select()},"click .autopair-link":"_clickAutopair","click .choose-filters .filter-choice":"_clickFilterChoice","click .clear-filters-link":"_clearFilters","change .reverse-unpaired-filter input":function(g){this.trigger("filter-change")},"focus .reverse-unpaired-filter input":function(g){$(g.currentTarget).select()},"click .forward-column .dataset.unpaired":"_clickUnpairedDataset","click .reverse-column .dataset.unpaired":"_clickUnpairedDataset","click .paired-column .dataset.unpaired":"_clickPairRow","click .unpaired-columns":"clearSelectedUnpaired","click .paired-column-title":"_clickShowOnlyPaired","mousedown .flexible-partition-drag":"_startPartitionDrag","click .paired-columns .paired-column .dataset-name":"_clickPairName","mouseover .dataset.paired":"_hoverPaired","mouseout .dataset.paired":"_hoverOutPaired","click .unpair-btn":"_clickUnpair","change .remove-extensions":function(g){this.toggleExtensions()},"change .collection-name":"_changeName","click .cancel-create":function(g){if(typeof this.oncancel==="function"){this.oncancel.call(this)}},"click .create-collection":"_clickCreate"},_clickMoreHelp:function(g){this.$(".main-help").addClass("expanded");this.$(".more-help").hide()},_clickLessHelp:function(g){this.$(".main-help").removeClass("expanded");this.$(".more-help").show()},_showAlert:function(h,g){g=g||"alert-danger";this.$(".main-help").hide();this.$(".header .alert").attr("class","alert alert-dismissable").addClass(g).show().find(".alert-message").html(h)},_hideAlert:function(g){this.$(".main-help").show();this.$(".header .alert").hide()},_clickShowOnlyUnpaired:function(g){if(this.$(".paired-columns").is(":visible")){this.hidePaired()}else{this.splitView()}},_clickShowOnlyPaired:function(g){if(this.$(".unpaired-columns").is(":visible")){this.hideUnpaired()}else{this.splitView()}},hideUnpaired:function(g,h){g=g||0;this.$(".unpaired-columns").hide(g,h);this.$(".paired-columns").show(g).css("flex","1 0 auto");this.unpairedPanelHidden=true},hidePaired:function(g,h){g=g||0;this.$(".unpaired-columns").show(g).css("flex","1 0 auto");this.$(".paired-columns").hide(g,h);this.pairedPanelHidden=true},splitView:function(g,h){g=g||0;this.unpairedPanelHidden=this.pairedPanelHidden=false;this._renderMiddle(g);return this},_clickUnpairAll:function(g){this.unpairAll()},_clickAutopair:function(h){var g=this.autoPair();this.trigger("autopair",g)},_clickFilterChoice:function(h){var g=$(h.currentTarget);this.$(".forward-unpaired-filter input").val(g.data("forward"));this.$(".reverse-unpaired-filter input").val(g.data("reverse"));this._hideChooseFilters();this.trigger("filter-change")},_hideChooseFilters:function(){this.$(".choose-filters-link").popover("hide");this.$(".popover").css("display","none")},_clearFilters:function(g){this.$(".forward-unpaired-filter input").val("");this.$(".reverse-unpaired-filter input").val("");this.trigger("filter-change")},_clickUnpairedDataset:function(g){g.stopPropagation();return this.toggleSelectUnpaired($(g.currentTarget))},toggleSelectUnpaired:function(i,h){h=h||{};var j=i.data("dataset"),g=h.force!==undefined?h.force:!i.hasClass("selected");if(!i.size()||j===undefined){return i}if(g){i.addClass("selected");if(!h.waitToPair){this.pairAllSelected()}}else{i.removeClass("selected")}return i},pairAllSelected:function(h){h=h||{};var i=this,j=[],g=[],k=[];i.$(".unpaired-columns .forward-column .dataset.selected").each(function(){j.push($(this).data("dataset"))});i.$(".unpaired-columns .reverse-column .dataset.selected").each(function(){g.push($(this).data("dataset"))});j.length=g.length=Math.min(j.length,g.length);j.forEach(function(m,l){try{k.push(i._pair(m,g[l],{silent:true}))}catch(n){console.error(n)}});if(k.length&&!h.silent){this.trigger("pair:new",k)}return k},clearSelectedUnpaired:function(){this.$(".unpaired-columns .dataset.selected").removeClass("selected")},_clickPairRow:function(i){var j=$(i.currentTarget).index(),h=$(".unpaired-columns .forward-column .dataset").eq(j).data("dataset"),g=$(".unpaired-columns .reverse-column .dataset").eq(j).data("dataset");this._pair(h,g)},_startPartitionDrag:function(h){var g=this,k=h.pageY;$("body").css("cursor","ns-resize");g.$(".flexible-partition-drag").css("color","black");function j(l){g.$(".flexible-partition-drag").css("color","");$("body").css("cursor","").unbind("mousemove",i)}function i(l){var m=l.pageY-k;if(!g.adjPartition(m)){$("body").trigger("mouseup")}k+=m}$("body").mousemove(i);$("body").one("mouseup",j)},adjPartition:function(h){var g=this.$(".unpaired-columns"),i=this.$(".paired-columns"),j=parseInt(g.css("height"),10),k=parseInt(i.css("height"),10);j=Math.max(10,j+h);k=k-h;if(j<=10){this.hideUnpaired();return false}else{if(!g.is("visible")){g.show()}}if(k<=15){this.hidePaired();if(k<10){return false}}else{if(!i.is("visible")){i.show()}}g.css({height:j+"px",flex:"0 0 auto"});return true},_clickPairName:function(i){var h=$(i.currentTarget),j=this.paired[h.parent().index()],g=prompt("Enter a new name for the pair:",j.name);if(g){j.name=g;j.customizedName=true;h.text(j.name)}},_clickUnpair:function(h){var g=Math.floor($(h.currentTarget).index()/2);this._unpair(this.paired[g])},_hoverPaired:function(i){var g=$(i.currentTarget),h=g.index();if(g.parents(".reverse-column").size()){h=Math.floor(h/2)}this.emphasizePair(h)},_hoverOutPaired:function(i){var g=$(i.currentTarget),h=g.index();if(g.parents(".reverse-column").size()){h=Math.floor(h/2)}this.deemphasizePair(h)},emphasizePair:function(g){this.$(".paired-columns .forward-column .dataset.paired").eq(g).add(this.$(".paired-columns .paired-column .dataset.paired").eq(g)).add(this.$(".paired-columns .reverse-column .dataset.paired").eq(g)).addClass("emphasized")},deemphasizePair:function(g){this.$(".paired-columns .forward-column .dataset.paired").eq(g).add(this.$(".paired-columns .paired-column .dataset.paired").eq(g)).add(this.$(".paired-columns .reverse-column .dataset.paired").eq(g)).removeClass("emphasized")},toggleExtensions:function(h){var g=this;g.removeExtensions=(h!==undefined)?(h):(!g.removeExtensions);_.each(g.paired,function(i){if(i.customizedName){return}i.name=g._guessNameForPair(i.forward,i.reverse)});g._renderPaired();g._renderFooter()},_changeName:function(g){this._validationWarning("name",!!this._getName())},_getName:function(){return _.escape(this.$(".collection-name").val())},_clickCreate:function(h){var g=this._getName();if(!g){this._validationWarning("name")}else{this.createList()}},_printList:function(h){var g=this;_.each(h,function(i){if(h===g.paired){g._printPair(i)}else{}})},_printPair:function(g){console.debug(g.forward.name,g.reverse.name,": ->",g.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"></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">','<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>"].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 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_Expre…"',' 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 g(i,h){i=i||"body";if(!this.size()){return this}$(this).each(function(){var k=$(this),j=k.data("target");if(j){k.mouseover(function(l){$(j,i).css({background:h})}).mouseout(function(l){$(j).css({background:""})})}});return this}})}());var b=function c(i,g){g=_.defaults(g||{},{datasets:i,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 h=new e(g).render();Galaxy.modal.show({title:"Create a collection of paired datasets",body:h.$el,width:"80%",height:"700px",closing_events:true});window.PCC=h;return h};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).html(_.template(['<span class="forward-dataset-name flex-column"><%= pair.forward.name %></span>','<span class="pair-name flex-column"><%= pair.name %></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))},_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},_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 .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){h=h||0;this.$(".unpaired-columns").hide(h,i);this.$(".paired-columns").show(h).css("flex","1 0 auto");this.unpairedPanelHidden=true},hidePaired:function(h,i){h=h||0;this.$(".unpaired-columns").show(h).css("flex","1 0 auto");this.$(".paired-columns").hide(h,i);this.pairedPanelHidden=true},splitView:function(h,i){h=h||0;this.unpairedPanelHidden=this.pairedPanelHidden=false;this._renderMiddle(h);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")}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;if(k<=10){if(!this.unpairedPanelHidden){this.hideUnpaired();return false}}else{if(this.unpairedPanelHidden){h.show();this.unpairedPanelHidden=false}}if(l<=15){if(!this.pairedPanelHidden){this.hidePaired();if(l<5){return false}}}else{if(this.pairedPanelHidden){j.show();this.pairedPanelHidden=false}}h.css({height:k+"px",flex:"0 0 auto"});return true},_clickPairName:function(j){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_Expre…"',' 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 ece8ef90a8289399bf9faca6a3265696da7e0beb -r 7c566a68d2d07375c53006191671dfed04332f55 static/scripts/packed/mvc/history/history-panel-edit.js
--- a/static/scripts/packed/mvc/history/history-panel-edit.js
+++ b/static/scripts/packed/mvc/history/history-panel-edit.js
@@ -1,1 +1,1 @@
-define(["mvc/history/history-panel","mvc/history/history-contents","mvc/dataset/states","mvc/history/hda-model","mvc/history/hda-li-edit","mvc/history/hdca-li-edit","mvc/tags","mvc/annotations","utils/localization"],function(f,h,k,d,c,g,j,a,b){var i=f.ReadOnlyHistoryPanel;var e=i.extend({HDAViewClass:c.HDAListItemEdit,HDCAViewClass:g.HDCAListItemEdit,initialize:function(l){l=l||{};this.selectedHdaIds=[];this.lastSelectedViewId=null;this.tagsEditor=null;this.annotationEditor=null;this.purgeAllowed=l.purgeAllowed||false;this.selecting=l.selecting||false;this.annotationEditorShown=l.annotationEditorShown||false;this.tagsEditorShown=l.tagsEditorShown||false;i.prototype.initialize.call(this,l)},_setUpModelEventHandlers:function(){i.prototype._setUpModelEventHandlers.call(this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);this.model.contents.on("change:deleted",this._handleHdaDeletionChange,this);this.model.contents.on("change:visible",this._handleHdaVisibleChange,this);this.model.contents.on("change:purged",function(l){this.model.fetch()},this)},renderModel:function(){var l=$("<div/>");l.append(e.templates.historyPanel(this.model.toJSON()));this.$emptyMessage(l).text(this.emptyMsg);if(Galaxy&&Galaxy.currUser&&Galaxy.currUser.id&&Galaxy.currUser.id===this.model.get("user_id")){this._renderTags(l);this._renderAnnotation(l)}l.find(".history-secondary-actions").prepend(this._renderSelectButton());l.find(".history-dataset-actions").toggle(this.selecting);l.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(l);this.renderHdas(l);return l},_renderTags:function(l){var m=this;this.tagsEditor=new j.TagsEditor({model:this.model,el:l.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},onshow:function(){m.toggleHDATagEditors(true,m.fxSpeed)},onhide:function(){m.toggleHDATagEditors(false,m.fxSpeed)},$activator:faIconButton({title:b("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(l.find(".history-secondary-actions"))})},_renderAnnotation:function(l){var m=this;this.annotationEditor=new a.AnnotationEditor({model:this.model,el:l.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},onshow:function(){m.toggleHDAAnnotationEditors(true,m.fxSpeed)},onhide:function(){m.toggleHDAAnnotationEditors(false,m.fxSpeed)},$activator:faIconButton({title:b("Edit history annotation"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(l.find(".history-secondary-actions"))})},_renderSelectButton:function(l){return faIconButton({title:b("Operations on multiple datasets"),classes:"history-select-btn",faIcon:"fa-check-square-o"})},_setUpBehaviours:function(l){l=l||this.$el;i.prototype._setUpBehaviours.call(this,l);if(!this.model){return}this._setUpDatasetActionsPopup(l);if((!Galaxy.currUser||Galaxy.currUser.isAnonymous())||(Galaxy.currUser.id!==this.model.get("user_id"))){return}var m=this;l.find(".history-name").attr("title",b("Click to rename history")).tooltip({placement:"bottom"}).make_text_editable({on_finish:function(n){var o=m.model.get("name");if(n&&n!==o){m.$el.find(".history-name").text(n);m.model.save({name:n}).fail(function(){m.$el.find(".history-name").text(m.model.previous("name"))})}else{m.$el.find(".history-name").text(o)}}})},_setUpDatasetActionsPopup:function(l){var m=this,n=[{html:b("Hide datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.hide;m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Unhide datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.unhide;m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Delete datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype["delete"];m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Undelete datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.undelete;m.getSelectedHdaCollection().ajaxQueue(o)}}];if(m.purgeAllowed){n.push({html:b("Permanently delete datasets"),func:function(){if(confirm(b("This will permanently remove the data in your datasets. Are you sure?"))){var o=d.HistoryDatasetAssociation.prototype.purge;m.getSelectedHdaCollection().ajaxQueue(o)}}})}n.push({html:b("Build Dataset List (Experimental)"),func:function(){m.getSelectedHdaCollection().promoteToHistoryDatasetCollection(m.model,"list")}});n.push({html:b("Build Dataset Pair (Experimental)"),func:function(){m.getSelectedHdaCollection().promoteToHistoryDatasetCollection(m.model,"paired")}});n.push({html:b("Build List of Dataset Pairs (Experimental)"),func:_.bind(m._showPairedCollectionModal,m)});return new PopupMenu(l.find(".history-dataset-action-popup-btn"),n)},_showPairedCollectionModal:function(){var l=this,m=l.getSelectedHdaCollection().toJSON().filter(function(n){return n.history_content_type==="dataset"&&n.state===k.OK});if(m.length){require(["mvc/collection/paired-collection-creator"],function(n){window.creator=n.pairedCollectionCreatorModal(m,{historyId:l.model.id})})}else{}},_handleHdaDeletionChange:function(l){if(l.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[l.id])}},_handleHdaVisibleChange:function(l){if(l.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[l.id])}},_getContentOptions:function(m){var l=i.prototype._getContentOptions.call(this,m);_.extend(l,{selectable:this.selecting,purgeAllowed:this.purgeAllowed,tagsEditorShown:(this.tagsEditor&&!this.tagsEditor.hidden),annotationEditorShown:(this.annotationEditor&&!this.annotationEditor.hidden)});return l},_setUpHdaListeners:function(m){var l=this;i.prototype._setUpHdaListeners.call(this,m);m.on("selected",function(p,o){if(!o){return}var n=[];if((o.shiftKey)&&(l.lastSelectedViewId&&_.has(l.hdaViews,l.lastSelectedViewId))){var r=l.hdaViews[l.lastSelectedViewId];n=l.selectDatasetRange(p,r).map(function(s){return s.model.id})}else{var q=p.model.id;l.lastSelectedViewId=q;n=[q]}l.selectedHdaIds=_.union(l.selectedHdaIds,n)});m.on("de-selected",function(o,n){var p=o.model.id;l.selectedHdaIds=_.without(l.selectedHdaIds,p)})},toggleHDATagEditors:function(l){var m=arguments;_.each(this.hdaViews,function(n){if(n.tagsEditor){n.tagsEditor.toggle.apply(n.tagsEditor,m)}})},toggleHDAAnnotationEditors:function(l){var m=arguments;_.each(this.hdaViews,function(n){if(n.annotationEditor){n.annotationEditor.toggle.apply(n.annotationEditor,m)}})},removeHdaView:function(m){if(!m){return}var l=this;m.$el.fadeOut(l.fxSpeed,function(){m.off();m.remove();delete l.hdaViews[m.model.id];if(_.isEmpty(l.hdaViews)){l.trigger("empty-history",l);l._renderEmptyMsg()}})},events:_.extend(_.clone(i.prototype.events),{"click .history-select-btn":"toggleSelectors","click .history-select-all-datasets-btn":"selectAllDatasets","click .history-deselect-all-datasets-btn":"deselectAllDatasets"}),updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},showSelectors:function(l){l=(l!==undefined)?(l):(this.fxSpeed);this.selecting=true;this.$(".history-dataset-actions").slideDown(l);_.each(this.hdaViews,function(m){m.showSelector()});this.selectedHdaIds=[];this.lastSelectedViewId=null},hideSelectors:function(l){l=(l!==undefined)?(l):(this.fxSpeed);this.selecting=false;this.$(".history-dataset-actions").slideUp(l);_.each(this.hdaViews,function(m){m.hideSelector()});this.selectedHdaIds=[];this.lastSelectedViewId=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAllDatasets:function(l){_.each(this.hdaViews,function(m){m.select(l)})},deselectAllDatasets:function(l){this.lastSelectedViewId=null;_.each(this.hdaViews,function(m){m.deselect(l)})},selectDatasetRange:function(n,m){var l=this.hdaViewRange(n,m);_.each(l,function(o){o.select()});return l},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(l){return l.selected})},getSelectedHdaCollection:function(){return new h.HistoryContents(_.map(this.getSelectedHdaViews(),function(l){return l.model}),{historyId:this.model.id})},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{HistoryPanel:e}});
\ No newline at end of file
+define(["mvc/history/history-panel","mvc/history/history-contents","mvc/dataset/states","mvc/history/hda-model","mvc/history/hda-li-edit","mvc/history/hdca-li-edit","mvc/tags","mvc/annotations","utils/localization"],function(f,h,k,d,c,g,j,a,b){var i=f.ReadOnlyHistoryPanel;var e=i.extend({HDAViewClass:c.HDAListItemEdit,HDCAViewClass:g.HDCAListItemEdit,initialize:function(l){l=l||{};this.selectedHdaIds=[];this.lastSelectedViewId=null;this.tagsEditor=null;this.annotationEditor=null;this.purgeAllowed=l.purgeAllowed||false;this.selecting=l.selecting||false;this.annotationEditorShown=l.annotationEditorShown||false;this.tagsEditorShown=l.tagsEditorShown||false;i.prototype.initialize.call(this,l)},_setUpModelEventHandlers:function(){i.prototype._setUpModelEventHandlers.call(this);this.model.on("change:nice_size",this.updateHistoryDiskSize,this);this.model.contents.on("change:deleted",this._handleHdaDeletionChange,this);this.model.contents.on("change:visible",this._handleHdaVisibleChange,this);this.model.contents.on("change:purged",function(l){this.model.fetch()},this)},renderModel:function(){var l=$("<div/>");l.append(e.templates.historyPanel(this.model.toJSON()));this.$emptyMessage(l).text(this.emptyMsg);if(Galaxy&&Galaxy.currUser&&Galaxy.currUser.id&&Galaxy.currUser.id===this.model.get("user_id")){this._renderTags(l);this._renderAnnotation(l)}l.find(".history-secondary-actions").prepend(this._renderSelectButton());l.find(".history-dataset-actions").toggle(this.selecting);l.find(".history-secondary-actions").prepend(this._renderSearchButton());this._setUpBehaviours(l);this.renderHdas(l);return l},_renderTags:function(l){var m=this;this.tagsEditor=new j.TagsEditor({model:this.model,el:l.find(".history-controls .tags-display"),onshowFirstTime:function(){this.render()},onshow:function(){m.toggleHDATagEditors(true,m.fxSpeed)},onhide:function(){m.toggleHDATagEditors(false,m.fxSpeed)},$activator:faIconButton({title:b("Edit history tags"),classes:"history-tag-btn",faIcon:"fa-tags"}).appendTo(l.find(".history-secondary-actions"))})},_renderAnnotation:function(l){var m=this;this.annotationEditor=new a.AnnotationEditor({model:this.model,el:l.find(".history-controls .annotation-display"),onshowFirstTime:function(){this.render()},onshow:function(){m.toggleHDAAnnotationEditors(true,m.fxSpeed)},onhide:function(){m.toggleHDAAnnotationEditors(false,m.fxSpeed)},$activator:faIconButton({title:b("Edit history annotation"),classes:"history-annotate-btn",faIcon:"fa-comment"}).appendTo(l.find(".history-secondary-actions"))})},_renderSelectButton:function(l){return faIconButton({title:b("Operations on multiple datasets"),classes:"history-select-btn",faIcon:"fa-check-square-o"})},_setUpBehaviours:function(l){l=l||this.$el;i.prototype._setUpBehaviours.call(this,l);if(!this.model){return}this.actionsPopup=this._setUpDatasetActionsPopup(l);if((!Galaxy.currUser||Galaxy.currUser.isAnonymous())||(Galaxy.currUser.id!==this.model.get("user_id"))){return}var m=this;l.find(".history-name").attr("title",b("Click to rename history")).tooltip({placement:"bottom"}).make_text_editable({on_finish:function(n){var o=m.model.get("name");if(n&&n!==o){m.$el.find(".history-name").text(n);m.model.save({name:n}).fail(function(){m.$el.find(".history-name").text(m.model.previous("name"))})}else{m.$el.find(".history-name").text(o)}}})},_setUpDatasetActionsPopup:function(l){var m=this,n=[{html:b("Hide datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.hide;m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Unhide datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.unhide;m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Delete datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype["delete"];m.getSelectedHdaCollection().ajaxQueue(o)}},{html:b("Undelete datasets"),func:function(){var o=d.HistoryDatasetAssociation.prototype.undelete;m.getSelectedHdaCollection().ajaxQueue(o)}}];if(m.purgeAllowed){n.push({html:b("Permanently delete datasets"),func:function(){if(confirm(b("This will permanently remove the data in your datasets. Are you sure?"))){var o=d.HistoryDatasetAssociation.prototype.purge;m.getSelectedHdaCollection().ajaxQueue(o)}}})}n.push({html:b("Build Dataset List (Experimental)"),func:function(){m.getSelectedHdaCollection().promoteToHistoryDatasetCollection(m.model,"list")}});n.push({html:b("Build Dataset Pair (Experimental)"),func:function(){m.getSelectedHdaCollection().promoteToHistoryDatasetCollection(m.model,"paired")}});n.push({html:b("Build List of Dataset Pairs (Experimental)"),func:_.bind(m._showPairedCollectionModal,m)});return new PopupMenu(l.find(".history-dataset-action-popup-btn"),n)},_showPairedCollectionModal:function(){var l=this,m=l.getSelectedHdaCollection().toJSON().filter(function(n){return n.history_content_type==="dataset"&&n.state===k.OK});if(m.length){require(["mvc/collection/paired-collection-creator"],function(n){window.creator=n.pairedCollectionCreatorModal(m,{historyId:l.model.id})})}else{}},_handleHdaDeletionChange:function(l){if(l.get("deleted")&&!this.storage.get("show_deleted")){this.removeHdaView(this.hdaViews[l.id])}},_handleHdaVisibleChange:function(l){if(l.hidden()&&!this.storage.get("show_hidden")){this.removeHdaView(this.hdaViews[l.id])}},_getContentOptions:function(m){var l=i.prototype._getContentOptions.call(this,m);_.extend(l,{selectable:this.selecting,purgeAllowed:this.purgeAllowed,tagsEditorShown:(this.tagsEditor&&!this.tagsEditor.hidden),annotationEditorShown:(this.annotationEditor&&!this.annotationEditor.hidden)});return l},_setUpHdaListeners:function(m){var l=this;i.prototype._setUpHdaListeners.call(this,m);m.on("selected",function(p,o){if(!o){return}var n=[];if((o.shiftKey)&&(l.lastSelectedViewId&&_.has(l.hdaViews,l.lastSelectedViewId))){var r=l.hdaViews[l.lastSelectedViewId];n=l.selectDatasetRange(p,r).map(function(s){return s.model.id})}else{var q=p.model.id;l.lastSelectedViewId=q;n=[q]}l.selectedHdaIds=_.union(l.selectedHdaIds,n)});m.on("de-selected",function(o,n){var p=o.model.id;l.selectedHdaIds=_.without(l.selectedHdaIds,p)})},toggleHDATagEditors:function(l){var m=arguments;_.each(this.hdaViews,function(n){if(n.tagsEditor){n.tagsEditor.toggle.apply(n.tagsEditor,m)}})},toggleHDAAnnotationEditors:function(l){var m=arguments;_.each(this.hdaViews,function(n){if(n.annotationEditor){n.annotationEditor.toggle.apply(n.annotationEditor,m)}})},removeHdaView:function(m){if(!m){return}var l=this;m.$el.fadeOut(l.fxSpeed,function(){m.off();m.remove();delete l.hdaViews[m.model.id];if(_.isEmpty(l.hdaViews)){l.trigger("empty-history",l);l._renderEmptyMsg()}})},events:_.extend(_.clone(i.prototype.events),{"click .history-select-btn":"toggleSelectors","click .history-select-all-datasets-btn":"selectAllDatasets","click .history-deselect-all-datasets-btn":"deselectAllDatasets"}),updateHistoryDiskSize:function(){this.$el.find(".history-size").text(this.model.get("nice_size"))},showSelectors:function(l){l=(l!==undefined)?(l):(this.fxSpeed);this.selecting=true;this.$(".history-dataset-actions").slideDown(l);_.each(this.hdaViews,function(m){m.showSelector()});this.selectedHdaIds=[];this.lastSelectedViewId=null},hideSelectors:function(l){l=(l!==undefined)?(l):(this.fxSpeed);this.selecting=false;this.$(".history-dataset-actions").slideUp(l);_.each(this.hdaViews,function(m){m.hideSelector()});this.selectedHdaIds=[];this.lastSelectedViewId=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAllDatasets:function(l){_.each(this.hdaViews,function(m){m.select(l)})},deselectAllDatasets:function(l){this.lastSelectedViewId=null;_.each(this.hdaViews,function(m){m.deselect(l)})},selectDatasetRange:function(n,m){var l=this.hdaViewRange(n,m);_.each(l,function(o){o.select()});return l},getSelectedHdaViews:function(){return _.filter(this.hdaViews,function(l){return l.selected})},getSelectedHdaCollection:function(){return new h.HistoryContents(_.map(this.getSelectedHdaViews(),function(l){return l.model}),{historyId:this.model.id})},toString:function(){return"HistoryPanel("+((this.model)?(this.model.get("name")):(""))+")"}});return{HistoryPanel:e}});
\ No newline at end of file
diff -r ece8ef90a8289399bf9faca6a3265696da7e0beb -r 7c566a68d2d07375c53006191671dfed04332f55 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1851,23 +1851,27 @@
.collection-creator .header .column-headers .column-header .unpaired-filter{width:100%}.collection-creator .header .column-headers .column-header .unpaired-filter .search-query{width:100%;height:22px}
.collection-creator .header .paired-column a:not(:last-child){margin-right:8px}
.collection-creator .header .reverse-column .column-title{text-align:right}
-.collection-creator .unpaired-columns,.collection-creator .paired-columns{height:0;border:1px solid lightgrey;border-width:1px 0 1px 0;padding:4px}
+.collection-creator .unpaired-columns,.collection-creator .paired-columns{height:0;border:1px solid lightgrey;border-width:1px 0 1px 0}
.collection-creator .paired-columns{margin-bottom:8px}
-.collection-creator .column-datasets{list-style:none;overflow:hidden}.collection-creator .column-datasets .dataset{height:32px;margin-bottom:2px;border:1px solid lightgrey;border-radius:3px;padding:0 8px 0 8px;line-height:28px;cursor:pointer;overflow:hidden}.collection-creator .column-datasets .dataset:last-child{margin-bottom:4px}
-.collection-creator .unpaired-columns .dataset.unpaired{border-color:grey}.collection-creator .unpaired-columns .dataset.unpaired:hover{border-color:black}
+.collection-creator .column-datasets{list-style:none;overflow:hidden}.collection-creator .column-datasets .dataset{height:32px;margin-bottom:2px;border:1px solid lightgrey;border-radius:3px;padding:0 8px 0 8px;line-height:28px;cursor:pointer}.collection-creator .column-datasets .dataset:last-child{margin-bottom:4px}
+.collection-creator .unpaired-columns .dataset.unpaired{margin-top:2px;border-color:grey}.collection-creator .unpaired-columns .dataset.unpaired:hover{border-color:black}
.collection-creator .unpaired-columns .dataset.unpaired.selected{border-color:black;background:black;color:white}
.collection-creator .unpaired-columns .forward-column .dataset.unpaired{margin-right:32px}
.collection-creator .unpaired-columns .paired-column .dataset.unpaired{border-color:lightgrey;color:lightgrey}.collection-creator .unpaired-columns .paired-column .dataset.unpaired:hover{border-color:black;color:black}
.collection-creator .unpaired-columns .reverse-column .dataset.unpaired{text-align:right;margin-left:32px}
-.collection-creator .flexible-partition .flexible-partition-drag{width:100%;height:8px;cursor:ns-resize}.collection-creator .flexible-partition .flexible-partition-drag:hover{background:lightgrey}
+.collection-creator .flexible-partition .flexible-partition-drag{width:100%;height:8px;cursor:ns-resize;line-height:2px;text-align:center;color:lightgrey}.collection-creator .flexible-partition .flexible-partition-drag:before{content:'...'}
+.collection-creator .flexible-partition .flexible-partition-drag:hover{background:lightgrey;color:black}
.collection-creator .flexible-partition .column-header{width:100%;text-align:center}.collection-creator .flexible-partition .column-header .column-title{display:inline}
.collection-creator .flexible-partition .column-header>*:not(:last-child){margin-right:8px}
.collection-creator .flexible-partition .column-header .remove-extensions-link{display:none}
-.collection-creator .paired-columns .dataset.paired{background:#AFF1AF;border-color:grey;border-width:2px}.collection-creator .paired-columns .dataset.paired:hover,.collection-creator .paired-columns .dataset.paired.emphasized{border-color:black}
-.collection-creator .paired-columns .forward-column .dataset.paired{margin-left:32px;border-radius:3px 0 0 3px;border-right-color:grey;border-right-width:1px;text-align:right}.collection-creator .paired-columns .forward-column .dataset.paired:after{margin-left:8px;font-family:FontAwesome;content:'\f061'}
-.collection-creator .paired-columns .paired-column .dataset.paired{border-radius:0;border-width:2px 0 2px 0}.collection-creator .paired-columns .paired-column .dataset.paired .dataset-name:hover{text-decoration:underline}
-.collection-creator .paired-columns .reverse-column .dataset.paired{margin-right:32px;border-radius:0 3px 3px 0;border-left-color:grey;border-left-width:1px}.collection-creator .paired-columns .reverse-column .dataset.paired:before{margin-right:8px;font-family:FontAwesome;content:'\f060'}
-.collection-creator .paired-columns .reverse-column .unpair-btn{float:right;margin-top:-34px;width:31px;height:32px;border-color:transparent;background:transparent;font-size:120%}.collection-creator .paired-columns .reverse-column .unpair-btn:hover{border-color:#BFBFBF;background:#DEDEDE}
+.collection-creator .paired-columns .column-datasets{width:100%;overflow:auto}.collection-creator .paired-columns .column-datasets .dataset.paired{margin:0px 34px 2px 34px;border-radius:3px;border:2px solid grey;background:#AFF1AF}.collection-creator .paired-columns .column-datasets .dataset.paired:first-child{margin-top:2px}
+.collection-creator .paired-columns .column-datasets .dataset.paired:hover,.collection-creator .paired-columns .column-datasets .dataset.paired.emphasized{border-color:black}
+.collection-creator .paired-columns .column-datasets .dataset.paired span{display:inline-block;overflow:hidden}
+.collection-creator .paired-columns .column-datasets .dataset.paired .forward-dataset-name{text-align:right;border-right:1px solid grey;padding-right:8px}.collection-creator .paired-columns .column-datasets .dataset.paired .forward-dataset-name:after{margin-left:8px;font-family:FontAwesome;content:'\f061'}
+.collection-creator .paired-columns .column-datasets .dataset.paired .pair-name{display:inline-block;text-align:center}.collection-creator .paired-columns .column-datasets .dataset.paired .pair-name:hover{text-decoration:underline}
+.collection-creator .paired-columns .column-datasets .dataset.paired .reverse-dataset-name{display:inline-block;border-left:1px solid grey;padding-left:8px}.collection-creator .paired-columns .column-datasets .dataset.paired .reverse-dataset-name:before{margin-right:8px;font-family:FontAwesome;content:'\f060'}
+.collection-creator .paired-columns .unpair-btn{float:right;margin-top:-34px;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 .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}
.collection-creator .footer .attributes .collection-name-prompt.validation-warning:before{content:'(required)';margin-right:4px;color:red}
diff -r ece8ef90a8289399bf9faca6a3265696da7e0beb -r 7c566a68d2d07375c53006191671dfed04332f55 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
@@ -221,8 +221,6 @@
border: 1px solid lightgrey;
border-width: 1px 0 1px 0;
- //overflow-y: auto;
- padding: 4px;
}
// ------------------------------------------------------------------------ unpaired
.paired-columns {
@@ -243,7 +241,7 @@
padding: 0 8px 0 8px;
line-height: 28px;
cursor: pointer;
- overflow: hidden;
+ //overflow: hidden;
&:last-child {
margin-bottom: 4px;
}
@@ -253,6 +251,7 @@
// ---- unpaired
.unpaired-columns {
.dataset.unpaired {
+ margin-top: 2px;
border-color: grey;
&:hover {
border-color: black;
@@ -292,8 +291,15 @@
width: 100%;
height: 8px;
cursor: ns-resize;
+ &:before {
+ content: '...';
+ }
+ line-height: 2px;
+ text-align: center;
+ color: lightgrey;
&:hover {
background: lightgrey;
+ color: black;
}
}
.column-header {
@@ -313,65 +319,76 @@
// ---- paired datasets
.paired-columns {
- .dataset.paired {
- background: #AFF1AF;
- border-color: grey;
- border-width: 2px;
- &:hover,
- &.emphasized {
- border-color: black;
- }
- }
- .forward-column {
+ .column-datasets {
+ width: 100%;
+ overflow: auto;
+
.dataset.paired {
- margin-left: 32px;
- border-radius: 3px 0 0 3px;
- border-right-color: grey;
- border-right-width: 1px;
- text-align: right;
- &:after {
- margin-left: 8px;
- font-family: FontAwesome;
- content: '\f061';
+ &:first-child {
+ margin-top: 2px;
+ }
+ margin: 0px 34px 2px 34px;
+
+ border-radius: 3px;
+ border: 2px solid grey;
+
+ background: #AFF1AF;
+
+ &:hover,
+ &.emphasized {
+ border-color: black;
+ }
+
+ span {
+ display: inline-block;
+ overflow: hidden;
+ }
+ .forward-dataset-name {
+ text-align: right;
+ border-right: 1px solid grey;
+ padding-right: 8px;
+ &:after {
+ margin-left: 8px;
+ font-family: FontAwesome;
+ content: '\f061';
+ }
+ }
+ .pair-name {
+ display: inline-block;
+ text-align: center;
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ .reverse-dataset-name {
+ display: inline-block;
+ border-left: 1px solid grey;
+ padding-left: 8px;
+ &:before {
+ margin-right: 8px;
+ font-family: FontAwesome;
+ content: '\f060';
+ }
}
}
}
- .paired-column {
- .dataset.paired {
- border-radius: 0;
- border-width: 2px 0 2px 0;
- .dataset-name:hover {
- text-decoration: underline;
- }
+ .unpair-btn {
+ float: right;
+ margin-top: -34px;
+ width: 31px;
+ height: 32px;
+ //z-index: 1;
+ border-color: transparent;
+ //border-color: #BFBFBF;
+ background: transparent;
+ font-size: 120%;
+ &:hover {
+ border-color: #BFBFBF;
+ background: #DEDEDE;
}
}
- .reverse-column {
- .dataset.paired {
- margin-right: 32px;
- border-radius: 0 3px 3px 0;
- border-left-color: grey;
- border-left-width: 1px;
- &:before {
- margin-right: 8px;
- font-family: FontAwesome;
- content: '\f060';
- }
- }
- .unpair-btn {
- float: right;
- margin-top: -34px;
- width: 31px;
- height: 32px;
- //z-index: 1;
- border-color: transparent;
- //border-color: #BFBFBF;
- background: transparent;
- font-size: 120%;
- &:hover {
- border-color: #BFBFBF;
- background: #DEDEDE;
- }
- }
+ .empty-message {
+ text-align: center;
}
}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/737f78bb4a45/
Changeset: 737f78bb4a45
User: carlfeberhard
Date: 2014-08-26 18:59:15
Summary: UI, Dataset choice control: add DatasetChoiceModal for choosing single or multiple datasets, add DatasetChoice and MultiDatasetChoice for displaying and activating selection modal from within a page; correct lookup of galaxy_config in dataset-model; add ListPanel for displaying collections of ListViews; add DatasetListPanel for displaying collections of generic datasets; add default no-op localizer (_l) to ui.js until that file is AMD; factor out icon-btn.less from history.less; remove make_popup_menus in default expandable behaviors
Affected #: 17 files
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/base-mvc.js
--- a/static/scripts/mvc/base-mvc.js
+++ b/static/scripts/mvc/base-mvc.js
@@ -1,6 +1,7 @@
define([
- 'utils/add-logging'
-], function( addLogging ){
+ 'utils/add-logging',
+ 'utils/localization'
+], function( addLogging, _l ){
//ASSUMES: backbone
//==============================================================================
/** @class Mixin to add logging capabilities to an object.
@@ -390,6 +391,7 @@
/** are the details of this view expanded/shown or not? */
this.expanded = attributes.expanded || false;
//this.log( '\t expanded:', this.expanded );
+ this.fxSpeed = attributes.fxSpeed || this.fxSpeed;
},
// ........................................................................ render main
@@ -451,7 +453,7 @@
_setUpBehaviors : function( $where ){
$where = $where || this.$el;
// set up canned behavior on children (bootstrap, popupmenus, editable_text, etc.)
- make_popup_menus( $where );
+ //make_popup_menus( $where );
$where.find( '[title]' ).tooltip({ placement : 'bottom' });
},
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/dataset-choice.js
--- /dev/null
+++ b/static/scripts/mvc/dataset/dataset-choice.js
@@ -0,0 +1,442 @@
+define([
+ 'mvc/dataset/dataset-model',
+ 'mvc/dataset/dataset-list',
+ 'mvc/ui/ui-modal',
+ 'mvc/base-mvc',
+ 'utils/localization'
+], function( DATASET, DATASET_LIST, MODAL, BASE_MVC, _l ){
+/* ============================================================================
+TODO:
+ does this really work with mixed contents?
+ Single dataset choice: allow none?
+ tooltips rendered *behind* modal
+ collection selector
+ better handling when no results returned from filterDatasetJSON
+ pass optional subtitle from choice display to modal
+ onfirstclick
+ drop target
+ return modal with promise?
+
+ auto showing the modal may not be best
+
+ add hidden inputs
+ // cut1 on single dataset (17 in the list)
+ __switch_default__ select_single
+ input 17
+
+ // cut1 on two datasets
+ __switch_default__ select_single
+ input|__multirun__ 13
+ input|__multirun__ 15
+
+ // cut1 on a collection
+ __switch_default__ select_collection
+ input|__collection_multirun__ f2db41e1fa331b3e
+
+============================================================================ */
+/** Filters an array of dataset plain JSON objs.
+ */
+function _filterDatasetJSON( datasetJSON, where, datasetsOnly ){
+//TODO: replace with _.matches (underscore 1.6.0)
+ function matches( obj, toMatch ){
+ for( var key in toMatch ){
+ if( toMatch.hasOwnProperty( key ) ){
+ if( obj[ key ] !== toMatch[ key ] ){
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ return datasetJSON.filter( function( json ){
+ return ( !json.deleted && json.visible )
+ && ( !datasetsOnly || json.collection_type === undefined )
+ && ( matches( json, where ) );
+ });
+}
+
+// ============================================================================
+/** Given an array of plain JSON objs rep. datasets, show a modal allowing a choice
+ * of one or more of those datasets.
+ *
+ * Pass:
+ * an array of plain JSON objects representing allowed dataset choices
+ * a map of options (see below)
+ *
+ * Options:
+ * datasetsOnly: T: display only datasets, F: datasets + dataset collections
+ * where: a map of attributes available choices *must have* (defaults to { state: 'ok' })
+ * multiselect: T: user can select more than one, F: only one
+ * selected: array of dataset ids to make them selected by default
+ *
+ * @example:
+ * var datasetJSON = // from ajax or bootstrap
+ * // returns a jQuery promise (that 'fail's only if no datasets are found matching 'where' below)
+ * var choice = new DatasetChoiceModal( datasetJSON, {
+ * datasetsOnly : false,
+ * where : { state: 'ok', data_type: 'bed', ... },
+ * multiselect : true,
+ * selected : [ 'df7a1f0c02a5b08e', 'abcdef0123456789' ]
+ *
+ * }).done( function( json ){
+ * if( json ){
+ * console.debug( json );
+ * // returned choice will always be an array (single or multi)
+ * // [{ <selected dataset JSON 1>, <selected dataset JSON 2>, ... }]
+ * // ... do stuff
+ * } else {
+ * // json will === null if the user cancelled selection
+ * console.debug( 'cancelled' );
+ * }
+ * });
+ */
+var DatasetChoiceModal = function( datasetJSON, options ){
+
+ // option defaults
+ options = _.defaults( options || {}, {
+ // show datasets or datasets and collections
+ datasetsOnly : true,
+ // map of attributes to filter datasetJSON by
+ where : { state: 'ok' },
+ // select more than one dataset?
+ multiselect : false,
+ // any dataset ids that will display as already selected
+ selected : []
+ });
+ // default title should depend on multiselect
+ options.title = options.title ||
+ ( options.multiselect? _l( 'Choose datasets:' ): _l( 'Choose a dataset:' ) );
+
+ var modal, list, buttons,
+ promise = jQuery.Deferred(),
+ filterFn = options.filter || _filterDatasetJSON;
+
+ // filter the given datasets and if none left return a rejected promise for use with fail()
+ datasetJSON = filterFn( datasetJSON, options.where, options.datasetsOnly );
+ if( !datasetJSON.length ){
+ return promise.reject( 'No matches found' );
+ }
+
+ // resolve the returned promise with the json of the selected datasets
+ function resolveWithSelected(){
+ promise.resolve( list.getSelectedModels().map( function( model ){
+ return model.toJSON();
+ }));
+ }
+ // if multiselect - add a button for the user to complete the changes
+ if( options.multiselect ){
+ buttons = {};
+ buttons[ _l( 'Ok' ) ] = resolveWithSelected;
+ }
+
+ // create a full-height modal that's cancellable, remove unneeded elements and styles
+ modal = new MODAL.View({
+ height : 'auto',
+ buttons : buttons,
+ closing_events : true,
+ closing_callback : function(){ promise.resolve( null ); },
+ body : [
+ '<div class="list-panel"></div>'
+ ].join('')
+ });
+ modal.$( '.modal-header' ).remove();
+ modal.$( '.modal-footer' ).css( 'margin-top', '0px' );
+
+ // attach a dataset list (of the filtered datasets) to that modal that's selectable
+ list = new DATASET_LIST.DatasetList({
+ title : options.title,
+ subtitle : options.subtitle || _l([
+//TODO: as option
+ 'Click the checkboxes on the right to select datasets. ',
+ 'Click the datasets names to see their details. '
+ ].join('')),
+ el : modal.$body.find( '.list-panel' ),
+ selecting : true,
+ selected : options.selected,
+ collection : new DATASET.DatasetAssociationCollection( datasetJSON )
+ });
+
+ // when the list is rendered, show the modal (also add a specifying class for css)
+ list.once( 'rendered:initial', function(){
+ modal.show();
+ modal.$el.addClass( 'dataset-choice-modal' );
+ });
+ if( !options.multiselect ){
+ // if single select, remove the all/none list actions from the panel
+ list.on( 'rendered', function(){
+ list.$( '.list-actions' ).hide();
+ });
+ // if single select, immediately resolve on a single selection
+ list.on( 'view:selected', function( view ){
+ promise.resolve([ view.model.toJSON() ]);
+ });
+ }
+ list.render( 0 );
+
+ // return the promise, and on any resolution close the modal
+ return promise.always( function(){
+ modal.hide();
+ });
+};
+
+
+// ============================================================================
+/** Activator for single dataset selection modal and display of the selected dataset.
+ * The activator/display will show as a single div and, when a dataset is selected,
+ * show the name and details of the selected dataset.
+ *
+ * When clicked the div will generate a DatasetChoiceModal of the available choices.
+ *
+ * Options:
+ * datasetJSON: array of plain json objects representing allowed choices
+ * datasetsOnly: T: only show datasets in the allowed choices, F: datasets + collections
+ * where: map of attributes to filter datasetJSON by (e.g. { data_type: 'bed' })
+ * label: the label/prompt displayed
+ * selected: array of dataset ids that will show as already selected in the control
+ *
+ * @example:
+ * var choice1 = new DATASET_CHOICE.DatasetChoice({
+ * datasetJSON : datasetJSON,
+ * label : 'Input dataset',
+ * selected : [ 'df7a1f0c02a5b08e' ]
+ * });
+ * $( 'body' ).append( choice1.render().$el )
+ *
+ * Listen to the DatasetChoice to react to changes in the user's choice/selection:
+ * @example:
+ * choice1.on( 'selected', function( chooser, selectionJSONArray ){
+ * // ... do stuff with new selections
+ * });
+ */
+var DatasetChoice = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend({
+
+ //logger : console,
+
+ className : 'dataset-choice',
+
+ /** set up defaults, options, and listeners */
+ initialize : function( attributes ){
+ this.debug( this + '(DatasetChoice).initialize:', attributes );
+
+ this.label = attributes.label !== undefined? _l( attributes.label ) : '';
+ this.where = attributes.where;
+ this.datasetsOnly = attributes.datasetsOnly !== undefined? attributes.datasetsOnly: true;
+
+ this.datasetJSON = attributes.datasetJSON || [];
+ this.selected = attributes.selected || [];
+
+ this._setUpListeners();
+ },
+
+ /** add any (bbone) listeners */
+ _setUpListeners : function(){
+ //this.on( 'all', function(){
+ // this.log( this + '', arguments );
+ //});
+ },
+
+ /** render the view */
+ render : function(){
+ var json = this.toJSON();
+ this.$el.html( this._template( json ) );
+ this.$( '.selected' ).replaceWith( this._renderSelected( json ) );
+ return this;
+ },
+
+ /** return plain html for the overall control */
+ _template : function( json ){
+ return _.template([
+ '<label>',
+ '<span class="prompt"><%= json.label %></span>',
+ '<div class="selected"></div>',
+ '</label>'
+ ].join(''), { json: json });
+ },
+
+ /** return jQ DOM for the selected dataset (only one) */
+ _renderSelected : function( json ){
+ if( json.selected.length ){
+//TODO: break out?
+ return $( _.template([
+ '<div class="selected">',
+ '<span class="title"><%= selected.hid %>: <%= selected.name %></span>',
+ '<span class="subtitle">',
+ '<i><%= selected.misc_blurb %></i>',
+ '<i>', _l( 'format' ) + ': ', '<%= selected.data_type %></i>',
+ '<i><%= selected.misc_info %></i>',
+ '</span>',
+ '</div>'
+ ].join( '' ), { selected: json.selected[0] }));
+ }
+ return $([
+ '<span class="none-selected-msg">(',
+ _l( 'click to select a dataset' ),
+ ')</span>'
+ ].join( '' ));
+ },
+
+//TODO:?? why not just pass in view?
+ /** return a plain JSON object with both the view and dataset attributes */
+ toJSON : function(){
+ var chooser = this;
+ return {
+ label : chooser.label,
+ datasets : chooser.datasetJSON,
+ selected : _.compact( _.map( chooser.selected, function( id ){
+ return _.findWhere( chooser.datasetJSON, { id: id });
+ }))
+ };
+ },
+
+ /** event map: when to open the modal */
+ events : {
+ // the whole thing functions as a button
+ 'click' : 'chooseWithModal'
+ },
+
+//TODO:?? modal to prop of this?
+//TODO:?? should be able to handle 'none selectable' on initialize
+ /** open the modal and handle the promise representing the user's choice
+ * @fires 'selected' when the user selects dataset(s) - passed full json of the selected datasets
+ * @fires 'cancelled' when the user clicks away/closes the modal (no selection made) - passed this
+ * @fires 'error' if the modal has no selectable datasets based on this.where - passed this and other args
+ */
+ chooseWithModal : function(){
+ var chooser = this;
+
+ return this._createModal()
+ .done( function( json ){
+ if( json ){
+ chooser.selected = _.pluck( json, 'id' );
+ chooser.trigger( 'selected', chooser, json );
+ chooser.render();
+
+ } else {
+ chooser.trigger( 'cancelled', chooser );
+ }
+ })
+
+ .fail( function(){
+ chooser.trigger( 'error', chooser, arguments );
+ });
+ },
+
+ /** create and return the modal to use for choosing */
+ _createModal : function(){
+ return new DatasetChoiceModal( this.datasetJSON, this._getModalOptions() );
+ },
+
+ /** return a plain JSON containing the options to pass to the modal */
+ _getModalOptions : function(){
+ return {
+ title : this.label,
+ multiselect : false,
+ selected : this.selected,
+ where : this.where,
+ datasetsOnly : this.datasetsOnly
+ };
+ },
+
+ // ------------------------------------------------------------------------ misc
+ /** string rep */
+ toString : function(){
+ return 'DatasetChoice(' + this.selected + ')';
+ }
+});
+
+
+// ============================================================================
+/** Activator for multiple dataset selection modal and display of the selected datasets.
+ * The activator/display will show as a table of all choices.
+ *
+ * See DatasetChoice (above) for example usage.
+ *
+ * Additional options:
+ * showHeaders: T: show headers for selected dataset attributes in the display table
+ * cells: map of attribute keys -> Human readable/localized column headers
+ * (e.g. { data_type: _l( 'Format' ) }) - defaults are listed below
+ */
+var MultiDatasetChoice = DatasetChoice.extend({
+
+ className : DatasetChoice.prototype.className + ' multi',
+
+ /** default (dataset attribute key -> table header text) map of what cells to display in the table */
+ cells : {
+ hid : _l( 'History #' ),
+ name : _l( 'Name' ),
+ misc_blurb : _l( 'Summary' ),
+ data_type : _l( 'Format' ),
+ genome_build : _l( 'Genome' ),
+ tags : _l( 'Tags' ),
+ annotation : _l( 'Annotation' )
+ },
+
+ /** in this override, add the showHeaders and cells options */
+ initialize : function( attributes ){
+ this.showHeaders = attributes.showHeaders !== undefined? attributes.showHeaders : true;
+ this.cells = attributes.cells || this.cells;
+ DatasetChoice.prototype.initialize.call( this, attributes );
+ },
+
+ /** in this override, display the selected datasets as a table with optional headers */
+ _renderSelected : function( json ){
+ if( json.selected.length ){
+ return $( _.template([
+ '<table class="selected">',
+ '<% if( json.showHeaders ){ %>',
+ '<thead><tr>',
+ '<% _.map( json.cells, function( val, key ){ %>',
+ '<th><%= val %></th>',
+ '<% }); %>',
+ '</tr></thead>',
+ '<% } %>',
+ '<tbody>',
+ '<% _.map( json.selected, function( selected ){ %>',
+ '<tr>',
+ '<% _.map( json.cells, function( val, key ){ %>',
+ '<td class="cell-<%= key %>"><%= selected[ key ] %></td>',
+ '<% }) %>',
+ '</tr>',
+ '<% }); %>',
+ '</tbody>',
+ '</table>'
+ ].join( '' ), { json: json }));
+ }
+ return $([
+ '<span class="none-selected-msg">(',
+ _l( 'click to select a dataset' ),
+ ')</span>'
+ ].join( '' ));
+ },
+
+ /** in this override, send the showHeaders and cells options as well */
+ toJSON : function(){
+ return _.extend( DatasetChoice.prototype.toJSON.call( this ), {
+ showHeaders : this.showHeaders,
+ cells : this.cells
+ });
+ },
+
+ /** in this override, set multiselect to true */
+ _getModalOptions : function(){
+ return _.extend( DatasetChoice.prototype._getModalOptions.call( this ), {
+ multiselect : true
+ });
+ },
+
+ // ------------------------------------------------------------------------ misc
+ /** string rep */
+ toString : function(){
+ return 'DatasetChoice(' + this.selected + ')';
+ }
+});
+
+
+// ============================================================================
+ return {
+ DatasetChoiceModal : DatasetChoiceModal,
+ DatasetChoice : DatasetChoice,
+ MultiDatasetChoice : MultiDatasetChoice
+ };
+});
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/dataset-li.js
--- a/static/scripts/mvc/dataset/dataset-li.js
+++ b/static/scripts/mvc/dataset/dataset-li.js
@@ -42,14 +42,14 @@
/** event listeners */
_setUpListeners : function(){
//TODO:?? may want to move this to ListItemView (although this is only needed in the *narrow* panel views (current))
- // hide the primary actions in the title bar when selectable
+ // hide the primary actions in the title bar when selectable and narrow
this.on( 'selectable', function( isSelectable ){
if( isSelectable ){
this.$( '.primary-actions' ).hide();
} else {
this.$( '.primary-actions' ).show();
}
- });
+ }, this );
// re-rendering on any model changes
this.model.on( 'change', function( model, options ){
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/dataset-list.js
--- /dev/null
+++ b/static/scripts/mvc/dataset/dataset-list.js
@@ -0,0 +1,45 @@
+define([
+ "mvc/dataset/list-panel",
+ "mvc/dataset/dataset-li",
+ "mvc/base-mvc",
+ "utils/localization"
+], function( LIST_PANEL, DATASET_LI, BASE_MVC, _l ){
+/* =============================================================================
+TODO:
+
+============================================================================= */
+var _super = LIST_PANEL.ListPanel;
+/** @class non-editable, read-only View/Controller for a list of datasets.
+ */
+var DatasetList = _super.extend(
+/** @lends DatasetList.prototype */{
+
+ /** logger used to record this.log messages, commonly set to console */
+ //logger : console,
+
+ /** class to use for constructing the sub-views */
+ viewClass : DATASET_LI.DatasetListItemView,
+ className : _super.prototype.className + ' dataset-list',
+
+ /** string to no hdas match the search terms */
+ noneFoundMsg : _l( 'No matching datasets found' ),
+
+ // ......................................................................... SET UP
+ /** Set up the view, set up storage, bind listeners to HistoryContents events
+ * @param {Object} attributes optional settings for the panel
+ */
+ initialize : function( attributes ){
+ _super.prototype.initialize.call( this, attributes );
+ },
+
+ /** Return a string rep of the history */
+ toString : function(){
+ return 'DatasetList(' + this.collection + ')';
+ }
+});
+
+//==============================================================================
+ return {
+ DatasetList : DatasetList
+ };
+});
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/dataset-model.js
--- a/static/scripts/mvc/dataset/dataset-model.js
+++ b/static/scripts/mvc/dataset/dataset-model.js
@@ -75,7 +75,7 @@
'meta_download' : 'dataset/get_metadata_file?hda_id=' + id + '&metadata_name='
};
//TODO: global
- var root = ( galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' );
+ var root = ( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' );
_.each( urls, function( value, key ){
urls[ key ] = root + value;
});
@@ -229,7 +229,210 @@
//==============================================================================
+/** @class Backbone collection for dataset associations.
+ */
+var DatasetAssociationCollection = Backbone.Collection.extend( BASE_MVC.LoggableMixin ).extend(
+/** @lends HistoryContents.prototype */{
+ model : DatasetAssociation,
+
+ /** logger used to record this.log messages, commonly set to console */
+ //logger : console,
+
+ /** root api url */
+ urlRoot : (( window.galaxy_config && galaxy_config.root )?( galaxy_config.root ):( '/' ))
+ + 'api/datasets',
+
+ // ........................................................................ common queries
+ /** Get the ids of every item in this collection
+ * @returns array of encoded ids
+ */
+ ids : function(){
+ return this.map( function( item ){ return item.get('id'); });
+ },
+
+ /** Get contents that are not ready
+ * @returns array of content models
+ */
+ notReady : function(){
+ return this.filter( function( content ){
+ return !content.inReadyState();
+ });
+ },
+
+// /** Get the id of every model in this collection not in a 'ready' state (running).
+// * @returns an array of model ids
+// */
+// running : function(){
+// var idList = [];
+// this.each( function( item ){
+// var isRunning = !item.inReadyState();
+// if( isRunning ){
+////TODO: is this still correct since type_id
+// idList.push( item.get( 'id' ) );
+// }
+// });
+// return idList;
+// },
+
+ /** return true if any datasets don't have details */
+ haveDetails : function(){
+ return this.all( function( dataset ){ return dataset.hasDetails(); });
+ },
+
+ // ........................................................................ ajax
+ ///** fetch detailed model data for all datasets in this collection */
+ //fetchAllDetails : function( options ){
+ // options = options || {};
+ // var detailsFlag = { details: 'all' };
+ // options.data = ( options.data )?( _.extend( options.data, detailsFlag ) ):( detailsFlag );
+ // return this.fetch( options );
+ //},
+
+ /** using a queue, perform ajaxFn on each of the models in this collection */
+ ajaxQueue : function( ajaxFn, options ){
+ var deferred = jQuery.Deferred(),
+ startingLength = this.length,
+ responses = [];
+
+ if( !startingLength ){
+ deferred.resolve([]);
+ return deferred;
+ }
+
+ // use reverse order (stylistic choice)
+ var ajaxFns = this.chain().reverse().map( function( dataset, i ){
+ return function(){
+ var xhr = ajaxFn.call( dataset, options );
+ // if successful, notify using the deferred to allow tracking progress
+ xhr.done( function( response ){
+ deferred.notify({ curr: i, total: startingLength, response: response, model: dataset });
+ });
+ // (regardless of previous error or success) if not last ajax call, shift and call the next
+ // if last fn, resolve deferred
+ xhr.always( function( response ){
+ responses.push( response );
+ if( ajaxFns.length ){
+ ajaxFns.shift()();
+ } else {
+ deferred.resolve( responses );
+ }
+ });
+ };
+ }).value();
+ // start the queue
+ ajaxFns.shift()();
+
+ return deferred;
+ },
+
+ // ........................................................................ sorting/filtering
+ /** return a new collection of datasets whose attributes contain the substring matchesWhat */
+ matches : function( matchesWhat ){
+ return this.filter( function( dataset ){
+ return dataset.matches( matchesWhat );
+ });
+ },
+
+ // ........................................................................ misc
+ /** override to get a correct/smarter merge when incoming data is partial */
+ set : function( models, options ){
+ // arrrrrrrrrrrrrrrrrg...
+ // (e.g. stupid backbone)
+ // w/o this partial models from the server will fill in missing data with model defaults
+ // and overwrite existing data on the client
+ // see Backbone.Collection.set and _prepareModel
+ var collection = this;
+ models = _.map( models, function( model ){
+ if( !collection.get( model.id ) ){ return model; }
+
+ // merge the models _BEFORE_ calling the superclass version
+ var merged = existing.toJSON();
+ _.extend( merged, model );
+ return merged;
+ });
+ // now call superclass when the data is filled
+ Backbone.Collection.prototype.set.call( this, models, options );
+ },
+
+// /** Convert this ad-hoc collection of hdas to a formal collection tracked
+// by the server.
+// **/
+// promoteToHistoryDatasetCollection : function _promote( history, collection_type, options ){
+////TODO: seems like this would be better in mvc/collections
+// options = options || {};
+// options.url = this.url();
+// options.type = "POST";
+// var full_collection_type = collection_type;
+// var element_identifiers = [],
+// name = null;
+//
+// // This mechanism is rough - no error handling, allows invalid selections, no way
+// // for user to pick/override element identifiers. This is only really meant
+// if( collection_type === "list" ) {
+// this.chain().each( function( hda ) {
+// // TODO: Handle duplicate names.
+// var name = hda.attributes.name;
+// var id = hda.get('id');
+// var content_type = hda.attributes.history_content_type;
+// if( content_type === "dataset" ) {
+// if( full_collection_type !== "list" ) {
+// this.log( "Invalid collection type" );
+// }
+// element_identifiers.push( { name: name, src: "hda", id: id } );
+// } else {
+// if( full_collection_type === "list" ) {
+// full_collection_type = "list:" + hda.attributes.collection_type;
+// } else {
+// if( full_collection_type !== "list:" + hda.attributes.collection_type ) {
+// this.log( "Invalid collection type" );
+// }
+// }
+// element_identifiers.push( { name: name, src: "hdca", id: id } );
+// }
+// });
+// name = "New Dataset List";
+// } else if( collection_type === "paired" ) {
+// var ids = this.ids();
+// if( ids.length !== 2 ){
+// // TODO: Do something...
+// }
+// element_identifiers.push( { name: "forward", src: "hda", id: ids[ 0 ] } );
+// element_identifiers.push( { name: "reverse", src: "hda", id: ids[ 1 ] } );
+// name = "New Dataset Pair";
+// }
+// options.data = {
+// type: "dataset_collection",
+// name: name,
+// collection_type: full_collection_type,
+// element_identifiers: JSON.stringify( element_identifiers )
+// };
+//
+// var xhr = jQuery.ajax( options );
+// xhr.done( function( message, status, responseObj ){
+// history.refresh( );
+// });
+// xhr.fail( function( xhr, status, message ){
+// if( xhr.responseJSON && xhr.responseJSON.error ){
+// error = xhr.responseJSON.error;
+// } else {
+// error = xhr.responseJSON;
+// }
+// xhr.responseText = error;
+// // Do something?
+// });
+// return xhr;
+// },
+
+ /** String representation. */
+ toString : function(){
+ return ([ 'DatasetAssociationCollection(', this.length, ')' ].join( '' ));
+ }
+});
+
+
+//==============================================================================
return {
- DatasetAssociation : DatasetAssociation
+ DatasetAssociation : DatasetAssociation,
+ DatasetAssociationCollection : DatasetAssociationCollection
};
});
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/dataset/list-panel.js
--- /dev/null
+++ b/static/scripts/mvc/dataset/list-panel.js
@@ -0,0 +1,687 @@
+define([
+ "mvc/base-mvc",
+ "utils/localization"
+], function( BASE_MVC, _l ){
+/* =============================================================================
+TODO:
+
+============================================================================= */
+/** @class List that contains ListItemViews.
+ */
+var ListPanel = Backbone.View.extend( BASE_MVC.LoggableMixin ).extend(
+/** @lends ReadOnlyHistoryPanel.prototype */{
+
+ /** logger used to record this.log messages, commonly set to console */
+ //logger : console,
+
+ /** class to use for constructing the sub-views */
+ viewClass : BASE_MVC.ListItemView,
+
+ tagName : 'div',
+ className : 'list-panel',
+
+ /** (in ms) that jquery effects will use */
+ fxSpeed : 'fast',
+
+ /** string to display when the model has no hdas */
+ emptyMsg : _l( 'This list is empty' ),
+ /** string to no hdas match the search terms */
+ noneFoundMsg : _l( 'No matching items found' ),
+
+ // ......................................................................... SET UP
+ /** Set up the view, set up storage, bind listeners to HistoryContents events
+ * @param {Object} attributes optional settings for the list
+ */
+ initialize : function( attributes, options ){
+ attributes = attributes || {};
+ // set the logger if requested
+ if( attributes.logger ){
+ this.logger = attributes.logger;
+ }
+ this.log( this + '.initialize:', attributes );
+
+ // ---- instance vars
+ /** how quickly should jquery fx run? */
+ this.fxSpeed = _.has( attributes, 'fxSpeed' )?( attributes.fxSpeed ):( this.fxSpeed );
+
+ /** filters for displaying subviews */
+ this.filters = [];
+ /** current search terms */
+ this.searchFor = attributes.searchFor || '';
+
+ /** loading indicator */
+ this.indicator = new LoadingIndicator( this.$el );
+
+ /** currently showing selectors on items? */
+ this.selecting = ( attributes.selecting !== undefined )? attributes.selecting : true;
+ //this.selecting = false;
+
+ /** cached selected item.model.ids to persist btwn renders */
+ this.selected = attributes.selected || [];
+ /** the last selected item.model.id */
+ this.lastSelected = null;
+
+ /** list item view class (when passed models) */
+ this.viewClass = attributes.viewClass || this.viewClass;
+
+ /** list item views */
+ this.views = [];
+ /** list item models */
+ this.collection = attributes.collection || ( new Backbone.Collection([]) );
+
+ /** filter fns run over collection items to see if they should show in the list */
+ this.filters = attributes.filters || [];
+
+//TODO: remove
+ this.title = attributes.title || '';
+ this.subtitle = attributes.subtitle || '';
+
+ this._setUpListeners();
+ },
+
+ /** create any event listeners for the list
+ */
+ _setUpListeners : function(){
+ this.on( 'error', function( model, xhr, options, msg, details ){
+ //this.errorHandler( model, xhr, options, msg, details );
+ console.error( model, xhr, options, msg, details );
+ }, this );
+
+ // show hide the loading indicator
+ this.on( 'loading', function(){
+ this._showLoadingIndicator( 'loading...', 40 );
+ }, this );
+ this.on( 'loading-done', function(){
+ this._hideLoadingIndicator( 40 );
+ }, this );
+
+ // throw the first render up as a diff namespace using once (for outside consumption)
+ this.once( 'rendered', function(){
+ this.trigger( 'rendered:initial', this );
+ }, this );
+
+ // debugging
+ if( this.logger ){
+ this.on( 'all', function( event ){
+ this.log( this + '', arguments );
+ }, this );
+ }
+
+ this._setUpCollectionListeners();
+ this._setUpViewListeners();
+ return this;
+ },
+
+ /** free any sub-views the list has */
+ freeViews : function(){
+//TODO: stopListening? remove?
+ this.views = [];
+ return this;
+ },
+
+ // ------------------------------------------------------------------------ item listeners
+ /** listening for history and HDA events */
+ _setUpCollectionListeners : function(){
+
+ this.collection.on( 'reset', function(){
+ this.renderItems();
+ }, this );
+
+ this.collection.on( 'add', this.addItemView, this );
+ this.collection.on( 'remove', this.removeItemView, this );
+
+ // debugging
+ if( this.logger ){
+ this.collection.on( 'all', function( event ){
+ this.info( this + '(collection)', arguments );
+ }, this );
+ }
+ return this;
+ },
+
+ /** listening for history and HDA events */
+ _setUpViewListeners : function(){
+
+ // shift to select a range
+ this.on( 'view:selected', function( view, ev ){
+ if( ev && ev.shiftKey && this.lastSelected ){
+ var lastSelectedView = _.find( this.views, function( view ){
+ return view.model.id === this.lastSelected;
+ });
+ if( lastSelectedView ){
+ this.selectRange( view, lastSelectedView );
+ }
+ }
+ this.selected.push( view.model.id );
+ this.lastSelected = view.model.id;
+ }, this );
+ },
+
+ // ------------------------------------------------------------------------ rendering
+ /** Render this content, set up ui.
+ * @param {Number or String} speed the speed of the render
+ */
+ render : function( speed ){
+ var $newRender = this._buildNewRender();
+ this._setUpBehaviors( $newRender );
+ this._queueNewRender( $newRender, speed );
+ return this;
+ },
+
+ /** Build a temp div containing the new children for the view's $el.
+ */
+ _buildNewRender : function(){
+ // create a new render using a skeleton template, render title buttons, render body, and set up events, etc.
+ var json = this.model? this.model.toJSON() : {},
+ $newRender = $( this.templates.el( json, this ) );
+ this._renderTitle( $newRender );
+ this._renderSubtitle( $newRender );
+ this._renderSearch( $newRender );
+ this.renderItems( $newRender );
+ return $newRender;
+ },
+
+ /**
+ */
+ _renderTitle : function( $where ){
+ //$where = $where || this.$el;
+ //$where.find( '.title' ).replaceWith( ... )
+ },
+
+ /**
+ */
+ _renderSubtitle : function( $where ){
+ //$where = $where || this.$el;
+ //$where.find( '.title' ).replaceWith( ... )
+ },
+
+ /** Fade out the old el, swap in the new contents, then fade in.
+ * @param {Number or String} speed jq speed to use for rendering effects
+ * @fires rendered when rendered
+ */
+ _queueNewRender : function( $newRender, speed ) {
+ speed = ( speed === undefined )?( this.fxSpeed ):( speed );
+ var view = this;
+
+ $( view ).queue( 'fx', [
+ function( next ){ this.$el.fadeOut( speed, next ); },
+ function( next ){
+ view._swapNewRender( $newRender );
+ next();
+ },
+ function( next ){ this.$el.fadeIn( speed, next ); },
+ function( next ){
+ view.trigger( 'rendered', view );
+ next();
+ }
+ ]);
+ },
+
+ /** empty out the current el, move the $newRender's children in */
+ _swapNewRender : function( $newRender ){
+ this.$el.empty().attr( 'class', this.className ).append( $newRender.children() );
+ if( this.selecting ){ this.showSelectors( 0 ); }
+ return this;
+ },
+
+ /** */
+ _setUpBehaviors : function( $where ){
+ $where = $where || this.$el;
+ $where.find( '.controls [title]' ).tooltip({ placement: 'bottom' });
+ return this;
+ },
+
+ // ------------------------------------------------------------------------ sub-$element shortcuts
+ /** the scroll container for this panel - can be $el, $el.parent(), or grandparent depending on context */
+ $scrollContainer : function(){
+ // override
+ return this.$el.parent().parent();
+ },
+ /** */
+ $list : function( $where ){
+ return ( $where || this.$el ).find( '.list-items' );
+ },
+ /** container where list messages are attached */
+ $messages : function( $where ){
+ return ( $where || this.$el ).find( '.message-container' );
+ },
+ /** the message displayed when no views can be shown (no views, none matching search) */
+ $emptyMessage : function( $where ){
+ return ( $where || this.$el ).find( '.empty-message' );
+ },
+
+ // ------------------------------------------------------------------------ hda sub-views
+ /**
+ * @param {jQuery} $whereTo what dom element to prepend the HDA views to
+ * @returns the visible item views
+ */
+ renderItems : function( $whereTo ){
+ $whereTo = $whereTo || this.$el;
+ var list = this,
+ newViews = [];
+
+ var $list = this.$list( $whereTo ),
+ item$els = this._filterCollection().map( function( itemModel ){
+//TODO: creates views each time - not neccessarily good
+ var view = list._createItemView( itemModel );
+ newViews.push( view );
+ return view.render( 0 ).$el;
+ });
+ this.debug( item$els );
+ this.debug( newViews );
+
+ $list.empty();
+ if( item$els.length ){
+ $list.append( item$els );
+ this.$emptyMessage( $whereTo ).hide();
+
+ } else {
+ this._renderEmptyMessage( $whereTo ).show();
+ }
+
+ this.views = newViews;
+ return newViews;
+ },
+
+ /**
+ */
+ _filterCollection : function(){
+ // override this
+ var list = this;
+ return list.collection.filter( _.bind( list._filterItem, list ) );
+ },
+
+ /**
+ */
+ _filterItem : function( model ){
+ // override this
+ var list = this;
+ return ( _.every( list.filters.map( function( fn ){ return fn.call( model ); }) ) )
+ && ( !list.searchFor || model.matchesAll( list.searchFor ) );
+ },
+
+ /**
+ */
+ _createItemView : function( model ){
+ var ViewClass = this._getItemViewClass( model ),
+ options = _.extend( this._getItemViewOptions( model ), {
+ model : model
+ }),
+ view = new ViewClass( options );
+ this._setUpItemViewListeners( view );
+ return view;
+ },
+
+ _getItemViewClass : function( model ){
+ // override this
+ return this.viewClass;
+ },
+
+ _getItemViewOptions : function( model ){
+ // override this
+ return {
+ //logger : this.logger,
+ fxSpeed : this.fxSpeed,
+ expanded : false,
+ selectable : this.selecting,
+ selected : _.contains( this.selected, model.id ),
+ draggable : this.dragging
+ };
+ },
+
+ /**
+ */
+ _setUpItemViewListeners : function( view ){
+ var list = this;
+ view.on( 'all', function(){
+ var args = Array.prototype.slice.call( arguments, 0 );
+ args[0] = 'view:' + args[0];
+ list.trigger.apply( list, args );
+ });
+
+ // debugging
+ //if( this.logger ){
+ // view.on( 'all', function( event ){
+ // this.log( this + '(view)', arguments );
+ // }, this );
+ //}
+ return this;
+ },
+
+ /** render the empty/none-found message */
+ _renderEmptyMessage : function( $whereTo ){
+ //this.debug( '_renderEmptyMessage', $whereTo, this.searchFor );
+ var text = this.searchFor? this.noneFoundMsg : this.emptyMsg;
+ return this.$emptyMessage( $whereTo ).text( text );
+ },
+
+ /** collapse all item views */
+ expandAll : function(){
+ _.each( this.views, function( view ){
+ view.expand();
+ });
+ },
+
+ /** collapse all item views */
+ collapseAll : function(){
+ _.each( this.views, function( view ){
+ view.collapse();
+ });
+ },
+
+ // ------------------------------------------------------------------------ collection/views syncing
+ /**
+ */
+ addItemView : function( model, collection, options ){
+ this.log( this + '.addItemView:', model );
+ var list = this;
+ if( !this._filterItem( model ) ){ return undefined; }
+
+//TODO: sorted? position?
+ var view = list._createItemView( model );
+ this.views.push( view );
+
+ $( view ).queue( 'fx', [
+ function( next ){ list.$emptyMessage().fadeOut( list.fxSpeed, next ); },
+ function( next ){
+//TODO: auto render?
+ list.$list().append( view.render().$el );
+ next();
+ }
+ ]);
+ return view;
+ },
+
+ /**
+ */
+ removeItemView : function( model, collection, options ){
+ this.log( this + '.removeItemView:', model );
+ var list = this,
+ view = list.viewFromModel( model );
+ if( !view ){ return undefined; }
+
+ this.views = _.without( this.views, view );
+ view.remove();
+ if( !this.views.length ){
+ list._renderEmptyMessage().fadeIn( list.fxSpeed );
+ }
+ return view;
+ },
+
+ /** get views based on model properties
+ */
+ viewFromModel : function( model ){
+ for( var i=0; i<this.views.length; i++ ){
+ var view = this.views[i];
+ if( view.model === model ){
+ return view;
+ }
+ }
+ return undefined;
+ },
+
+ /** get views based on model properties
+ */
+ viewsWhereModel : function( properties ){
+ return this.views.filter( function( view ){
+ //return view.model.matches( properties );
+//TODO: replace with _.matches (underscore 1.6.0)
+ var json = view.model.toJSON();
+ //console.debug( '\t', json, properties );
+ for( var key in properties ){
+ if( properties.hasOwnPropery( key ) ){
+ //console.debug( '\t\t', json[ key ], view.model.properties[ key ] );
+ if( json[ key ] !== view.model.properties[ key ] ){
+ return false;
+ }
+ }
+ }
+ return true;
+ });
+ },
+
+ /**
+ */
+ viewRange : function( viewA, viewB ){
+ if( viewA === viewB ){ return ( viewA )?( [ viewA ] ):( [] ); }
+
+ var indexA = this.views.indexOf( viewA ),
+ indexB = this.views.indexOf( viewB );
+
+ // handle not found
+ if( indexA === -1 || indexB === -1 ){
+ if( indexA === indexB ){ return []; }
+ return ( indexA === -1 )?( [ viewB ] ):( [ viewA ] );
+ }
+ // reverse if indeces are
+ //note: end inclusive
+ return ( indexA < indexB )?
+ this.views.slice( indexA, indexB + 1 ) :
+ this.views.slice( indexB, indexA + 1 );
+ },
+
+ // ------------------------------------------------------------------------ searching
+ /** render a search input for filtering datasets shown
+ * (see the search section in the HDA model for implementation of the actual searching)
+ * return will start the search
+ * esc will clear the search
+ * clicking the clear button will clear the search
+ * uses searchInput in ui.js
+ */
+ _renderSearch : function( $where ){
+ $where.find( '.controls .search-input' ).searchInput({
+ placeholder : 'search',
+ initialVal : this.searchFor,
+ onfirstsearch : _.bind( this._firstSearch, this ),
+ onsearch : _.bind( this.searchItems, this ),
+ onclear : _.bind( this.clearSearch, this )
+ });
+ return $where;
+ },
+
+ _firstSearch : function( searchFor ){
+ this.log( 'onFirstSearch', searchFor );
+ return this.searchItems( searchFor );
+ },
+
+ /** filter view list to those that contain the searchFor terms */
+ searchItems : function( searchFor ){
+ this.searchFor = searchFor;
+ this.trigger( 'search:searching', searchFor, this );
+ this.renderItems();
+ return this;
+ },
+
+ /** clear the search filters and show all views that are normally shown */
+ clearSearch : function( searchFor ){
+ //this.log( 'onSearchClear', this );
+ this.searchFor = '';
+ this.trigger( 'search:clear', this );
+ this.renderItems();
+ return this;
+ },
+
+ // ------------------------------------------------------------------------ selection
+ /** show selectors on all visible hdas and associated controls */
+ showSelectors : function( speed ){
+ speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
+ this.selecting = true;
+ this.$( '.list-actions' ).slideDown( speed );
+ _.each( this.views, function( view ){
+ view.showSelector( speed );
+ });
+ this.selected = [];
+ this.lastSelected = null;
+ },
+
+ /** hide selectors on all visible hdas and associated controls */
+ hideSelectors : function( speed ){
+ speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
+ this.selecting = false;
+ this.$( '.list-actions' ).slideUp( speed );
+ _.each( this.views, function( view ){
+ view.hideSelector( speed );
+ });
+ this.selected = [];
+ this.lastSelected = null;
+ },
+
+ /** show or hide selectors on all visible hdas and associated controls */
+ toggleSelectors : function(){
+ if( !this.selecting ){
+ this.showSelectors();
+ } else {
+ this.hideSelectors();
+ }
+ },
+
+ /** select all visible hdas */
+ selectAll : function( event ){
+ _.each( this.views, function( view ){
+ view.select( event );
+ });
+ },
+
+ /** deselect all visible hdas */
+ deselectAll : function( event ){
+ this.lastSelected = null;
+ _.each( this.views, function( view ){
+ view.deselect( event );
+ });
+ },
+
+ /** select a range of datasets between A and B */
+ selectRange : function( viewA, viewB ){
+ var range = this.viewRange( viewA, viewB );
+ _.each( range, function( view ){
+ view.select();
+ });
+ return range;
+ },
+
+ /** return an array of all currently selected hdas */
+ getSelectedViews : function(){
+ return _.filter( this.views, function( v ){
+ return v.selected;
+ });
+ },
+
+ /** return an collection of the models of all currenly selected hdas */
+ getSelectedModels : function(){
+ return new this.collection.constructor( _.map( this.getSelectedViews(), function( view ){
+ return view.model;
+ }));
+ },
+
+ // ------------------------------------------------------------------------ loading indicator
+//TODO: questionable
+ /** hide the $el and display a loading indicator (in the $el's parent) when loading new data */
+ _showLoadingIndicator : function( msg, speed, callback ){
+ speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
+ if( !this.indicator ){
+ this.indicator = new LoadingIndicator( this.$el, this.$el.parent() );
+ }
+ if( !this.$el.is( ':visible' ) ){
+ this.indicator.show( 0, callback );
+ } else {
+ this.$el.fadeOut( speed );
+ this.indicator.show( msg, speed, callback );
+ }
+ },
+
+ /** hide the loading indicator */
+ _hideLoadingIndicator : function( speed, callback ){
+ speed = ( speed !== undefined )?( speed ):( this.fxSpeed );
+ if( this.indicator ){
+ this.indicator.hide( speed, callback );
+ }
+ },
+
+ // ------------------------------------------------------------------------ scrolling
+ /** get the current scroll position of the panel in its parent */
+ scrollPosition : function(){
+ return this.$scrollContainer().scrollTop();
+ },
+
+ /** set the current scroll position of the panel in its parent */
+ scrollTo : function( pos ){
+ this.$scrollContainer().scrollTop( pos );
+ return this;
+ },
+
+ /** Scrolls the panel to the top. */
+ scrollToTop : function(){
+ this.$scrollContainer().scrollTop( 0 );
+ return this;
+ },
+
+ /** */
+ scrollToItem : function( view ){
+ if( !view ){ return; }
+ var itemTop = view.$el.offset().top;
+ this.$scrollContainer().scrollTop( itemTop );
+ },
+
+ // ------------------------------------------------------------------------ panel events
+ /** event map */
+ events : {
+ 'click .select-all' : 'selectAll',
+ 'click .deselect-all' : 'deselectAll'
+ },
+
+ // ------------------------------------------------------------------------ misc
+ /** Return a string rep of the history */
+ toString : function(){
+ return 'ListPanel(' + this.collection + ')';
+ }
+});
+
+// ............................................................................ TEMPLATES
+/** underscore templates */
+ListPanel.prototype.templates = (function(){
+//TODO: move to require text! plugin
+
+ var elTemplate = BASE_MVC.wrapTemplate([
+ // temp container
+ '<div>',
+ '<div class="controls">',
+ '<div class="title">',
+ '<div class="name"><%= model.name || view.title %></div>',
+ '</div>',
+ '<div class="subtitle"><%= view.subtitle %></div>',
+ '<div class="actions"></div>',
+ '<div class="messages"></div>',
+
+ '<div class="search">',
+ '<div class="search-input"></div>',
+ '</div>',
+
+ '<div class="list-actions">',
+ '<div class="btn-group">',
+ '<button class="select-all btn btn-default"',
+ 'data-mode="select">', _l( 'All' ), '</button>',
+ '<button class="deselect-all btn btn-default"',
+ 'data-mode="select">', _l( 'None' ), '</button>',
+ '</div>',
+ //'<button class="action-popup-btn btn btn-default">',
+ // _l( 'For all selected' ), '...',
+ //'</button>',
+ '</div>',
+ '</div>',
+ '<div class="list-items"></div>',
+ '<div class="empty-message infomessagesmall"></div>',
+ '</div>'
+ ]);
+
+ return {
+ el : elTemplate
+ };
+}());
+
+
+
+//==============================================================================
+ return {
+ ListPanel: ListPanel
+ };
+});
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/mvc/ui.js
--- a/static/scripts/mvc/ui.js
+++ b/static/scripts/mvc/ui.js
@@ -610,6 +610,7 @@
* of characters, a callback is called. Pressing ESC when the input
* is focused will clear the input and call a separate callback.
*/
+ var _l = window._l || function( s ){ return s; }
// contructor
function searchInput( parentNode, options ){
@@ -670,6 +671,11 @@
})
// attach behaviors to esc, return if desired, search on some min len string
.keyup( function( event ){
+ event.preventDefault();
+ event.stopPropagation();
+//TODO: doesn't work
+ if( !$( this ).val() ){ $( this ).blur(); }
+
// esc key will clear if desired
if( event.which === KEYCODE_ESC && options.escWillClear ){
clearSearchInput.call( this, event );
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/packed/mvc/base-mvc.js
--- a/static/scripts/packed/mvc/base-mvc.js
+++ b/static/scripts/packed/mvc/base-mvc.js
@@ -1,1 +1,1 @@
-define(["utils/add-logging"],function(i){var j={logger:null,_logNamespace:"?",log:function(){if(this.logger){var l=this.logger.log;if(typeof this.logger.log==="object"){l=Function.prototype.bind.call(this.logger.log,this.logger)}return l.apply(this.logger,arguments)}return undefined}};i(j);var a=Backbone.Model.extend({initialize:function(m){this._checkEnabledSessionStorage();if(!m.id){throw new Error("SessionStorageModel requires an id in the initial attributes")}this.id=m.id;var l=(!this.isNew())?(this._read(this)):({});this.clear({silent:true});this.save(_.extend({},this.defaults,l,m),{silent:true});this.on("change",function(){this.save()})},_checkEnabledSessionStorage:function(){try{return sessionStorage.length}catch(l){alert("Please enable cookies in your browser for this Galaxy site");return false}},sync:function(o,m,l){if(!l.silent){m.trigger("request",m,{},l)}var n;switch(o){case"create":n=this._create(m);break;case"read":n=this._read(m);break;case"update":n=this._update(m);break;case"delete":n=this._delete(m);break}if(n!==undefined||n!==null){if(l.success){l.success()}}else{if(l.error){l.error()}}return n},_create:function(l){var m=l.toJSON(),n=sessionStorage.setItem(l.id,JSON.stringify(m));return(n===null)?(n):(m)},_read:function(l){return JSON.parse(sessionStorage.getItem(l.id))},_update:function(l){return l._create(l)},_delete:function(l){return sessionStorage.removeItem(l.id)},isNew:function(){return !sessionStorage.hasOwnProperty(this.id)},_log:function(){return JSON.stringify(this.toJSON(),null," ")},toString:function(){return"SessionStorageModel("+this.id+")"}});(function(){a.prototype=_.omit(a.prototype,"url","urlRoot")}());var g={searchAttributes:[],searchAliases:{},searchAttribute:function(n,l){var m=this.get(n);if(!l||(m===undefined||m===null)){return false}if(_.isArray(m)){return this._searchArrayAttribute(m,l)}return(m.toString().toLowerCase().indexOf(l.toLowerCase())!==-1)},_searchArrayAttribute:function(m,l){l=l.toLowerCase();return _.any(m,function(n){return(n.toString().toLowerCase().indexOf(l.toLowerCase())!==-1)})},search:function(l){var m=this;return _.filter(this.searchAttributes,function(n){return m.searchAttribute(n,l)})},matches:function(m){var o="=",l=m.split(o);if(l.length>=2){var n=l[0];n=this.searchAliases[n]||n;return this.searchAttribute(n,l[1])}return !!this.search(m).length},matchesAll:function(m){var l=this;m=m.match(/(".*"|\w*=".*"|\S*)/g).filter(function(n){return !!n});return _.all(m,function(n){n=n.replace(/"/g,"");return l.matches(n)})}};var c={hiddenUntilActivated:function(l,n){n=n||{};this.HUAVOptions={$elementShown:this.$el,showFn:jQuery.prototype.toggle,showSpeed:"fast"};_.extend(this.HUAVOptions,n||{});this.HUAVOptions.hasBeenShown=this.HUAVOptions.$elementShown.is(":visible");this.hidden=this.isHidden();if(l){var m=this;l.on("click",function(o){m.toggle(m.HUAVOptions.showSpeed)})}},isHidden:function(){return(this.HUAVOptions.$elementShown.is(":hidden"))},toggle:function(){if(this.hidden){if(!this.HUAVOptions.hasBeenShown){if(_.isFunction(this.HUAVOptions.onshowFirstTime)){this.HUAVOptions.hasBeenShown=true;this.HUAVOptions.onshowFirstTime.call(this)}}if(_.isFunction(this.HUAVOptions.onshow)){this.HUAVOptions.onshow.call(this);this.trigger("hiddenUntilActivated:shown",this)}this.hidden=false}else{if(_.isFunction(this.HUAVOptions.onhide)){this.HUAVOptions.onhide.call(this);this.trigger("hiddenUntilActivated:hidden",this)}this.hidden=true}return this.HUAVOptions.showFn.apply(this.HUAVOptions.$elementShown,arguments)}};function k(o,n){var l=Array.prototype.slice.call(arguments,0),m=l.pop();l.unshift(m);return _.defaults.apply(_,l)}function e(m,l){l=l||"model";var n=_.template(m.join(""));return function(p,o){var q={view:o||{},_l:_l};q[l]=p||{};return n(q)}}var b=Backbone.View.extend(j).extend({initialize:function(l){this.expanded=l.expanded||false},fxSpeed:"fast",render:function(m){var l=this._buildNewRender();this._setUpBehaviors(l);this._queueNewRender(l,m);return this},_buildNewRender:function(){var l=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(l).replaceWith(this._renderDetails().show())}return l},_queueNewRender:function(m,n){n=(n===undefined)?(this.fxSpeed):(n);var l=this;$(l).queue("fx",[function(o){this.$el.fadeOut(n,o)},function(o){l._swapNewRender(m);o()},function(o){this.$el.fadeIn(n,o)},function(o){this.trigger("rendered",l);o()}])},_swapNewRender:function(l){return this.$el.empty().attr("class",this.className).append(l.children())},_setUpBehaviors:function(l){l=l||this.$el;make_popup_menus(l);l.find("[title]").tooltip({placement:"bottom"})},$details:function(l){l=l||this.$el;return l.find(".details")},_renderDetails:function(){var l=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(l);return l},toggleExpanded:function(l){l=(l===undefined)?(!this.expanded):(l);if(l){this.expand()}else{this.collapse()}return this},expand:function(){var l=this;return l._fetchModelDetails().always(function(){var m=l._renderDetails();l.$details().replaceWith(m);l.expanded=true;m.slideDown(l.fxSpeed,function(){l.trigger("expanded",l)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){var l=this;l.expanded=false;this.$details().slideUp(l.fxSpeed,function(){l.trigger("collapsed",l)})}});var f={initialize:function(l){this.draggable=l.draggable||false},$dragHandle:function(){return this.$(".title-bar")},toggleDraggable:function(){if(this.draggable){this.draggableOff()}else{this.draggableOn()}},draggableOn:function(){this.draggable=true;this.dragStartHandler=_.bind(this._dragStartHandler,this);this.dragEndHandler=_.bind(this._dragEndHandler,this);var l=this.$dragHandle().attr("draggable",true).get(0);l.addEventListener("dragstart",this.dragStartHandler,false);l.addEventListener("dragend",this.dragEndHandler,false)},draggableOff:function(){this.draggable=false;var l=this.$dragHandle().attr("draggable",false).get(0);l.removeEventListener("dragstart",this.dragStartHandler,false);l.removeEventListener("dragend",this.dragEndHandler,false)},_dragStartHandler:function(l){this.trigger("dragstart",this);l.dataTransfer.effectAllowed="move";l.dataTransfer.setData("text",JSON.stringify(this.model.toJSON()));return false},_dragEndHandler:function(l){this.trigger("dragend",this);return false}};var d={initialize:function(l){this.selectable=l.selectable||false;this.selected=l.selected||false},$selector:function(){return this.$(".selector")},_renderSelected:function(){this.$selector().find("span").toggleClass("fa-check-square-o",this.selected).toggleClass("fa-square-o",!this.selected)},toggleSelector:function(){if(!this.$selector().is(":visible")){this.showSelector()}else{this.hideSelector()}},showSelector:function(l){l=l!==undefined?l:this.fxSpeed;this.selectable=true;this.trigger("selectable",true,this);this._renderSelected();this.$selector().show(l)},hideSelector:function(l){l=l!==undefined?l:this.fxSpeed;this.selectable=false;this.trigger("selectable",false,this);this.$selector().hide(l)},toggleSelect:function(l){if(this.selected){this.deselect(l)}else{this.select(l)}},select:function(l){if(!this.selected){this.trigger("selected",this,l);this.selected=true;this._renderSelected()}return false},deselect:function(l){if(this.selected){this.trigger("de-selected",this,l);this.selected=false;this._renderSelected()}return false}};var h=b.extend(k(d,f,{tagName:"div",className:"list-item",initialize:function(l){b.prototype.initialize.call(this,l);d.initialize.call(this,l);f.initialize.call(this,l)},_buildNewRender:function(){var l=b.prototype._buildNewRender.call(this);l.find(".warnings").replaceWith(this._renderWarnings());l.find(".title-bar").replaceWith(this._renderTitleBar());l.find(".primary-actions").append(this._renderPrimaryActions());l.find(".subtitle").replaceWith(this._renderSubtitle());return l},_swapNewRender:function(l){b.prototype._swapNewRender.call(this,l);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var l=this,n=$('<div class="warnings"></div>'),m=l.model.toJSON();_.each(l.templates.warnings,function(o){n.append($(o(m,l)))});return n},_renderTitleBar:function(){return $(this.templates.titleBar(this.model.toJSON(),this))},_renderPrimaryActions:function(){return[]},_renderSubtitle:function(){return $(this.templates.subtitle(this.model.toJSON(),this))},events:{"click .title-bar":"_clickTitleBar","keydown .title-bar":"_keyDownTitleBar","click .selector":"toggleSelect"},_clickTitleBar:function(l){l.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(n){var l=32,m=13;if(n&&(n.type==="keydown")&&(n.keyCode===l||n.keyCode===m)){this.toggleExpanded();n.stopPropagation();return false}return true},toString:function(){var l=(this.model)?(this.model+""):("(no model)");return"ListItemView("+l+")"}}));h.prototype.templates=(function(){var n=e(['<div class="list-element">','<div class="warnings"></div>','<div class="selector">','<span class="fa fa-2x fa-square-o"></span>',"</div>",'<div class="primary-actions"></div>','<div class="title-bar"></div>','<div class="details"></div>',"</div>"]);var l={};var o=e(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");var p=e(['<div class="subtitle"></div>']);var m=e(['<div class="details"></div>']);return{el:n,warnings:l,titleBar:o,subtitle:p,details:m}}());return{LoggableMixin:j,SessionStorageModel:a,SearchableModelMixin:g,HiddenUntilActivatedViewMixin:c,mixin:k,wrapTemplate:e,ExpandableView:b,DraggableViewMixin:f,SelectableViewMixin:d,ListItemView:h}});
\ No newline at end of file
+define(["utils/add-logging","utils/localization"],function(j,b){var k={logger:null,_logNamespace:"?",log:function(){if(this.logger){var m=this.logger.log;if(typeof this.logger.log==="object"){m=Function.prototype.bind.call(this.logger.log,this.logger)}return m.apply(this.logger,arguments)}return undefined}};j(k);var a=Backbone.Model.extend({initialize:function(n){this._checkEnabledSessionStorage();if(!n.id){throw new Error("SessionStorageModel requires an id in the initial attributes")}this.id=n.id;var m=(!this.isNew())?(this._read(this)):({});this.clear({silent:true});this.save(_.extend({},this.defaults,m,n),{silent:true});this.on("change",function(){this.save()})},_checkEnabledSessionStorage:function(){try{return sessionStorage.length}catch(m){alert("Please enable cookies in your browser for this Galaxy site");return false}},sync:function(p,n,m){if(!m.silent){n.trigger("request",n,{},m)}var o;switch(p){case"create":o=this._create(n);break;case"read":o=this._read(n);break;case"update":o=this._update(n);break;case"delete":o=this._delete(n);break}if(o!==undefined||o!==null){if(m.success){m.success()}}else{if(m.error){m.error()}}return o},_create:function(m){var n=m.toJSON(),o=sessionStorage.setItem(m.id,JSON.stringify(n));return(o===null)?(o):(n)},_read:function(m){return JSON.parse(sessionStorage.getItem(m.id))},_update:function(m){return m._create(m)},_delete:function(m){return sessionStorage.removeItem(m.id)},isNew:function(){return !sessionStorage.hasOwnProperty(this.id)},_log:function(){return JSON.stringify(this.toJSON(),null," ")},toString:function(){return"SessionStorageModel("+this.id+")"}});(function(){a.prototype=_.omit(a.prototype,"url","urlRoot")}());var h={searchAttributes:[],searchAliases:{},searchAttribute:function(o,m){var n=this.get(o);if(!m||(n===undefined||n===null)){return false}if(_.isArray(n)){return this._searchArrayAttribute(n,m)}return(n.toString().toLowerCase().indexOf(m.toLowerCase())!==-1)},_searchArrayAttribute:function(n,m){m=m.toLowerCase();return _.any(n,function(o){return(o.toString().toLowerCase().indexOf(m.toLowerCase())!==-1)})},search:function(m){var n=this;return _.filter(this.searchAttributes,function(o){return n.searchAttribute(o,m)})},matches:function(n){var p="=",m=n.split(p);if(m.length>=2){var o=m[0];o=this.searchAliases[o]||o;return this.searchAttribute(o,m[1])}return !!this.search(n).length},matchesAll:function(n){var m=this;n=n.match(/(".*"|\w*=".*"|\S*)/g).filter(function(o){return !!o});return _.all(n,function(o){o=o.replace(/"/g,"");return m.matches(o)})}};var d={hiddenUntilActivated:function(m,o){o=o||{};this.HUAVOptions={$elementShown:this.$el,showFn:jQuery.prototype.toggle,showSpeed:"fast"};_.extend(this.HUAVOptions,o||{});this.HUAVOptions.hasBeenShown=this.HUAVOptions.$elementShown.is(":visible");this.hidden=this.isHidden();if(m){var n=this;m.on("click",function(p){n.toggle(n.HUAVOptions.showSpeed)})}},isHidden:function(){return(this.HUAVOptions.$elementShown.is(":hidden"))},toggle:function(){if(this.hidden){if(!this.HUAVOptions.hasBeenShown){if(_.isFunction(this.HUAVOptions.onshowFirstTime)){this.HUAVOptions.hasBeenShown=true;this.HUAVOptions.onshowFirstTime.call(this)}}if(_.isFunction(this.HUAVOptions.onshow)){this.HUAVOptions.onshow.call(this);this.trigger("hiddenUntilActivated:shown",this)}this.hidden=false}else{if(_.isFunction(this.HUAVOptions.onhide)){this.HUAVOptions.onhide.call(this);this.trigger("hiddenUntilActivated:hidden",this)}this.hidden=true}return this.HUAVOptions.showFn.apply(this.HUAVOptions.$elementShown,arguments)}};function l(p,o){var m=Array.prototype.slice.call(arguments,0),n=m.pop();m.unshift(n);return _.defaults.apply(_,m)}function f(n,m){m=m||"model";var o=_.template(n.join(""));return function(q,p){var r={view:p||{},_l:b};r[m]=q||{};return o(r)}}var c=Backbone.View.extend(k).extend({initialize:function(m){this.expanded=m.expanded||false;this.fxSpeed=m.fxSpeed||this.fxSpeed},fxSpeed:"fast",render:function(n){var m=this._buildNewRender();this._setUpBehaviors(m);this._queueNewRender(m,n);return this},_buildNewRender:function(){var m=$(this.templates.el(this.model.toJSON(),this));if(this.expanded){this.$details(m).replaceWith(this._renderDetails().show())}return m},_queueNewRender:function(n,o){o=(o===undefined)?(this.fxSpeed):(o);var m=this;$(m).queue("fx",[function(p){this.$el.fadeOut(o,p)},function(p){m._swapNewRender(n);p()},function(p){this.$el.fadeIn(o,p)},function(p){this.trigger("rendered",m);p()}])},_swapNewRender:function(m){return this.$el.empty().attr("class",this.className).append(m.children())},_setUpBehaviors:function(m){m=m||this.$el;m.find("[title]").tooltip({placement:"bottom"})},$details:function(m){m=m||this.$el;return m.find(".details")},_renderDetails:function(){var m=$(this.templates.details(this.model.toJSON(),this));this._setUpBehaviors(m);return m},toggleExpanded:function(m){m=(m===undefined)?(!this.expanded):(m);if(m){this.expand()}else{this.collapse()}return this},expand:function(){var m=this;return m._fetchModelDetails().always(function(){var n=m._renderDetails();m.$details().replaceWith(n);m.expanded=true;n.slideDown(m.fxSpeed,function(){m.trigger("expanded",m)})})},_fetchModelDetails:function(){if(!this.model.hasDetails()){return this.model.fetch()}return jQuery.when()},collapse:function(){var m=this;m.expanded=false;this.$details().slideUp(m.fxSpeed,function(){m.trigger("collapsed",m)})}});var g={initialize:function(m){this.draggable=m.draggable||false},$dragHandle:function(){return this.$(".title-bar")},toggleDraggable:function(){if(this.draggable){this.draggableOff()}else{this.draggableOn()}},draggableOn:function(){this.draggable=true;this.dragStartHandler=_.bind(this._dragStartHandler,this);this.dragEndHandler=_.bind(this._dragEndHandler,this);var m=this.$dragHandle().attr("draggable",true).get(0);m.addEventListener("dragstart",this.dragStartHandler,false);m.addEventListener("dragend",this.dragEndHandler,false)},draggableOff:function(){this.draggable=false;var m=this.$dragHandle().attr("draggable",false).get(0);m.removeEventListener("dragstart",this.dragStartHandler,false);m.removeEventListener("dragend",this.dragEndHandler,false)},_dragStartHandler:function(m){this.trigger("dragstart",this);m.dataTransfer.effectAllowed="move";m.dataTransfer.setData("text",JSON.stringify(this.model.toJSON()));return false},_dragEndHandler:function(m){this.trigger("dragend",this);return false}};var e={initialize:function(m){this.selectable=m.selectable||false;this.selected=m.selected||false},$selector:function(){return this.$(".selector")},_renderSelected:function(){this.$selector().find("span").toggleClass("fa-check-square-o",this.selected).toggleClass("fa-square-o",!this.selected)},toggleSelector:function(){if(!this.$selector().is(":visible")){this.showSelector()}else{this.hideSelector()}},showSelector:function(m){m=m!==undefined?m:this.fxSpeed;this.selectable=true;this.trigger("selectable",true,this);this._renderSelected();this.$selector().show(m)},hideSelector:function(m){m=m!==undefined?m:this.fxSpeed;this.selectable=false;this.trigger("selectable",false,this);this.$selector().hide(m)},toggleSelect:function(m){if(this.selected){this.deselect(m)}else{this.select(m)}},select:function(m){if(!this.selected){this.trigger("selected",this,m);this.selected=true;this._renderSelected()}return false},deselect:function(m){if(this.selected){this.trigger("de-selected",this,m);this.selected=false;this._renderSelected()}return false}};var i=c.extend(l(e,g,{tagName:"div",className:"list-item",initialize:function(m){c.prototype.initialize.call(this,m);e.initialize.call(this,m);g.initialize.call(this,m)},_buildNewRender:function(){var m=c.prototype._buildNewRender.call(this);m.find(".warnings").replaceWith(this._renderWarnings());m.find(".title-bar").replaceWith(this._renderTitleBar());m.find(".primary-actions").append(this._renderPrimaryActions());m.find(".subtitle").replaceWith(this._renderSubtitle());return m},_swapNewRender:function(m){c.prototype._swapNewRender.call(this,m);if(this.selectable){this.showSelector(0)}if(this.draggable){this.draggableOn()}return this.$el},_renderWarnings:function(){var m=this,o=$('<div class="warnings"></div>'),n=m.model.toJSON();_.each(m.templates.warnings,function(p){o.append($(p(n,m)))});return o},_renderTitleBar:function(){return $(this.templates.titleBar(this.model.toJSON(),this))},_renderPrimaryActions:function(){return[]},_renderSubtitle:function(){return $(this.templates.subtitle(this.model.toJSON(),this))},events:{"click .title-bar":"_clickTitleBar","keydown .title-bar":"_keyDownTitleBar","click .selector":"toggleSelect"},_clickTitleBar:function(m){m.stopPropagation();this.toggleExpanded()},_keyDownTitleBar:function(o){var m=32,n=13;if(o&&(o.type==="keydown")&&(o.keyCode===m||o.keyCode===n)){this.toggleExpanded();o.stopPropagation();return false}return true},toString:function(){var m=(this.model)?(this.model+""):("(no model)");return"ListItemView("+m+")"}}));i.prototype.templates=(function(){var o=f(['<div class="list-element">','<div class="warnings"></div>','<div class="selector">','<span class="fa fa-2x fa-square-o"></span>',"</div>",'<div class="primary-actions"></div>','<div class="title-bar"></div>','<div class="details"></div>',"</div>"]);var m={};var p=f(['<div class="title-bar clear" tabindex="0">','<span class="state-icon"></span>','<div class="title">','<span class="name"><%- element.name %></span>',"</div>",'<div class="subtitle"></div>',"</div>"],"element");var q=f(['<div class="subtitle"></div>']);var n=f(['<div class="details"></div>']);return{el:o,warnings:m,titleBar:p,subtitle:q,details:n}}());return{LoggableMixin:k,SessionStorageModel:a,SearchableModelMixin:h,HiddenUntilActivatedViewMixin:d,mixin:l,wrapTemplate:f,ExpandableView:c,DraggableViewMixin:g,SelectableViewMixin:e,ListItemView:i}});
\ No newline at end of file
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/packed/mvc/dataset/dataset-li.js
--- a/static/scripts/packed/mvc/dataset/dataset-li.js
+++ b/static/scripts/packed/mvc/dataset/dataset-li.js
@@ -1,1 +1,1 @@
-define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,c){var e=b.ListItemView;var d=e.extend({className:e.prototype.className+" dataset",id:function(){return["dataset",this.model.get("id")].join("-")},initialize:function(f){if(f.logger){this.logger=this.model.logger=f.logger}this.log(this+".initialize:",f);e.prototype.initialize.call(this,f);this.linkTarget=f.linkTarget||"_blank";this._setUpListeners()},_setUpListeners:function(){this.on("selectable",function(f){if(f){this.$(".primary-actions").hide()}else{this.$(".primary-actions").show()}});this.model.on("change",function(g,f){if(this.model.changedAttributes().state&&this.model.inReadyState()&&this.expanded&&!this.model.hasDetails()){this.model.fetch()}else{this.render()}},this);this.on("all",function(f){this.log(f)},this)},_fetchModelDetails:function(){var f=this;if(f.model.inReadyState()&&!f.model.hasDetails()){return f.model.fetch({silent:true})}return jQuery.when()},remove:function(g,h){var f=this;g=g||this.fxSpeed;this.$el.fadeOut(g,function(){Backbone.View.prototype.remove.call(f);if(h){h.call(f)}})},render:function(f){return e.prototype.render.call(this,f)},_swapNewRender:function(f){e.prototype._swapNewRender.call(this,f);if(this.model.has("state")){this.$el.addClass("state-"+this.model.get("state"))}return this.$el},_renderPrimaryActions:function(){return[this._renderDisplayButton()]},_renderDisplayButton:function(){var h=this.model.get("state");if((h===a.NOT_VIEWABLE)||(h===a.DISCARDED)||(!this.model.get("accessible"))){return null}var g={target:this.linkTarget,classes:"display-btn"};if(this.model.get("purged")){g.disabled=true;g.title=c("Cannot display datasets removed from disk")}else{if(h===a.UPLOAD){g.disabled=true;g.title=c("This dataset must finish uploading before it can be viewed")}else{if(h===a.NEW){g.disabled=true;g.title=c("This dataset is not yet viewable")}else{g.title=c("View data");g.href=this.model.urls.display;var f=this;g.onclick=function(i){if(Galaxy.frame&&Galaxy.frame.active){Galaxy.frame.add({title:"Data Viewer: "+f.model.get("name"),type:"other",content:function(j){require(["mvc/data"],function(k){var l=new k.TabularDataset({id:f.model.get("id")});$.when(l.fetch()).then(function(){k.createTabularDatasetChunkedView({model:l,parent_elt:j,embedded:true,height:"100%"})})})}});i.preventDefault()}}}}}g.faIcon="fa-eye";return faIconButton(g)},_renderDetails:function(){if(this.model.get("state")===a.NOT_VIEWABLE){return $(this.templates.noAccess(this.model.toJSON(),this))}var f=e.prototype._renderDetails.call(this);f.find(".actions .left").empty().append(this._renderSecondaryActions());f.find(".summary").html(this._renderSummary()).prepend(this._renderDetailMessages());f.find(".display-applications").html(this._renderDisplayApplications());this._setUpBehaviors(f);return f},_renderSummary:function(){var f=this.model.toJSON(),g=this.templates.summaries[f.state];g=g||this.templates.summaries.unknown;return g(f,this)},_renderDetailMessages:function(){var f=this,h=$('<div class="detail-messages"></div>'),g=f.model.toJSON();_.each(f.templates.detailMessages,function(i){h.append($(i(g,f)))});return h},_renderDisplayApplications:function(){if(this.model.isDeletedOrPurged()){return""}return[this.templates.displayApplications(this.model.get("display_apps"),this),this.templates.displayApplications(this.model.get("display_types"),this)].join("")},_renderSecondaryActions:function(){this.debug("_renderSecondaryActions");switch(this.model.get("state")){case a.NOT_VIEWABLE:return[];case a.OK:case a.FAILED_METADATA:case a.ERROR:return[this._renderDownloadButton(),this._renderShowParamsButton()]}return[this._renderShowParamsButton()]},_renderShowParamsButton:function(){return faIconButton({title:c("View details"),classes:"params-btn",href:this.model.urls.show_params,target:this.linkTarget,faIcon:"fa-info-circle"})},_renderDownloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}if(!_.isEmpty(this.model.get("meta_files"))){return this._renderMetaFileDownloadButton()}return $(['<a class="download-btn icon-btn" href="',this.model.urls.download,'" title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>"].join(""))},_renderMetaFileDownloadButton:function(){var f=this.model.urls;return $(['<div class="metafile-dropdown dropdown">','<a class="download-btn icon-btn" href="javascript:void(0)" data-toggle="dropdown"',' title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>",'<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">','<li><a href="'+f.download+'">',c("Download dataset"),"</a></li>",_.map(this.model.get("meta_files"),function(g){return['<li><a href="',f.meta_download+g.file_type,'">',c("Download")," ",g.file_type,"</a></li>"].join("")}).join("\n"),"</ul>","</div>"].join("\n"))},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"DatasetListItemView("+f+")"}});d.prototype.templates=(function(){var h=_.extend({},e.prototype.templates.warnings,{failed_metadata:b.wrapTemplate(['<% if( model.state === "failed_metadata" ){ %>','<div class="warningmessagesmall">',c("An error occurred setting the metadata for this dataset"),"</div>","<% } %>"]),error:b.wrapTemplate(["<% if( model.error ){ %>",'<div class="errormessagesmall">',c("There was an error getting the data for this dataset"),": <%- model.error %>","</div>","<% } %>"]),purged:b.wrapTemplate(["<% if( model.purged ){ %>",'<div class="purged-msg warningmessagesmall">',c("This dataset has been deleted and removed from disk"),"</div>","<% } %>"]),deleted:b.wrapTemplate(["<% if( model.deleted && !model.purged ){ %>",'<div class="deleted-msg warningmessagesmall">',c("This dataset has been deleted"),"</div>","<% } %>"])});var i=b.wrapTemplate(['<div class="details">','<div class="summary"></div>','<div class="actions clear">','<div class="left"></div>','<div class="right"></div>',"</div>","<% if( !dataset.deleted && !dataset.purged ){ %>",'<div class="tags-display"></div>','<div class="annotation-display"></div>','<div class="display-applications"></div>',"<% if( dataset.peek ){ %>",'<pre class="dataset-peek"><%= dataset.peek %></pre>',"<% } %>","<% } %>","</div>"],"dataset");var g=b.wrapTemplate(['<div class="details">','<div class="summary">',c("You do not have permission to view this dataset"),"</div>","</div>"],"dataset");var j={};j[a.OK]=j[a.FAILED_METADATA]=b.wrapTemplate(["<% if( dataset.misc_blurb ){ %>",'<div class="blurb">','<span class="value"><%- dataset.misc_blurb %></span>',"</div>","<% } %>","<% if( dataset.data_type ){ %>",'<div class="datatype">','<label class="prompt">',c("format"),"</label>",'<span class="value"><%- dataset.data_type %></span>',"</div>","<% } %>","<% if( dataset.metadata_dbkey ){ %>",'<div class="dbkey">','<label class="prompt">',c("database"),"</label>",'<span class="value">',"<%- dataset.metadata_dbkey %>","</span>","</div>","<% } %>","<% if( dataset.misc_info ){ %>",'<div class="info">','<span class="value"><%- dataset.misc_info %></span>',"</div>","<% } %>"],"dataset");j[a.NEW]=b.wrapTemplate(["<div>",c("This is a new dataset and not all of its data are available yet"),"</div>"],"dataset");j[a.NOT_VIEWABLE]=b.wrapTemplate(["<div>",c("You do not have permission to view this dataset"),"</div>"],"dataset");j[a.DISCARDED]=b.wrapTemplate(["<div>",c("The job creating this dataset was cancelled before completion"),"</div>"],"dataset");j[a.QUEUED]=b.wrapTemplate(["<div>",c("This job is waiting to run"),"</div>"],"dataset");j[a.RUNNING]=b.wrapTemplate(["<div>",c("This job is currently running"),"</div>"],"dataset");j[a.UPLOAD]=b.wrapTemplate(["<div>",c("This dataset is currently uploading"),"</div>"],"dataset");j[a.SETTING_METADATA]=b.wrapTemplate(["<div>",c("Metadata is being auto-detected"),"</div>"],"dataset");j[a.PAUSED]=b.wrapTemplate(["<div>",c('This job is paused. Use the "Resume Paused Jobs" in the history menu to resume'),"</div>"],"dataset");j[a.ERROR]=b.wrapTemplate(["<% if( !dataset.purged ){ %>","<div><%- dataset.misc_blurb %></div>","<% } %>",'<span class="help-text">',c("An error occurred with this dataset"),":</span>",'<div class="job-error-text"><%- dataset.misc_info %></div>'],"dataset");j[a.EMPTY]=b.wrapTemplate(["<div>",c("No data"),": <i><%- dataset.misc_blurb %></i></div>"],"dataset");j.unknown=b.wrapTemplate(['<div>Error: unknown dataset state: "<%- dataset.state %>"</div>'],"dataset");var k={resubmitted:b.wrapTemplate(["<% if( model.resubmitted ){ %>",'<div class="resubmitted-msg infomessagesmall">',c("The job creating this dataset has been resubmitted"),"</div>","<% } %>"])};var f=b.wrapTemplate(["<% _.each( apps, function( app ){ %>",'<div class="display-application">','<span class="display-application-location"><%- app.label %></span> ','<span class="display-application-links">',"<% _.each( app.links, function( link ){ %>",'<a target="<%= link.target %>" href="<%= link.href %>">',"<% print( _l( link.text ) ); %>","</a> ","<% }); %>","</span>","</div>","<% }); %>"],"apps");return _.extend({},e.prototype.templates,{warnings:h,details:i,noAccess:g,summaries:j,detailMessages:k,displayApplications:f})}());return{DatasetListItemView:d}});
\ No newline at end of file
+define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,c){var e=b.ListItemView;var d=e.extend({className:e.prototype.className+" dataset",id:function(){return["dataset",this.model.get("id")].join("-")},initialize:function(f){if(f.logger){this.logger=this.model.logger=f.logger}this.log(this+".initialize:",f);e.prototype.initialize.call(this,f);this.linkTarget=f.linkTarget||"_blank";this._setUpListeners()},_setUpListeners:function(){this.on("selectable",function(f){if(f){this.$(".primary-actions").hide()}else{this.$(".primary-actions").show()}},this);this.model.on("change",function(g,f){if(this.model.changedAttributes().state&&this.model.inReadyState()&&this.expanded&&!this.model.hasDetails()){this.model.fetch()}else{this.render()}},this);this.on("all",function(f){this.log(f)},this)},_fetchModelDetails:function(){var f=this;if(f.model.inReadyState()&&!f.model.hasDetails()){return f.model.fetch({silent:true})}return jQuery.when()},remove:function(g,h){var f=this;g=g||this.fxSpeed;this.$el.fadeOut(g,function(){Backbone.View.prototype.remove.call(f);if(h){h.call(f)}})},render:function(f){return e.prototype.render.call(this,f)},_swapNewRender:function(f){e.prototype._swapNewRender.call(this,f);if(this.model.has("state")){this.$el.addClass("state-"+this.model.get("state"))}return this.$el},_renderPrimaryActions:function(){return[this._renderDisplayButton()]},_renderDisplayButton:function(){var h=this.model.get("state");if((h===a.NOT_VIEWABLE)||(h===a.DISCARDED)||(!this.model.get("accessible"))){return null}var g={target:this.linkTarget,classes:"display-btn"};if(this.model.get("purged")){g.disabled=true;g.title=c("Cannot display datasets removed from disk")}else{if(h===a.UPLOAD){g.disabled=true;g.title=c("This dataset must finish uploading before it can be viewed")}else{if(h===a.NEW){g.disabled=true;g.title=c("This dataset is not yet viewable")}else{g.title=c("View data");g.href=this.model.urls.display;var f=this;g.onclick=function(i){if(Galaxy.frame&&Galaxy.frame.active){Galaxy.frame.add({title:"Data Viewer: "+f.model.get("name"),type:"other",content:function(j){require(["mvc/data"],function(k){var l=new k.TabularDataset({id:f.model.get("id")});$.when(l.fetch()).then(function(){k.createTabularDatasetChunkedView({model:l,parent_elt:j,embedded:true,height:"100%"})})})}});i.preventDefault()}}}}}g.faIcon="fa-eye";return faIconButton(g)},_renderDetails:function(){if(this.model.get("state")===a.NOT_VIEWABLE){return $(this.templates.noAccess(this.model.toJSON(),this))}var f=e.prototype._renderDetails.call(this);f.find(".actions .left").empty().append(this._renderSecondaryActions());f.find(".summary").html(this._renderSummary()).prepend(this._renderDetailMessages());f.find(".display-applications").html(this._renderDisplayApplications());this._setUpBehaviors(f);return f},_renderSummary:function(){var f=this.model.toJSON(),g=this.templates.summaries[f.state];g=g||this.templates.summaries.unknown;return g(f,this)},_renderDetailMessages:function(){var f=this,h=$('<div class="detail-messages"></div>'),g=f.model.toJSON();_.each(f.templates.detailMessages,function(i){h.append($(i(g,f)))});return h},_renderDisplayApplications:function(){if(this.model.isDeletedOrPurged()){return""}return[this.templates.displayApplications(this.model.get("display_apps"),this),this.templates.displayApplications(this.model.get("display_types"),this)].join("")},_renderSecondaryActions:function(){this.debug("_renderSecondaryActions");switch(this.model.get("state")){case a.NOT_VIEWABLE:return[];case a.OK:case a.FAILED_METADATA:case a.ERROR:return[this._renderDownloadButton(),this._renderShowParamsButton()]}return[this._renderShowParamsButton()]},_renderShowParamsButton:function(){return faIconButton({title:c("View details"),classes:"params-btn",href:this.model.urls.show_params,target:this.linkTarget,faIcon:"fa-info-circle"})},_renderDownloadButton:function(){if(this.model.get("purged")||!this.model.hasData()){return null}if(!_.isEmpty(this.model.get("meta_files"))){return this._renderMetaFileDownloadButton()}return $(['<a class="download-btn icon-btn" href="',this.model.urls.download,'" title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>"].join(""))},_renderMetaFileDownloadButton:function(){var f=this.model.urls;return $(['<div class="metafile-dropdown dropdown">','<a class="download-btn icon-btn" href="javascript:void(0)" data-toggle="dropdown"',' title="'+c("Download")+'">','<span class="fa fa-floppy-o"></span>',"</a>",'<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">','<li><a href="'+f.download+'">',c("Download dataset"),"</a></li>",_.map(this.model.get("meta_files"),function(g){return['<li><a href="',f.meta_download+g.file_type,'">',c("Download")," ",g.file_type,"</a></li>"].join("")}).join("\n"),"</ul>","</div>"].join("\n"))},toString:function(){var f=(this.model)?(this.model+""):("(no model)");return"DatasetListItemView("+f+")"}});d.prototype.templates=(function(){var h=_.extend({},e.prototype.templates.warnings,{failed_metadata:b.wrapTemplate(['<% if( model.state === "failed_metadata" ){ %>','<div class="warningmessagesmall">',c("An error occurred setting the metadata for this dataset"),"</div>","<% } %>"]),error:b.wrapTemplate(["<% if( model.error ){ %>",'<div class="errormessagesmall">',c("There was an error getting the data for this dataset"),": <%- model.error %>","</div>","<% } %>"]),purged:b.wrapTemplate(["<% if( model.purged ){ %>",'<div class="purged-msg warningmessagesmall">',c("This dataset has been deleted and removed from disk"),"</div>","<% } %>"]),deleted:b.wrapTemplate(["<% if( model.deleted && !model.purged ){ %>",'<div class="deleted-msg warningmessagesmall">',c("This dataset has been deleted"),"</div>","<% } %>"])});var i=b.wrapTemplate(['<div class="details">','<div class="summary"></div>','<div class="actions clear">','<div class="left"></div>','<div class="right"></div>',"</div>","<% if( !dataset.deleted && !dataset.purged ){ %>",'<div class="tags-display"></div>','<div class="annotation-display"></div>','<div class="display-applications"></div>',"<% if( dataset.peek ){ %>",'<pre class="dataset-peek"><%= dataset.peek %></pre>',"<% } %>","<% } %>","</div>"],"dataset");var g=b.wrapTemplate(['<div class="details">','<div class="summary">',c("You do not have permission to view this dataset"),"</div>","</div>"],"dataset");var j={};j[a.OK]=j[a.FAILED_METADATA]=b.wrapTemplate(["<% if( dataset.misc_blurb ){ %>",'<div class="blurb">','<span class="value"><%- dataset.misc_blurb %></span>',"</div>","<% } %>","<% if( dataset.data_type ){ %>",'<div class="datatype">','<label class="prompt">',c("format"),"</label>",'<span class="value"><%- dataset.data_type %></span>',"</div>","<% } %>","<% if( dataset.metadata_dbkey ){ %>",'<div class="dbkey">','<label class="prompt">',c("database"),"</label>",'<span class="value">',"<%- dataset.metadata_dbkey %>","</span>","</div>","<% } %>","<% if( dataset.misc_info ){ %>",'<div class="info">','<span class="value"><%- dataset.misc_info %></span>',"</div>","<% } %>"],"dataset");j[a.NEW]=b.wrapTemplate(["<div>",c("This is a new dataset and not all of its data are available yet"),"</div>"],"dataset");j[a.NOT_VIEWABLE]=b.wrapTemplate(["<div>",c("You do not have permission to view this dataset"),"</div>"],"dataset");j[a.DISCARDED]=b.wrapTemplate(["<div>",c("The job creating this dataset was cancelled before completion"),"</div>"],"dataset");j[a.QUEUED]=b.wrapTemplate(["<div>",c("This job is waiting to run"),"</div>"],"dataset");j[a.RUNNING]=b.wrapTemplate(["<div>",c("This job is currently running"),"</div>"],"dataset");j[a.UPLOAD]=b.wrapTemplate(["<div>",c("This dataset is currently uploading"),"</div>"],"dataset");j[a.SETTING_METADATA]=b.wrapTemplate(["<div>",c("Metadata is being auto-detected"),"</div>"],"dataset");j[a.PAUSED]=b.wrapTemplate(["<div>",c('This job is paused. Use the "Resume Paused Jobs" in the history menu to resume'),"</div>"],"dataset");j[a.ERROR]=b.wrapTemplate(["<% if( !dataset.purged ){ %>","<div><%- dataset.misc_blurb %></div>","<% } %>",'<span class="help-text">',c("An error occurred with this dataset"),":</span>",'<div class="job-error-text"><%- dataset.misc_info %></div>'],"dataset");j[a.EMPTY]=b.wrapTemplate(["<div>",c("No data"),": <i><%- dataset.misc_blurb %></i></div>"],"dataset");j.unknown=b.wrapTemplate(['<div>Error: unknown dataset state: "<%- dataset.state %>"</div>'],"dataset");var k={resubmitted:b.wrapTemplate(["<% if( model.resubmitted ){ %>",'<div class="resubmitted-msg infomessagesmall">',c("The job creating this dataset has been resubmitted"),"</div>","<% } %>"])};var f=b.wrapTemplate(["<% _.each( apps, function( app ){ %>",'<div class="display-application">','<span class="display-application-location"><%- app.label %></span> ','<span class="display-application-links">',"<% _.each( app.links, function( link ){ %>",'<a target="<%= link.target %>" href="<%= link.href %>">',"<% print( _l( link.text ) ); %>","</a> ","<% }); %>","</span>","</div>","<% }); %>"],"apps");return _.extend({},e.prototype.templates,{warnings:h,details:i,noAccess:g,summaries:j,detailMessages:k,displayApplications:f})}());return{DatasetListItemView:d}});
\ No newline at end of file
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/packed/mvc/dataset/dataset-model.js
--- a/static/scripts/packed/mvc/dataset/dataset-model.js
+++ b/static/scripts/packed/mvc/dataset/dataset-model.js
@@ -1,1 +1,1 @@
-define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,c){var f=b.SearchableModelMixin;var e=Backbone.Model.extend(b.LoggableMixin).extend(b.mixin(f,{defaults:{state:a.NEW,deleted:false,purged:false,name:"(unnamed dataset)",accessible:true,data_type:"",file_ext:"",file_size:0,meta_files:[],misc_blurb:"",misc_info:"",tags:[]},initialize:function(g,h){this.debug(this+"(Dataset).initialize",g,h);if(!this.get("accessible")){this.set("state",a.NOT_VIEWABLE)}this.urls=this._generateUrls();this._setUpListeners()},_generateUrls:function(){var i=this.get("id");if(!i){return{}}var h={purge:"datasets/"+i+"/purge_async",display:"datasets/"+i+"/display/?preview=True",edit:"datasets/"+i+"/edit",download:"datasets/"+i+"/display?to_ext="+this.get("file_ext"),report_error:"dataset/errors?id="+i,rerun:"tool_runner/rerun?id="+i,show_params:"datasets/"+i+"/show_params",visualization:"visualization",meta_download:"dataset/get_metadata_file?hda_id="+i+"&metadata_name="};var g=(galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/");_.each(h,function(k,j){h[j]=g+k});this.urls=h;return h},_setUpListeners:function(){this.on("change:state",function(h,g){this.log(this+" has changed state:",h,g);if(this.inReadyState()){this.trigger("state:ready",h,g,this.previous("state"))}});this.on("change:id change:file_ext",function(g){this._generateUrls()})},toJSON:function(){var g=Backbone.Model.prototype.toJSON.call(this);return _.extend(g,{urls:this.urls})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},inReadyState:function(){var g=_.contains(a.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||g)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function(g){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},g)},undelete:function(g){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},g)},purge:function d(g){if(this.get("purged")){return jQuery.when()}g=g||{};g.url=this.urls.purge;var h=this,i=jQuery.ajax(g);i.done(function(l,j,k){h.set({deleted:true,purged:true})});i.fail(function(n,j,m){var k=c("Unable to purge dataset");var l=("Removal of datasets by users is not allowed in this Galaxy instance");if(n.responseJSON&&n.responseJSON.error){k=n.responseJSON.error}else{if(n.responseText.indexOf(l)!==-1){k=l}}n.responseText=k;h.trigger("error",h,n,g,c(k),{error:k})});return i},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},toString:function(){var g=this.get("id")||"";if(this.get("name")){g='"'+this.get("name")+'",'+g}return"Dataset("+g+")"}}));return{DatasetAssociation:e}});
\ No newline at end of file
+define(["mvc/dataset/states","mvc/base-mvc","utils/localization"],function(a,b,d){var g=b.SearchableModelMixin;var f=Backbone.Model.extend(b.LoggableMixin).extend(b.mixin(g,{defaults:{state:a.NEW,deleted:false,purged:false,name:"(unnamed dataset)",accessible:true,data_type:"",file_ext:"",file_size:0,meta_files:[],misc_blurb:"",misc_info:"",tags:[]},initialize:function(h,i){this.debug(this+"(Dataset).initialize",h,i);if(!this.get("accessible")){this.set("state",a.NOT_VIEWABLE)}this.urls=this._generateUrls();this._setUpListeners()},_generateUrls:function(){var j=this.get("id");if(!j){return{}}var i={purge:"datasets/"+j+"/purge_async",display:"datasets/"+j+"/display/?preview=True",edit:"datasets/"+j+"/edit",download:"datasets/"+j+"/display?to_ext="+this.get("file_ext"),report_error:"dataset/errors?id="+j,rerun:"tool_runner/rerun?id="+j,show_params:"datasets/"+j+"/show_params",visualization:"visualization",meta_download:"dataset/get_metadata_file?hda_id="+j+"&metadata_name="};var h=(window.galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/");_.each(i,function(l,k){i[k]=h+l});this.urls=i;return i},_setUpListeners:function(){this.on("change:state",function(i,h){this.log(this+" has changed state:",i,h);if(this.inReadyState()){this.trigger("state:ready",i,h,this.previous("state"))}});this.on("change:id change:file_ext",function(h){this._generateUrls()})},toJSON:function(){var h=Backbone.Model.prototype.toJSON.call(this);return _.extend(h,{urls:this.urls})},isDeletedOrPurged:function(){return(this.get("deleted")||this.get("purged"))},inReadyState:function(){var h=_.contains(a.READY_STATES,this.get("state"));return(this.isDeletedOrPurged()||h)},hasDetails:function(){return _.has(this.attributes,"genome_build")},hasData:function(){return(this.get("file_size")>0)},"delete":function(h){if(this.get("deleted")){return jQuery.when()}return this.save({deleted:true},h)},undelete:function(h){if(!this.get("deleted")||this.get("purged")){return jQuery.when()}return this.save({deleted:false},h)},purge:function e(h){if(this.get("purged")){return jQuery.when()}h=h||{};h.url=this.urls.purge;var i=this,j=jQuery.ajax(h);j.done(function(m,k,l){i.set({deleted:true,purged:true})});j.fail(function(o,k,n){var l=d("Unable to purge dataset");var m=("Removal of datasets by users is not allowed in this Galaxy instance");if(o.responseJSON&&o.responseJSON.error){l=o.responseJSON.error}else{if(o.responseText.indexOf(m)!==-1){l=m}}o.responseText=l;i.trigger("error",i,o,h,d(l),{error:l})});return j},searchAttributes:["name","file_ext","genome_build","misc_blurb","misc_info","annotation","tags"],searchAliases:{title:"name",format:"file_ext",database:"genome_build",blurb:"misc_blurb",description:"misc_blurb",info:"misc_info",tag:"tags"},toString:function(){var h=this.get("id")||"";if(this.get("name")){h='"'+this.get("name")+'",'+h}return"Dataset("+h+")"}}));var c=Backbone.Collection.extend(b.LoggableMixin).extend({model:f,urlRoot:((window.galaxy_config&&galaxy_config.root)?(galaxy_config.root):("/"))+"api/datasets",ids:function(){return this.map(function(h){return h.get("id")})},notReady:function(){return this.filter(function(h){return !h.inReadyState()})},haveDetails:function(){return this.all(function(h){return h.hasDetails()})},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(l){if(!i.get(l.id)){return l}var k=existing.toJSON();_.extend(k,l);return k});Backbone.Collection.prototype.set.call(this,j,h)},toString:function(){return(["DatasetAssociationCollection(",this.length,")"].join(""))}});return{DatasetAssociation:f,DatasetAssociationCollection:c}});
\ No newline at end of file
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/scripts/packed/mvc/ui.js
--- a/static/scripts/packed/mvc/ui.js
+++ b/static/scripts/packed/mvc/ui.js
@@ -1,1 +1,1 @@
-var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,is_menu_button:true,id:null,href:null,target:null,enabled:true,visible:true,tooltip_config:{}}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=this.template(this.model.toJSON());a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(_.isFunction(this.model.get("on_click"))){this.model.get("on_click")(a);return false}return true},template:function(b){var a='title="'+b.title+'" class="icon-button';if(b.is_menu_button){a+=" menu-button"}a+=" "+b.icon_class;if(!b.enabled){a+="_disabled"}a+='"';if(b.id){a+=' id="'+b.id+'"'}a+=' href="'+b.href+'"';if(b.target){a+=' target="'+b.target+'"'}if(!b.visible){a+=' style="display: none;"'}if(b.enabled){a="<a "+a+"/>"}else{a="<span "+a+"/>"}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("<a/>").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b;if(!this.$button.size()){this.$button=$("<div/>")}this.options=a||[];var c=this;this.$button.click(function(d){$(".popmenu-wrapper").remove();c._renderAndShow(d);return false})},_renderAndShow:function(a){this.render();this.$el.appendTo("body").css(this._getShownPosition(a)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var a=this;this.$el.find("li").each(function(c,b){var d=a.options[c];if(d.func){$(this).children("a.popupmenu-option").click(function(e){d.func.call(a,e,d)})}})}return this},template:function(b,a){return['<ul id="',b,'-menu" class="dropdown-menu">',this._templateOptions(a),"</ul>"].join("")},_templateOptions:function(a){if(!a.length){return"<li>(no options)</li>"}return _.map(a,function(d){if(d.divider){return'<li class="divider"></li>'}else{if(d.header){return['<li class="head"><a href="javascript:void(0);">',d.html,"</a></li>"].join("")}}var c=d.href||"javascript:void(0);",e=(d.target)?(' target="'+d.target+'"'):(""),b=(d.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',c,'"',e,">",b,d.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(b){var c=this.$el.width();var a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_setUpCloseBehavior:function(){var c=this;function a(e){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(d){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(d){}}c.remove()}$("html").one("click.close_popup",a);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",a)}catch(b){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",a)}catch(b){}}},addItem:function(b,a){a=(a>=0)?a:this.options.length;this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a<this.options.length;a++){if(_.has(this.options[a],"html")&&(this.options[a].html===b)){return a}}return null},findItemByHtml:function(a){return this.options[(this.findIndexByHtml(a))]},toString:function(){return"PopupMenu"}});PopupMenu.create=function _create(b,a){return new PopupMenu(b,a)};PopupMenu.make_popupmenu=function(b,c){var a=[];_.each(c,function(f,d){var e={html:d};if(f===null){e.header=true}else{if(jQuery.type(f)==="function"){e.func=f}}a.push(e)});return new PopupMenu($(b),a)};PopupMenu.convertLinksToOptions=function(c,a){c=$(c);a=a||"a";var b=[];c.find(a).each(function(g,e){var f={},d=$(g);f.html=d.text();if(d.attr("href")){var j=d.attr("href"),k=d.attr("target"),h=d.attr("confirm");f.func=function(){if((h)&&(!confirm(h))){return}switch(k){case"_parent":window.parent.location=j;break;case"_top":window.top.location=j;break;default:window.location=j}}}b.push(f)});return b};PopupMenu.fromExistingDom=function(d,c,a){d=$(d);c=$(c);var b=PopupMenu.convertLinksToOptions(c,a);c.remove();return new PopupMenu(d,b)};PopupMenu.make_popup_menus=function(c,b,d){c=c||document;b=b||"div[popupmenu]";d=d||function(e,f){return"#"+e.attr("popupmenu")};var a=[];$(c).find(b).each(function(){var e=$(this),f=$(c).find(d(e,c));a.push(PopupMenu.fromDom(f,e));f.addClass("popup")});return a};var faIconButton=function(a){a=a||{};a.tooltipConfig=a.tooltipConfig||{placement:"bottom"};a.classes=["icon-btn"].concat(a.classes||[]);if(a.disabled){a.classes.push("disabled")}var b=['<a class="',a.classes.join(" "),'"',((a.title)?(' title="'+a.title+'"'):("")),((!a.disabled&&a.target)?(' target="'+a.target+'"'):("")),' href="',((!a.disabled&&a.href)?(a.href):("javascript:void(0);")),'">','<span class="fa ',a.faIcon,'"></span>',"</a>"].join("");var c=$(b).tooltip(a.tooltipConfig);if(_.isFunction(a.onclick)){c.click(a.onclick)}return c};function LoadingIndicator(a,c){var b=this;c=jQuery.extend({cover:false},c||{});function d(){var e=['<div class="loading-indicator">','<div class="loading-indicator-text">','<span class="fa fa-spinner fa-spin fa-lg"></span>','<span class="loading-indicator-message">loading...</span>',"</div>","</div>"].join("\n");var g=$(e).hide().css(c.css||{position:"fixed"}),f=g.children(".loading-indicator-text");if(c.cover){g.css({"z-index":2,top:a.css("top"),bottom:a.css("bottom"),left:a.css("left"),right:a.css("right"),opacity:0.5,"background-color":"white","text-align":"center"});f=g.children(".loading-indicator-text").css({"margin-top":"20px"})}else{f=g.children(".loading-indicator-text").css({margin:"12px 0px 0px 10px",opacity:"0.85",color:"grey"});f.children(".loading-indicator-message").css({margin:"0px 8px 0px 0px","font-style":"italic"})}return g}b.show=function(f,e,g){f=f||"loading...";e=e||"fast";b.$indicator=d().insertBefore(a);b.message(f);b.$indicator.fadeIn(e,g);return b};b.message=function(e){b.$indicator.find("i").text(e)};b.hide=function(e,f){e=e||"fast";if(b.$indicator&&b.$indicator.size()){b.$indicator.fadeOut(e,function(){b.$indicator.remove();if(f){f()}})}else{if(f){f()}}return b};return b}(function(){function a(j,p){var d=27,m=13,c=$(j),e=true,g={initialVal:"",name:"search",placeholder:"search",classes:"",onclear:function(){},onfirstsearch:null,onsearch:function(q){},minSearchLen:0,escWillClear:true,oninit:function(){}};function i(q){var r=$(this).parent().children("input");r.val("");r.trigger("clear:searchInput");p.onclear()}function o(r,q){$(this).trigger("search:searchInput",q);if(typeof p.onfirstsearch==="function"&&e){e=false;p.onfirstsearch(q)}else{p.onsearch(q)}}function f(){return['<input type="text" name="',p.name,'" placeholder="',p.placeholder,'" ','class="search-query ',p.classes,'" ',"/>"].join("")}function l(){return $(f()).focus(function(q){$(this).select()}).keyup(function(r){if(r.which===d&&p.escWillClear){i.call(this,r)}else{var q=$(this).val();if((r.which===m)||(p.minSearchLen&&q.length>=p.minSearchLen)){o.call(this,r,q)}else{if(!q.length){i.call(this,r)}}}}).val(p.initialVal)}function k(){return $(['<span class="search-clear fa fa-times-circle" ','title="',_l("clear search (esc)"),'"></span>'].join("")).tooltip({placement:"bottom"}).click(function(q){i.call(this,q)})}function n(){return $(['<span class="search-loading fa fa-spinner fa-spin" ','title="',_l("loading..."),'"></span>'].join("")).hide().tooltip({placement:"bottom"})}function h(){c.find(".search-loading").toggle();c.find(".search-clear").toggle()}if(jQuery.type(p)==="string"){if(p==="toggle-loading"){h()}return c}if(jQuery.type(p)==="object"){p=jQuery.extend(true,{},g,p)}return c.addClass("search-input").prepend([l(),k(),n()])}jQuery.fn.extend({searchInput:function b(c){return this.each(function(){return a(this,c)})}})}());(function(){function 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";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 b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1428,7 +1428,7 @@
.pagination-scroll-container .pagination-page-list>li:last-child>a,.pagination-scroll-container .pagination-page-list>li:last-child>span{border-radius:0px}
.pagination-scroll-container .pagination-page-list>li>a{float:none;position:static;border:1px solid #BFBFBF;border-width:0px 0px 0px 1px}
.peek-control{border-radius:3px;border:1px solid #5f6990}
-.peek-control td,th{padding:4px 10px 4px 4px}
+.peek-control td,.peek-control th{padding:4px 10px 4px 4px}
.peek-control th:last-child{width:100%}
.peek-control .top-left{width:10%;white-space:normal;vertical-align:top;text-align:right;font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;font-weight:normal}
.peek-control .renamable-header:hover{background-color:black}
@@ -1625,6 +1625,13 @@
.icon-button.link{background:url(../images/silk/link.png) no-repeat;cursor:pointer;float:none;display:inline-block;margin-left:10px}
.icon-button.link-broken{background:url(../images/silk/link_break.png) no-repeat;cursor:pointer;float:none;display:inline-block;margin-left:10px}
.workflow-invocation-complete{border:solid 1px #6A6;border-left-width:5px;margin:10px 0;padding-left:5px}
+.icon-btn{display:inline-block;height:22px;width:22px;text-align:center;line-height:19px;font-size:1.2em;border-radius:3px;border:1px solid #bfbfbf;background-color:#f2f2f2;color:#333;cursor:pointer}
+.icon-btn:hover{background-color:white;color:maroon}
+.icon-btn.disabled{background-color:transparent;color:#BBB;border-color:#BBB}
+.icon-btn-group{display:inline-block}.icon-btn-group .icon-btn:not(:last-child){margin:0px;border-radius:0px;border-right:none}
+.icon-btn-group .icon-btn:first-child{margin-right:0px;border-top-left-radius:3px;border-bottom-left-radius:3px}
+.icon-btn-group .icon-btn:last-child{margin-left:0px;border-radius:0px 3px 3px 0px}
+.icon-btn-group .icon-btn:only-child{margin:0px;border-radius:3px}
.list-item{border:1px solid #bfbfbf}.list-item .vertical-spacing{margin-bottom:8px}
.list-item .info-section{border-radius:3px;border:1px solid rgba(153,153,153,0.30000000000000004);padding:4px}
.list-item .padded{padding:6px 10px 6px 8px}
@@ -1642,13 +1649,22 @@
.list-item .details label{margin:0px;padding:0px;font-weight:normal}
.list-item .details .prompt{font-weight:normal;color:#555}
.list-item .details .prompt:after{content:':';margin-right:4px}
-.icon-btn{display:inline-block;height:22px;width:22px;text-align:center;line-height:19px;font-size:1.2em;border-radius:3px;border:1px solid #bfbfbf;background-color:#f2f2f2;color:#333;cursor:pointer}
-.icon-btn:hover{background-color:white;color:maroon}
-.icon-btn.disabled{background-color:transparent;color:#BBB;border-color:#BBB}
-.icon-btn-group{display:inline-block}.icon-btn-group .icon-btn:not(:last-child){margin:0px;border-radius:0px;border-right:none}
-.icon-btn-group .icon-btn:first-child{margin-right:0px;border-top-left-radius:3px;border-bottom-left-radius:3px}
-.icon-btn-group .icon-btn:last-child{margin-left:0px;border-radius:0px 3px 3px 0px}
-.icon-btn-group .icon-btn:only-child{margin:0px;border-radius:3px}
+.list-panel .controls>*:not(:empty){margin-bottom:8px}
+.list-panel .controls .name{word-wrap:break-word;font-weight:bold}
+.list-panel .controls .subtitle{color:grey}.list-panel .controls .subtitle:not(:empty){margin-top:-8px}
+.list-panel .controls .actions{display:inline-block;float:right}.list-panel .controls .actions .icon-btn:not(:last-child){margin:0px;border-radius:0px;border-right:none}
+.list-panel .controls .actions .icon-btn:first-child{margin-right:0px;border-top-left-radius:3px;border-bottom-left-radius:3px}
+.list-panel .controls .actions .icon-btn:last-child{margin-left:0px;border-radius:0px 3px 3px 0px}
+.list-panel .controls .actions .icon-btn:only-child{margin:0px;border-radius:3px}
+.list-panel .controls .actions .icon-btn{margin-left:2px}
+.list-panel .controls .messages [class$=message]{margin:0px}.list-panel .controls .messages [class$=message]:not(:last-child){margin-bottom:8px}
+.list-panel .controls .list-actions{display:none}.list-panel .controls .list-actions:before,.list-panel .controls .list-actions:after{content:" ";display:table;}
+.list-panel .controls .list-actions:after{clear:both}
+.list-panel .controls .list-actions:before,.list-panel .controls .list-actions:after{content:" ";display:table;}
+.list-panel .controls .list-actions:after{clear:both}
+.list-panel .controls .list-actions .btn{padding-top:2px;padding-bottom:2px;font-size:90%}
+.list-panel .list-items .list-item:not(:last-child){border-bottom-width:0px}
+.list-panel .empty-message{display:none;margin:0px}
.search-input .search-query{width:100%;padding-right:24px}
.search-input .search-clear,.search-input .search-loading{position:relative;display:inline-block;float:right;margin-top:-24px;margin-right:4px;font-size:1.4em;line-height:23px;color:grey}
.search-input .search-clear:hover{color:#303030}
@@ -1857,6 +1873,20 @@
.collection-creator .footer .attributes .collection-name-prompt.validation-warning:before{content:'(required)';margin-right:4px;color:red}
.collection-creator .footer .attributes .collection-name{width:50%}.collection-creator .footer .attributes .collection-name.validation-warning{border-color:red}
.collection-creator .footer .actions .other-options>*{display:none;margin-left:4px}
+.dataset-choice{border:1px solid lightgrey;border-radius:3px;overflow:hidden;padding:10px 8px 8px 8px}.dataset-choice:hover{border-color:black;cursor:pointer}.dataset-choice:hover>*{cursor:pointer}
+.dataset-choice .prompt{margin-right:8px}.dataset-choice .prompt:after{content:':'}
+.dataset-choice .prompt:empty{display:none}
+.dataset-choice .none-selected-msg{color:grey}
+.dataset-choice .selected{display:inline-block}.dataset-choice .selected .title{font-weight:bold}
+.dataset-choice .selected .subtitle{color:grey}.dataset-choice .selected .subtitle:before{content:'-';margin:0px 4px 0px 4px}
+.dataset-choice .selected .subtitle i{font-style:normal}.dataset-choice .selected .subtitle i:not(:last-child):after{content:', '}
+.dataset-choice.multi .selected{display:block;font-weight:normal}
+.dataset-choice.multi table{width:100%;margin-top:8px;cursor:pointer}.dataset-choice.multi table:hover{border-color:black}
+.dataset-choice.multi table tr:nth-child(even){background-color:aliceblue}
+.dataset-choice.multi table th{padding:0px;font-weight:normal;font-size:80%;color:grey}
+.dataset-choice.multi table th:not(:last-child),.dataset-choice.multi table td:not(:last-child){padding-right:8px}
+.dataset-choice.multi table td.cell-name{font-weight:bold}
+.dataset-choice-modal .list-panel .controls .title .name{font-size:120%}
.toolMenuContainer{color:#000;background:#dfe5f9;min-height:100%;padding:5px 10px}
div.toolSectionPad{margin:0;padding:0;height:5px;font-size:0px}
div.toolSectionWrapper{margin-bottom:5px}
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/base.less
--- a/static/style/src/less/base.less
+++ b/static/style/src/less/base.less
@@ -551,7 +551,8 @@
border: 1px solid rgb(95, 105, 144);
}
-.peek-control td, th {
+.peek-control td,
+.peek-control th {
padding: 4px 10px 4px 4px;
}
@@ -1551,16 +1552,18 @@
padding-left:5px;
}
-// ==== History styles ====
+// ============================================================================ History
@import "sprite-history-states.less";
@import "sprite-history-buttons.less";
+@import "ui/icon-btn.less";
@import "list-item.less";
@import "history.less";
@import "collections.less";
@import "ui/paired-collection-creator.less";
+@import "ui/dataset-choice.less";
// ==== Tool menu styles
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/history.less
--- a/static/style/src/less/history.less
+++ b/static/style/src/less/history.less
@@ -1,89 +1,3 @@
-// trello-ish style
-//@icon-btn-size: 18px;
-//@icon-btn-margin: 2px;
-//@icon-btn-color: #AAA;
-//@icon-btn-bg: @btn-default-bg;
-//@icon-btn-border: lightgrey;
-
-// no bg
-//@icon-btn-size: 16px;
-//@icon-btn-margin: 0px;
-//@icon-btn-color: #444;
-//@icon-btn-bg: transparent;
-//@icon-btn-border: transparent;
-
-// dark bg
-//@icon-btn-size: 16px;
-//@icon-btn-margin: 1px;
-//@icon-btn-color: @link-color;
-//@icon-btn-bg: rgba( 0, 0, 0, 0.1 );
-//@icon-btn-border: transparent;
-
-// big & dark style
-@icon-btn-size: 22px;
-@icon-btn-margin: 2px;
-@icon-btn-color: @btn-default-color;
-//@icon-btn-bg: transparent;
-@icon-btn-bg: @btn-default-bg;
-@icon-btn-border: @btn-default-border;
-
-.icon-btn {
- display : inline-block;
- height : @icon-btn-size;
- width : @icon-btn-size;
- // center the icon
- text-align: center;
- line-height: @icon-btn-size - 3;
- font-size: 1.2em;
-
- // colors and borders
- border-radius: 3px;
- border: 1px solid @icon-btn-border;
- background-color: @icon-btn-bg;
- color : @icon-btn-color;
-
- cursor: pointer;
-
- // tweaks
- //TODO: not working - span
- //.fa-comment {
- // display: inline-block;
- // margin-bottom: 4px;
- //}
-}
-.icon-btn:hover {
- background-color: white;
- color: maroon;
-}
-.icon-btn.disabled {
- background-color: transparent;
- color: #BBB;
- border-color: #BBB;
- //color: @icon-btn-border;
-}
-.icon-btn-group {
- display: inline-block;
- .icon-btn:not(:last-child) {
- margin: 0px;
- border-radius: 0px;
- border-right: none;
- }
- .icon-btn:first-child {
- margin-right: 0px;
- border-top-left-radius: 3px;
- border-bottom-left-radius: 3px;
- }
- .icon-btn:last-child {
- margin-left: 0px;
- border-radius: 0px 3px 3px 0px;
- }
- .icon-btn:only-child {
- margin: 0px;
- border-radius: 3px;
- }
-}
-
-
// ---------------------------------------------------------------------------- search bar
.search-input {
.search-query {
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/list-item.less
--- a/static/style/src/less/list-item.less
+++ b/static/style/src/less/list-item.less
@@ -98,3 +98,69 @@
}
}
+// ---------------------------------------------------------------------------- generic panel list (of list-items)
+.list-panel {
+
+ .controls {
+ & > *:not(:empty) {
+ margin-bottom: 8px;
+ }
+ .title {
+ }
+ .name {
+ word-wrap: break-word;
+ font-weight: bold;
+ }
+
+ .subtitle {
+ color: grey;
+ &:not(:empty) {
+ margin-top: -8px;
+ }
+ }
+
+ .actions {
+ .icon-btn-group();
+ float: right;
+ .icon-btn {
+ margin-left: @icon-btn-margin;
+ }
+ }
+
+ .messages {
+ [class$=message] {
+ margin: 0px;
+ &:not(:last-child) {
+ margin-bottom: 8px;
+ }
+ }
+ }
+
+ .search {
+ }
+
+ .list-actions {
+ display: none;
+ .clear;
+ .btn {
+ padding-top: 2px;
+ padding-bottom: 2px;
+ font-size: 90%;
+ }
+ }
+ }
+
+ // display only a top border on all
+ .list-items {
+ .list-item {
+ &:not(:last-child) {
+ border-bottom-width: 0px;
+ }
+ }
+ }
+
+ .empty-message {
+ display: none;
+ margin: 0px;
+ }
+}
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/ui/dataset-choice.less
--- /dev/null
+++ b/static/style/src/less/ui/dataset-choice.less
@@ -0,0 +1,88 @@
+// component to display a dataset choice and activate a modal chooser (single *and* multiple datasets)
+.dataset-choice {
+ border: 1px solid lightgrey;
+ border-radius: 3px;
+ overflow: hidden;
+ padding: 10px 8px 8px 8px;
+
+ &:hover {
+ border-color: black;
+ cursor: pointer;
+ & > * {
+ cursor: pointer;
+ }
+ }
+ .prompt {
+ margin-right: 8px;
+ &:after {
+ content: ':';
+ }
+ &:empty {
+ display: none;
+ }
+ }
+ .none-selected-msg {
+ color: grey;
+ }
+
+ .selected {
+ display: inline-block;
+
+ .title {
+ font-weight: bold;
+ }
+ .subtitle {
+ color: grey;
+ &:before {
+ content: '-';
+ margin: 0px 4px 0px 4px;
+ }
+ i {
+ font-style: normal;
+ &:not(:last-child):after {
+ content: ', ';
+ }
+ }
+ }
+ }
+}
+
+// component to display a dataset choice and activate a modal chooser (multiple datasets)
+.dataset-choice.multi {
+ .selected {
+ display: block;
+ font-weight: normal;
+ }
+
+ table {
+ width: 100%;
+ margin-top: 8px;
+ cursor: pointer;
+
+ &:hover {
+ border-color: black;
+ }
+ tr:nth-child(even) {
+ background-color: aliceblue;
+ }
+ th {
+ padding: 0px;
+ font-weight: normal;
+ font-size: 80%;
+ color: grey;
+ }
+ th:not(:last-child),
+ td:not(:last-child) {
+ padding-right: 8px;
+ }
+ td.cell-name {
+ font-weight: bold;
+ }
+ }
+}
+
+// modal allowing single or multiple dataset selection - often activated by .dataset-choice above
+.dataset-choice-modal .list-panel .controls .title .name {
+ font-size: 120%;
+}
+
diff -r b7fb63b197362424b39c2cc73d1589a0e383443e -r 737f78bb4a4581630734a693d6675daaae35b641 static/style/src/less/ui/icon-btn.less
--- /dev/null
+++ b/static/style/src/less/ui/icon-btn.less
@@ -0,0 +1,84 @@
+// trello-ish style
+//@icon-btn-size: 18px;
+//@icon-btn-margin: 2px;
+//@icon-btn-color: #AAA;
+//@icon-btn-bg: @btn-default-bg;
+//@icon-btn-border: lightgrey;
+
+// no bg
+//@icon-btn-size: 16px;
+//@icon-btn-margin: 0px;
+//@icon-btn-color: #444;
+//@icon-btn-bg: transparent;
+//@icon-btn-border: transparent;
+
+// dark bg
+//@icon-btn-size: 16px;
+//@icon-btn-margin: 1px;
+//@icon-btn-color: @link-color;
+//@icon-btn-bg: rgba( 0, 0, 0, 0.1 );
+//@icon-btn-border: transparent;
+
+// big & dark style
+@icon-btn-size: 22px;
+@icon-btn-margin: 2px;
+@icon-btn-color: @btn-default-color;
+//@icon-btn-bg: transparent;
+@icon-btn-bg: @btn-default-bg;
+@icon-btn-border: @btn-default-border;
+
+.icon-btn {
+ display : inline-block;
+ height : @icon-btn-size;
+ width : @icon-btn-size;
+ // center the icon
+ text-align: center;
+ line-height: @icon-btn-size - 3;
+ font-size: 1.2em;
+
+ // colors and borders
+ border-radius: 3px;
+ border: 1px solid @icon-btn-border;
+ background-color: @icon-btn-bg;
+ color : @icon-btn-color;
+
+ cursor: pointer;
+
+ // tweaks
+ //TODO: not working - span
+ //.fa-comment {
+ // display: inline-block;
+ // margin-bottom: 4px;
+ //}
+}
+.icon-btn:hover {
+ background-color: white;
+ color: maroon;
+}
+.icon-btn.disabled {
+ background-color: transparent;
+ color: #BBB;
+ border-color: #BBB;
+ //color: @icon-btn-border;
+}
+.icon-btn-group {
+ display: inline-block;
+ .icon-btn:not(:last-child) {
+ margin: 0px;
+ border-radius: 0px;
+ border-right: none;
+ }
+ .icon-btn:first-child {
+ margin-right: 0px;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ }
+ .icon-btn:last-child {
+ margin-left: 0px;
+ border-radius: 0px 3px 3px 0px;
+ }
+ .icon-btn:only-child {
+ margin: 0px;
+ border-radius: 3px;
+ }
+}
https://bitbucket.org/galaxy/galaxy-central/commits/ece8ef90a828/
Changeset: ece8ef90a828
User: carlfeberhard
Date: 2014-08-26 18:59:59
Summary: (add packed scripts)
Affected #: 3 files
diff -r 737f78bb4a4581630734a693d6675daaae35b641 -r ece8ef90a8289399bf9faca6a3265696da7e0beb static/scripts/packed/mvc/dataset/dataset-choice.js
--- /dev/null
+++ b/static/scripts/packed/mvc/dataset/dataset-choice.js
@@ -0,0 +1,1 @@
+define(["mvc/dataset/dataset-model","mvc/dataset/dataset-list","mvc/ui/ui-modal","mvc/base-mvc","utils/localization"],function(a,d,f,i,c){function g(k,j,m){function l(p,o){for(var n in o){if(o.hasOwnProperty(n)){if(p[n]!==o[n]){return false}}}return true}return k.filter(function(n){return(!n.deleted&&n.visible)&&(!m||n.collection_type===undefined)&&(l(n,j))})}var b=function(n,j){j=_.defaults(j||{},{datasetsOnly:true,where:{state:"ok"},multiselect:false,selected:[]});j.title=j.title||(j.multiselect?c("Choose datasets:"):c("Choose a dataset:"));var m,o,l,q=jQuery.Deferred(),p=j.filter||g;n=p(n,j.where,j.datasetsOnly);if(!n.length){return q.reject("No matches found")}function k(){q.resolve(o.getSelectedModels().map(function(r){return r.toJSON()}))}if(j.multiselect){l={};l[c("Ok")]=k}m=new f.View({height:"auto",buttons:l,closing_events:true,closing_callback:function(){q.resolve(null)},body:['<div class="list-panel"></div>'].join("")});m.$(".modal-header").remove();m.$(".modal-footer").css("margin-top","0px");o=new d.DatasetList({title:j.title,subtitle:j.subtitle||c(["Click the checkboxes on the right to select datasets. ","Click the datasets names to see their details. "].join("")),el:m.$body.find(".list-panel"),selecting:true,selected:j.selected,collection:new a.DatasetAssociationCollection(n)});o.once("rendered:initial",function(){m.show();m.$el.addClass("dataset-choice-modal")});if(!j.multiselect){o.on("rendered",function(){o.$(".list-actions").hide()});o.on("view:selected",function(r){q.resolve([r.model.toJSON()])})}o.render(0);return q.always(function(){m.hide()})};var e=Backbone.View.extend(i.LoggableMixin).extend({className:"dataset-choice",initialize:function(j){this.debug(this+"(DatasetChoice).initialize:",j);this.label=j.label!==undefined?c(j.label):"";this.where=j.where;this.datasetsOnly=j.datasetsOnly!==undefined?j.datasetsOnly:true;this.datasetJSON=j.datasetJSON||[];this.selected=j.selected||[];this._setUpListeners()},_setUpListeners:function(){},render:function(){var j=this.toJSON();this.$el.html(this._template(j));this.$(".selected").replaceWith(this._renderSelected(j));return this},_template:function(j){return _.template(["<label>",'<span class="prompt"><%= json.label %></span>','<div class="selected"></div>',"</label>"].join(""),{json:j})},_renderSelected:function(j){if(j.selected.length){return $(_.template(['<div class="selected">','<span class="title"><%= selected.hid %>: <%= selected.name %></span>','<span class="subtitle">',"<i><%= selected.misc_blurb %></i>","<i>",c("format")+": ","<%= selected.data_type %></i>","<i><%= selected.misc_info %></i>","</span>","</div>"].join(""),{selected:j.selected[0]}))}return $(['<span class="none-selected-msg">(',c("click to select a dataset"),")</span>"].join(""))},toJSON:function(){var j=this;return{label:j.label,datasets:j.datasetJSON,selected:_.compact(_.map(j.selected,function(k){return _.findWhere(j.datasetJSON,{id:k})}))}},events:{click:"chooseWithModal"},chooseWithModal:function(){var j=this;return this._createModal().done(function(k){if(k){j.selected=_.pluck(k,"id");j.trigger("selected",j,k);j.render()}else{j.trigger("cancelled",j)}}).fail(function(){j.trigger("error",j,arguments)})},_createModal:function(){return new b(this.datasetJSON,this._getModalOptions())},_getModalOptions:function(){return{title:this.label,multiselect:false,selected:this.selected,where:this.where,datasetsOnly:this.datasetsOnly}},toString:function(){return"DatasetChoice("+this.selected+")"}});var h=e.extend({className:e.prototype.className+" multi",cells:{hid:c("History #"),name:c("Name"),misc_blurb:c("Summary"),data_type:c("Format"),genome_build:c("Genome"),tags:c("Tags"),annotation:c("Annotation")},initialize:function(j){this.showHeaders=j.showHeaders!==undefined?j.showHeaders:true;this.cells=j.cells||this.cells;e.prototype.initialize.call(this,j)},_renderSelected:function(j){if(j.selected.length){return $(_.template(['<table class="selected">',"<% if( json.showHeaders ){ %>","<thead><tr>","<% _.map( json.cells, function( val, key ){ %>","<th><%= val %></th>","<% }); %>","</tr></thead>","<% } %>","<tbody>","<% _.map( json.selected, function( selected ){ %>","<tr>","<% _.map( json.cells, function( val, key ){ %>",'<td class="cell-<%= key %>"><%= selected[ key ] %></td>',"<% }) %>","</tr>","<% }); %>","</tbody>","</table>"].join(""),{json:j}))}return $(['<span class="none-selected-msg">(',c("click to select a dataset"),")</span>"].join(""))},toJSON:function(){return _.extend(e.prototype.toJSON.call(this),{showHeaders:this.showHeaders,cells:this.cells})},_getModalOptions:function(){return _.extend(e.prototype._getModalOptions.call(this),{multiselect:true})},toString:function(){return"DatasetChoice("+this.selected+")"}});return{DatasetChoiceModal:b,DatasetChoice:e,MultiDatasetChoice:h}});
\ No newline at end of file
diff -r 737f78bb4a4581630734a693d6675daaae35b641 -r ece8ef90a8289399bf9faca6a3265696da7e0beb static/scripts/packed/mvc/dataset/dataset-list.js
--- /dev/null
+++ b/static/scripts/packed/mvc/dataset/dataset-list.js
@@ -0,0 +1,1 @@
+define(["mvc/dataset/list-panel","mvc/dataset/dataset-li","mvc/base-mvc","utils/localization"],function(c,f,a,b){var e=c.ListPanel;var d=e.extend({viewClass:f.DatasetListItemView,className:e.prototype.className+" dataset-list",noneFoundMsg:b("No matching datasets found"),initialize:function(g){e.prototype.initialize.call(this,g)},toString:function(){return"DatasetList("+this.collection+")"}});return{DatasetList:d}});
\ No newline at end of file
diff -r 737f78bb4a4581630734a693d6675daaae35b641 -r ece8ef90a8289399bf9faca6a3265696da7e0beb static/scripts/packed/mvc/dataset/list-panel.js
--- /dev/null
+++ b/static/scripts/packed/mvc/dataset/list-panel.js
@@ -0,0 +1,1 @@
+define(["mvc/base-mvc","utils/localization"],function(a,b){var c=Backbone.View.extend(a.LoggableMixin).extend({viewClass:a.ListItemView,tagName:"div",className:"list-panel",fxSpeed:"fast",emptyMsg:b("This list is empty"),noneFoundMsg:b("No matching items found"),initialize:function(d,e){d=d||{};if(d.logger){this.logger=d.logger}this.log(this+".initialize:",d);this.fxSpeed=_.has(d,"fxSpeed")?(d.fxSpeed):(this.fxSpeed);this.filters=[];this.searchFor=d.searchFor||"";this.indicator=new LoadingIndicator(this.$el);this.selecting=(d.selecting!==undefined)?d.selecting:true;this.selected=d.selected||[];this.lastSelected=null;this.viewClass=d.viewClass||this.viewClass;this.views=[];this.collection=d.collection||(new Backbone.Collection([]));this.filters=d.filters||[];this.title=d.title||"";this.subtitle=d.subtitle||"";this._setUpListeners()},_setUpListeners:function(){this.on("error",function(e,h,d,g,f){console.error(e,h,d,g,f)},this);this.on("loading",function(){this._showLoadingIndicator("loading...",40)},this);this.on("loading-done",function(){this._hideLoadingIndicator(40)},this);this.once("rendered",function(){this.trigger("rendered:initial",this)},this);if(this.logger){this.on("all",function(d){this.log(this+"",arguments)},this)}this._setUpCollectionListeners();this._setUpViewListeners();return this},freeViews:function(){this.views=[];return this},_setUpCollectionListeners:function(){this.collection.on("reset",function(){this.renderItems()},this);this.collection.on("add",this.addItemView,this);this.collection.on("remove",this.removeItemView,this);if(this.logger){this.collection.on("all",function(d){this.info(this+"(collection)",arguments)},this)}return this},_setUpViewListeners:function(){this.on("view:selected",function(d,e){if(e&&e.shiftKey&&this.lastSelected){var f=_.find(this.views,function(g){return g.model.id===this.lastSelected});if(f){this.selectRange(d,f)}}this.selected.push(d.model.id);this.lastSelected=d.model.id},this)},render:function(e){var d=this._buildNewRender();this._setUpBehaviors(d);this._queueNewRender(d,e);return this},_buildNewRender:function(){var e=this.model?this.model.toJSON():{},d=$(this.templates.el(e,this));this._renderTitle(d);this._renderSubtitle(d);this._renderSearch(d);this.renderItems(d);return d},_renderTitle:function(d){},_renderSubtitle:function(d){},_queueNewRender:function(e,f){f=(f===undefined)?(this.fxSpeed):(f);var d=this;$(d).queue("fx",[function(g){this.$el.fadeOut(f,g)},function(g){d._swapNewRender(e);g()},function(g){this.$el.fadeIn(f,g)},function(g){d.trigger("rendered",d);g()}])},_swapNewRender:function(d){this.$el.empty().attr("class",this.className).append(d.children());if(this.selecting){this.showSelectors(0)}return this},_setUpBehaviors:function(d){d=d||this.$el;d.find(".controls [title]").tooltip({placement:"bottom"});return this},$scrollContainer:function(){return this.$el.parent().parent()},$list:function(d){return(d||this.$el).find(".list-items")},$messages:function(d){return(d||this.$el).find(".message-container")},$emptyMessage:function(d){return(d||this.$el).find(".empty-message")},renderItems:function(g){g=g||this.$el;var h=this,e=[];var f=this.$list(g),d=this._filterCollection().map(function(j){var i=h._createItemView(j);e.push(i);return i.render(0).$el});this.debug(d);this.debug(e);f.empty();if(d.length){f.append(d);this.$emptyMessage(g).hide()}else{this._renderEmptyMessage(g).show()}this.views=e;return e},_filterCollection:function(){var d=this;return d.collection.filter(_.bind(d._filterItem,d))},_filterItem:function(d){var e=this;return(_.every(e.filters.map(function(f){return f.call(d)})))&&(!e.searchFor||d.matchesAll(e.searchFor))},_createItemView:function(f){var g=this._getItemViewClass(f),e=_.extend(this._getItemViewOptions(f),{model:f}),d=new g(e);this._setUpItemViewListeners(d);return d},_getItemViewClass:function(d){return this.viewClass},_getItemViewOptions:function(d){return{fxSpeed:this.fxSpeed,expanded:false,selectable:this.selecting,selected:_.contains(this.selected,d.id),draggable:this.dragging}},_setUpItemViewListeners:function(d){var e=this;d.on("all",function(){var f=Array.prototype.slice.call(arguments,0);f[0]="view:"+f[0];e.trigger.apply(e,f)});return this},_renderEmptyMessage:function(d){var e=this.searchFor?this.noneFoundMsg:this.emptyMsg;return this.$emptyMessage(d).text(e)},expandAll:function(){_.each(this.views,function(d){d.expand()})},collapseAll:function(){_.each(this.views,function(d){d.collapse()})},addItemView:function(f,h,e){this.log(this+".addItemView:",f);var g=this;if(!this._filterItem(f)){return undefined}var d=g._createItemView(f);this.views.push(d);$(d).queue("fx",[function(i){g.$emptyMessage().fadeOut(g.fxSpeed,i)},function(i){g.$list().append(d.render().$el);i()}]);return d},removeItemView:function(f,h,e){this.log(this+".removeItemView:",f);var g=this,d=g.viewFromModel(f);if(!d){return undefined}this.views=_.without(this.views,d);d.remove();if(!this.views.length){g._renderEmptyMessage().fadeIn(g.fxSpeed)}return d},viewFromModel:function(e){for(var f=0;f<this.views.length;f++){var d=this.views[f];if(d.model===e){return d}}return undefined},viewsWhereModel:function(d){return this.views.filter(function(e){var g=e.model.toJSON();for(var f in d){if(d.hasOwnPropery(f)){if(g[f]!==e.model.properties[f]){return false}}}return true})},viewRange:function(g,f){if(g===f){return(g)?([g]):([])}var e=this.views.indexOf(g),d=this.views.indexOf(f);if(e===-1||d===-1){if(e===d){return[]}return(e===-1)?([f]):([g])}return(e<d)?this.views.slice(e,d+1):this.views.slice(d,e+1)},_renderSearch:function(d){d.find(".controls .search-input").searchInput({placeholder:"search",initialVal:this.searchFor,onfirstsearch:_.bind(this._firstSearch,this),onsearch:_.bind(this.searchItems,this),onclear:_.bind(this.clearSearch,this)});return d},_firstSearch:function(d){this.log("onFirstSearch",d);return this.searchItems(d)},searchItems:function(d){this.searchFor=d;this.trigger("search:searching",d,this);this.renderItems();return this},clearSearch:function(d){this.searchFor="";this.trigger("search:clear",this);this.renderItems();return this},showSelectors:function(d){d=(d!==undefined)?(d):(this.fxSpeed);this.selecting=true;this.$(".list-actions").slideDown(d);_.each(this.views,function(e){e.showSelector(d)});this.selected=[];this.lastSelected=null},hideSelectors:function(d){d=(d!==undefined)?(d):(this.fxSpeed);this.selecting=false;this.$(".list-actions").slideUp(d);_.each(this.views,function(e){e.hideSelector(d)});this.selected=[];this.lastSelected=null},toggleSelectors:function(){if(!this.selecting){this.showSelectors()}else{this.hideSelectors()}},selectAll:function(d){_.each(this.views,function(e){e.select(d)})},deselectAll:function(d){this.lastSelected=null;_.each(this.views,function(e){e.deselect(d)})},selectRange:function(f,e){var d=this.viewRange(f,e);_.each(d,function(g){g.select()});return d},getSelectedViews:function(){return _.filter(this.views,function(d){return d.selected})},getSelectedModels:function(){return new this.collection.constructor(_.map(this.getSelectedViews(),function(d){return d.model}))},_showLoadingIndicator:function(e,d,f){d=(d!==undefined)?(d):(this.fxSpeed);if(!this.indicator){this.indicator=new LoadingIndicator(this.$el,this.$el.parent())}if(!this.$el.is(":visible")){this.indicator.show(0,f)}else{this.$el.fadeOut(d);this.indicator.show(e,d,f)}},_hideLoadingIndicator:function(d,e){d=(d!==undefined)?(d):(this.fxSpeed);if(this.indicator){this.indicator.hide(d,e)}},scrollPosition:function(){return this.$scrollContainer().scrollTop()},scrollTo:function(d){this.$scrollContainer().scrollTop(d);return this},scrollToTop:function(){this.$scrollContainer().scrollTop(0);return this},scrollToItem:function(d){if(!d){return}var e=d.$el.offset().top;this.$scrollContainer().scrollTop(e)},events:{"click .select-all":"selectAll","click .deselect-all":"deselectAll"},toString:function(){return"ListPanel("+this.collection+")"}});c.prototype.templates=(function(){var d=a.wrapTemplate(["<div>",'<div class="controls">','<div class="title">','<div class="name"><%= model.name || view.title %></div>',"</div>",'<div class="subtitle"><%= view.subtitle %></div>','<div class="actions"></div>','<div class="messages"></div>','<div class="search">','<div class="search-input"></div>',"</div>",'<div class="list-actions">','<div class="btn-group">','<button class="select-all btn btn-default"','data-mode="select">',b("All"),"</button>",'<button class="deselect-all btn btn-default"','data-mode="select">',b("None"),"</button>","</div>","</div>","</div>",'<div class="list-items"></div>','<div class="empty-message infomessagesmall"></div>',"</div>"]);return{el:d}}());return{ListPanel:c}});
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0