galaxy-commits
Threads by month
- ----- 2026 -----
- October
- 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 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/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 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/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 26 Aug '14
by commits-noreply@bitbucket.org 26 Aug '14
26 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
commit/galaxy-central: dannon: Merged in kellrott/galaxy-farm/workflow-uuid (pull request #471)
by commits-noreply@bitbucket.org 26 Aug '14
by commits-noreply@bitbucket.org 26 Aug '14
26 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b7fb63b19736/
Changeset: b7fb63b19736
User: dannon
Date: 2014-08-26 17:26:31
Summary: Merged in kellrott/galaxy-farm/workflow-uuid (pull request #471)
Workflow UUIDs
Affected #: 6 files
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2974,6 +2974,7 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
rval['tags'] = tags_str_list
+ rval['latest_workflow_uuid'] = ( lambda uuid: str( uuid ) if self.latest_workflow.uuid else None )( self.latest_workflow.uuid )
return rval
@@ -2982,12 +2983,16 @@
dict_collection_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
dict_element_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
- def __init__( self ):
+ def __init__( self, uuid=None ):
self.user = None
self.name = None
self.has_cycles = None
self.has_errors = None
self.steps = []
+ if uuid is None:
+ self.uuid = uuid4()
+ else:
+ self.uuid = UUID(str(uuid))
def has_outputs_defined(self):
"""
@@ -2998,6 +3003,11 @@
return True
return False
+ def to_dict( self, view='collection', value_mapper=None):
+ rval = super( Workflow, self ).to_dict( view=view, value_mapper = value_mapper )
+ rval['uuid'] = ( lambda uuid: str( uuid ) if uuid else None )( self.uuid )
+ return rval
+
class WorkflowStep( object ):
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -690,7 +690,8 @@
Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True, nullable=False ),
Column( "name", TEXT ),
Column( "has_cycles", Boolean ),
- Column( "has_errors", Boolean )
+ Column( "has_errors", Boolean ),
+ Column( "uuid", UUIDType, nullable=True )
)
model.WorkflowStep.table = Table( "workflow_step", metadata,
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
@@ -0,0 +1,55 @@
+"""
+Add UUIDs to workflows
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+from galaxy.model.custom_types import UUIDType, TrimmedString
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData()
+
+
+
+"""
+Because both workflow and job requests can be determined
+based the a fixed data structure, their IDs are based on
+hashing the data structure
+"""
+workflow_uuid_column = Column( "uuid", UUIDType, nullable=True )
+
+
+def display_migration_details():
+ print "This migration script adds a UUID column to workflows"
+
+def upgrade(migrate_engine):
+ print __doc__
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Add the uuid colum to the workflow table
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid_column.create( workflow_table )
+ assert workflow_uuid_column is workflow_table.c.uuid
+ except Exception, e:
+ print str(e)
+ log.error( "Adding column 'uuid' to workflow table failed: %s" % str( e ) )
+ return
+
+def downgrade(migrate_engine):
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Drop the workflow table's uuid column.
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid = workflow_table.c.uuid
+ workflow_uuid.drop()
+ except Exception, e:
+ log.debug( "Dropping 'uuid' column from workflow table failed: %s" % ( str( e ) ) )
+
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1791,6 +1791,8 @@
data['format-version'] = "0.1"
data['name'] = workflow.name
data['annotation'] = annotation_str
+ if workflow.uuid is not None:
+ data['uuid'] = str(workflow.uuid)
data['steps'] = {}
# For each step, rebuild the form and encode the state
for step in workflow.steps:
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -4,8 +4,9 @@
from __future__ import absolute_import
+import uuid
import logging
-from sqlalchemy import desc, or_
+from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
from galaxy.managers import histories
@@ -432,11 +433,23 @@
return stored_workflow
def __get_stored_workflow( self, trans, workflow_id ):
- workflow_id = self.__decode_id( trans, workflow_id )
try:
+ workflow_id = self.__decode_id( trans, workflow_id )
query = trans.sa_session.query( trans.app.model.StoredWorkflow )
stored_workflow = query.get( workflow_id )
except Exception:
+ try:
+ #see if they have passed in the UUID for a workflow that is attached to a stored workflow
+ workflow_uuid = uuid.UUID(workflow_id)
+ stored_workflow = trans.sa_session.query(trans.app.model.StoredWorkflow).filter( and_(
+ trans.app.model.StoredWorkflow.latest_workflow_id == trans.app.model.Workflow.id,
+ trans.app.model.Workflow.uuid == workflow_uuid
+ )).first()
+ if stored_workflow is None:
+ raise exceptions.ObjectNotFound( "Workflow not found: %s" % workflow_id )
+ return stored_workflow
+ except:
+ pass #let the outer raise exception happen
raise exceptions.ObjectNotFound( "No such workflow found - invalid workflow identifier." )
if stored_workflow is None:
raise exceptions.ObjectNotFound( "No such workflow found." )
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e scripts/cleanup_datasets/populate_uuid.py
--- a/scripts/cleanup_datasets/populate_uuid.py
+++ b/scripts/cleanup_datasets/populate_uuid.py
@@ -33,6 +33,12 @@
row.uuid = uuid.uuid4()
print "Setting dataset:", row.id, " UUID to ", row.uuid
model.context.flush()
+
+ for row in model.context.query( model.Workflow ):
+ if row.uuid is None:
+ row.uuid = uuid.uuid4()
+ print "Setting Workflow:", row.id, " UUID to ", row.uuid
+ model.context.flush()
if __name__ == "__main__":
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e9152659a0be/
Changeset: e9152659a0be
Branch: workflow-uuid
User: kellrott
Date: 2014-08-20 23:10:43
Summary: Refactoring work to add in Workflow UUIDs
Affected #: 6 files
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2974,6 +2974,7 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
rval['tags'] = tags_str_list
+ rval['latest_workflow_uuid'] = ( lambda uuid: str( uuid ) if self.latest_workflow.uuid else None )( self.latest_workflow.uuid )
return rval
@@ -2982,12 +2983,16 @@
dict_collection_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
dict_element_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
- def __init__( self ):
+ def __init__( self, uuid=None ):
self.user = None
self.name = None
self.has_cycles = None
self.has_errors = None
self.steps = []
+ if uuid is None:
+ self.uuid = uuid4()
+ else:
+ self.uuid = UUID(str(uuid))
def has_outputs_defined(self):
"""
@@ -2998,6 +3003,11 @@
return True
return False
+ def to_dict( self, view='collection', value_mapper=None):
+ rval = super( Workflow, self ).to_dict( view=view, value_mapper = value_mapper )
+ rval['uuid'] = ( lambda uuid: str( uuid ) if uuid else None )( self.uuid )
+ return rval
+
class WorkflowStep( object ):
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -690,7 +690,8 @@
Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True, nullable=False ),
Column( "name", TEXT ),
Column( "has_cycles", Boolean ),
- Column( "has_errors", Boolean )
+ Column( "has_errors", Boolean ),
+ Column( "uuid", UUIDType, nullable=True )
)
model.WorkflowStep.table = Table( "workflow_step", metadata,
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
@@ -0,0 +1,55 @@
+"""
+Add UUIDs to workflows
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+from galaxy.model.custom_types import UUIDType, TrimmedString
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData()
+
+
+
+"""
+Because both workflow and job requests can be determined
+based the a fixed data structure, their IDs are based on
+hashing the data structure
+"""
+workflow_uuid_column = Column( "uuid", UUIDType, nullable=True )
+
+
+def display_migration_details():
+ print "This migration script adds a UUID column to workflows"
+
+def upgrade(migrate_engine):
+ print __doc__
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Add the uuid colum to the workflow table
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid_column.create( workflow_table )
+ assert workflow_uuid_column is workflow_table.c.uuid
+ except Exception, e:
+ print str(e)
+ log.error( "Adding column 'uuid' to workflow table failed: %s" % str( e ) )
+ return
+
+def downgrade(migrate_engine):
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Drop the workflow table's uuid column.
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid = workflow_table.c.uuid
+ workflow_uuid.drop()
+ except Exception, e:
+ log.debug( "Dropping 'uuid' column from workflow table failed: %s" % ( str( e ) ) )
+
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1791,6 +1791,8 @@
data['format-version'] = "0.1"
data['name'] = workflow.name
data['annotation'] = annotation_str
+ if workflow.uuid is not None:
+ data['uuid'] = str(workflow.uuid)
data['steps'] = {}
# For each step, rebuild the form and encode the state
for step in workflow.steps:
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -4,6 +4,7 @@
from __future__ import absolute_import
+import uuid
import logging
from sqlalchemy import desc, or_
from galaxy import exceptions, util
@@ -437,6 +438,17 @@
query = trans.sa_session.query( trans.app.model.StoredWorkflow )
stored_workflow = query.get( workflow_id )
except Exception:
+ try:
+ #see if they have passed in the UUID for a workflow that is attached to a stored workflow
+ workflow_uuid = uuid.UUID(workflow_id)
+ stored_workflow = trans.sa_session.query(trans.app.model.StoredWorkflow).filter( and_(
+ trans.app.model.StoredWorkflow.latest_workflow_id == trans.app.model.Workflow.id,
+ trans.app.model.Workflow.uuid == workflow_uuid
+ )).first()
+ if stored_workflow is None:
+ raise exceptions.ObjectNotFound( "Workflow not found: %s" % workflow_id )
+ except:
+ pass #let the outer raise exception happen
raise exceptions.ObjectNotFound( "No such workflow found - invalid workflow identifier." )
if stored_workflow is None:
raise exceptions.ObjectNotFound( "No such workflow found." )
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 scripts/cleanup_datasets/populate_uuid.py
--- a/scripts/cleanup_datasets/populate_uuid.py
+++ b/scripts/cleanup_datasets/populate_uuid.py
@@ -33,6 +33,12 @@
row.uuid = uuid.uuid4()
print "Setting dataset:", row.id, " UUID to ", row.uuid
model.context.flush()
+
+ for row in model.context.query( model.Workflow ):
+ if row.uuid is None:
+ row.uuid = uuid.uuid4()
+ print "Setting Workflow:", row.id, " UUID to ", row.uuid
+ model.context.flush()
if __name__ == "__main__":
https://bitbucket.org/galaxy/galaxy-central/commits/80dfc96a9666/
Changeset: 80dfc96a9666
Branch: workflow-uuid
User: kellrott
Date: 2014-08-20 23:27:56
Summary: Fixing some small bugs to get the code to work
Affected #: 1 file
diff -r e9152659a0be5e932e6eea591bd6c99977983854 -r 80dfc96a96665052fdd213b77008d88c6935506b lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -6,7 +6,7 @@
import uuid
import logging
-from sqlalchemy import desc, or_
+from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
from galaxy.managers import histories
@@ -433,8 +433,8 @@
return stored_workflow
def __get_stored_workflow( self, trans, workflow_id ):
- workflow_id = self.__decode_id( trans, workflow_id )
try:
+ workflow_id = self.__decode_id( trans, workflow_id )
query = trans.sa_session.query( trans.app.model.StoredWorkflow )
stored_workflow = query.get( workflow_id )
except Exception:
@@ -447,6 +447,7 @@
)).first()
if stored_workflow is None:
raise exceptions.ObjectNotFound( "Workflow not found: %s" % workflow_id )
+ return stored_workflow
except:
pass #let the outer raise exception happen
raise exceptions.ObjectNotFound( "No such workflow found - invalid workflow identifier." )
https://bitbucket.org/galaxy/galaxy-central/commits/b7fb63b19736/
Changeset: b7fb63b19736
User: dannon
Date: 2014-08-26 17:26:31
Summary: Merged in kellrott/galaxy-farm/workflow-uuid (pull request #471)
Workflow UUIDs
Affected #: 6 files
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2974,6 +2974,7 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
rval['tags'] = tags_str_list
+ rval['latest_workflow_uuid'] = ( lambda uuid: str( uuid ) if self.latest_workflow.uuid else None )( self.latest_workflow.uuid )
return rval
@@ -2982,12 +2983,16 @@
dict_collection_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
dict_element_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
- def __init__( self ):
+ def __init__( self, uuid=None ):
self.user = None
self.name = None
self.has_cycles = None
self.has_errors = None
self.steps = []
+ if uuid is None:
+ self.uuid = uuid4()
+ else:
+ self.uuid = UUID(str(uuid))
def has_outputs_defined(self):
"""
@@ -2998,6 +3003,11 @@
return True
return False
+ def to_dict( self, view='collection', value_mapper=None):
+ rval = super( Workflow, self ).to_dict( view=view, value_mapper = value_mapper )
+ rval['uuid'] = ( lambda uuid: str( uuid ) if uuid else None )( self.uuid )
+ return rval
+
class WorkflowStep( object ):
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -690,7 +690,8 @@
Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True, nullable=False ),
Column( "name", TEXT ),
Column( "has_cycles", Boolean ),
- Column( "has_errors", Boolean )
+ Column( "has_errors", Boolean ),
+ Column( "uuid", UUIDType, nullable=True )
)
model.WorkflowStep.table = Table( "workflow_step", metadata,
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
@@ -0,0 +1,55 @@
+"""
+Add UUIDs to workflows
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+from galaxy.model.custom_types import UUIDType, TrimmedString
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData()
+
+
+
+"""
+Because both workflow and job requests can be determined
+based the a fixed data structure, their IDs are based on
+hashing the data structure
+"""
+workflow_uuid_column = Column( "uuid", UUIDType, nullable=True )
+
+
+def display_migration_details():
+ print "This migration script adds a UUID column to workflows"
+
+def upgrade(migrate_engine):
+ print __doc__
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Add the uuid colum to the workflow table
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid_column.create( workflow_table )
+ assert workflow_uuid_column is workflow_table.c.uuid
+ except Exception, e:
+ print str(e)
+ log.error( "Adding column 'uuid' to workflow table failed: %s" % str( e ) )
+ return
+
+def downgrade(migrate_engine):
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Drop the workflow table's uuid column.
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid = workflow_table.c.uuid
+ workflow_uuid.drop()
+ except Exception, e:
+ log.debug( "Dropping 'uuid' column from workflow table failed: %s" % ( str( e ) ) )
+
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1791,6 +1791,8 @@
data['format-version'] = "0.1"
data['name'] = workflow.name
data['annotation'] = annotation_str
+ if workflow.uuid is not None:
+ data['uuid'] = str(workflow.uuid)
data['steps'] = {}
# For each step, rebuild the form and encode the state
for step in workflow.steps:
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -4,8 +4,9 @@
from __future__ import absolute_import
+import uuid
import logging
-from sqlalchemy import desc, or_
+from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
from galaxy.managers import histories
@@ -432,11 +433,23 @@
return stored_workflow
def __get_stored_workflow( self, trans, workflow_id ):
- workflow_id = self.__decode_id( trans, workflow_id )
try:
+ workflow_id = self.__decode_id( trans, workflow_id )
query = trans.sa_session.query( trans.app.model.StoredWorkflow )
stored_workflow = query.get( workflow_id )
except Exception:
+ try:
+ #see if they have passed in the UUID for a workflow that is attached to a stored workflow
+ workflow_uuid = uuid.UUID(workflow_id)
+ stored_workflow = trans.sa_session.query(trans.app.model.StoredWorkflow).filter( and_(
+ trans.app.model.StoredWorkflow.latest_workflow_id == trans.app.model.Workflow.id,
+ trans.app.model.Workflow.uuid == workflow_uuid
+ )).first()
+ if stored_workflow is None:
+ raise exceptions.ObjectNotFound( "Workflow not found: %s" % workflow_id )
+ return stored_workflow
+ except:
+ pass #let the outer raise exception happen
raise exceptions.ObjectNotFound( "No such workflow found - invalid workflow identifier." )
if stored_workflow is None:
raise exceptions.ObjectNotFound( "No such workflow found." )
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e scripts/cleanup_datasets/populate_uuid.py
--- a/scripts/cleanup_datasets/populate_uuid.py
+++ b/scripts/cleanup_datasets/populate_uuid.py
@@ -33,6 +33,12 @@
row.uuid = uuid.uuid4()
print "Setting dataset:", row.id, " UUID to ", row.uuid
model.context.flush()
+
+ for row in model.context.query( model.Workflow ):
+ if row.uuid is None:
+ row.uuid = uuid.uuid4()
+ print "Setting Workflow:", row.id, " UUID to ", row.uuid
+ model.context.flush()
if __name__ == "__main__":
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
5 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/567d72ce3a8b/
Changeset: 567d72ce3a8b
User: dannon
Date: 2014-08-26 16:28:00
Summary: Merge 'recent jobs' view from PR466/467. Work in progress.
Affected #: 2 files
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 567d72ce3a8b4ab3d07e677692d04499bf4c4e36 lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -1089,6 +1089,11 @@
trans.app.model.Job.state == trans.app.model.Job.states.RUNNING,
trans.app.model.Job.state == trans.app.model.Job.states.UPLOAD ) ) ) \
.order_by( trans.app.model.Job.table.c.update_time.desc() )
+ recent_jobs = trans.sa_session.query( trans.app.model.Job ) \
+ .filter( and_( trans.app.model.Job.table.c.update_time > cutoff_time,
+ or_( trans.app.model.Job.state == trans.app.model.Job.states.ERROR,
+ trans.app.model.Job.state == trans.app.model.Job.states.OK) ) ) \
+ .order_by( trans.app.model.Job.table.c.update_time.desc() )
last_updated = {}
for job in jobs:
delta = datetime.utcnow() - job.update_time
@@ -1096,14 +1101,35 @@
last_updated[job.id] = '%s hours' % int( delta.seconds / 60 / 60 )
else:
last_updated[job.id] = '%s minutes' % int( delta.seconds / 60 )
+ finished = {}
+ for job in recent_jobs:
+ delta = datetime.utcnow() - job.update_time
+ if delta > timedelta( minutes=60 ):
+ finished[job.id] = '%s hours' % int( delta.seconds / 60 / 60 )
+ else:
+ finished[job.id] = '%s minutes' % int( delta.seconds / 60 )
return trans.fill_template( '/admin/jobs.mako',
jobs = jobs,
+ recent_jobs = recent_jobs,
last_updated = last_updated,
+ finished = finished,
cutoff = cutoff,
msg = msg,
status = status,
job_lock = job_lock)
+
+ @web.expose
+ @web.require_admin
+ def job_info( self, trans, jobid=None ):
+ job = None
+ if jobid is not None:
+ job = trans.sa_session.query( trans.app.model.Job ).get(jobid)
+ return trans.fill_template( '/webapps/reports/job_info.mako',
+ job=job,
+ message="<a href='jobs'>Back</a>" )
+
+
## ---- Utility methods -------------------------------------------------------
def get_user( trans, user_id ):
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 567d72ce3a8b4ab3d07e677692d04499bf4c4e36 templates/admin/jobs.mako
--- a/templates/admin/jobs.mako
+++ b/templates/admin/jobs.mako
@@ -109,6 +109,52 @@
<div class="infomessage">There are no unfinished jobs to show with current cutoff time.</div><p/>
%endif
+
+%if recent_jobs:
+ <p>
+ Recent Jobs: These jobs have completed
+ </p>
+ <table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr class="header">
+ <td>Job ID</td>
+ <td>User</td>
+ <td>Finished</td>
+ <td>Tool</td>
+ <td>State</td>
+ <td>Inputs</td>
+ <td>Command Line</td>
+ <td>Job Runner</td>
+ <td>PID/Cluster ID</td>
+ </tr>
+ %for job in recent_jobs:
+ <td><a href="${h.url_for( controller="admin", action="job_info" )}?jobid=${job.id}">${job.id}</a></td>
+ %if job.history and job.history.user:
+ <td>${job.history.user.email}</td>
+ %else:
+ <td>anonymous</td>
+ %endif
+ <td>${finished[job.id]} ago</td>
+ <td>${job.tool_id}</td>
+ <td>${job.state}</td>
+ <%
+ try:
+ inputs = ", ".join( [ '%s %s' % ( da.dataset.id, da.dataset.state ) for da in job.input_datasets ] )
+ except:
+ inputs = 'Unable to determine inputs'
+ %>
+ <td>${inputs}</td>
+ <td>${job.command_line}</td>
+ <td>${job.job_runner_name}</td>
+ <td>${job.job_runner_external_id}</td>
+ </tr>
+ %endfor
+ </table>
+ <p/>
+%else:
+ <div class="infomessage">There are no recently finished jobs to show with current cutoff time.</div>
+ <p/>
+%endif
+
<form name="jobs" action="${h.url_for(controller='admin', action='jobs')}" method="POST"><div class="toolForm"><div class="toolFormTitle">
https://bitbucket.org/galaxy/galaxy-central/commits/44fe3904feb4/
Changeset: 44fe3904feb4
User: dannon
Date: 2014-08-26 16:28:38
Summary: Remove extra p tag from jobs admin.
Affected #: 1 file
diff -r 567d72ce3a8b4ab3d07e677692d04499bf4c4e36 -r 44fe3904feb44dd465f79934f999bc5c3bf99cc7 templates/admin/jobs.mako
--- a/templates/admin/jobs.mako
+++ b/templates/admin/jobs.mako
@@ -33,9 +33,6 @@
report this error".
</p>
-
-<p/>
-
%if jobs:
<form name="jobs" action="${h.url_for(controller='admin', action='jobs')}" method="POST"><table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
https://bitbucket.org/galaxy/galaxy-central/commits/81e2b1d1984e/
Changeset: 81e2b1d1984e
User: dannon
Date: 2014-08-26 16:34:31
Summary: Fix (old) bug causing Jobs grid to display even when there were no jobs to show in it. Issue was 'jobs' (and the new recent_jobs) was actually a Query object and not an empty list of results, causing 'if jobs' to evaluate True regardless of whether or not there were jobs.
Affected #: 1 file
diff -r 44fe3904feb44dd465f79934f999bc5c3bf99cc7 -r 81e2b1d1984e8f4bcdd2d1f82055e815cbced985 lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -1088,12 +1088,12 @@
trans.app.model.Job.state == trans.app.model.Job.states.QUEUED,
trans.app.model.Job.state == trans.app.model.Job.states.RUNNING,
trans.app.model.Job.state == trans.app.model.Job.states.UPLOAD ) ) ) \
- .order_by( trans.app.model.Job.table.c.update_time.desc() )
+ .order_by( trans.app.model.Job.table.c.update_time.desc() ).all()
recent_jobs = trans.sa_session.query( trans.app.model.Job ) \
.filter( and_( trans.app.model.Job.table.c.update_time > cutoff_time,
or_( trans.app.model.Job.state == trans.app.model.Job.states.ERROR,
trans.app.model.Job.state == trans.app.model.Job.states.OK) ) ) \
- .order_by( trans.app.model.Job.table.c.update_time.desc() )
+ .order_by( trans.app.model.Job.table.c.update_time.desc() ).all()
last_updated = {}
for job in jobs:
delta = datetime.utcnow() - job.update_time
https://bitbucket.org/galaxy/galaxy-central/commits/314326446ec5/
Changeset: 314326446ec5
User: dannon
Date: 2014-08-26 16:48:12
Summary: Clarify wording, explain cutoff. Add headers to better segment the page and prevent confusion between the two grids.
Affected #: 1 file
diff -r 81e2b1d1984e8f4bcdd2d1f82055e815cbced985 -r 314326446ec51483341eaacae7902fff44c8ac02 templates/admin/jobs.mako
--- a/templates/admin/jobs.mako
+++ b/templates/admin/jobs.mako
@@ -22,9 +22,11 @@
%endif
<p>
- All unfinished jobs are displayed here. To display only jobs that have not
- had their job state updated recently, set a cutoff value in the 'cutoff'
- box below.
+ Unfinished and recently finished jobs are displayed on this page. The
+ 'cutoff' input box will do two things -- it will limit the display of
+ unfinished jobs to only those jobs that have not had their job state
+ updated recently, and it will limit the recently finished jobs list to only
+ displaying jobs that have finished since the cutoff.
</p><p>
If any jobs are displayed, you may choose to stop them. Your stop message
@@ -35,6 +37,9 @@
%if jobs:
<form name="jobs" action="${h.url_for(controller='admin', action='jobs')}" method="POST">
+ <h4>
+ Unfinished Jobs: These jobs are unfinished and have had their state updated in the previous ${cutoff} seconds.
+ </h4><table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%"><tr class="header"><td><input type="checkbox" onClick="toggle_all(this)"/></td>
@@ -108,9 +113,9 @@
%endif
%if recent_jobs:
- <p>
- Recent Jobs: These jobs have completed
- </p>
+ <h4>
+ Recent Jobs: These jobs have completed in the previous ${cutoff} seconds.
+ </h4><table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%"><tr class="header"><td>Job ID</td>
https://bitbucket.org/galaxy/galaxy-central/commits/3a51eaf209f2/
Changeset: 3a51eaf209f2
User: dannon
Date: 2014-08-26 16:48:35
Summary: Merge.
Affected #: 11 files
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -18,4 +18,4 @@
81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04
2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
-7e4d21621ce12e13ebbdf9fd3259df58c3ef124c latest_2014.08.11
+7e22f35798522100ff03e1fdd4eced962b292360 latest_2014.08.11
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -24,7 +24,7 @@
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 module_factory
+from galaxy.workflow.modules import module_factory, is_tool_module_type
from galaxy.workflow.run import invoke
from galaxy.workflow.run import WorkflowRunConfig
from galaxy.workflow.extract import summarize
@@ -836,8 +836,8 @@
steps_by_external_id = {}
errors = []
for key, step_dict in data['steps'].iteritems():
- is_input = step_dict[ 'type' ] in [ 'data_input', 'data_collection_input' ]
- if not is_input and step_dict['tool_id'] not in trans.app.toolbox.tools_by_id:
+ is_tool = is_tool_module_type( step_dict[ 'type' ] )
+ if is_tool and step_dict['tool_id'] not in trans.app.toolbox.tools_by_id:
errors.append("Step %s requires tool '%s'." % (step_dict['id'], step_dict['tool_id']))
if errors:
return dict( name=workflow.name,
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -71,9 +71,18 @@
## ---- Configuration time -----------------------------------------------
def get_state( self ):
+ """ Return a serializable representation of the persistable state of
+ the step - for tools it DefaultToolState.encode returns a string and
+ for inputs a json description is dumped out.
+ """
return None
def get_errors( self ):
+ """ It seems like this is effectively just used as boolean - some places
+ in the tool shed self.errors is set to boolean, other places 'unavailable',
+ likewise in Galaxy it stores a list containing a string with an unrecognized
+ tool id error message.
+ """
return None
def get_data_inputs( self ):
@@ -292,6 +301,9 @@
@classmethod
def new( Class, trans, tool_id=None ):
module = Class( trans, tool_id )
+ if module.tool is None:
+ error_message = "Attempted to create new workflow module for invalid tool_id, no tool with id - %s." % tool_id
+ raise Exception( error_message )
module.state = module.tool.new_state( trans, all_pages=True )
return module
@@ -536,5 +548,14 @@
type = step.type
return self.module_types[type].from_workflow_step( trans, step )
-module_types = dict( data_input=InputDataModule, data_collection_input=InputDataCollectionModule, tool=ToolModule )
+
+def is_tool_module_type( module_type ):
+ return not module_type or module_type == "tool"
+
+
+module_types = dict(
+ data_input=InputDataModule,
+ data_collection_input=InputDataCollectionModule,
+ tool=ToolModule,
+)
module_factory = WorkflowModuleFactory( module_types )
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -71,7 +71,7 @@
self.trans.sa_session.add( workflow_invocation )
# Not flushing in here, because web controller may create multiple
- # invokations.
+ # invocations.
return self.outputs
def _invoke_step( self, step ):
@@ -211,10 +211,9 @@
"""
replacement = None
if prefixed_name in step.input_connections_by_name:
- outputs = self.outputs
connection = step.input_connections_by_name[ prefixed_name ]
if input.multiple:
- replacement = [ outputs[ c.output_step.id ][ c.output_name ] for c in connection ]
+ replacement = [ self._replacement_for_connection( c ) for c in connection ]
# If replacement is just one dataset collection, replace tool
# input with dataset collection - tool framework will extract
# datasets properly.
@@ -222,9 +221,12 @@
if isinstance( replacement[ 0 ], model.HistoryDatasetCollectionAssociation ):
replacement = replacement[ 0 ]
else:
- replacement = outputs[ connection[ 0 ].output_step.id ][ connection[ 0 ].output_name ]
+ replacement = self._replacement_for_connection( connection[ 0 ] )
return replacement
+ def _replacement_for_connection( self, connection ):
+ return self.outputs[ connection.output_step.id ][ connection.output_name ]
+
def _populate_state( self ):
# Build the state for each step
for step in self.workflow.steps:
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea static/scripts/packed/viz/trackster/painters.js
--- a/static/scripts/packed/viz/trackster/painters.js
+++ b/static/scripts/packed/viz/trackster/painters.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(_){var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=_.extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};_.extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords,incomplete_features=[];for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};_.extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,rect_y+(draw_height-1)/2,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,draw_height=(mode==="Pack"?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;var line_height=y_start+1+(draw_height-1)/2;dashedLine(ctx,b1_end,line_height,b2_start,line_height)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};_.extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
+define(["libs/underscore"],function(_){var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=_.extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};_.extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords,incomplete_features=[];for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid].slot:null);if((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};_.extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,rect_y+(draw_height-1)/2,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,draw_height=(mode==="Pack"?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;var line_height=y_start+1+(draw_height-1)/2;dashedLine(ctx,b1_end,line_height,b2_start,line_height)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};_.extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea static/scripts/packed/viz/trackster/slotting.js
--- a/static/scripts/packed/viz/trackster/slotting.js
+++ b/static/scripts/packed/viz/trackster/slotting.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(b){var e=b.extend;var c=2,a=5;var d=function(i,h,f,g){this.slots={};this.start_end_dct={};this.w_scale=i;this.mode=h;this.include_label=(h==="Pack");this.max_rows=f;this.measureText=g};e(d.prototype,{slot_features:function(m){var p=this.w_scale,h=this.start_end_dct,x=[],z=[],n=0,y=this.max_rows;for(var v=0,w=m.length;v<w;v++){var k=m[v],o=k[0];if(this.slots[o]!==undefined){n=Math.max(n,this.slots[o]);z.push(this.slots[o])}else{x.push(v)}}var q=function(E,F){for(var D=0;D<=y;D++){var B=false,G=h[D];if(G!==undefined){for(var A=0,C=G.length;A<C;A++){var i=G[A];if(F>i[0]&&E<i[1]){B=true;break}}}if(!B){return D}}return -1};for(var v=0,w=x.length;v<w;v++){var k=m[x[v]],o=k[0],t=k[1],f=k[2],r=k[3],g=Math.floor(t*p),l=Math.ceil(f*p),u=this.measureText(r).width,j;if(r!==undefined&&this.include_label){u+=(c+a);if(g-u>=0){g-=u;j="left"}else{l+=u;j="right"}}var s=q(g,l);if(s>=0){if(h[s]===undefined){h[s]=[]}h[s].push([g,l]);this.slots[o]=s;n=Math.max(n,s)}}return n+1}});return{FeatureSlotter:d}});
\ No newline at end of file
+define(["libs/underscore"],function(c){var f=c.extend;var d=2,b=5;var a=function(h,g){this.slot=h;this.feature=g};var e=function(j,i,g,h){this.slots={};this.start_end_dct={};this.w_scale=j;this.mode=i;this.include_label=(i==="Pack");this.max_rows=g;this.measureText=h};f(e.prototype,{_get_draw_coords:function(j){var h=Math.floor(j[1]*this.w_scale),i=Math.ceil(j[2]*this.w_scale),g=j[3],k;if(g!==undefined&&this.include_label){var l=this.measureText(g).width+(d+b);if(h-l>=0){h-=l;k="left"}else{i+=l;k="right"}}return[h,i]},_find_slot:function(j){var o=j[0],n=j[1];for(var l=0;l<=this.max_rows;l++){var p=false,m=this.start_end_dct[l];if(m!==undefined){for(var g=0,h=m.length;g<h;g++){var i=m[g];if(n>i[0]&&o<i[1]){p=true;break}}}if(!p){return l}}return -1},slot_features:function(h){var q=this.start_end_dct,v=[],m=0,x,l;for(var o=0,t=h.length;o<t;o++){x=h[o];l=x[0];var g=this.slots[l];if(g){if(x[1]<g.feature[1]||g.feature[2]<x[2]){console.log(x[3],g.slot,this._find_slot(this._get_draw_coords(x)));var s=this._get_draw_coords(g.feature),p=this._get_draw_coords(x),j=this.start_end_dct[g.slot];for(var n=0;n<j.length;n++){var w=j[n];if(w[0]===s[0]&&w[1]===s[1]){j[n]=p}}}m=Math.max(m,this.slots[l].slot)}else{v.push(o)}}for(var o=0,t=v.length;o<t;o++){x=h[v[o]];l=x[0];var r=this._get_draw_coords(x);var u=this._find_slot(r);if(u>=0){if(q[u]===undefined){q[u]=[]}q[u].push(r);this.slots[l]=new a(u,x);m=Math.max(m,u)}}return m+1}});return{FeatureSlotter:e}});
\ No newline at end of file
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -396,7 +396,7 @@
feature_end = feature[2],
// Slot valid only if features are slotted and this feature is slotted;
// feature may not be due to lack of space.
- slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid] : null);
+ slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid].slot : null);
// Draw feature if (a) mode is dense or feature is slotted (as it must be for all non-dense modes) and
// (b) there's overlap between the feature and drawing region.
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea static/scripts/viz/trackster/slotting.js
--- a/static/scripts/viz/trackster/slotting.js
+++ b/static/scripts/viz/trackster/slotting.js
@@ -7,6 +7,14 @@
PACK_SPACING = 5;
/**
+ * Hold slotting information for a feature.
+ */
+var SlottedInfo = function(slot, feature) {
+ this.slot = slot;
+ this.feature = feature;
+};
+
+/**
* FeatureSlotter determines slots in which to draw features for vertical
* packing.
*
@@ -28,118 +36,148 @@
* the largest slot required for the passed set of features is returned
*/
extend( FeatureSlotter.prototype, {
+ /**
+ * Get drawing coordinate for a feature.
+ */
+ _get_draw_coords: function(feature) {
+ // Get initial draw coordinates using w_scale.
+ var draw_start = Math.floor(feature[1] * this.w_scale),
+ draw_end = Math.ceil(feature[2] * this.w_scale),
+ f_name = feature[3],
+ text_align;
+
+ // Update start, end drawing locations to include feature name.
+ // Try to put the name on the left, if not, put on right.
+ if (f_name !== undefined && this.include_label ) {
+ // Add gap for label spacing and extra pack space padding
+ // TODO: Fix constants
+ var text_len = this.measureText(f_name).width + (LABEL_SPACING + PACK_SPACING);
+ if (draw_start - text_len >= 0) {
+ draw_start -= text_len;
+ text_align = "left";
+ } else {
+ draw_end += text_len;
+ text_align = "right";
+ }
+ }
+
+ /*
+ if (slot_num < 0) {
+
+ TODO: this is not yet working --
+ console.log(feature_uid, "looking for slot with text on the right");
+ // Slot not found. If text was on left, try on right and see
+ // if slot can be found.
+ // TODO: are there any checks we need to do to ensure that text
+ // will fit on tile?
+ if (text_align === "left") {
+ draw_start -= text_len;
+ draw_end -= text_len;
+ text_align = "right";
+ slot_num = find_slot(draw_start, draw_end);
+ }
+ if (slot_num >= 0) {
+ console.log(feature_uid, "found slot with text on the right");
+ }
+
+ }
+ */
+
+ return [draw_start, draw_end];
+ },
+
+ /**
+ * Find the first slot such that current feature doesn't overlap any other features in that slot.
+ * Returns -1 if no slot was found.
+ */
+ _find_slot: function(draw_coords) {
+ // TODO: Use a data structure for faster searching of available slots.
+ var draw_start = draw_coords[0],
+ draw_end = draw_coords[1];
+ for (var slot_num = 0; slot_num <= this.max_rows; slot_num++) {
+ var has_overlap = false,
+ slot = this.start_end_dct[slot_num];
+ if (slot !== undefined) {
+ // Iterate through features already in slot to see if current feature will fit.
+ for (var k = 0, k_len = slot.length; k < k_len; k++) {
+ var s_e = slot[k];
+ if (draw_end > s_e[0] && draw_start < s_e[1]) {
+ // There is overlap
+ has_overlap = true;
+ break;
+ }
+ }
+ }
+ if (!has_overlap) {
+ return slot_num;
+ }
+ }
+ return -1;
+ },
+
+ /**
+ * Slot features.
+ */
slot_features: function( features ) {
- var w_scale = this.w_scale,
- start_end_dct = this.start_end_dct,
+ var start_end_dct = this.start_end_dct,
undone = [],
- slotted = [],
- highest_slot = 0,
- max_rows = this.max_rows;
-
- // If feature already exists in slots (from previously seen tiles), use the same slot,
- // otherwise if not seen, add to "undone" list for slot calculation.
-
- // TODO: Should calculate zoom tile index, which will improve performance
- // by only having to look at a smaller subset
- // if (this.start_end_dct[0] === undefined) { this.start_end_dct[0] = []; }
+ highest_slot = 0,
+ feature,
+ feature_uid;
+
+ // Loop through features to (a) find those that are not yet slotted and (b) update
+ // those that are slotted if new information is availabe. For (a), features already
+ // slotted (based on slotting from other tiles) will retain their current slot.
for (var i = 0, len = features.length; i < len; i++) {
- var feature = features[i],
- feature_uid = feature[0];
- if (this.slots[feature_uid] !== undefined) {
- highest_slot = Math.max(highest_slot, this.slots[feature_uid]);
- slotted.push(this.slots[feature_uid]);
- } else {
+ feature = features[i];
+ feature_uid = feature[0];
+ var slotted_info = this.slots[feature_uid];
+
+ // Separate and handle slotted vs. unslotted features.
+ if (slotted_info) {
+ // Feature is slotted; if feature now has larger start/end coordinates,
+ // update drawing coordinates.
+ if (feature[1] < slotted_info.feature[1] || slotted_info.feature[2] < feature[2]) {
+ console.log(feature[3], slotted_info.slot, this._find_slot(this._get_draw_coords(feature)));
+ // Feature has changed (e.g. a single read now has its pair), so recalculate its
+ // drawing coordinates.
+ var old_draw_coords = this._get_draw_coords(slotted_info.feature),
+ new_draw_coords = this._get_draw_coords(feature),
+ slotted_coords = this.start_end_dct[slotted_info.slot];
+ for (var k = 0; k < slotted_coords.length; k++) {
+ var dc = slotted_coords[k];
+ if (dc[0] === old_draw_coords[0] && dc[1] === old_draw_coords[1]) {
+ // Replace old drawing coordinates with new ones.
+ slotted_coords[k] = new_draw_coords;
+ }
+ }
+ }
+ highest_slot = Math.max(highest_slot, this.slots[feature_uid].slot);
+ }
+ else {
undone.push(i);
}
}
-
+
// Slot unslotted features.
- // Find the first slot such that current feature doesn't overlap any other features in that slot.
- // Returns -1 if no slot was found.
- var find_slot = function(f_start, f_end) {
- // TODO: Fix constants
- for (var slot_num = 0; slot_num <= max_rows; slot_num++) {
- var has_overlap = false,
- slot = start_end_dct[slot_num];
- if (slot !== undefined) {
- // Iterate through features already in slot to see if current feature will fit.
- for (var k = 0, k_len = slot.length; k < k_len; k++) {
- var s_e = slot[k];
- if (f_end > s_e[0] && f_start < s_e[1]) {
- // There is overlap
- has_overlap = true;
- break;
- }
- }
- }
- if (!has_overlap) {
- return slot_num;
- }
- }
- return -1;
- };
-
// Do slotting.
for (var i = 0, len = undone.length; i < len; i++) {
- var feature = features[undone[i]],
- feature_uid = feature[0],
- feature_start = feature[1],
- feature_end = feature[2],
- feature_name = feature[3],
- // Where to start, end drawing on screen.
- f_start = Math.floor( feature_start * w_scale ),
- f_end = Math.ceil( feature_end * w_scale ),
- text_len = this.measureText(feature_name).width,
- text_align;
-
- // Update start, end drawing locations to include feature name.
- // Try to put the name on the left, if not, put on right.
- if (feature_name !== undefined && this.include_label ) {
- // Add gap for label spacing and extra pack space padding
- // TODO: Fix constants
- text_len += (LABEL_SPACING + PACK_SPACING);
- if (f_start - text_len >= 0) {
- f_start -= text_len;
- text_align = "left";
- } else {
- f_end += text_len;
- text_align = "right";
- }
- }
+ feature = features[undone[i]];
+ feature_uid = feature[0];
+ var draw_coords = this._get_draw_coords(feature);
// Find slot.
- var slot_num = find_slot(f_start, f_end);
+ var slot_num = this._find_slot(draw_coords);
- /*
- if (slot_num < 0) {
-
- TODO: this is not yet working --
- console.log(feature_uid, "looking for slot with text on the right");
- // Slot not found. If text was on left, try on right and see
- // if slot can be found.
- // TODO: are there any checks we need to do to ensure that text
- // will fit on tile?
- if (text_align === "left") {
- f_start -= text_len;
- f_end -= text_len;
- text_align = "right";
- slot_num = find_slot(f_start, f_end);
- }
- if (slot_num >= 0) {
- console.log(feature_uid, "found slot with text on the right");
- }
-
- }
- */
// Do slotting.
if (slot_num >= 0) {
// Add current feature to slot.
if (start_end_dct[slot_num] === undefined) {
start_end_dct[slot_num] = [];
}
- start_end_dct[slot_num].push([f_start, f_end]);
- this.slots[feature_uid] = slot_num;
+ start_end_dct[slot_num].push(draw_coords);
+ this.slots[feature_uid] = new SlottedInfo(slot_num, feature);
highest_slot = Math.max(highest_slot, slot_num);
}
}
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea test/unit/workflows/test_modules.py
--- /dev/null
+++ b/test/unit/workflows/test_modules.py
@@ -0,0 +1,39 @@
+from galaxy import eggs
+eggs.require( "mock" )
+
+
+import mock
+
+from galaxy.workflow import modules
+from .workflow_support import MockTrans
+
+
+def test_input_has_no_errors():
+ trans = MockTrans()
+ input_step_module = modules.module_factory.new( trans, 'data_input' )
+ assert not input_step_module.get_errors()
+
+
+def test_valid_new_tool_has_no_errors():
+ trans = MockTrans()
+ mock_tool = mock.Mock()
+ trans.app.toolbox.tools[ "cat1" ] = mock_tool
+ tool_module = modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ assert not tool_module.get_errors()
+
+
+def test_missing_tool_has_errors():
+ trans = MockTrans()
+ tool_dict = { "type": "tool", "tool_id": "cat1" }
+ tool_module = modules.module_factory.from_dict( trans, tool_dict )
+ assert tool_module.get_errors()
+
+
+def test_cannot_create_tool_modules_for_missing_tools():
+ trans = MockTrans()
+ exception = False
+ try:
+ modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ except Exception:
+ exception = True
+ assert exception
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea test/unit/workflows/workflow_support.py
--- a/test/unit/workflows/workflow_support.py
+++ b/test/unit/workflows/workflow_support.py
@@ -17,3 +17,14 @@
"sqlite:///:memory:",
create_tables=True
)
+ self.toolbox = TestToolbox()
+
+
+class TestToolbox( object ):
+
+ def __init__( self ):
+ self.tools = {}
+
+ def get_tool( self, tool_id ):
+ # Real tool box returns None of missing tool also
+ return self.tools.get( tool_id, None )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/94e8e0d8bb6c/
Changeset: 94e8e0d8bb6c
User: jmchilton
Date: 2014-08-26 16:02:49
Summary: Doc spelling fix in lib/galaxy/workflow/run.py.
Affected #: 1 file
diff -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a -r 94e8e0d8bb6c2d9d4a941ba5706a057570f25741 lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -71,7 +71,7 @@
self.trans.sa_session.add( workflow_invocation )
# Not flushing in here, because web controller may create multiple
- # invokations.
+ # invocations.
return self.outputs
def _invoke_step( self, step ):
https://bitbucket.org/galaxy/galaxy-central/commits/d15f9a1b4782/
Changeset: d15f9a1b4782
User: jmchilton
Date: 2014-08-26 16:02:49
Summary: Some very basic unit tests and docs for workflow modules.
Just a start - I need to keep going with this and test and document all methods.
Affected #: 3 files
diff -r 94e8e0d8bb6c2d9d4a941ba5706a057570f25741 -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -71,9 +71,18 @@
## ---- Configuration time -----------------------------------------------
def get_state( self ):
+ """ Return a serializable representation of the persistable state of
+ the step - for tools it DefaultToolState.encode returns a string and
+ for inputs a json description is dumped out.
+ """
return None
def get_errors( self ):
+ """ It seems like this is effectively just used as boolean - some places
+ in the tool shed self.errors is set to boolean, other places 'unavailable',
+ likewise in Galaxy it stores a list containing a string with an unrecognized
+ tool id error message.
+ """
return None
def get_data_inputs( self ):
@@ -292,6 +301,9 @@
@classmethod
def new( Class, trans, tool_id=None ):
module = Class( trans, tool_id )
+ if module.tool is None:
+ error_message = "Attempted to create new workflow module for invalid tool_id, no tool with id - %s." % tool_id
+ raise Exception( error_message )
module.state = module.tool.new_state( trans, all_pages=True )
return module
diff -r 94e8e0d8bb6c2d9d4a941ba5706a057570f25741 -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec test/unit/workflows/test_modules.py
--- /dev/null
+++ b/test/unit/workflows/test_modules.py
@@ -0,0 +1,39 @@
+from galaxy import eggs
+eggs.require( "mock" )
+
+
+import mock
+
+from galaxy.workflow import modules
+from .workflow_support import MockTrans
+
+
+def test_input_has_no_errors():
+ trans = MockTrans()
+ input_step_module = modules.module_factory.new( trans, 'data_input' )
+ assert not input_step_module.get_errors()
+
+
+def test_valid_new_tool_has_no_errors():
+ trans = MockTrans()
+ mock_tool = mock.Mock()
+ trans.app.toolbox.tools[ "cat1" ] = mock_tool
+ tool_module = modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ assert not tool_module.get_errors()
+
+
+def test_missing_tool_has_errors():
+ trans = MockTrans()
+ tool_dict = { "type": "tool", "tool_id": "cat1" }
+ tool_module = modules.module_factory.from_dict( trans, tool_dict )
+ assert tool_module.get_errors()
+
+
+def test_cannot_create_tool_modules_for_missing_tools():
+ trans = MockTrans()
+ exception = False
+ try:
+ modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ except Exception:
+ exception = True
+ assert exception
diff -r 94e8e0d8bb6c2d9d4a941ba5706a057570f25741 -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec test/unit/workflows/workflow_support.py
--- a/test/unit/workflows/workflow_support.py
+++ b/test/unit/workflows/workflow_support.py
@@ -17,3 +17,14 @@
"sqlite:///:memory:",
create_tables=True
)
+ self.toolbox = TestToolbox()
+
+
+class TestToolbox( object ):
+
+ def __init__( self ):
+ self.tools = {}
+
+ def get_tool( self, tool_id ):
+ # Real tool box returns None of missing tool also
+ return self.tools.get( tool_id, None )
https://bitbucket.org/galaxy/galaxy-central/commits/abcccd35b958/
Changeset: abcccd35b958
User: jmchilton
Date: 2014-08-26 16:02:49
Summary: Couple simple refactors making it slightly cleaner to create new module types.
Also slightly reduces shared logic galaxy.workflow.run.
Affected #: 3 files
diff -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec -r abcccd35b958bbbf3ad97debe029b8c5452f5d32 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -24,7 +24,7 @@
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 module_factory
+from galaxy.workflow.modules import module_factory, is_tool_module_type
from galaxy.workflow.run import invoke
from galaxy.workflow.run import WorkflowRunConfig
from galaxy.workflow.extract import summarize
@@ -836,8 +836,8 @@
steps_by_external_id = {}
errors = []
for key, step_dict in data['steps'].iteritems():
- is_input = step_dict[ 'type' ] in [ 'data_input', 'data_collection_input' ]
- if not is_input and step_dict['tool_id'] not in trans.app.toolbox.tools_by_id:
+ is_tool = is_tool_module_type( step_dict[ 'type' ] )
+ if is_tool and step_dict['tool_id'] not in trans.app.toolbox.tools_by_id:
errors.append("Step %s requires tool '%s'." % (step_dict['id'], step_dict['tool_id']))
if errors:
return dict( name=workflow.name,
diff -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec -r abcccd35b958bbbf3ad97debe029b8c5452f5d32 lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -548,5 +548,14 @@
type = step.type
return self.module_types[type].from_workflow_step( trans, step )
-module_types = dict( data_input=InputDataModule, data_collection_input=InputDataCollectionModule, tool=ToolModule )
+
+def is_tool_module_type( module_type ):
+ return not module_type or module_type == "tool"
+
+
+module_types = dict(
+ data_input=InputDataModule,
+ data_collection_input=InputDataCollectionModule,
+ tool=ToolModule,
+)
module_factory = WorkflowModuleFactory( module_types )
diff -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec -r abcccd35b958bbbf3ad97debe029b8c5452f5d32 lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -211,10 +211,9 @@
"""
replacement = None
if prefixed_name in step.input_connections_by_name:
- outputs = self.outputs
connection = step.input_connections_by_name[ prefixed_name ]
if input.multiple:
- replacement = [ outputs[ c.output_step.id ][ c.output_name ] for c in connection ]
+ replacement = [ self._replacement_for_connection( c ) for c in connection ]
# If replacement is just one dataset collection, replace tool
# input with dataset collection - tool framework will extract
# datasets properly.
@@ -222,9 +221,12 @@
if isinstance( replacement[ 0 ], model.HistoryDatasetCollectionAssociation ):
replacement = replacement[ 0 ]
else:
- replacement = outputs[ connection[ 0 ].output_step.id ][ connection[ 0 ].output_name ]
+ replacement = self._replacement_for_connection( connection[ 0 ] )
return replacement
+ def _replacement_for_connection( self, connection ):
+ return self.outputs[ connection.output_step.id ][ connection.output_name ]
+
def _populate_state( self ):
# Build the state for each step
for step in self.workflow.steps:
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 9a4b43021fd1
by commits-noreply@bitbucket.org 26 Aug '14
by commits-noreply@bitbucket.org 26 Aug '14
26 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/51de5214e6f9/
Changeset: 51de5214e6f9
Branch: stable
User: natefoo
Date: 2014-08-26 15:00:14
Summary: Update tag latest_2014.08.11 for changeset 9a4b43021fd1
Affected #: 1 file
diff -r 9a4b43021fd1c5808c17329da7b6acbfd9ae27ed -r 51de5214e6f9e59b9bad5a05ae6a79d6e8944a9e .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -18,4 +18,4 @@
81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04
2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
-7e22f35798522100ff03e1fdd4eced962b292360 latest_2014.08.11
+9a4b43021fd1c5808c17329da7b6acbfd9ae27ed 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
25 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0dc11a77b3cd/
Changeset: 0dc11a77b3cd
User: jmchilton
Date: 2014-08-25 21:35:45
Summary: Merge latest stable.
Affected #: 6 files
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -18,4 +18,4 @@
81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04
2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
-7e4d21621ce12e13ebbdf9fd3259df58c3ef124c latest_2014.08.11
+7e22f35798522100ff03e1fdd4eced962b292360 latest_2014.08.11
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a static/scripts/packed/viz/trackster/painters.js
--- a/static/scripts/packed/viz/trackster/painters.js
+++ b/static/scripts/packed/viz/trackster/painters.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(_){var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=_.extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};_.extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords,incomplete_features=[];for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};_.extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,rect_y+(draw_height-1)/2,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,draw_height=(mode==="Pack"?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;var line_height=y_start+1+(draw_height-1)/2;dashedLine(ctx,b1_end,line_height,b2_start,line_height)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};_.extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
+define(["libs/underscore"],function(_){var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=_.extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};_.extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords,incomplete_features=[];for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid].slot:null);if((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};_.extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,rect_y+(draw_height-1)/2,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,draw_height=(mode==="Pack"?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;var line_height=y_start+1+(draw_height-1)/2;dashedLine(ctx,b1_end,line_height,b2_start,line_height)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};_.extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a static/scripts/packed/viz/trackster/slotting.js
--- a/static/scripts/packed/viz/trackster/slotting.js
+++ b/static/scripts/packed/viz/trackster/slotting.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(b){var e=b.extend;var c=2,a=5;var d=function(i,h,f,g){this.slots={};this.start_end_dct={};this.w_scale=i;this.mode=h;this.include_label=(h==="Pack");this.max_rows=f;this.measureText=g};e(d.prototype,{slot_features:function(m){var p=this.w_scale,h=this.start_end_dct,x=[],z=[],n=0,y=this.max_rows;for(var v=0,w=m.length;v<w;v++){var k=m[v],o=k[0];if(this.slots[o]!==undefined){n=Math.max(n,this.slots[o]);z.push(this.slots[o])}else{x.push(v)}}var q=function(E,F){for(var D=0;D<=y;D++){var B=false,G=h[D];if(G!==undefined){for(var A=0,C=G.length;A<C;A++){var i=G[A];if(F>i[0]&&E<i[1]){B=true;break}}}if(!B){return D}}return -1};for(var v=0,w=x.length;v<w;v++){var k=m[x[v]],o=k[0],t=k[1],f=k[2],r=k[3],g=Math.floor(t*p),l=Math.ceil(f*p),u=this.measureText(r).width,j;if(r!==undefined&&this.include_label){u+=(c+a);if(g-u>=0){g-=u;j="left"}else{l+=u;j="right"}}var s=q(g,l);if(s>=0){if(h[s]===undefined){h[s]=[]}h[s].push([g,l]);this.slots[o]=s;n=Math.max(n,s)}}return n+1}});return{FeatureSlotter:d}});
\ No newline at end of file
+define(["libs/underscore"],function(c){var f=c.extend;var d=2,b=5;var a=function(h,g){this.slot=h;this.feature=g};var e=function(j,i,g,h){this.slots={};this.start_end_dct={};this.w_scale=j;this.mode=i;this.include_label=(i==="Pack");this.max_rows=g;this.measureText=h};f(e.prototype,{_get_draw_coords:function(j){var h=Math.floor(j[1]*this.w_scale),i=Math.ceil(j[2]*this.w_scale),g=j[3],k;if(g!==undefined&&this.include_label){var l=this.measureText(g).width+(d+b);if(h-l>=0){h-=l;k="left"}else{i+=l;k="right"}}return[h,i]},_find_slot:function(j){var o=j[0],n=j[1];for(var l=0;l<=this.max_rows;l++){var p=false,m=this.start_end_dct[l];if(m!==undefined){for(var g=0,h=m.length;g<h;g++){var i=m[g];if(n>i[0]&&o<i[1]){p=true;break}}}if(!p){return l}}return -1},slot_features:function(h){var q=this.start_end_dct,v=[],m=0,x,l;for(var o=0,t=h.length;o<t;o++){x=h[o];l=x[0];var g=this.slots[l];if(g){if(x[1]<g.feature[1]||g.feature[2]<x[2]){console.log(x[3],g.slot,this._find_slot(this._get_draw_coords(x)));var s=this._get_draw_coords(g.feature),p=this._get_draw_coords(x),j=this.start_end_dct[g.slot];for(var n=0;n<j.length;n++){var w=j[n];if(w[0]===s[0]&&w[1]===s[1]){j[n]=p}}}m=Math.max(m,this.slots[l].slot)}else{v.push(o)}}for(var o=0,t=v.length;o<t;o++){x=h[v[o]];l=x[0];var r=this._get_draw_coords(x);var u=this._find_slot(r);if(u>=0){if(q[u]===undefined){q[u]=[]}q[u].push(r);this.slots[l]=new a(u,x);m=Math.max(m,u)}}return m+1}});return{FeatureSlotter:e}});
\ No newline at end of file
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -396,7 +396,7 @@
feature_end = feature[2],
// Slot valid only if features are slotted and this feature is slotted;
// feature may not be due to lack of space.
- slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid] : null);
+ slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid].slot : null);
// Draw feature if (a) mode is dense or feature is slotted (as it must be for all non-dense modes) and
// (b) there's overlap between the feature and drawing region.
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a static/scripts/viz/trackster/slotting.js
--- a/static/scripts/viz/trackster/slotting.js
+++ b/static/scripts/viz/trackster/slotting.js
@@ -7,6 +7,14 @@
PACK_SPACING = 5;
/**
+ * Hold slotting information for a feature.
+ */
+var SlottedInfo = function(slot, feature) {
+ this.slot = slot;
+ this.feature = feature;
+};
+
+/**
* FeatureSlotter determines slots in which to draw features for vertical
* packing.
*
@@ -28,118 +36,148 @@
* the largest slot required for the passed set of features is returned
*/
extend( FeatureSlotter.prototype, {
+ /**
+ * Get drawing coordinate for a feature.
+ */
+ _get_draw_coords: function(feature) {
+ // Get initial draw coordinates using w_scale.
+ var draw_start = Math.floor(feature[1] * this.w_scale),
+ draw_end = Math.ceil(feature[2] * this.w_scale),
+ f_name = feature[3],
+ text_align;
+
+ // Update start, end drawing locations to include feature name.
+ // Try to put the name on the left, if not, put on right.
+ if (f_name !== undefined && this.include_label ) {
+ // Add gap for label spacing and extra pack space padding
+ // TODO: Fix constants
+ var text_len = this.measureText(f_name).width + (LABEL_SPACING + PACK_SPACING);
+ if (draw_start - text_len >= 0) {
+ draw_start -= text_len;
+ text_align = "left";
+ } else {
+ draw_end += text_len;
+ text_align = "right";
+ }
+ }
+
+ /*
+ if (slot_num < 0) {
+
+ TODO: this is not yet working --
+ console.log(feature_uid, "looking for slot with text on the right");
+ // Slot not found. If text was on left, try on right and see
+ // if slot can be found.
+ // TODO: are there any checks we need to do to ensure that text
+ // will fit on tile?
+ if (text_align === "left") {
+ draw_start -= text_len;
+ draw_end -= text_len;
+ text_align = "right";
+ slot_num = find_slot(draw_start, draw_end);
+ }
+ if (slot_num >= 0) {
+ console.log(feature_uid, "found slot with text on the right");
+ }
+
+ }
+ */
+
+ return [draw_start, draw_end];
+ },
+
+ /**
+ * Find the first slot such that current feature doesn't overlap any other features in that slot.
+ * Returns -1 if no slot was found.
+ */
+ _find_slot: function(draw_coords) {
+ // TODO: Use a data structure for faster searching of available slots.
+ var draw_start = draw_coords[0],
+ draw_end = draw_coords[1];
+ for (var slot_num = 0; slot_num <= this.max_rows; slot_num++) {
+ var has_overlap = false,
+ slot = this.start_end_dct[slot_num];
+ if (slot !== undefined) {
+ // Iterate through features already in slot to see if current feature will fit.
+ for (var k = 0, k_len = slot.length; k < k_len; k++) {
+ var s_e = slot[k];
+ if (draw_end > s_e[0] && draw_start < s_e[1]) {
+ // There is overlap
+ has_overlap = true;
+ break;
+ }
+ }
+ }
+ if (!has_overlap) {
+ return slot_num;
+ }
+ }
+ return -1;
+ },
+
+ /**
+ * Slot features.
+ */
slot_features: function( features ) {
- var w_scale = this.w_scale,
- start_end_dct = this.start_end_dct,
+ var start_end_dct = this.start_end_dct,
undone = [],
- slotted = [],
- highest_slot = 0,
- max_rows = this.max_rows;
-
- // If feature already exists in slots (from previously seen tiles), use the same slot,
- // otherwise if not seen, add to "undone" list for slot calculation.
-
- // TODO: Should calculate zoom tile index, which will improve performance
- // by only having to look at a smaller subset
- // if (this.start_end_dct[0] === undefined) { this.start_end_dct[0] = []; }
+ highest_slot = 0,
+ feature,
+ feature_uid;
+
+ // Loop through features to (a) find those that are not yet slotted and (b) update
+ // those that are slotted if new information is availabe. For (a), features already
+ // slotted (based on slotting from other tiles) will retain their current slot.
for (var i = 0, len = features.length; i < len; i++) {
- var feature = features[i],
- feature_uid = feature[0];
- if (this.slots[feature_uid] !== undefined) {
- highest_slot = Math.max(highest_slot, this.slots[feature_uid]);
- slotted.push(this.slots[feature_uid]);
- } else {
+ feature = features[i];
+ feature_uid = feature[0];
+ var slotted_info = this.slots[feature_uid];
+
+ // Separate and handle slotted vs. unslotted features.
+ if (slotted_info) {
+ // Feature is slotted; if feature now has larger start/end coordinates,
+ // update drawing coordinates.
+ if (feature[1] < slotted_info.feature[1] || slotted_info.feature[2] < feature[2]) {
+ console.log(feature[3], slotted_info.slot, this._find_slot(this._get_draw_coords(feature)));
+ // Feature has changed (e.g. a single read now has its pair), so recalculate its
+ // drawing coordinates.
+ var old_draw_coords = this._get_draw_coords(slotted_info.feature),
+ new_draw_coords = this._get_draw_coords(feature),
+ slotted_coords = this.start_end_dct[slotted_info.slot];
+ for (var k = 0; k < slotted_coords.length; k++) {
+ var dc = slotted_coords[k];
+ if (dc[0] === old_draw_coords[0] && dc[1] === old_draw_coords[1]) {
+ // Replace old drawing coordinates with new ones.
+ slotted_coords[k] = new_draw_coords;
+ }
+ }
+ }
+ highest_slot = Math.max(highest_slot, this.slots[feature_uid].slot);
+ }
+ else {
undone.push(i);
}
}
-
+
// Slot unslotted features.
- // Find the first slot such that current feature doesn't overlap any other features in that slot.
- // Returns -1 if no slot was found.
- var find_slot = function(f_start, f_end) {
- // TODO: Fix constants
- for (var slot_num = 0; slot_num <= max_rows; slot_num++) {
- var has_overlap = false,
- slot = start_end_dct[slot_num];
- if (slot !== undefined) {
- // Iterate through features already in slot to see if current feature will fit.
- for (var k = 0, k_len = slot.length; k < k_len; k++) {
- var s_e = slot[k];
- if (f_end > s_e[0] && f_start < s_e[1]) {
- // There is overlap
- has_overlap = true;
- break;
- }
- }
- }
- if (!has_overlap) {
- return slot_num;
- }
- }
- return -1;
- };
-
// Do slotting.
for (var i = 0, len = undone.length; i < len; i++) {
- var feature = features[undone[i]],
- feature_uid = feature[0],
- feature_start = feature[1],
- feature_end = feature[2],
- feature_name = feature[3],
- // Where to start, end drawing on screen.
- f_start = Math.floor( feature_start * w_scale ),
- f_end = Math.ceil( feature_end * w_scale ),
- text_len = this.measureText(feature_name).width,
- text_align;
-
- // Update start, end drawing locations to include feature name.
- // Try to put the name on the left, if not, put on right.
- if (feature_name !== undefined && this.include_label ) {
- // Add gap for label spacing and extra pack space padding
- // TODO: Fix constants
- text_len += (LABEL_SPACING + PACK_SPACING);
- if (f_start - text_len >= 0) {
- f_start -= text_len;
- text_align = "left";
- } else {
- f_end += text_len;
- text_align = "right";
- }
- }
+ feature = features[undone[i]];
+ feature_uid = feature[0];
+ var draw_coords = this._get_draw_coords(feature);
// Find slot.
- var slot_num = find_slot(f_start, f_end);
+ var slot_num = this._find_slot(draw_coords);
- /*
- if (slot_num < 0) {
-
- TODO: this is not yet working --
- console.log(feature_uid, "looking for slot with text on the right");
- // Slot not found. If text was on left, try on right and see
- // if slot can be found.
- // TODO: are there any checks we need to do to ensure that text
- // will fit on tile?
- if (text_align === "left") {
- f_start -= text_len;
- f_end -= text_len;
- text_align = "right";
- slot_num = find_slot(f_start, f_end);
- }
- if (slot_num >= 0) {
- console.log(feature_uid, "found slot with text on the right");
- }
-
- }
- */
// Do slotting.
if (slot_num >= 0) {
// Add current feature to slot.
if (start_end_dct[slot_num] === undefined) {
start_end_dct[slot_num] = [];
}
- start_end_dct[slot_num].push([f_start, f_end]);
- this.slots[feature_uid] = slot_num;
+ start_end_dct[slot_num].push(draw_coords);
+ this.slots[feature_uid] = new SlottedInfo(slot_num, feature);
highest_slot = Math.max(highest_slot, slot_num);
}
}
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: Bugfix for 0750859: Don't generate duplicate workflow slugs for private workflows.
by commits-noreply@bitbucket.org 25 Aug '14
by commits-noreply@bitbucket.org 25 Aug '14
25 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9a4b43021fd1/
Changeset: 9a4b43021fd1
Branch: stable
User: jmchilton
Date: 2014-08-25 18:36:34
Summary: Bugfix for 0750859: Don't generate duplicate workflow slugs for private workflows.
See full conversation on https://bitbucket.org/galaxy/galaxy-central/commits/07508592cb65845474b9f3e….
Would like to better and allow slugs of deleted items to be reused - they cannot be for workflows for instance. Because the slugs are not really handled uniformly though - pages do not have this problem and deleted pages can have their slugs reused because this is included in a check in the web controller which directly assigns valid slugs at that point. Slugs for deleted histories cannot be re-used - but they couldn't be prior to this commit - so this isn't making things worse in that respect.
Affected #: 1 file
diff -r d86834553f0e2d3636b3f545f61ae3250ead31e9 -r 9a4b43021fd1c5808c17329da7b6acbfd9ae27ed lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -27,7 +27,7 @@
from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea, TextField
from galaxy.web.form_builder import build_select_field, HistoryField, PasswordField, WorkflowField, WorkflowMappingField
from galaxy.workflow.modules import module_factory
-from galaxy.model.orm import eagerload, eagerload_all, desc
+from galaxy.model.orm import eagerload, eagerload_all, desc, not_
from galaxy.security.validate_user_input import validate_publicname
from galaxy.util.sanitize_html import sanitize_html
from galaxy.model.item_attrs import Dictifiable, UsesAnnotations
@@ -2694,7 +2694,7 @@
item = self.get_item( trans, id )
if item:
# Only update slug if slug is not already in use.
- if trans.sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug, importable=True ).count() == 0:
+ if trans.sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug ).count() == 0:
item.slug = new_slug
trans.sa_session.flush()
@@ -2729,7 +2729,9 @@
# add integer to end.
new_slug = slug_base
count = 1
- while sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug, importable=True ).count() != 0:
+ # Ensure unique across model class and user and don't include this item
+ # in the check in case it has previously been assigned a valid slug.
+ while sa_session.query( item.__class__ ).filter( item.__class__.user == item.user, item.__class__.slug == new_slug, item.__class__.id != item.id).count() != 0:
# Slug taken; choose a new slug based on count. This approach can
# handle numerous items with the same name gracefully.
new_slug = '%s-%i' % ( slug_base, count )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: ToolForm: Add repeat blocks, refactor conditionals, fix styles, pack scripts
by commits-noreply@bitbucket.org 25 Aug '14
by commits-noreply@bitbucket.org 25 Aug '14
25 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c665ed80227c/
Changeset: c665ed80227c
User: guerler
Date: 2014-08-25 18:27:18
Summary: ToolForm: Add repeat blocks, refactor conditionals, fix styles, pack scripts
Affected #: 11 files
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/mvc/tools/tools-form.js
--- a/static/scripts/mvc/tools/tools-form.js
+++ b/static/scripts/mvc/tools/tools-form.js
@@ -1,8 +1,8 @@
-define(['mvc/ui/ui-portlet', 'mvc/ui/ui-table', 'mvc/ui/ui-misc',
+define(['mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
'mvc/citation/citation-model', 'mvc/citation/citation-view',
- 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-datasets'],
- function(Portlet, Table, Ui, CitationModel, CitationView,
- Tools, ToolTemplate, ToolDatasets) {
+ 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-datasets', 'mvc/tools/tools-section'],
+ function(Portlet, Ui, CitationModel, CitationView,
+ Tools, ToolTemplate, ToolDatasets, ToolSection) {
// create tool model
var Model = Backbone.Model.extend({
@@ -39,9 +39,19 @@
// initialize tool form
_initializeToolForm: function() {
+
+ // reset field list
+ this.field_list = {};
+
+ // reset sequential input definition list
+ this.inputs_sequential = {};
+
// fetch model and render form
var self = this;
this.model.fetch({
+ error: function(response) {
+ console.debug('tools-form::_initializeToolForm() : Attempt to fetch tool model failed.');
+ },
success: function() {
// inputs
self.inputs = self.model.get('inputs');
@@ -62,9 +72,6 @@
}
});
- // create table
- self.table = new Table.View();
-
// create message
self.message = new Ui.Message();
self.portlet.append(self.message.$el);
@@ -92,380 +99,14 @@
// configure portlet and form table
self.setElement(self.portlet.content());
- self.portlet.append(self.table.$el);
- self.render();
- }
- });
- },
-
- // update
- render: function() {
- // reset table
- this.table.delAll();
-
- // reset field list
- this.field_list = {};
-
- // reset sequential input definition list
- this.inputs_sequential = {};
-
- // model
- var data = new Backbone.Model();
-
- // load settings elements into table
- for (var id in this.inputs) {
- this._add(this.inputs[id], data);
- }
-
- // trigger change
- for (var id in this.field_list) {
- this.field_list[id].trigger('change');
- }
- },
-
- // add table row
- _add: function(inputs_def, data) {
- // identify field type
- var type = inputs_def.type;
- switch(type) {
- // conditional field
- case 'conditional':
- // add label to input definition root
- inputs_def.label = inputs_def.test_param.label;
-
- // add id to input definition root
- inputs_def.name = inputs_def.test_param.name;
-
- // build options field
- this._addRow('conditional', inputs_def, data);
- // add fields
- for (var i in inputs_def.cases) {
- var cases = inputs_def.cases[i];
- for (var j in cases.inputs) {
- // add element to form
- this._add(cases.inputs[j], data);
- }
- }
- break;
-
- // default single element row
- default:
- this._addRow(type, inputs_def, data);
- }
- },
-
- // add table row
- _addRow: function(field_type, inputs_def, data) {
- // get id
- var id = inputs_def.name;
-
- // field wrapper
- var field = null;
-
- // identify field type
- switch(field_type) {
- // text input field
- case 'text' :
- field = this._field_text(inputs_def, data);
- break;
-
- // select field
- case 'select' :
- field = this._field_select(inputs_def, data);
- break;
-
- // radiobox field
- case 'radiobutton' :
- field = this._field_radio(inputs_def, data);
- break;
-
- // dataset
- case 'data':
- field = this._field_data(inputs_def, data);
- break;
-
- // dataset column
- case 'data_column':
- field = this._field_column(inputs_def, data);
- break;
-
- // text area field
- case 'textarea' :
- field = this._field_textarea(inputs_def, data);
- break;
-
- // conditional select field
- case 'conditional':
- field = this._field_conditional(inputs_def, data);
- break;
- }
-
- // check if field type was detected
- if (!field) {
- console.debug('tools-form::_addRow() : Unmatched field type (' + field_type + ').');
- return;
- }
-
- // set value
- if (!data.get(id)) {
- data.set(id, inputs_def.value);
- }
- field.value(data.get(id));
-
- // add to field list
- this.field_list[id] = field;
-
- // add to input definition into sequential list
- this.inputs_sequential[id] = inputs_def;
-
- // combine field and info
- var $input = $('<div/>');
- $input.append(field.$el);
- if (inputs_def.info) {
- $input.append('<div class="ui-table-form-info">' + inputs_def.info + '</div>');
- }
-
- // add row to table
- this.table.add('<span class="ui-table-form-title">' + inputs_def.label + '</span>', '25%');
- this.table.add($input);
-
- // add to table
- this.table.append(id);
-
- // show/hide
- if (inputs_def.hide) {
- this.table.get(id).hide();
- }
- },
-
- // text input field
- _field_text : function(inputs_def, data) {
- var id = inputs_def.name;
- return new Ui.Input({
- id : 'field-' + id,
- value : data.get(id),
- onchange : function(value) {
- data.set(id, value);
- }
- });
- },
-
- // text area
- _field_textarea : function(inputs_def, data) {
- var id = inputs_def.name;
- return new Ui.Textarea({
- id : 'field-' + id,
- onchange : function() {
- data.set(id, field.value());
- }
- });
- },
-
- // conditional input field
- _field_conditional : function(inputs_def, data) {
- // link this
- var self = this;
-
- // configure options fields
- var options = [];
- for (var i in inputs_def.test_param.options) {
- var option = inputs_def.test_param.options[i];
- options.push({
- label: option[0],
- value: option[1]
- });
- }
-
- // select field
- var id = inputs_def.name;
- return new Ui.Select.View({
- id : 'field-' + id,
- data : options,
- value : data.get(id),
- onchange : function(value) {
- // update value
- data.set(id, value);
-
- // recursively hide/show options
- function _updateVisibility(root, show) {
- // loop through all inputs
- for (var i in root.inputs) {
- // get input element
- var element = root.inputs[i];
-
- // identify element name
- var element_id = element.name;
-
- // identify row
- var element_row = self.table.get(element_id);
-
- // show/hide row
- if (show) {
- element_row.fadeIn();
- } else {
- element_row.hide();
- }
-
- // check if its a nested conditional
- if (element.type == 'conditional') {
- // identify all cases
- for (var j in element.cases) {
- _updateVisibility(element.cases[j], show);
- }
- }
- }
- }
-
- // check value in order to hide/show options
- for (var i in inputs_def.cases) {
- var case_def = inputs_def.cases[i];
- _updateVisibility(case_def, case_def.value == value);
- }
- }
- });
- },
-
- // data input field
- _field_data : function(inputs_def, data) {
- // link this
- var self = this;
-
- // get element id
- var id = inputs_def.name;
-
- // get datasets
- var datasets = this.datasets.filterType();
-
- // configure options fields
- var options = [];
- for (var i in datasets) {
- options.push({
- label: datasets[i].get('name'),
- value: datasets[i].get('id')
- });
- }
-
- // select field
- return new Ui.Select.View({
- id : 'field-' + id,
- data : options,
- value : options[0].value,
- onchange : function(value) {
- // update value
- data.set(id, value);
-
- // find referenced columns
- var column_list = _.where(self.inputs_sequential, {
- data_ref : id,
- type : 'data_column'
+ // create tool form section
+ self.section = new ToolSection.View(self, {
+ inputs : self.model.get('inputs')
});
- // find selected dataset
- var dataset = self.datasets.filter(value);
-
- // check dataset
- if (dataset && column_list.length > 0) {
- // log selection
- console.debug('tool-form::field_data() - Selected dataset ' + value + '.');
-
- // get meta data
- var meta = dataset.get('metadata_column_types');
-
- // check meta data
- if (!meta) {
- console.debug('tool-form::field_data() - FAILED: Could not find metadata for dataset ' + value + '.');
- }
-
- // load column options
- var columns = [];
- for (var key in meta) {
- // add to selection
- columns.push({
- 'label' : 'Column: ' + (parseInt(key) + 1) + ' [' + meta[key] + ']',
- 'value' : key
- });
- }
-
- // update referenced columns
- for (var i in column_list) {
- var column_field = self.field_list[column_list[i].name]
- if (column_field) {
- column_field.update(columns);
- column_field.value(column_field.first());
- }
- }
- } else {
- // log failure
- console.debug('tool-form::field_data() - FAILED: Could not find dataset ' + value + '.');
- }
- }
- });
- },
-
- // select field
- _field_column : function (inputs_def, data) {
- // configure options fields
- var options = [];
- for (var i in inputs_def.options) {
- var option = inputs_def.options[i];
- options.push({
- label: option[0],
- value: option[1]
- });
- }
-
- // select field
- var id = inputs_def.name;
- return new Ui.Select.View({
- id : 'field-' + id,
- data : options,
- value : data.get(id),
- onchange : function(value) {
- data.set(id, value);
- }
- });
- },
-
- // select field
- _field_select : function (inputs_def, data) {
- // configure options fields
- var options = [];
- for (var i in inputs_def.options) {
- var option = inputs_def.options[i];
- options.push({
- label: option[0],
- value: option[1]
- });
- }
-
- // identify display type
- var SelectClass = Ui.Select;
- if (inputs_def.display == 'checkboxes') {
- SelectClass = Ui.Checkbox;
- }
-
- // select field
- var id = inputs_def.name;
- return new SelectClass.View({
- id : 'field-' + id,
- data : options,
- value : data.get(id),
- onchange : function(value) {
- data.set(id, value);
- }
- });
- },
-
- // radio field
- _field_radio : function(inputs_def, data) {
- var id = inputs_def.name;
- return new Ui.RadioButton({
- id : 'field-' + id,
- data : inputs_def.data,
- value : data.get(id),
- onchange : function(value) {
- data.set(id, value);
+ // append tool section
+ self.portlet.append(self.section.$el);
}
});
}
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/mvc/tools/tools-section.js
--- /dev/null
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -0,0 +1,409 @@
+define(['mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs'], function(Table, Ui, Tabs) {
+
+ // create form view
+ var View = Backbone.View.extend({
+ // initialize
+ initialize: function(app, options) {
+ // link app
+ this.app = app;
+
+ // link inputs
+ this.inputs = options.inputs;
+
+ // link datasets
+ this.datasets = app.datasets;
+
+ // create table
+ this.table = new Table.View(options);
+
+ // configure portlet and form table
+ this.setElement(this.table.$el);
+
+ // render tool section
+ this.render();
+ },
+
+ // update
+ render: function() {
+ // reset table
+ this.table.delAll();
+
+ // model
+ var data = new Backbone.Model();
+
+ // load settings elements into table
+ for (var id in this.inputs) {
+ this._add(this.inputs[id], data);
+ }
+
+ // trigger change
+ for (var id in this.app.field_list) {
+ this.app.field_list[id].trigger('change');
+ }
+ },
+
+ // add table row
+ _add: function(inputs_def, data) {
+ // link this
+ var self = this;
+
+ // identify field type
+ var type = inputs_def.type;
+ switch(type) {
+ // conditional field
+ case 'conditional':
+ // add label to input definition root
+ inputs_def.label = inputs_def.test_param.label;
+
+ // add id to input definition root
+ inputs_def.name = inputs_def.test_param.name;
+
+ // build options field
+ this._addRow('conditional', inputs_def, data);
+
+ // add fields
+ for (var i in inputs_def.cases) {
+ // create sub section
+ var sub_section = new View(this.app, {
+ inputs : inputs_def.cases[i].inputs,
+ cls : 'ui-table-plain'
+ });
+
+ // append sub section
+ this.table.add('');
+ this.table.add(sub_section.$el);
+ this.table.append(inputs_def.name + '_formsection_' + i);
+ }
+ break;
+ // repeat block
+ case 'repeat':
+ // create tab field
+ var tabs = new Tabs.View({
+ title_new : 'Add Group',
+ onnew : function() {
+ // create sub section
+ var sub_section = new View(self.app, {
+ inputs : inputs_def.inputs,
+ cls : 'ui-table-plain'
+ });
+
+ // create id tag
+ var sub_section_id = inputs_def.name + '_formsection_' + tabs.size();
+
+ // add new tab
+ tabs.add({
+ id : sub_section_id,
+ title : 'Repeat',
+ $el : sub_section.$el,
+ ondel : function() {
+ tabs.del(sub_section_id);
+ }
+ });
+
+ // show tab
+ tabs.show(sub_section_id);
+ }
+ });
+
+ // append sub section
+ this.table.add(inputs_def.title);
+ this.table.add(tabs.$el);
+ this.table.append(inputs_def.name);
+ break;
+ // default single element row
+ default:
+ this._addRow(type, inputs_def, data);
+ }
+ },
+
+ // add table row
+ _addRow: function(field_type, inputs_def, data) {
+ // get id
+ var id = inputs_def.name;
+
+ // field wrapper
+ var field = null;
+
+ // identify field type
+ switch(field_type) {
+ // text input field
+ case 'text' :
+ field = this._field_text(inputs_def, data);
+ break;
+
+ // select field
+ case 'select' :
+ field = this._field_select(inputs_def, data);
+ break;
+
+ // radiobox field
+ case 'radiobutton' :
+ field = this._field_radio(inputs_def, data);
+ break;
+
+ // dataset
+ case 'data':
+ field = this._field_data(inputs_def, data);
+ break;
+
+ // dataset column
+ case 'data_column':
+ field = this._field_column(inputs_def, data);
+ break;
+
+ // text area field
+ case 'textarea' :
+ field = this._field_textarea(inputs_def, data);
+ break;
+
+ // conditional select field
+ case 'conditional':
+ field = this._field_conditional(inputs_def, data);
+ break;
+ }
+
+ // check if field type was detected
+ if (!field) {
+ console.debug('tools-form::_addRow() : Unmatched field type (' + field_type + ').');
+ return;
+ }
+
+ // set value
+ if (!data.get(id)) {
+ data.set(id, inputs_def.value);
+ }
+ field.value(data.get(id));
+
+ // add to field list
+ this.app.field_list[id] = field;
+
+ // add to input definition into sequential list
+ this.app.inputs_sequential[id] = inputs_def;
+
+ // combine field and info
+ var $input = $('<div/>');
+ $input.append(field.$el);
+ if (inputs_def.help) {
+ $input.append('<div class="ui-table-form-info">' + inputs_def.help + '</div>');
+ }
+
+ // add row to table
+ this.table.add('<span class="ui-table-form-title">' + inputs_def.label + '</span>', '25%');
+ this.table.add($input);
+
+ // add to table
+ this.table.append(id);
+
+ // show/hide
+ if (inputs_def.hide) {
+ this.table.get(id).hide();
+ }
+ },
+
+ // text input field
+ _field_text : function(inputs_def, data) {
+ var id = inputs_def.name;
+ return new Ui.Input({
+ id : 'field-' + id,
+ value : data.get(id),
+ onchange : function(value) {
+ data.set(id, value);
+ }
+ });
+ },
+
+ // text area
+ _field_textarea : function(inputs_def, data) {
+ var id = inputs_def.name;
+ return new Ui.Textarea({
+ id : 'field-' + id,
+ onchange : function() {
+ data.set(id, field.value());
+ }
+ });
+ },
+
+ // conditional input field
+ _field_conditional : function(inputs_def, data) {
+ // link this
+ var self = this;
+
+ // configure options fields
+ var options = [];
+ for (var i in inputs_def.test_param.options) {
+ var option = inputs_def.test_param.options[i];
+ options.push({
+ label: option[0],
+ value: option[1]
+ });
+ }
+
+ // select field
+ var id = inputs_def.name;
+ return new Ui.Select.View({
+ id : 'field-' + id,
+ data : options,
+ value : data.get(id),
+ onchange : function(value) {
+ // update value
+ data.set(id, value);
+
+ // check value in order to hide/show options
+ for (var i in inputs_def.cases) {
+ // get case
+ var case_def = inputs_def.cases[i];
+
+ // identify subsection name
+ var section_id = inputs_def.name + '_formsection_' + i;
+
+ // identify row
+ var section_row = self.table.get(section_id);
+
+ // check
+ if (case_def.value == value) {
+ section_row.show();
+ } else {
+ section_row.hide();
+ }
+ }
+ }
+ });
+ },
+
+ // data input field
+ _field_data : function(inputs_def, data) {
+ // link this
+ var self = this;
+
+ // get element id
+ var id = inputs_def.name;
+
+ // get datasets
+ var datasets = this.datasets.filterType();
+
+ // configure options fields
+ var options = [];
+ for (var i in datasets) {
+ options.push({
+ label: datasets[i].get('name'),
+ value: datasets[i].get('id')
+ });
+ }
+
+ // select field
+ return new Ui.Select.View({
+ id : 'field-' + id,
+ data : options,
+ value : options[0].value,
+ onchange : function(value) {
+ // update value
+ data.set(id, value);
+
+ // find referenced columns
+ var column_list = _.where(self.app.inputs_sequential, {
+ data_ref : id,
+ type : 'data_column'
+ });
+
+ // find selected dataset
+ var dataset = self.datasets.filter(value);
+
+ // check dataset
+ if (dataset && column_list.length > 0) {
+ // log selection
+ console.debug('tool-form::field_data() - Selected dataset ' + value + '.');
+
+ // get meta data
+ var meta = dataset.get('metadata_column_types');
+
+ // check meta data
+ if (!meta) {
+ console.debug('tool-form::field_data() - FAILED: Could not find metadata for dataset ' + value + '.');
+ }
+
+ // load column options
+ var columns = [];
+ for (var key in meta) {
+ // add to selection
+ columns.push({
+ 'label' : 'Column: ' + (parseInt(key) + 1) + ' [' + meta[key] + ']',
+ 'value' : key
+ });
+ }
+
+ // update referenced columns
+ for (var i in column_list) {
+ var column_field = self.app.field_list[column_list[i].name]
+ if (column_field) {
+ column_field.update(columns);
+ column_field.value(column_field.first());
+ }
+ }
+ } else {
+ // log failure
+ console.debug('tool-form::field_data() - FAILED: Could not find dataset ' + value + '.');
+ }
+ }
+ });
+ },
+
+ // column selection field
+ _field_column : function (inputs_def, data) {
+ var id = inputs_def.name;
+ return new Ui.Select.View({
+ id : 'field-' + id,
+ value : data.get(id),
+ onchange : function(value) {
+ data.set(id, value);
+ }
+ });
+ },
+
+ // select field
+ _field_select : function (inputs_def, data) {
+ // configure options fields
+ var options = [];
+ for (var i in inputs_def.options) {
+ var option = inputs_def.options[i];
+ options.push({
+ label: option[0],
+ value: option[1]
+ });
+ }
+
+ // identify display type
+ var SelectClass = Ui.Select;
+ if (inputs_def.display == 'checkboxes') {
+ SelectClass = Ui.Checkbox;
+ }
+
+ // select field
+ var id = inputs_def.name;
+ return new SelectClass.View({
+ id : 'field-' + id,
+ data : options,
+ value : data.get(id),
+ onchange : function(value) {
+ data.set(id, value);
+ }
+ });
+ },
+
+ // radio field
+ _field_radio : function(inputs_def, data) {
+ var id = inputs_def.name;
+ return new Ui.RadioButton({
+ id : 'field-' + id,
+ data : inputs_def.data,
+ value : data.get(id),
+ onchange : function(value) {
+ data.set(id, value);
+ }
+ });
+ }
+ });
+
+ return {
+ View: View
+ };
+});
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/mvc/ui/ui-table.js
--- a/static/scripts/mvc/ui/ui-table.js
+++ b/static/scripts/mvc/ui/ui-table.js
@@ -17,7 +17,7 @@
onchange : null,
ondblclick : null,
onconfirm : null,
- cls : ''
+ cls : 'ui-table'
},
// events
@@ -198,12 +198,11 @@
},
// load html template
- _template: function(options)
- {
+ _template: function(options) {
return '<div>' +
- '<table class="ui-table ' + options.cls + '">' +
+ '<table class="' + options.cls + '">' +
'<thead></thead>' +
- '<tbody style="cursor: pointer;"></tbody>' +
+ '<tbody></tbody>' +
'</table>' +
'<tmessage>' + options.content + '</tmessage>' +
'<div>';
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/mvc/ui/ui-tabs.js
--- a/static/scripts/mvc/ui/ui-tabs.js
+++ b/static/scripts/mvc/ui/ui-tabs.js
@@ -2,8 +2,7 @@
define(['utils/utils'], function(Utils) {
// return
-var View = Backbone.View.extend(
-{
+var View = Backbone.View.extend({
// defaults options
optionsDefault: {
title_new : '',
@@ -65,6 +64,11 @@
}
},
+ // size
+ size: function() {
+ return _.size(this.list);
+ },
+
// append
add: function(options) {
// self
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/galaxy.menu.js
--- a/static/scripts/packed/galaxy.menu.js
+++ b/static/scripts/packed/galaxy.menu.js
@@ -1,1 +1,1 @@
-define(["galaxy.masthead"],function(b){var a=Backbone.Model.extend({options:null,masthead:null,initialize:function(c){this.options=c.config;this.masthead=c.masthead;this.create()},create:function(){var e=new b.GalaxyMastheadTab({id:"analysis",title:"Analyze Data",content:"root/index",title_attribute:"Analysis home view"});this.masthead.append(e);var g={id:"workflow",title:"Workflow",content:"workflow",title_attribute:"Chain tools into workflows"};if(!this.options.user.valid){g.disabled=true}var d=new b.GalaxyMastheadTab(g);this.masthead.append(d);var i=new b.GalaxyMastheadTab({id:"shared",title:"Shared Data",content:"library/index",title_attribute:"Access published resources"});i.add({title:"Data Libraries",content:"library/index"});i.add({title:"Data Libraries Beta",content:"library/list",divider:true});i.add({title:"Published Histories",content:"history/list_published"});i.add({title:"Published Workflows",content:"workflow/list_published"});i.add({title:"Published Visualizations",content:"visualization/list_published"});i.add({title:"Published Pages",content:"page/list_published"});this.masthead.append(i);if(this.options.user.requests){var j=new b.GalaxyMastheadTab({id:"lab",title:"Lab"});j.add({title:"Sequencing Requests",content:"requests/index"});j.add({title:"Find Samples",content:"requests/find_samples_index"});j.add({title:"Help",content:this.options.lims_doc_url});this.masthead.append(j)}var c={id:"visualization",title:"Visualization",content:"visualization/list",title_attribute:"Visualize datasets"};if(!this.options.user.valid){c.disabled=true}var m=new b.GalaxyMastheadTab(c);if(this.options.user.valid){m.add({title:"New Track Browser",content:"visualization/trackster",target:"_frame"});m.add({title:"Saved Visualizations",content:"visualization/list",target:"_frame"})}this.masthead.append(m);if(this.options.enable_cloud_launch){var f=new b.GalaxyMastheadTab({id:"cloud",title:"Cloud",content:"cloudlaunch/index"});f.add({title:"New Cloud Cluster",content:"cloudlaunch/index"});this.masthead.append(f)}if(this.options.is_admin_user){var h=new b.GalaxyMastheadTab({id:"admin",title:"Admin",content:"admin/index",extra_class:"admin-only",title_attribute:"Administer this Galaxy"});this.masthead.append(h)}var l=new b.GalaxyMastheadTab({id:"help",title:"Help",title_attribute:"Support, contact, and community hubs"});if(this.options.biostar_url){l.add({title:"Galaxy Biostar",content:this.options.biostar_url_redirect,target:"_blank"});l.add({title:"Ask a question",content:"biostar/biostar_question_redirect",target:"_blank"})}l.add({title:"Support",content:this.options.support_url,target:"_blank"});l.add({title:"Search",content:this.options.search_url,target:"_blank"});l.add({title:"Mailing Lists",content:this.options.mailing_lists,target:"_blank"});l.add({title:"Videos",content:this.options.screencasts_url,target:"_blank"});l.add({title:"Wiki",content:this.options.wiki_url,target:"_blank"});l.add({title:"How to Cite Galaxy",content:this.options.citation_url,target:"_blank"});if(this.options.terms_url){l.add({title:"Terms and Conditions",content:this.options.terms_url,target:"_blank"})}this.masthead.append(l);if(!this.options.user.valid){var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedout-only",title_attribute:"Account registration or login"});k.add({title:"Login",content:"user/login",target:"galaxy_main"});if(this.options.allow_user_creation){k.add({title:"Register",content:"user/create",target:"galaxy_main"})}this.masthead.append(k)}else{var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedin-only",title_attribute:"Account preferences and saved data"});k.add({title:"Logged in as "+this.options.user.email});if(this.options.use_remote_user&&this.options.remote_user_logout_href){k.add({title:"Logout",content:this.options.remote_user_logout_href,target:"_top"})}else{k.add({title:"Preferences",content:"user?cntrller=user",target:"galaxy_main"});k.add({title:"Custom Builds",content:"user/dbkeys",target:"galaxy_main"});k.add({title:"Logout",content:"user/logout",target:"_top",divider:true})}k.add({title:"Saved Histories",content:"history/list",target:"galaxy_main"});k.add({title:"Saved Datasets",content:"dataset/list",target:"galaxy_main"});k.add({title:"Saved Pages",content:"page/list",target:"_top"});k.add({title:"API Keys",content:"user/api_keys?cntrller=user",target:"galaxy_main"});if(this.options.use_remote_user){k.add({title:"Public Name",content:"user/edit_username?cntrller=user",target:"galaxy_main"})}this.masthead.append(k)}if(this.options.active_view){this.masthead.highlight(this.options.active_view)}}});return{GalaxyMenu:a}});
\ No newline at end of file
+define(["galaxy.masthead"],function(b){var a=Backbone.Model.extend({options:null,masthead:null,initialize:function(c){this.options=c.config;this.masthead=c.masthead;this.create()},create:function(){var e=new b.GalaxyMastheadTab({id:"analysis",title:"Analyze Data",content:"root/index",title_attribute:"Analysis home view"});this.masthead.append(e);var g={id:"workflow",title:"Workflow",content:"workflow",title_attribute:"Chain tools into workflows"};if(!this.options.user.valid){g.disabled=true}var d=new b.GalaxyMastheadTab(g);this.masthead.append(d);var i=new b.GalaxyMastheadTab({id:"shared",title:"Shared Data",content:"library/index",title_attribute:"Access published resources"});i.add({title:"Data Libraries",content:"library/index"});i.add({title:"Data Libraries Beta",content:"library/list",divider:true});i.add({title:"Published Histories",content:"history/list_published"});i.add({title:"Published Workflows",content:"workflow/list_published"});i.add({title:"Published Visualizations",content:"visualization/list_published"});i.add({title:"Published Pages",content:"page/list_published"});this.masthead.append(i);if(this.options.user.requests){var j=new b.GalaxyMastheadTab({id:"lab",title:"Lab"});j.add({title:"Sequencing Requests",content:"requests/index"});j.add({title:"Find Samples",content:"requests/find_samples_index"});j.add({title:"Help",content:this.options.lims_doc_url});this.masthead.append(j)}var c={id:"visualization",title:"Visualization",content:"visualization/list",title_attribute:"Visualize datasets"};if(!this.options.user.valid){c.disabled=true}var m=new b.GalaxyMastheadTab(c);if(this.options.user.valid){m.add({title:"New Track Browser",content:"visualization/trackster",target:"_frame"});m.add({title:"Saved Visualizations",content:"visualization/list",target:"_frame"})}this.masthead.append(m);if(this.options.enable_cloud_launch){var f=new b.GalaxyMastheadTab({id:"cloud",title:"Cloud",content:"cloudlaunch/index"});f.add({title:"New Cloud Cluster",content:"cloudlaunch/index"});this.masthead.append(f)}if(this.options.is_admin_user){var h=new b.GalaxyMastheadTab({id:"admin",title:"Admin",content:"admin/index",extra_class:"admin-only",title_attribute:"Administer this Galaxy"});this.masthead.append(h)}var l=new b.GalaxyMastheadTab({id:"help",title:"Help",title_attribute:"Support, contact, and community hubs"});if(this.options.biostar_url){l.add({title:"Galaxy Biostar",content:this.options.biostar_url_redirect,target:"_blank"});l.add({title:"Ask a question",content:"biostar/biostar_question_redirect",target:"_blank"})}l.add({title:"Support",content:this.options.support_url,target:"_blank"});l.add({title:"Search",content:this.options.search_url,target:"_blank"});l.add({title:"Mailing Lists",content:this.options.mailing_lists,target:"_blank"});l.add({title:"Videos",content:this.options.screencasts_url,target:"_blank"});l.add({title:"Wiki",content:this.options.wiki_url,target:"_blank"});l.add({title:"How to Cite Galaxy",content:this.options.citation_url,target:"_blank"});if(this.options.terms_url){l.add({title:"Terms and Conditions",content:this.options.terms_url,target:"_blank"})}this.masthead.append(l);if(!this.options.user.valid){var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedout-only",title_attribute:"Account registration or login"});k.add({title:"Login",content:"user/login",target:"galaxy_main"});if(this.options.allow_user_creation){k.add({title:"Register",content:"user/create",target:"galaxy_main"})}this.masthead.append(k)}else{var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedin-only",title_attribute:"Account preferences and saved data"});k.add({title:"Logged in as "+this.options.user.email});k.add({title:"Preferences",content:"user?cntrller=user",target:"galaxy_main"});k.add({title:"Custom Builds",content:"user/dbkeys",target:"galaxy_main"});k.add({title:"Logout",content:"user/logout",target:"_top",divider:true});k.add({title:"Saved Histories",content:"history/list",target:"galaxy_main"});k.add({title:"Saved Datasets",content:"dataset/list",target:"galaxy_main"});k.add({title:"Saved Pages",content:"page/list",target:"_top"});k.add({title:"API Keys",content:"user/api_keys?cntrller=user",target:"galaxy_main"});if(this.options.use_remote_user){k.add({title:"Public Name",content:"user/edit_username?cntrller=user",target:"galaxy_main"})}this.masthead.append(k)}if(this.options.active_view){this.masthead.highlight(this.options.active_view)}}});return{GalaxyMenu:a}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/mvc/tools/tools-form.js
--- a/static/scripts/packed/mvc/tools/tools-form.js
+++ b/static/scripts/packed/mvc/tools/tools-form.js
@@ -1,1 +1,1 @@
-define(["mvc/ui/ui-portlet","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets"],function(f,i,j,h,a,e,c,g){var d=Backbone.Model.extend({initialize:function(k){this.url=galaxy_config.root+"api/tools/"+k.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(l){var k=this;this.options=l;this.model=new d({id:l.id});this.datasets=new g({success:function(){k._initializeToolForm()}})},_initializeToolForm:function(){var k=this;this.model.fetch({success:function(){k.inputs=k.model.get("inputs");k.portlet=new f.View({icon:"fa-wrench",title:"<b>"+k.model.get("name")+"</b> "+k.model.get("description"),buttons:{execute:new j.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){}})}});k.table=new i.View();k.message=new j.Message();k.portlet.append(k.message.$el);$(k.main_el).append(k.portlet.$el);if(k.options.help!=""){$(k.main_el).append(c.help(k.options.help))}if(k.options.citations){$(k.main_el).append(c.citations());var l=new h.ToolCitationCollection();l.tool_id=k.options.id;var m=new a.CitationListView({collection:l});m.render();l.fetch()}k.setElement(k.portlet.content());k.portlet.append(k.table.$el);k.render()}})},render:function(){this.table.delAll();this.field_list={};this.inputs_sequential={};var k=new Backbone.Model();for(var l in this.inputs){this._add(this.inputs[l],k)}for(var l in this.field_list){this.field_list[l].trigger("change")}},_add:function(l,p){var n=l.type;switch(n){case"conditional":l.label=l.test_param.label;l.name=l.test_param.name;this._addRow("conditional",l,p);for(var m in l.cases){var o=l.cases[m];for(var k in o.inputs){this._add(o.inputs[k],p)}}break;default:this._addRow(n,l,p)}},_addRow:function(n,k,l){var p=k.name;var m=null;switch(n){case"text":m=this._field_text(k,l);break;case"select":m=this._field_select(k,l);break;case"radiobutton":m=this._field_radio(k,l);break;case"data":m=this._field_data(k,l);break;case"data_column":m=this._field_column(k,l);break;case"textarea":m=this._field_textarea(k,l);break;case"conditional":m=this._field_conditional(k,l);break}if(!m){console.debug("tools-form::_addRow() : Unmatched field type ("+n+").");return}if(!l.get(p)){l.set(p,k.value)}m.value(l.get(p));this.field_list[p]=m;this.inputs_sequential[p]=k;var o=$("<div/>");o.append(m.$el);if(k.info){o.append('<div class="ui-table-form-info">'+k.info+"</div>")}this.table.add('<span class="ui-table-form-title">'+k.label+"</span>","25%");this.table.add(o);this.table.append(p);if(k.hide){this.table.get(p).hide()}},_field_text:function(k,l){var m=k.name;return new j.Input({id:"field-"+m,value:l.get(m),onchange:function(n){l.set(m,n)}})},_field_textarea:function(k,l){var m=k.name;return new j.Textarea({id:"field-"+m,onchange:function(){l.set(m,field.value())}})},_field_conditional:function(m,p){var k=this;var l=[];for(var n in m.test_param.options){var o=m.test_param.options[n];l.push({label:o[0],value:o[1]})}var q=m.name;return new j.Select.View({id:"field-"+q,data:l,value:p.get(q),onchange:function(u){p.set(q,u);function t(x,w){for(var A in x.inputs){var z=x.inputs[A];var v=z.name;var B=k.table.get(v);if(w){B.fadeIn()}else{B.hide()}if(z.type=="conditional"){for(var y in z.cases){t(z.cases[y],w)}}}}for(var s in m.cases){var r=m.cases[s];t(r,r.value==u)}}})},_field_data:function(m,p){var k=this;var q=m.name;var o=this.datasets.filterType();var l=[];for(var n in o){l.push({label:o[n].get("name"),value:o[n].get("id")})}return new j.Select.View({id:"field-"+q,data:l,value:l[0].value,onchange:function(w){p.set(q,w);var s=_.where(k.inputs_sequential,{data_ref:q,type:"data_column"});var y=k.datasets.filter(w);if(y&&s.length>0){console.debug("tool-form::field_data() - Selected dataset "+w+".");var x=y.get("metadata_column_types");if(!x){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+w+".")}var v=[];for(var u in x){v.push({label:"Column: "+(parseInt(u)+1)+" ["+x[u]+"]",value:u})}for(var t in s){var r=k.field_list[s[t].name];if(r){r.update(v);r.value(r.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+w+".")}}})},_field_column:function(l,o){var k=[];for(var m in l.options){var n=l.options[m];k.push({label:n[0],value:n[1]})}var p=l.name;return new j.Select.View({id:"field-"+p,data:k,value:o.get(p),onchange:function(q){o.set(p,q)}})},_field_select:function(l,p){var k=[];for(var m in l.options){var n=l.options[m];k.push({label:n[0],value:n[1]})}var o=j.Select;if(l.display=="checkboxes"){o=j.Checkbox}var q=l.name;return new o.View({id:"field-"+q,data:k,value:p.get(q),onchange:function(r){p.set(q,r)}})},_field_radio:function(k,l){var m=k.name;return new j.RadioButton({id:"field-"+m,data:k.data,value:l.get(m),onchange:function(n){l.set(m,n)}})}});return{View:b}});
\ No newline at end of file
+define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section"],function(f,j,h,a,e,c,g,i){var d=Backbone.Model.extend({initialize:function(k){this.url=galaxy_config.root+"api/tools/"+k.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(l){var k=this;this.options=l;this.model=new d({id:l.id});this.datasets=new g({success:function(){k._initializeToolForm()}})},_initializeToolForm:function(){this.field_list={};this.inputs_sequential={};var k=this;this.model.fetch({error:function(l){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){k.inputs=k.model.get("inputs");k.portlet=new f.View({icon:"fa-wrench",title:"<b>"+k.model.get("name")+"</b> "+k.model.get("description"),buttons:{execute:new j.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){}})}});k.message=new j.Message();k.portlet.append(k.message.$el);$(k.main_el).append(k.portlet.$el);if(k.options.help!=""){$(k.main_el).append(c.help(k.options.help))}if(k.options.citations){$(k.main_el).append(c.citations());var l=new h.ToolCitationCollection();l.tool_id=k.options.id;var m=new a.CitationListView({collection:l});m.render();l.fetch()}k.setElement(k.portlet.content());k.section=new i.View(k,{inputs:k.model.get("inputs")});k.portlet.append(k.section.$el)}})}});return{View:b}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/mvc/tools/tools-section.js
--- /dev/null
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -0,0 +1,1 @@
+define(["mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-tabs"],function(b,d,a){var c=Backbone.View.extend({initialize:function(f,e){this.app=f;this.inputs=e.inputs;this.datasets=f.datasets;this.table=new b.View(e);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();var e=new Backbone.Model();for(var f in this.inputs){this._add(this.inputs[f],e)}for(var f in this.app.field_list){this.app.field_list[f].trigger("change")}},_add:function(f,k){var e=this;var j=f.type;switch(j){case"conditional":f.label=f.test_param.label;f.name=f.test_param.name;this._addRow("conditional",f,k);for(var h in f.cases){var l=new c(this.app,{inputs:f.cases[h].inputs,cls:"ui-table-plain"});this.table.add("");this.table.add(l.$el);this.table.append(f.name+"_formsection_"+h)}break;case"repeat":var g=new a.View({title_new:"Add Group",onnew:function(){var m=new c(e.app,{inputs:f.inputs,cls:"ui-table-plain"});var i=f.name+"_formsection_"+g.size();g.add({id:i,title:"Repeat",$el:m.$el,ondel:function(){g.del(i)}});g.show(i)}});this.table.add(f.title);this.table.add(g.$el);this.table.append(f.name);break;default:this._addRow(j,f,k)}},_addRow:function(h,e,f){var j=e.name;var g=null;switch(h){case"text":g=this._field_text(e,f);break;case"select":g=this._field_select(e,f);break;case"radiobutton":g=this._field_radio(e,f);break;case"data":g=this._field_data(e,f);break;case"data_column":g=this._field_column(e,f);break;case"textarea":g=this._field_textarea(e,f);break;case"conditional":g=this._field_conditional(e,f);break}if(!g){console.debug("tools-form::_addRow() : Unmatched field type ("+h+").");return}if(!f.get(j)){f.set(j,e.value)}g.value(f.get(j));this.app.field_list[j]=g;this.app.inputs_sequential[j]=e;var i=$("<div/>");i.append(g.$el);if(e.help){i.append('<div class="ui-table-form-info">'+e.help+"</div>")}this.table.add('<span class="ui-table-form-title">'+e.label+"</span>","25%");this.table.add(i);this.table.append(j);if(e.hide){this.table.get(j).hide()}},_field_text:function(e,f){var g=e.name;return new d.Input({id:"field-"+g,value:f.get(g),onchange:function(h){f.set(g,h)}})},_field_textarea:function(e,f){var g=e.name;return new d.Textarea({id:"field-"+g,onchange:function(){f.set(g,field.value())}})},_field_conditional:function(g,k){var e=this;var f=[];for(var h in g.test_param.options){var j=g.test_param.options[h];f.push({label:j[0],value:j[1]})}var l=g.name;return new d.Select.View({id:"field-"+l,data:f,value:k.get(l),onchange:function(q){k.set(l,q);for(var p in g.cases){var n=g.cases[p];var o=g.name+"_formsection_"+p;var m=e.table.get(o);if(n.value==q){m.show()}else{m.hide()}}}})},_field_data:function(g,k){var e=this;var l=g.name;var j=this.datasets.filterType();var f=[];for(var h in j){f.push({label:j[h].get("name"),value:j[h].get("id")})}return new d.Select.View({id:"field-"+l,data:f,value:f[0].value,onchange:function(r){k.set(l,r);var n=_.where(e.app.inputs_sequential,{data_ref:l,type:"data_column"});var t=e.datasets.filter(r);if(t&&n.length>0){console.debug("tool-form::field_data() - Selected dataset "+r+".");var s=t.get("metadata_column_types");if(!s){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+r+".")}var q=[];for(var p in s){q.push({label:"Column: "+(parseInt(p)+1)+" ["+s[p]+"]",value:p})}for(var o in n){var m=e.app.field_list[n[o].name];if(m){m.update(q);m.value(m.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+r+".")}}})},_field_column:function(e,f){var g=e.name;return new d.Select.View({id:"field-"+g,value:f.get(g),onchange:function(h){f.set(g,h)}})},_field_select:function(f,k){var e=[];for(var g in f.options){var h=f.options[g];e.push({label:h[0],value:h[1]})}var j=d.Select;if(f.display=="checkboxes"){j=d.Checkbox}var l=f.name;return new j.View({id:"field-"+l,data:e,value:k.get(l),onchange:function(i){k.set(l,i)}})},_field_radio:function(e,f){var g=e.name;return new d.RadioButton({id:"field-"+g,data:e.data,value:f.get(g),onchange:function(h){f.set(g,h)}})}});return{View:c}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/mvc/ui/ui-table.js
--- a/static/scripts/packed/mvc/ui/ui-table.js
+++ b/static/scripts/packed/mvc/ui/ui-table.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){var b=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null,cls:""},events:{click:"_onclick",dblclick:"_ondblclick"},initialize:function(c){this.options=a.merge(c,this.optionsDefault);var d=$(this._template(this.options));this.$thead=d.find("thead");this.$tbody=d.find("tbody");this.$tmessage=d.find("tmessage");this.setElement(d);this.row=$("<tr></tr>")},addHeader:function(c){var d=$("<th></th>");d.append(c);this.row.append(d)},appendHeader:function(){this.$thead.append(this.row);this.row=$("<tr></tr>")},add:function(c,d,f){var e=$("<td></td>");if(d){e.css("width",d)}if(f){e.css("text-align",f)}e.append(c);this.row.append(e)},append:function(c){this._commit(c)},prepend:function(c){this._commit(c,true)},get:function(c){return this.$el.find("#"+c)},del:function(d){var c=this.$tbody.find("#"+d);if(c.length>0){c.remove();this.row_count--;this._refresh()}},delAll:function(){this.$tbody.empty();this.row_count=0;this._refresh()},value:function(c){this.before=this.$tbody.find(".current").attr("id");if(c!==undefined){this.$tbody.find("tr").removeClass("current");if(c){this.$tbody.find("#"+c).addClass("current")}}var d=this.$tbody.find(".current").attr("id");if(d===undefined){return null}else{if(d!=this.before&&this.options.onchange){this.options.onchange(c)}return d}},size:function(){return this.$tbody.find("tr").length},_commit:function(d,c){this.del(d);this.row.attr("id",d);if(c){this.$tbody.prepend(this.row)}else{this.$tbody.append(this.row)}this.row=$("<tr></tr>");this.row_count++;this._refresh()},_onclick:function(f){var c=this.value();var d=$(f.target).closest("tr").attr("id");if(d!=""){if(d&&c!=d){if(this.options.onconfirm){this.options.onconfirm(d)}else{this.value(d)}}}},_ondblclick:function(d){var c=this.value();if(c&&this.options.ondblclick){this.options.ondblclick(c)}},_refresh:function(){if(this.row_count==0){this.$tmessage.show()}else{this.$tmessage.hide()}},_template:function(c){return'<div><table class="ui-table '+c.cls+'"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+c.content+"</tmessage><div>"}});return{View:b}});
\ No newline at end of file
+define(["utils/utils"],function(a){var b=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null,cls:"ui-table"},events:{click:"_onclick",dblclick:"_ondblclick"},initialize:function(c){this.options=a.merge(c,this.optionsDefault);var d=$(this._template(this.options));this.$thead=d.find("thead");this.$tbody=d.find("tbody");this.$tmessage=d.find("tmessage");this.setElement(d);this.row=$("<tr></tr>")},addHeader:function(c){var d=$("<th></th>");d.append(c);this.row.append(d)},appendHeader:function(){this.$thead.append(this.row);this.row=$("<tr></tr>")},add:function(c,d,f){var e=$("<td></td>");if(d){e.css("width",d)}if(f){e.css("text-align",f)}e.append(c);this.row.append(e)},append:function(c){this._commit(c)},prepend:function(c){this._commit(c,true)},get:function(c){return this.$el.find("#"+c)},del:function(d){var c=this.$tbody.find("#"+d);if(c.length>0){c.remove();this.row_count--;this._refresh()}},delAll:function(){this.$tbody.empty();this.row_count=0;this._refresh()},value:function(c){this.before=this.$tbody.find(".current").attr("id");if(c!==undefined){this.$tbody.find("tr").removeClass("current");if(c){this.$tbody.find("#"+c).addClass("current")}}var d=this.$tbody.find(".current").attr("id");if(d===undefined){return null}else{if(d!=this.before&&this.options.onchange){this.options.onchange(c)}return d}},size:function(){return this.$tbody.find("tr").length},_commit:function(d,c){this.del(d);this.row.attr("id",d);if(c){this.$tbody.prepend(this.row)}else{this.$tbody.append(this.row)}this.row=$("<tr></tr>");this.row_count++;this._refresh()},_onclick:function(f){var c=this.value();var d=$(f.target).closest("tr").attr("id");if(d!=""){if(d&&c!=d){if(this.options.onconfirm){this.options.onconfirm(d)}else{this.value(d)}}}},_ondblclick:function(d){var c=this.value();if(c&&this.options.ondblclick){this.options.ondblclick(c)}},_refresh:function(){if(this.row_count==0){this.$tmessage.show()}else{this.$tmessage.hide()}},_template:function(c){return'<div><table class="'+c.cls+'"><thead></thead><tbody></tbody></table><tmessage>'+c.content+"</tmessage><div>"}});return{View:b}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/mvc/ui/ui-tabs.js
--- a/static/scripts/packed/mvc/ui/ui-tabs.js
+++ b/static/scripts/packed/mvc/ui/ui-tabs.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(_.size(this.list)==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#tab-content-"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}},delRemovable:function(){for(var c in this.list){if(this.list[c]){this.del(c)}}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#tab-content-"+c).addClass("active")}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#tab-content-'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="tab-content-'+c.id+'" class="tab-pane"/>'}});return{View:b}});
\ No newline at end of file
+define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},size:function(){return _.size(this.list)},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(_.size(this.list)==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#tab-content-"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}},delRemovable:function(){for(var c in this.list){if(this.list[c]){this.del(c)}}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#tab-content-"+c).addClass("active")}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#tab-content-'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="tab-content-'+c.id+'" class="tab-pane"/>'}});return{View:b}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1279,6 +1279,9 @@
.upload-ftp .upload-ftp-warning{text-align:center;margin-top:20px}
.upload-settings .upload-settings-cover{position:absolute;width:100%;height:100%;top:0px;left:0px;background:#fff;opacity:0.4;cursor:no-drop}
.ui-radiobutton label{height:23px;line-height:1em}
+.ui-table tbody{cursor:pointer}
+.ui-table-plain tbody td{padding:5px 0px 5px 5px !important;border:none !important}
+.ui-table-plain tbody{cursor:auto !important}
.ui-table-form-separator{font-weight:bold;font-size:0.9em}
.ui-label{font-weight:bold}
.ui-message{padding:2px 2px 2px 10px}
@@ -1528,13 +1531,13 @@
.grid-header{padding-bottom:1em}
.grid-header h2{margin:0;margin-bottom:0.5em}
.grid-header .title{font-weight:bold}
-.grid,.ui-table{padding-top:1em;border-collapse:collapse;width:100%}
+.grid,.ui-table,.ui-table-plain{padding-top:1em;border-collapse:collapse;width:100%}
.grid tbody td,.ui-table tbody td{line-height:1.428571429;border-top:solid #DDDDDD 1px;border-bottom:solid #DDDDDD 1px;padding:5px}
.grid tbody td:empty{padding:0}
.grid thead tr{height:2em}
.grid thead th{line-height:1.428571429;background:#ebd9b2;color:#000;border-top:solid #d6b161 1px;border-bottom:solid #d6b161 1px;padding:5px;text-align:left;white-space:nowrap}
.grid tfoot td{background-color:#F8F8F8;border-top:solid #DDDDDD 1px;border-bottom:solid #DDDDDD 1px;padding:5px}
-.grid .current,.ui-table .current{background-color:#EEEEFF}
+.grid .current{background-color:#EEEEFF}
.count-box{min-width:1.1em;padding:5px;border-width:1px;border-style:solid;text-align:center;display:inline-block}
.text-filter-val{border:solid 1px #AAAAAA;padding:1px 2px 1px 3px;margin-right:5px;-moz-border-radius:.5em;-webkit-border-radius:.5em;font-style:italic}
.page-link a,.inactive-link{padding:0px 7px 0px 7px;color:#555}
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/style/src/less/ui.less
--- a/static/style/src/less/ui.less
+++ b/static/style/src/less/ui.less
@@ -11,8 +11,22 @@
tbody td {
&:extend(.grid tbody td);
}
- .current {
- &:extend(.grid .current);
+
+ tbody {
+ cursor: pointer;
+ }
+}
+
+.ui-table-plain {
+ &:extend(.grid);
+
+ tbody td {
+ padding: 5px 0px 5px 5px !important;
+ border: none !important;
+ }
+
+ tbody {
+ cursor: auto !important;
}
}
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: dannon: Merged in kellrott/galaxy-farm/upload_uuid (pull request #463)
by commits-noreply@bitbucket.org 25 Aug '14
by commits-noreply@bitbucket.org 25 Aug '14
25 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/261471d04763/
Changeset: 261471d04763
User: dannon
Date: 2014-08-25 15:28:26
Summary: Merged in kellrott/galaxy-farm/upload_uuid (pull request #463)
Enabling UUID in file upload
Affected #: 3 files
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -243,6 +243,7 @@
else:
data.extension = uploaded_dataset.file_type
data.dbkey = uploaded_dataset.dbkey
+ data.uuid = uploaded_dataset.uuid
trans.sa_session.add( data )
trans.sa_session.flush()
if library_bunch:
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -278,6 +278,7 @@
ftp_files = context['ftp_files']
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
+ uuid = context.get( 'uuid', None )
warnings = []
to_posix_lines = False
if context.get( 'to_posix_lines', None ) not in [ "None", None, False ]:
@@ -316,12 +317,14 @@
break
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
+ file_bunch.uuid = uuid
return file_bunch, warnings
def get_filenames( context ):
rval = []
data_file = context['file_data']
url_paste = context['url_paste']
ftp_files = context['ftp_files']
+ uuid = context.get( 'uuid', None )
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
to_posix_lines = False
@@ -332,12 +335,14 @@
space_to_tab = True
warnings = []
file_bunch = get_data_file_filename( data_file, override_name = name, override_info = info )
+ file_bunch.uuid = uuid
if file_bunch.path:
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
for file_bunch in get_url_paste_urls_or_filename( context, override_name = name, override_info = info ):
if file_bunch.path:
+ file_bunch.uuid = uuid
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,6 +41,7 @@
<!-- Swap the following parameter for the select one that follows to
enable the to_posix_lines option in the Web GUI. See Bitbucket
Pull Request 171 for more information. -->
+ <param name="uuid" type="hidden" required="False" /><param name="to_posix_lines" type="hidden" value="Yes" /><!--
<param name="to_posix_lines" type="select" display="checkboxes" multiple="True" label="Convert universal line endings to Posix line endings" help="Turn this option off if you upload a gzip, bz2 or zip archive which contains a binary file." value="Yes">
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6cb895d18331/
Changeset: 6cb895d18331
Branch: upload_uuid
User: kellrott
Date: 2014-08-15 02:08:29
Summary: Enabling UUID in file upload
Affected #: 3 files
diff -r d301ac50aa86a94e230d44eb2ae10c6c0e354b88 -r 6cb895d18331fa542b7e3e95598c59de63724246 lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -243,6 +243,7 @@
else:
data.extension = uploaded_dataset.file_type
data.dbkey = uploaded_dataset.dbkey
+ data.uuid = uploaded_dataset.uuid
trans.sa_session.add( data )
trans.sa_session.flush()
if library_bunch:
diff -r d301ac50aa86a94e230d44eb2ae10c6c0e354b88 -r 6cb895d18331fa542b7e3e95598c59de63724246 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -278,6 +278,7 @@
ftp_files = context['ftp_files']
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
+ uuid = context.get( 'uuid', None )
warnings = []
to_posix_lines = False
if context.get( 'to_posix_lines', None ) not in [ "None", None, False ]:
@@ -316,12 +317,14 @@
break
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
+ file_bunch.uuid = uuid
return file_bunch, warnings
def get_filenames( context ):
rval = []
data_file = context['file_data']
url_paste = context['url_paste']
ftp_files = context['ftp_files']
+ uuid = context.get( 'uuid', None )
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
to_posix_lines = False
@@ -332,12 +335,14 @@
space_to_tab = True
warnings = []
file_bunch = get_data_file_filename( data_file, override_name = name, override_info = info )
+ file_bunch.uuid = uuid
if file_bunch.path:
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
for file_bunch in get_url_paste_urls_or_filename( context, override_name = name, override_info = info ):
if file_bunch.path:
+ file_bunch.uuid = uuid
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
diff -r d301ac50aa86a94e230d44eb2ae10c6c0e354b88 -r 6cb895d18331fa542b7e3e95598c59de63724246 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,6 +41,7 @@
<!-- Swap the following parameter for the select one that follows to
enable the to_posix_lines option in the Web GUI. See Bitbucket
Pull Request 171 for more information. -->
+ <param name="uuid" type="text" required="False" /><param name="to_posix_lines" type="hidden" value="Yes" /><!--
<param name="to_posix_lines" type="select" display="checkboxes" multiple="True" label="Convert universal line endings to Posix line endings" help="Turn this option off if you upload a gzip, bz2 or zip archive which contains a binary file." value="Yes">
https://bitbucket.org/galaxy/galaxy-central/commits/67dbeb43ebd2/
Changeset: 67dbeb43ebd2
Branch: upload_uuid
User: kellrott
Date: 2014-08-19 01:37:30
Summary: Hiding UUID input for upload tool
Affected #: 1 file
diff -r 6cb895d18331fa542b7e3e95598c59de63724246 -r 67dbeb43ebd21ebad8ad579315f3bf807692f9c8 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,7 +41,7 @@
<!-- Swap the following parameter for the select one that follows to
enable the to_posix_lines option in the Web GUI. See Bitbucket
Pull Request 171 for more information. -->
- <param name="uuid" type="text" required="False" />
+ <param name="uuid" type="hidden" required="False" /><param name="to_posix_lines" type="hidden" value="Yes" /><!--
<param name="to_posix_lines" type="select" display="checkboxes" multiple="True" label="Convert universal line endings to Posix line endings" help="Turn this option off if you upload a gzip, bz2 or zip archive which contains a binary file." value="Yes">
https://bitbucket.org/galaxy/galaxy-central/commits/261471d04763/
Changeset: 261471d04763
User: dannon
Date: 2014-08-25 15:28:26
Summary: Merged in kellrott/galaxy-farm/upload_uuid (pull request #463)
Enabling UUID in file upload
Affected #: 3 files
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -243,6 +243,7 @@
else:
data.extension = uploaded_dataset.file_type
data.dbkey = uploaded_dataset.dbkey
+ data.uuid = uploaded_dataset.uuid
trans.sa_session.add( data )
trans.sa_session.flush()
if library_bunch:
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -278,6 +278,7 @@
ftp_files = context['ftp_files']
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
+ uuid = context.get( 'uuid', None )
warnings = []
to_posix_lines = False
if context.get( 'to_posix_lines', None ) not in [ "None", None, False ]:
@@ -316,12 +317,14 @@
break
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
+ file_bunch.uuid = uuid
return file_bunch, warnings
def get_filenames( context ):
rval = []
data_file = context['file_data']
url_paste = context['url_paste']
ftp_files = context['ftp_files']
+ uuid = context.get( 'uuid', None )
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
to_posix_lines = False
@@ -332,12 +335,14 @@
space_to_tab = True
warnings = []
file_bunch = get_data_file_filename( data_file, override_name = name, override_info = info )
+ file_bunch.uuid = uuid
if file_bunch.path:
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
for file_bunch in get_url_paste_urls_or_filename( context, override_name = name, override_info = info ):
if file_bunch.path:
+ file_bunch.uuid = uuid
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,6 +41,7 @@
<!-- Swap the following parameter for the select one that follows to
enable the to_posix_lines option in the Web GUI. See Bitbucket
Pull Request 171 for more information. -->
+ <param name="uuid" type="hidden" required="False" /><param name="to_posix_lines" type="hidden" value="Yes" /><!--
<param name="to_posix_lines" type="select" display="checkboxes" multiple="True" label="Convert universal line endings to Posix line endings" help="Turn this option off if you upload a gzip, bz2 or zip archive which contains a binary file." value="Yes">
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: Improvements to API import/export test case.
by commits-noreply@bitbucket.org 24 Aug '14
by commits-noreply@bitbucket.org 24 Aug '14
24 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9d8b9171a945/
Changeset: 9d8b9171a945
User: jmchilton
Date: 2014-08-25 01:37:33
Summary: Improvements to API import/export test case.
Actually do some verification of imported history, eliminiate use of deprecated mixin, timeout operations that 'wait', break up big function and name test better.
Affected #: 2 files
diff -r 4e51563b62b5bf497ad42c53868dc9d48d39146c -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 test/api/helpers.py
--- a/test/api/helpers.py
+++ b/test/api/helpers.py
@@ -343,17 +343,27 @@
def wait_on_state( state_func, assert_ok=False, timeout=5 ):
+ def get_state( ):
+ response = state_func()
+ assert response.status_code == 200, "Failed to fetch state update while waiting."
+ state = response.json()[ "state" ]
+ if state not in [ "running", "queued", "new" ]:
+ if assert_ok:
+ assert state == "ok", "Final state - %s - not okay." % state
+ return state
+ else:
+ return None
+ wait_on( get_state, desc="state", timeout=timeout)
+
+
+def wait_on( function, desc, timeout=5 ):
delta = .25
iteration = 0
while True:
if (delta * iteration) > timeout:
- assert False, "Timed out waiting on state."
+ assert False, "Timed out waiting on %s." % desc
iteration += 1
- response = state_func()
- assert response.status_code == 200, "Failed to fetch state update while waiting."
- state = response.json()[ "state" ]
- if state not in [ "running", "queued", "new" ]:
- break
+ value = function()
+ if value is not None:
+ return value
time.sleep( delta )
- if assert_ok:
- assert state == "ok", "Final state - %s - not okay." % state
diff -r 4e51563b62b5bf497ad42c53868dc9d48d39146c -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 test/api/test_histories.py
--- a/test/api/test_histories.py
+++ b/test/api/test_histories.py
@@ -1,13 +1,16 @@
-import time
from base import api
# requests.{post,put,get} or something like it if unavailable
from base.interactor import post_request
from base.interactor import put_request
from base.interactor import get_request
-from .helpers import TestsDatasets
+from .helpers import DatasetPopulator, wait_on
-class HistoriesApiTestCase( api.ApiTestCase, TestsDatasets ):
+class HistoriesApiTestCase( api.ApiTestCase ):
+
+ def setUp( self ):
+ super( HistoriesApiTestCase, self ).setUp( )
+ self.dataset_populator = DatasetPopulator( self.galaxy_interactor )
def test_create_history( self ):
# Create a history.
@@ -29,31 +32,18 @@
create_response = post_request( url=histories_url, data=post_data )
self._assert_status_code_is( create_response, 403 )
- def test_export( self ):
- history_id = self._new_history( name="for_export" )
- self._new_dataset( history_id, content="1 2 3" )
- self._wait_for_history( history_id, assert_ok=True )
- export_url = self._api_url( "histories/%s/exports" % history_id , use_key=True )
- put_response = put_request( export_url )
- self._assert_status_code_is( put_response, 202 )
- # TODO: Break after some period of time.
- while True:
- put_response = put_request( export_url )
- if put_response.status_code == 202:
- time.sleep( .1 )
- else:
- break
- self._assert_status_code_is( put_response, 200 )
- response = put_response.json()
- self._assert_has_keys( response, "download_url" )
- download_path = response[ "download_url" ]
+ def test_import_export( self ):
+ history_id = self.dataset_populator.new_history( name="for_export" )
+ self.dataset_populator.new_dataset( history_id, content="1 2 3" )
+ self.dataset_populator.wait_for_history( history_id, assert_ok=True )
+ download_path = self._export( history_id )
full_download_url = "%s%s?key=%s" % ( self.url, download_path, self.galaxy_interactor.api_key )
download_response = get_request( full_download_url )
self._assert_status_code_is( download_response, 200 )
def history_names():
history_index = self._get( "histories" )
- return map( lambda h: h[ "name" ], history_index.json() )
+ return dict( map( lambda h: ( h[ "name" ], h ), history_index.json() ) )
import_name = "imported from archive: for_export"
assert import_name not in history_names()
@@ -62,11 +52,40 @@
import_response = self._post( "histories", data=import_data )
self._assert_status_code_is( import_response, 200 )
- found = False
- while not found:
- time.sleep( .1 )
- if import_name in history_names():
- found = True
- assert found, "%s not in history names %s" % ( import_name, history_names() )
+
+ def has_history_with_name():
+ histories = history_names()
+ return histories.get( import_name, None )
+
+ imported_history = wait_on( has_history_with_name, desc="import history" )
+ imported_history_id = imported_history[ "id" ]
+ self.dataset_populator.wait_for_history( imported_history_id )
+ contents_response = self._get( "histories/%s/contents" % imported_history_id )
+ self._assert_status_code_is( contents_response, 200 )
+ contents = contents_response.json()
+ assert len( contents ) == 1
+ imported_content = self.dataset_populator.get_history_dataset_content(
+ history_id=imported_history_id,
+ dataset_id=contents[ 0 ][ "id" ]
+ )
+ assert imported_content == "1 2 3\n"
+
+ def _export(self, history_id):
+ export_url = self._api_url( "histories/%s/exports" % history_id, use_key=True )
+ put_response = put_request( export_url )
+ self._assert_status_code_is( put_response, 202 )
+
+ def export_ready_response():
+ put_response = put_request( export_url )
+ if put_response.status_code == 202:
+ return None
+ return put_response
+
+ put_response = wait_on( export_ready_response, desc="export ready" )
+ self._assert_status_code_is( put_response, 200 )
+ response = put_response.json()
+ self._assert_has_keys( response, "download_url" )
+ download_path = response[ "download_url" ]
+ return download_path
#TODO: (CE) test_create_from_copy
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Fix for FASTQ datasets peek/display of sequence counts.
by commits-noreply@bitbucket.org 22 Aug '14
by commits-noreply@bitbucket.org 22 Aug '14
22 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4e51563b62b5/
Changeset: 4e51563b62b5
User: dan
Date: 2014-08-21 21:52:35
Summary: Fix for FASTQ datasets peek/display of sequence counts.
Affected #: 1 file
diff -r 41f9ca7a24c5748f80ed19315786ba51f4cc19b5 -r 4e51563b62b5bf497ad42c53868dc9d48d39146c lib/galaxy/datatypes/sequence.py
--- a/lib/galaxy/datatypes/sequence.py
+++ b/lib/galaxy/datatypes/sequence.py
@@ -460,6 +460,7 @@
"""
Set the number of sequences and the number of data lines
in dataset.
+ FIXME: This does not properly handle line wrapping
"""
if self.max_optional_metadata_filesize >= 0 and dataset.get_size() > self.max_optional_metadata_filesize:
dataset.metadata.data_lines = None
@@ -470,22 +471,17 @@
seq_counter = 0 # blocks should be 4 lines long
for line in file( dataset.file_name ):
line = line.strip()
- if line and line.startswith( '#' ) and not sequences:
+ if line and line.startswith( '#' ) and not data_lines:
# We don't count comment lines for sequence data types
continue
+ seq_counter += 1
+ data_lines += 1
if line and line.startswith( '@' ):
if seq_counter >= 4:
# count previous block
# blocks should be 4 lines long
sequences += 1
seq_counter = 1
- else:
- # in case quality line starts with @
- seq_counter += 1
- data_lines += 1
- else:
- data_lines += 1
- seq_counter += 1
if seq_counter >= 4:
# count final block
sequences += 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: guerler: ToolForm: Implements conditionals
by commits-noreply@bitbucket.org 22 Aug '14
by commits-noreply@bitbucket.org 22 Aug '14
22 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/41f9ca7a24c5/
Changeset: 41f9ca7a24c5
User: guerler
Date: 2014-08-22 20:32:07
Summary: ToolForm: Implements conditionals
Affected #: 2 files
diff -r 0c2fd93d22b796bb38687ca5489e7c57c3e14c21 -r 41f9ca7a24c5748f80ed19315786ba51f4cc19b5 static/scripts/mvc/tools/tools-form.js
--- a/static/scripts/mvc/tools/tools-form.js
+++ b/static/scripts/mvc/tools/tools-form.js
@@ -103,8 +103,11 @@
// reset table
this.table.delAll();
- // reset list
- this.list = [];
+ // reset field list
+ this.field_list = {};
+
+ // reset sequential input definition list
+ this.inputs_sequential = {};
// model
var data = new Backbone.Model();
@@ -115,65 +118,93 @@
}
// trigger change
- for (var id in this.list) {
- this.list[id].trigger('change');
+ for (var id in this.field_list) {
+ this.field_list[id].trigger('change');
}
},
// add table row
_add: function(inputs_def, data) {
- // link this
- var self = this;
-
+ // identify field type
+ var type = inputs_def.type;
+ switch(type) {
+ // conditional field
+ case 'conditional':
+ // add label to input definition root
+ inputs_def.label = inputs_def.test_param.label;
+
+ // add id to input definition root
+ inputs_def.name = inputs_def.test_param.name;
+
+ // build options field
+ this._addRow('conditional', inputs_def, data);
+
+ // add fields
+ for (var i in inputs_def.cases) {
+ var cases = inputs_def.cases[i];
+ for (var j in cases.inputs) {
+ // add element to form
+ this._add(cases.inputs[j], data);
+ }
+ }
+ break;
+
+ // default single element row
+ default:
+ this._addRow(type, inputs_def, data);
+ }
+ },
+
+ // add table row
+ _addRow: function(field_type, inputs_def, data) {
// get id
var id = inputs_def.name;
// field wrapper
var field = null;
- console.log(inputs_def);
- // create select field
- var type = inputs_def.type;
- switch(type) {
+
+ // identify field type
+ switch(field_type) {
// text input field
case 'text' :
- field = this.field_text(inputs_def, data);
+ field = this._field_text(inputs_def, data);
break;
// select field
case 'select' :
- field = this.field_select(inputs_def, data);
+ field = this._field_select(inputs_def, data);
break;
// radiobox field
case 'radiobutton' :
- field = this.field_radio(inputs_def, data);
+ field = this._field_radio(inputs_def, data);
break;
// dataset
case 'data':
- field = this.field_data(inputs_def, data);
+ field = this._field_data(inputs_def, data);
break;
// dataset column
case 'data_column':
- field = this.field_column(inputs_def, data);
+ field = this._field_column(inputs_def, data);
break;
// text area field
case 'textarea' :
- field = this.field_textarea(inputs_def, data);
+ field = this._field_textarea(inputs_def, data);
break;
-
- // default
- default:
- field = new Ui.Input({
- id : 'field-' + id,
- placeholder : inputs_def.placeholder,
- type : inputs_def.type,
- onchange : function() {
- data.set(id, field.value());
- }
- });
+
+ // conditional select field
+ case 'conditional':
+ field = this._field_conditional(inputs_def, data);
+ break;
+ }
+
+ // check if field type was detected
+ if (!field) {
+ console.debug('tools-form::_addRow() : Unmatched field type (' + field_type + ').');
+ return;
}
// set value
@@ -182,8 +213,11 @@
}
field.value(data.get(id));
- // add list
- this.list[id] = field;
+ // add to field list
+ this.field_list[id] = field;
+
+ // add to input definition into sequential list
+ this.inputs_sequential[id] = inputs_def;
// combine field and info
var $input = $('<div/>');
@@ -206,7 +240,7 @@
},
// text input field
- field_text : function(inputs_def, data) {
+ _field_text : function(inputs_def, data) {
var id = inputs_def.name;
return new Ui.Input({
id : 'field-' + id,
@@ -218,7 +252,7 @@
},
// text area
- field_textarea : function(inputs_def, data) {
+ _field_textarea : function(inputs_def, data) {
var id = inputs_def.name;
return new Ui.Textarea({
id : 'field-' + id,
@@ -228,8 +262,72 @@
});
},
+ // conditional input field
+ _field_conditional : function(inputs_def, data) {
+ // link this
+ var self = this;
+
+ // configure options fields
+ var options = [];
+ for (var i in inputs_def.test_param.options) {
+ var option = inputs_def.test_param.options[i];
+ options.push({
+ label: option[0],
+ value: option[1]
+ });
+ }
+
+ // select field
+ var id = inputs_def.name;
+ return new Ui.Select.View({
+ id : 'field-' + id,
+ data : options,
+ value : data.get(id),
+ onchange : function(value) {
+ // update value
+ data.set(id, value);
+
+ // recursively hide/show options
+ function _updateVisibility(root, show) {
+ // loop through all inputs
+ for (var i in root.inputs) {
+ // get input element
+ var element = root.inputs[i];
+
+ // identify element name
+ var element_id = element.name;
+
+ // identify row
+ var element_row = self.table.get(element_id);
+
+ // show/hide row
+ if (show) {
+ element_row.fadeIn();
+ } else {
+ element_row.hide();
+ }
+
+ // check if its a nested conditional
+ if (element.type == 'conditional') {
+ // identify all cases
+ for (var j in element.cases) {
+ _updateVisibility(element.cases[j], show);
+ }
+ }
+ }
+ }
+
+ // check value in order to hide/show options
+ for (var i in inputs_def.cases) {
+ var case_def = inputs_def.cases[i];
+ _updateVisibility(case_def, case_def.value == value);
+ }
+ }
+ });
+ },
+
// data input field
- field_data : function(inputs_def, data) {
+ _field_data : function(inputs_def, data) {
// link this
var self = this;
@@ -248,12 +346,6 @@
});
}
- // find referenced columns
- var column_list = _.where(this.inputs, {
- data_ref : id,
- type : 'data_column'
- });
-
// select field
return new Ui.Select.View({
id : 'field-' + id,
@@ -263,6 +355,12 @@
// update value
data.set(id, value);
+ // find referenced columns
+ var column_list = _.where(self.inputs_sequential, {
+ data_ref : id,
+ type : 'data_column'
+ });
+
// find selected dataset
var dataset = self.datasets.filter(value);
@@ -291,7 +389,7 @@
// update referenced columns
for (var i in column_list) {
- var column_field = self.list[column_list[i].name]
+ var column_field = self.field_list[column_list[i].name]
if (column_field) {
column_field.update(columns);
column_field.value(column_field.first());
@@ -306,7 +404,7 @@
},
// select field
- field_column : function (inputs_def, data) {
+ _field_column : function (inputs_def, data) {
// configure options fields
var options = [];
for (var i in inputs_def.options) {
@@ -330,7 +428,7 @@
},
// select field
- field_select : function (inputs_def, data) {
+ _field_select : function (inputs_def, data) {
// configure options fields
var options = [];
for (var i in inputs_def.options) {
@@ -360,7 +458,7 @@
},
// radio field
- field_radio : function(inputs_def, data) {
+ _field_radio : function(inputs_def, data) {
var id = inputs_def.name;
return new Ui.RadioButton({
id : 'field-' + id,
diff -r 0c2fd93d22b796bb38687ca5489e7c57c3e14c21 -r 41f9ca7a24c5748f80ed19315786ba51f4cc19b5 static/scripts/packed/mvc/tools/tools-form.js
--- a/static/scripts/packed/mvc/tools/tools-form.js
+++ b/static/scripts/packed/mvc/tools/tools-form.js
@@ -1,1 +1,1 @@
-define(["mvc/ui/ui-portlet","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets"],function(f,i,j,h,a,e,c,g){var d=Backbone.Model.extend({initialize:function(k){this.url=galaxy_config.root+"api/tools/"+k.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(l){var k=this;this.options=l;this.model=new d({id:l.id});this.datasets=new g({success:function(){k._initializeToolForm()}})},_initializeToolForm:function(){var k=this;this.model.fetch({success:function(){k.inputs=k.model.get("inputs");k.portlet=new f.View({icon:"fa-wrench",title:"<b>"+k.model.get("name")+"</b> "+k.model.get("description"),buttons:{execute:new j.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){}})}});k.table=new i.View();k.message=new j.Message();k.portlet.append(k.message.$el);$(k.main_el).append(k.portlet.$el);if(k.options.help!=""){$(k.main_el).append(c.help(k.options.help))}if(k.options.citations){$(k.main_el).append(c.citations());var l=new h.ToolCitationCollection();l.tool_id=k.options.id;var m=new a.CitationListView({collection:l});m.render();l.fetch()}k.setElement(k.portlet.content());k.portlet.append(k.table.$el);k.render()}})},render:function(){this.table.delAll();this.list=[];var k=new Backbone.Model();for(var l in this.inputs){this._add(this.inputs[l],k)}for(var l in this.list){this.list[l].trigger("change")}},_add:function(l,n){var k=this;var q=l.name;var o=null;console.log(l);var m=l.type;switch(m){case"text":o=this.field_text(l,n);break;case"select":o=this.field_select(l,n);break;case"radiobutton":o=this.field_radio(l,n);break;case"data":o=this.field_data(l,n);break;case"data_column":o=this.field_column(l,n);break;case"textarea":o=this.field_textarea(l,n);break;default:o=new j.Input({id:"field-"+q,placeholder:l.placeholder,type:l.type,onchange:function(){n.set(q,o.value())}})}if(!n.get(q)){n.set(q,l.value)}o.value(n.get(q));this.list[q]=o;var p=$("<div/>");p.append(o.$el);if(l.info){p.append('<div class="ui-table-form-info">'+l.info+"</div>")}this.table.add('<span class="ui-table-form-title">'+l.label+"</span>","25%");this.table.add(p);this.table.append(q);if(l.hide){this.table.get(q).hide()}},field_text:function(k,l){var m=k.name;return new j.Input({id:"field-"+m,value:l.get(m),onchange:function(n){l.set(m,n)}})},field_textarea:function(k,l){var m=k.name;return new j.Textarea({id:"field-"+m,onchange:function(){l.set(m,field.value())}})},field_data:function(n,q){var l=this;var r=n.name;var p=this.datasets.filterType();var m=[];for(var o in p){m.push({label:p[o].get("name"),value:p[o].get("id")})}var k=_.where(this.inputs,{data_ref:r,type:"data_column"});return new j.Select.View({id:"field-"+r,data:m,value:m[0].value,onchange:function(w){q.set(r,w);var y=l.datasets.filter(w);if(y&&k.length>0){console.debug("tool-form::field_data() - Selected dataset "+w+".");var x=y.get("metadata_column_types");if(!x){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+w+".")}var v=[];for(var u in x){v.push({label:"Column: "+(parseInt(u)+1)+" ["+x[u]+"]",value:u})}for(var t in k){var s=l.list[k[t].name];if(s){s.update(v);s.value(s.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+w+".")}}})},field_column:function(l,o){var k=[];for(var m in l.options){var n=l.options[m];k.push({label:n[0],value:n[1]})}var p=l.name;return new j.Select.View({id:"field-"+p,data:k,value:o.get(p),onchange:function(q){o.set(p,q)}})},field_select:function(l,p){var k=[];for(var m in l.options){var n=l.options[m];k.push({label:n[0],value:n[1]})}var o=j.Select;if(l.display=="checkboxes"){o=j.Checkbox}var q=l.name;return new o.View({id:"field-"+q,data:k,value:p.get(q),onchange:function(r){p.set(q,r)}})},field_radio:function(k,l){var m=k.name;return new j.RadioButton({id:"field-"+m,data:k.data,value:l.get(m),onchange:function(n){l.set(m,n)}})}});return{View:b}});
\ No newline at end of file
+define(["mvc/ui/ui-portlet","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets"],function(f,i,j,h,a,e,c,g){var d=Backbone.Model.extend({initialize:function(k){this.url=galaxy_config.root+"api/tools/"+k.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(l){var k=this;this.options=l;this.model=new d({id:l.id});this.datasets=new g({success:function(){k._initializeToolForm()}})},_initializeToolForm:function(){var k=this;this.model.fetch({success:function(){k.inputs=k.model.get("inputs");k.portlet=new f.View({icon:"fa-wrench",title:"<b>"+k.model.get("name")+"</b> "+k.model.get("description"),buttons:{execute:new j.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){}})}});k.table=new i.View();k.message=new j.Message();k.portlet.append(k.message.$el);$(k.main_el).append(k.portlet.$el);if(k.options.help!=""){$(k.main_el).append(c.help(k.options.help))}if(k.options.citations){$(k.main_el).append(c.citations());var l=new h.ToolCitationCollection();l.tool_id=k.options.id;var m=new a.CitationListView({collection:l});m.render();l.fetch()}k.setElement(k.portlet.content());k.portlet.append(k.table.$el);k.render()}})},render:function(){this.table.delAll();this.field_list={};this.inputs_sequential={};var k=new Backbone.Model();for(var l in this.inputs){this._add(this.inputs[l],k)}for(var l in this.field_list){this.field_list[l].trigger("change")}},_add:function(l,p){var n=l.type;switch(n){case"conditional":l.label=l.test_param.label;l.name=l.test_param.name;this._addRow("conditional",l,p);for(var m in l.cases){var o=l.cases[m];for(var k in o.inputs){this._add(o.inputs[k],p)}}break;default:this._addRow(n,l,p)}},_addRow:function(n,k,l){var p=k.name;var m=null;switch(n){case"text":m=this._field_text(k,l);break;case"select":m=this._field_select(k,l);break;case"radiobutton":m=this._field_radio(k,l);break;case"data":m=this._field_data(k,l);break;case"data_column":m=this._field_column(k,l);break;case"textarea":m=this._field_textarea(k,l);break;case"conditional":m=this._field_conditional(k,l);break}if(!m){console.debug("tools-form::_addRow() : Unmatched field type ("+n+").");return}if(!l.get(p)){l.set(p,k.value)}m.value(l.get(p));this.field_list[p]=m;this.inputs_sequential[p]=k;var o=$("<div/>");o.append(m.$el);if(k.info){o.append('<div class="ui-table-form-info">'+k.info+"</div>")}this.table.add('<span class="ui-table-form-title">'+k.label+"</span>","25%");this.table.add(o);this.table.append(p);if(k.hide){this.table.get(p).hide()}},_field_text:function(k,l){var m=k.name;return new j.Input({id:"field-"+m,value:l.get(m),onchange:function(n){l.set(m,n)}})},_field_textarea:function(k,l){var m=k.name;return new j.Textarea({id:"field-"+m,onchange:function(){l.set(m,field.value())}})},_field_conditional:function(m,p){var k=this;var l=[];for(var n in m.test_param.options){var o=m.test_param.options[n];l.push({label:o[0],value:o[1]})}var q=m.name;return new j.Select.View({id:"field-"+q,data:l,value:p.get(q),onchange:function(u){p.set(q,u);function t(x,w){for(var A in x.inputs){var z=x.inputs[A];var v=z.name;var B=k.table.get(v);if(w){B.fadeIn()}else{B.hide()}if(z.type=="conditional"){for(var y in z.cases){t(z.cases[y],w)}}}}for(var s in m.cases){var r=m.cases[s];t(r,r.value==u)}}})},_field_data:function(m,p){var k=this;var q=m.name;var o=this.datasets.filterType();var l=[];for(var n in o){l.push({label:o[n].get("name"),value:o[n].get("id")})}return new j.Select.View({id:"field-"+q,data:l,value:l[0].value,onchange:function(w){p.set(q,w);var s=_.where(k.inputs_sequential,{data_ref:q,type:"data_column"});var y=k.datasets.filter(w);if(y&&s.length>0){console.debug("tool-form::field_data() - Selected dataset "+w+".");var x=y.get("metadata_column_types");if(!x){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+w+".")}var v=[];for(var u in x){v.push({label:"Column: "+(parseInt(u)+1)+" ["+x[u]+"]",value:u})}for(var t in s){var r=k.field_list[s[t].name];if(r){r.update(v);r.value(r.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+w+".")}}})},_field_column:function(l,o){var k=[];for(var m in l.options){var n=l.options[m];k.push({label:n[0],value:n[1]})}var p=l.name;return new j.Select.View({id:"field-"+p,data:k,value:o.get(p),onchange:function(q){o.set(p,q)}})},_field_select:function(l,p){var k=[];for(var m in l.options){var n=l.options[m];k.push({label:n[0],value:n[1]})}var o=j.Select;if(l.display=="checkboxes"){o=j.Checkbox}var q=l.name;return new o.View({id:"field-"+q,data:k,value:p.get(q),onchange:function(r){p.set(q,r)}})},_field_radio:function(k,l){var m=k.name;return new j.RadioButton({id:"field-"+m,data:k.data,value:l.get(m),onchange:function(n){l.set(m,n)}})}});return{View:b}});
\ 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
commit/galaxy-central: natefoo: Update tag latest_2014.08.11 for changeset 7e22f3579852
by commits-noreply@bitbucket.org 22 Aug '14
by commits-noreply@bitbucket.org 22 Aug '14
22 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d86834553f0e/
Changeset: d86834553f0e
Branch: stable
User: natefoo
Date: 2014-08-22 15:00:42
Summary: Update tag latest_2014.08.11 for changeset 7e22f3579852
Affected #: 1 file
diff -r 7e22f35798522100ff03e1fdd4eced962b292360 -r d86834553f0e2d3636b3f545f61ae3250ead31e9 .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -18,4 +18,4 @@
81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04
2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
-6445c0fe761258410a17b95ad2f221a9e60fc5c7 latest_2014.08.11
+7e22f35798522100ff03e1fdd4eced962b292360 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: dan: Fix for FASTQ datasets peek/display of sequence counts.
by commits-noreply@bitbucket.org 21 Aug '14
by commits-noreply@bitbucket.org 21 Aug '14
21 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7e22f3579852/
Changeset: 7e22f3579852
Branch: stable
User: dan
Date: 2014-08-21 21:52:35
Summary: Fix for FASTQ datasets peek/display of sequence counts.
Affected #: 1 file
diff -r b6c8afd2c2a1a214ef96c4ccf05aab8c8bc826f2 -r 7e22f35798522100ff03e1fdd4eced962b292360 lib/galaxy/datatypes/sequence.py
--- a/lib/galaxy/datatypes/sequence.py
+++ b/lib/galaxy/datatypes/sequence.py
@@ -460,6 +460,7 @@
"""
Set the number of sequences and the number of data lines
in dataset.
+ FIXME: This does not properly handle line wrapping
"""
if self.max_optional_metadata_filesize >= 0 and dataset.get_size() > self.max_optional_metadata_filesize:
dataset.metadata.data_lines = None
@@ -470,22 +471,17 @@
seq_counter = 0 # blocks should be 4 lines long
for line in file( dataset.file_name ):
line = line.strip()
- if line and line.startswith( '#' ) and not sequences:
+ if line and line.startswith( '#' ) and not data_lines:
# We don't count comment lines for sequence data types
continue
+ seq_counter += 1
+ data_lines += 1
if line and line.startswith( '@' ):
if seq_counter >= 4:
# count previous block
# blocks should be 4 lines long
sequences += 1
seq_counter = 1
- else:
- # in case quality line starts with @
- seq_counter += 1
- data_lines += 1
- else:
- data_lines += 1
- seq_counter += 1
if seq_counter >= 4:
# count final block
sequences += 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