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
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/39bc0ce6bb54/
Changeset: 39bc0ce6bb54
User: jmchilton
Date: 2014-12-11 04:51:45+00:00
Summary: PEP-8 fixes for tool related stuff.
Affected #: 1 file
diff -r fc60d0eeb22b28a2e61db5c6ec672a3dc5663845 -r 39bc0ce6bb543238c1ee67fc5491e65ed16fe6f0 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -1417,12 +1417,12 @@
def recurse_option_elems( cur_options, option_elems ):
for option_elem in option_elems:
selected = string_as_bool( option_elem.get( 'selected', False ) )
- cur_options.append( { 'name':option_elem.get( 'name' ), 'value': option_elem.get( 'value'), 'options':[], 'selected':selected } )
+ cur_options.append( { 'name': option_elem.get( 'name' ), 'value': option_elem.get( 'value' ), 'options': [], 'selected': selected } )
recurse_option_elems( cur_options[-1]['options'], option_elem.findall( 'option' ) )
ToolParameter.__init__( self, tool, elem )
self.multiple = string_as_bool( elem.get( 'multiple', False ) )
self.display = elem.get( 'display', None )
- self.hierarchy = elem.get( 'hierarchy', 'exact' ) #exact or recurse
+ self.hierarchy = elem.get( 'hierarchy', 'exact' ) # exact or recurse
self.separator = elem.get( 'separator', ',' )
from_file = elem.get( 'from_file', None )
if from_file:
@@ -1430,7 +1430,7 @@
from_file = os.path.join( tool.app.config.tool_data_path, from_file )
elem = XML( "<root>%s</root>" % open( from_file ).read() )
self.is_dynamic = False
- self.dynamic_options = elem.get( 'dynamic_options' , None )
+ self.dynamic_options = elem.get( 'dynamic_options', None )
if self.dynamic_options:
self.is_dynamic = True
self.options = []
@@ -1509,17 +1509,18 @@
return form_builder.TextArea( self.name, value=value )
else:
return form_builder.TextField( self.name, value=(value or "") )
- return form_builder.DrillDownField( self.name, self.multiple, self.display, self.refresh_on_change, self.get_options( trans, value, other_values ), value, refresh_on_change_values = self.refresh_on_change_values )
+ return form_builder.DrillDownField( self.name, self.multiple, self.display, self.refresh_on_change, self.get_options( trans, value, other_values ), value, refresh_on_change_values=self.refresh_on_change_values )
def from_html( self, value, trans=None, other_values={} ):
if self.need_late_validation( trans, other_values ):
if self.multiple:
- if value == '': #No option selected
+ if value == '': # No option selected
value = None
else:
value = value.split( "\n" )
return UnvalidatedValue( value )
- if not value: return None
+ if not value:
+ return None
if not isinstance( value, list ):
value = [value]
if not( self.repeat ) and len( value ) > 1:
@@ -1540,8 +1541,10 @@
if value == option['value']:
return option
rval = get_base_option( value, option['options'] )
- if rval: return rval
- return None #not found
+ if rval:
+ return rval
+ return None # not found
+
def recurse_option( option_list, option ):
if not option['options']:
option_list.append( option['value'] )
@@ -1931,7 +1934,7 @@
if value in [None, "None"]:
return None
if isinstance( value, str ) and value.find( "," ) > 0:
- value = [ int( value_part ) for value_part in value.split( "," ) ]
+ value = [ int( value_part ) for value_part in value.split( "," ) ]
if isinstance( value, list ):
rval = []
for single_value in value:
@@ -2368,6 +2371,7 @@
# return final dictionary
return d
+
class HiddenDataToolParameter( HiddenToolParameter, DataToolParameter ):
"""
Hidden parameter that behaves as a DataToolParameter. As with all hidden
https://bitbucket.org/galaxy/galaxy-central/commits/b9c5b028e389/
Changeset: b9c5b028e389
User: jmchilton
Date: 2014-12-11 04:51:45+00:00
Summary: More testing for parameter parsing.
Affected #: 1 file
diff -r 39bc0ce6bb543238c1ee67fc5491e65ed16fe6f0 -r b9c5b028e389678c1a073f11c9aba5104ae17e89 test/unit/tools/test_parameter_parsing.py
--- a/test/unit/tools/test_parameter_parsing.py
+++ b/test/unit/tools/test_parameter_parsing.py
@@ -177,9 +177,11 @@
<option value="b" selected="true">B</option></param>
""")
+ assert param.display is None
assert param.multiple is True
assert param.name == "selectp"
assert param.type == "select"
+ assert param.separator == ","
assert param.options is None
assert param.dynamic_options is None
@@ -196,7 +198,7 @@
def test_select_dynamic(self):
param = self._parameter_for(xml="""
- <param name="selectp" type="select" dynamic_options="cow">
+ <param name="selectp" type="select" dynamic_options="cow" display="checkboxes" separator="moo"></param>
""")
assert param.multiple is False
@@ -206,6 +208,9 @@
# assert not param.static_options
assert param.is_dynamic
+ assert param.display == "checkboxes"
+ assert param.separator == "moo"
+
def test_select_options_from(self):
param = self._parameter_for(xml="""
<param name="selectp" type="select">
@@ -229,8 +234,79 @@
assert param.name == "genomep"
assert param.static_options
- # Column and Data have sufficient test coverage in
- # other modules.
+ def test_column_params(self):
+ param = self._parameter_for(xml="""
+ <param name="col1" type="data_column" data_ref="input1">
+ </param>
+ """)
+ assert param.data_ref == "input1"
+ assert param.usecolnames is False
+ assert param.force_select is True
+ assert param.numerical is False
+
+ param = self._parameter_for(xml="""
+ <param name="col1" type="data_column" data_ref="input1" use_header_names="true" numerical="true" force_select="false">
+ </param>
+ """)
+ assert param.data_ref == "input1"
+ assert param.usecolnames is True
+ assert param.force_select is False
+ assert param.numerical is True
+
+ def test_data_param_no_validation(self):
+ param = self._parameter_for(xml="""
+ <param name="input" type="data">
+ </param>
+ """)
+ assert len(param.validators) == 1
+ param = self._parameter_for(xml="""
+ <param name="input" type="data" no_validation="true">
+ </param>
+ """)
+ assert len(param.validators) == 0
+
+ def test_data_param_dynamic_options(self):
+ param = self._parameter_for(xml="""
+ <param name="input" type="data" />
+ """)
+ assert param.options is None
+ assert param.options_filter_attribute is None
+
+ param = self._parameter_for(xml="""
+ <param name="input" type="data">
+ <options from_data_table="cow">
+ </options>
+ </param>
+ """)
+ assert param.options is not None
+ assert param.options_filter_attribute is None
+
+ param = self._parameter_for(xml="""
+ <param name="input" type="data">
+ <options from_data_table="cow" options_filter_attribute="cow">
+ </options>
+ </param>
+ """)
+ assert param.options is not None
+ assert param.options_filter_attribute == "cow"
+
+ def test_conversions(self):
+ param = self._parameter_for(xml="""
+ <param name="input" type="data" />
+ """)
+ assert param.conversions == []
+
+ param = self._parameter_for(xml="""
+ <param name="input" type="data">
+ <conversion name="foo" type="txt" />
+ <conversion name="foo2" type="bam" />
+ </param>
+ """)
+ assert param.conversions[0][0] == "foo"
+ assert param.conversions[0][1] == "txt"
+ assert param.conversions[1][0] == "foo2"
+ assert param.conversions[1][1] == "bam"
+
def test_drilldown(self):
param = self._parameter_for(xml="""
<param name="some_name" type="drill_down" display="checkbox" hierarchy="recurse" multiple="true">
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
[galaxyproject/usegalaxy-playbook] b78a21: Dropped VSU workshop slide from rotation. Almost ...
by GitHub 10 Dec '14
by GitHub 10 Dec '14
10 Dec '14
Branch: refs/heads/master
Home: https://github.com/galaxyproject/usegalaxy-playbook
Commit: b78a21b5954c3f89311c4223e403bea47f4ff677
https://github.com/galaxyproject/usegalaxy-playbook/commit/b78a21b5954c3f89…
Author: Dave Clements <clements(a)Clements-Galaxy.local>
Date: 2014-12-10 (Wed, 10 Dec 2014)
Changed paths:
M templates/galaxy/common/static/welcome.html.j2
Log Message:
-----------
Dropped VSU workshop slide from rotation. Almost full.
1
0
commit/galaxy-central: dannon: Merged in peterjc/galaxy-central-2/peterjc/clearer-error-messages-where-parameter-v-1418233351514 (pull request #604)
by commits-noreply@bitbucket.org 10 Dec '14
by commits-noreply@bitbucket.org 10 Dec '14
10 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/fc60d0eeb22b/
Changeset: fc60d0eeb22b
User: dannon
Date: 2014-12-10 21:53:09+00:00
Summary: Merged in peterjc/galaxy-central-2/peterjc/clearer-error-messages-where-parameter-v-1418233351514 (pull request #604)
Clearer error messages where parameter validation fails
Affected #: 1 file
diff -r 0852880c97bdcc5730d0fc396c094fbadd296931 -r fc60d0eeb22b28a2e61db5c6ec672a3dc5663845 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -837,13 +837,14 @@
value = value.split()
return UnvalidatedValue( value )
legal_values = self.get_legal_values( trans, context )
+ assert legal_values, "Parameter %s requires a value, but has no legal values defined" % self.name
if isinstance( value, list ):
if not(self.repeat):
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
rval = []
for v in value:
if v not in legal_values:
- raise ValueError( "An invalid option was selected, please verify" )
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, v))
rval.append( v )
return rval
else:
@@ -853,9 +854,9 @@
if self.optional:
return []
else:
- raise ValueError( "No option was selected but input is not optional." )
+ raise ValueError( "No option was selected for %s but input is not optional." % self.name)
if value not in legal_values:
- raise ValueError( "An invalid option was selected, please verify" )
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, value))
return value
def to_html_value( self, value, app ):
@@ -869,7 +870,7 @@
return "None"
if isinstance( value, list ):
if not( self.repeat ):
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
value = map( str, value )
else:
value = str( value )
@@ -1522,10 +1523,13 @@
if not isinstance( value, list ):
value = [value]
if not( self.repeat ) and len( value ) > 1:
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
rval = []
+ legal_values = self.get_legal_values( trans, other_values )
+ assert legal_values, "Parameter %s requires a value, but has no legal values defined" % self.name
for val in value:
- if val not in self.get_legal_values( trans, other_values ): raise ValueError( "An invalid option was selected, please verify" )
+ if val not in legal_values:
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, val))
rval.append( val )
return rval
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/9ba27992bfed/
Changeset: 9ba27992bfed
Branch: peterjc/clearer-error-messages-where-parameter-v-1418233351514
User: peterjc
Date: 2014-12-10 17:43:03+00:00
Summary: Clearer error messages where parameter validation fails
Affected #: 1 file
diff -r d66ad58a40e31defb6de0eb8b8b543b7e0f26ae5 -r 9ba27992bfed77dccbe59768d7de587f40f3c64b lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -839,11 +839,11 @@
legal_values = self.get_legal_values( trans, context )
if isinstance( value, list ):
if not(self.repeat):
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
rval = []
for v in value:
if v not in legal_values:
- raise ValueError( "An invalid option was selected, please verify" )
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, v))
rval.append( v )
return rval
else:
@@ -853,9 +853,9 @@
if self.optional:
return []
else:
- raise ValueError( "No option was selected but input is not optional." )
+ raise ValueError( "No option was selected for %s but input is not optional." % self.name)
if value not in legal_values:
- raise ValueError( "An invalid option was selected, please verify" )
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, value))
return value
def to_html_value( self, value, app ):
@@ -869,7 +869,7 @@
return "None"
if isinstance( value, list ):
if not( self.repeat ):
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
value = map( str, value )
else:
value = str( value )
@@ -1522,10 +1522,10 @@
if not isinstance( value, list ):
value = [value]
if not( self.repeat ) and len( value ) > 1:
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
rval = []
for val in value:
- if val not in self.get_legal_values( trans, other_values ): raise ValueError( "An invalid option was selected, please verify" )
+ if val not in self.get_legal_values( trans, other_values ): raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, val))
rval.append( val )
return rval
https://bitbucket.org/galaxy/galaxy-central/commits/f77d82d21050/
Changeset: f77d82d21050
Branch: peterjc/clearer-error-messages-where-parameter-v-1418233351514
User: peterjc
Date: 2014-12-10 18:00:21+00:00
Summary: Clearer error messages if parameter as no legal values
Affected #: 1 file
diff -r 9ba27992bfed77dccbe59768d7de587f40f3c64b -r f77d82d2105034f021c82aee20bdffdaf862915a lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -837,6 +837,7 @@
value = value.split()
return UnvalidatedValue( value )
legal_values = self.get_legal_values( trans, context )
+ assert legal_values, "Parameter %s requires a value, but has no legal values defined" % self.name
if isinstance( value, list ):
if not(self.repeat):
assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
@@ -1524,8 +1525,11 @@
if not( self.repeat ) and len( value ) > 1:
assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
rval = []
+ legal_values = self.get_legal_values( trans, other_values )
+ assert legal_values, "Parameter %s requires a value, but has no legal values defined" % self.name
for val in value:
- if val not in self.get_legal_values( trans, other_values ): raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, val))
+ if val not in legal_values:
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, val))
rval.append( val )
return rval
https://bitbucket.org/galaxy/galaxy-central/commits/fc60d0eeb22b/
Changeset: fc60d0eeb22b
User: dannon
Date: 2014-12-10 21:53:09+00:00
Summary: Merged in peterjc/galaxy-central-2/peterjc/clearer-error-messages-where-parameter-v-1418233351514 (pull request #604)
Clearer error messages where parameter validation fails
Affected #: 1 file
diff -r 0852880c97bdcc5730d0fc396c094fbadd296931 -r fc60d0eeb22b28a2e61db5c6ec672a3dc5663845 lib/galaxy/tools/parameters/basic.py
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -837,13 +837,14 @@
value = value.split()
return UnvalidatedValue( value )
legal_values = self.get_legal_values( trans, context )
+ assert legal_values, "Parameter %s requires a value, but has no legal values defined" % self.name
if isinstance( value, list ):
if not(self.repeat):
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
rval = []
for v in value:
if v not in legal_values:
- raise ValueError( "An invalid option was selected, please verify" )
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, v))
rval.append( v )
return rval
else:
@@ -853,9 +854,9 @@
if self.optional:
return []
else:
- raise ValueError( "No option was selected but input is not optional." )
+ raise ValueError( "No option was selected for %s but input is not optional." % self.name)
if value not in legal_values:
- raise ValueError( "An invalid option was selected, please verify" )
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, value))
return value
def to_html_value( self, value, app ):
@@ -869,7 +870,7 @@
return "None"
if isinstance( value, list ):
if not( self.repeat ):
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
value = map( str, value )
else:
value = str( value )
@@ -1522,10 +1523,13 @@
if not isinstance( value, list ):
value = [value]
if not( self.repeat ) and len( value ) > 1:
- assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
+ assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
rval = []
+ legal_values = self.get_legal_values( trans, other_values )
+ assert legal_values, "Parameter %s requires a value, but has no legal values defined" % self.name
for val in value:
- if val not in self.get_legal_values( trans, other_values ): raise ValueError( "An invalid option was selected, please verify" )
+ if val not in legal_values:
+ raise ValueError( "An invalid option was selected for %s, %r, please verify" % (self.name, val))
rval.append( val )
return rval
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: Client: update libs/underscore.js to 1.7
by commits-noreply@bitbucket.org 10 Dec '14
by commits-noreply@bitbucket.org 10 Dec '14
10 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0852880c97bd/
Changeset: 0852880c97bd
User: carlfeberhard
Date: 2014-12-10 21:23:21+00:00
Summary: Client: update libs/underscore.js to 1.7
Affected #: 3 files
diff -r d66ad58a40e31defb6de0eb8b8b543b7e0f26ae5 -r 0852880c97bdcc5730d0fc396c094fbadd296931 client/galaxy/scripts/libs/underscore.js
--- a/client/galaxy/scripts/libs/underscore.js
+++ b/client/galaxy/scripts/libs/underscore.js
@@ -1,6 +1,6 @@
-// Underscore.js 1.4.4
+// Underscore.js 1.7.0
// http://underscorejs.org
-// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
+// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license.
(function() {
@@ -8,37 +8,26 @@
// Baseline setup
// --------------
- // Establish the root object, `window` in the browser, or `global` on the server.
+ // Establish the root object, `window` in the browser, or `exports` on the server.
var root = this;
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
- // Establish the object that gets returned to break out of a loop iteration.
- var breaker = {};
-
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
// Create quick reference variables for speed access to core prototypes.
- var push = ArrayProto.push,
- slice = ArrayProto.slice,
- concat = ArrayProto.concat,
- toString = ObjProto.toString,
- hasOwnProperty = ObjProto.hasOwnProperty;
+ var
+ push = ArrayProto.push,
+ slice = ArrayProto.slice,
+ concat = ArrayProto.concat,
+ toString = ObjProto.toString,
+ hasOwnProperty = ObjProto.hasOwnProperty;
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
var
- nativeForEach = ArrayProto.forEach,
- nativeMap = ArrayProto.map,
- nativeReduce = ArrayProto.reduce,
- nativeReduceRight = ArrayProto.reduceRight,
- nativeFilter = ArrayProto.filter,
- nativeEvery = ArrayProto.every,
- nativeSome = ArrayProto.some,
- nativeIndexOf = ArrayProto.indexOf,
- nativeLastIndexOf = ArrayProto.lastIndexOf,
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind;
@@ -52,8 +41,7 @@
// Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in
- // the browser, add `_` as a global object via a string identifier,
- // for Closure Compiler "advanced" mode.
+ // the browser, add `_` as a global object.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
@@ -64,98 +52,125 @@
}
// Current version.
- _.VERSION = '1.4.4';
+ _.VERSION = '1.7.0';
+
+ // Internal function that returns an efficient (for current engines) version
+ // of the passed-in callback, to be repeatedly applied in other Underscore
+ // functions.
+ var createCallback = function(func, context, argCount) {
+ if (context === void 0) return func;
+ switch (argCount == null ? 3 : argCount) {
+ case 1: return function(value) {
+ return func.call(context, value);
+ };
+ case 2: return function(value, other) {
+ return func.call(context, value, other);
+ };
+ case 3: return function(value, index, collection) {
+ return func.call(context, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(context, accumulator, value, index, collection);
+ };
+ }
+ return function() {
+ return func.apply(context, arguments);
+ };
+ };
+
+ // A mostly-internal function to generate callbacks that can be applied
+ // to each element in a collection, returning the desired result — either
+ // identity, an arbitrary callback, a property matcher, or a property accessor.
+ _.iteratee = function(value, context, argCount) {
+ if (value == null) return _.identity;
+ if (_.isFunction(value)) return createCallback(value, context, argCount);
+ if (_.isObject(value)) return _.matches(value);
+ return _.property(value);
+ };
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
- // Handles objects with the built-in `forEach`, arrays, and raw objects.
- // Delegates to **ECMAScript 5**'s native `forEach` if available.
- var each = _.each = _.forEach = function(obj, iterator, context) {
- if (obj == null) return;
- if (nativeForEach && obj.forEach === nativeForEach) {
- obj.forEach(iterator, context);
- } else if (obj.length === +obj.length) {
- for (var i = 0, l = obj.length; i < l; i++) {
- if (iterator.call(context, obj[i], i, obj) === breaker) return;
+ // Handles raw objects in addition to array-likes. Treats all
+ // sparse array-likes as if they were dense.
+ _.each = _.forEach = function(obj, iteratee, context) {
+ if (obj == null) return obj;
+ iteratee = createCallback(iteratee, context);
+ var i, length = obj.length;
+ if (length === +length) {
+ for (i = 0; i < length; i++) {
+ iteratee(obj[i], i, obj);
}
} else {
- for (var key in obj) {
- if (_.has(obj, key)) {
- if (iterator.call(context, obj[key], key, obj) === breaker) return;
- }
+ var keys = _.keys(obj);
+ for (i = 0, length = keys.length; i < length; i++) {
+ iteratee(obj[keys[i]], keys[i], obj);
}
}
+ return obj;
};
- // Return the results of applying the iterator to each element.
- // Delegates to **ECMAScript 5**'s native `map` if available.
- _.map = _.collect = function(obj, iterator, context) {
- var results = [];
- if (obj == null) return results;
- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
- each(obj, function(value, index, list) {
- results.push(iterator.call(context, value, index, list));
- });
+ // Return the results of applying the iteratee to each element.
+ _.map = _.collect = function(obj, iteratee, context) {
+ if (obj == null) return [];
+ iteratee = _.iteratee(iteratee, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ results = Array(length),
+ currentKey;
+ for (var index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ results[index] = iteratee(obj[currentKey], currentKey, obj);
+ }
return results;
};
var reduceError = 'Reduce of empty array with no initial value';
// **Reduce** builds up a single result from a list of values, aka `inject`,
- // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
+ // or `foldl`.
+ _.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
if (obj == null) obj = [];
- if (nativeReduce && obj.reduce === nativeReduce) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
+ iteratee = createCallback(iteratee, context, 4);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ index = 0, currentKey;
+ if (arguments.length < 3) {
+ if (!length) throw new TypeError(reduceError);
+ memo = obj[keys ? keys[index++] : index++];
}
- each(obj, function(value, index, list) {
- if (!initial) {
- memo = value;
- initial = true;
- } else {
- memo = iterator.call(context, memo, value, index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
+ for (; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
+ }
return memo;
};
// The right-associative version of reduce, also known as `foldr`.
- // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
+ _.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
if (obj == null) obj = [];
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+ iteratee = createCallback(iteratee, context, 4);
+ var keys = obj.length !== + obj.length && _.keys(obj),
+ index = (keys || obj).length,
+ currentKey;
+ if (arguments.length < 3) {
+ if (!index) throw new TypeError(reduceError);
+ memo = obj[keys ? keys[--index] : --index];
}
- var length = obj.length;
- if (length !== +length) {
- var keys = _.keys(obj);
- length = keys.length;
+ while (index--) {
+ currentKey = keys ? keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
- each(obj, function(value, index, list) {
- index = keys ? keys[--length] : --length;
- if (!initial) {
- memo = obj[index];
- initial = true;
- } else {
- memo = iterator.call(context, memo, obj[index], index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
return memo;
};
// Return the first value which passes a truth test. Aliased as `detect`.
- _.find = _.detect = function(obj, iterator, context) {
+ _.find = _.detect = function(obj, predicate, context) {
var result;
- any(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) {
+ predicate = _.iteratee(predicate, context);
+ _.some(obj, function(value, index, list) {
+ if (predicate(value, index, list)) {
result = value;
return true;
}
@@ -164,61 +179,58 @@
};
// Return all the elements that pass a truth test.
- // Delegates to **ECMAScript 5**'s native `filter` if available.
// Aliased as `select`.
- _.filter = _.select = function(obj, iterator, context) {
+ _.filter = _.select = function(obj, predicate, context) {
var results = [];
if (obj == null) return results;
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
- each(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) results.push(value);
+ predicate = _.iteratee(predicate, context);
+ _.each(obj, function(value, index, list) {
+ if (predicate(value, index, list)) results.push(value);
});
return results;
};
// Return all the elements for which a truth test fails.
- _.reject = function(obj, iterator, context) {
- return _.filter(obj, function(value, index, list) {
- return !iterator.call(context, value, index, list);
- }, context);
+ _.reject = function(obj, predicate, context) {
+ return _.filter(obj, _.negate(_.iteratee(predicate)), context);
};
// Determine whether all of the elements match a truth test.
- // Delegates to **ECMAScript 5**'s native `every` if available.
// Aliased as `all`.
- _.every = _.all = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = true;
- if (obj == null) return result;
- if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
- each(obj, function(value, index, list) {
- if (!(result = result && iterator.call(context, value, index, list))) return breaker;
- });
- return !!result;
+ _.every = _.all = function(obj, predicate, context) {
+ if (obj == null) return true;
+ predicate = _.iteratee(predicate, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ index, currentKey;
+ for (index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
+ }
+ return true;
};
// Determine if at least one element in the object matches a truth test.
- // Delegates to **ECMAScript 5**'s native `some` if available.
// Aliased as `any`.
- var any = _.some = _.any = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = false;
- if (obj == null) return result;
- if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
- each(obj, function(value, index, list) {
- if (result || (result = iterator.call(context, value, index, list))) return breaker;
- });
- return !!result;
+ _.some = _.any = function(obj, predicate, context) {
+ if (obj == null) return false;
+ predicate = _.iteratee(predicate, context);
+ var keys = obj.length !== +obj.length && _.keys(obj),
+ length = (keys || obj).length,
+ index, currentKey;
+ for (index = 0; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ if (predicate(obj[currentKey], currentKey, obj)) return true;
+ }
+ return false;
};
// Determine if the array or object contains a given value (using `===`).
// Aliased as `include`.
_.contains = _.include = function(obj, target) {
if (obj == null) return false;
- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
- return any(obj, function(value) {
- return value === target;
- });
+ if (obj.length !== +obj.length) obj = _.values(obj);
+ return _.indexOf(obj, target) >= 0;
};
// Invoke a method (with arguments) on every item in a collection.
@@ -232,83 +244,104 @@
// Convenience version of a common use case of `map`: fetching a property.
_.pluck = function(obj, key) {
- return _.map(obj, function(value){ return value[key]; });
+ return _.map(obj, _.property(key));
};
// Convenience version of a common use case of `filter`: selecting only objects
// containing specific `key:value` pairs.
- _.where = function(obj, attrs, first) {
- if (_.isEmpty(attrs)) return first ? void 0 : [];
- return _[first ? 'find' : 'filter'](obj, function(value) {
- for (var key in attrs) {
- if (attrs[key] !== value[key]) return false;
- }
- return true;
- });
+ _.where = function(obj, attrs) {
+ return _.filter(obj, _.matches(attrs));
};
// Convenience version of a common use case of `find`: getting the first object
// containing specific `key:value` pairs.
_.findWhere = function(obj, attrs) {
- return _.where(obj, attrs, true);
+ return _.find(obj, _.matches(attrs));
};
- // Return the maximum element or (element-based computation).
- // Can't optimize arrays of integers longer than 65,535 elements.
- // See: https://bugs.webkit.org/show_bug.cgi?id=80797
- _.max = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.max.apply(Math, obj);
+ // Return the maximum element (or element-based computation).
+ _.max = function(obj, iteratee, context) {
+ var result = -Infinity, lastComputed = -Infinity,
+ value, computed;
+ if (iteratee == null && obj != null) {
+ obj = obj.length === +obj.length ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value > result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index, list) {
+ computed = iteratee(value, index, list);
+ if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+ result = value;
+ lastComputed = computed;
+ }
+ });
}
- if (!iterator && _.isEmpty(obj)) return -Infinity;
- var result = {computed : -Infinity, value: -Infinity};
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- computed >= result.computed && (result = {value : value, computed : computed});
- });
- return result.value;
+ return result;
};
// Return the minimum element (or element-based computation).
- _.min = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.min.apply(Math, obj);
+ _.min = function(obj, iteratee, context) {
+ var result = Infinity, lastComputed = Infinity,
+ value, computed;
+ if (iteratee == null && obj != null) {
+ obj = obj.length === +obj.length ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value < result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index, list) {
+ computed = iteratee(value, index, list);
+ if (computed < lastComputed || computed === Infinity && result === Infinity) {
+ result = value;
+ lastComputed = computed;
+ }
+ });
}
- if (!iterator && _.isEmpty(obj)) return Infinity;
- var result = {computed : Infinity, value: Infinity};
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- computed < result.computed && (result = {value : value, computed : computed});
- });
- return result.value;
+ return result;
};
- // Shuffle an array.
+ // Shuffle a collection, using the modern version of the
+ // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
_.shuffle = function(obj) {
- var rand;
- var index = 0;
- var shuffled = [];
- each(obj, function(value) {
- rand = _.random(index++);
- shuffled[index - 1] = shuffled[rand];
- shuffled[rand] = value;
- });
+ var set = obj && obj.length === +obj.length ? obj : _.values(obj);
+ var length = set.length;
+ var shuffled = Array(length);
+ for (var index = 0, rand; index < length; index++) {
+ rand = _.random(0, index);
+ if (rand !== index) shuffled[index] = shuffled[rand];
+ shuffled[rand] = set[index];
+ }
return shuffled;
};
- // An internal function to generate lookup iterators.
- var lookupIterator = function(value) {
- return _.isFunction(value) ? value : function(obj){ return obj[value]; };
+ // Sample **n** random values from a collection.
+ // If **n** is not specified, returns a single random element.
+ // The internal `guard` argument allows it to work with `map`.
+ _.sample = function(obj, n, guard) {
+ if (n == null || guard) {
+ if (obj.length !== +obj.length) obj = _.values(obj);
+ return obj[_.random(obj.length - 1)];
+ }
+ return _.shuffle(obj).slice(0, Math.max(0, n));
};
- // Sort the object's values by a criterion produced by an iterator.
- _.sortBy = function(obj, value, context) {
- var iterator = lookupIterator(value);
+ // Sort the object's values by a criterion produced by an iteratee.
+ _.sortBy = function(obj, iteratee, context) {
+ iteratee = _.iteratee(iteratee, context);
return _.pluck(_.map(obj, function(value, index, list) {
return {
- value : value,
- index : index,
- criteria : iterator.call(context, value, index, list)
+ value: value,
+ index: index,
+ criteria: iteratee(value, index, list)
};
}).sort(function(left, right) {
var a = left.criteria;
@@ -317,53 +350,56 @@
if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1;
}
- return left.index < right.index ? -1 : 1;
+ return left.index - right.index;
}), 'value');
};
// An internal function used for aggregate "group by" operations.
- var group = function(obj, value, context, behavior) {
- var result = {};
- var iterator = lookupIterator(value == null ? _.identity : value);
- each(obj, function(value, index) {
- var key = iterator.call(context, value, index, obj);
- behavior(result, key, value);
- });
- return result;
+ var group = function(behavior) {
+ return function(obj, iteratee, context) {
+ var result = {};
+ iteratee = _.iteratee(iteratee, context);
+ _.each(obj, function(value, index) {
+ var key = iteratee(value, index, obj);
+ behavior(result, value, key);
+ });
+ return result;
+ };
};
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
- _.groupBy = function(obj, value, context) {
- return group(obj, value, context, function(result, key, value) {
- (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
- });
- };
+ _.groupBy = group(function(result, value, key) {
+ if (_.has(result, key)) result[key].push(value); else result[key] = [value];
+ });
+
+ // Indexes the object's values by a criterion, similar to `groupBy`, but for
+ // when you know that your index values will be unique.
+ _.indexBy = group(function(result, value, key) {
+ result[key] = value;
+ });
// Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the
// criterion.
- _.countBy = function(obj, value, context) {
- return group(obj, value, context, function(result, key) {
- if (!_.has(result, key)) result[key] = 0;
- result[key]++;
- });
- };
+ _.countBy = group(function(result, value, key) {
+ if (_.has(result, key)) result[key]++; else result[key] = 1;
+ });
// Use a comparator function to figure out the smallest index at which
// an object should be inserted so as to maintain order. Uses binary search.
- _.sortedIndex = function(array, obj, iterator, context) {
- iterator = iterator == null ? _.identity : lookupIterator(iterator);
- var value = iterator.call(context, obj);
+ _.sortedIndex = function(array, obj, iteratee, context) {
+ iteratee = _.iteratee(iteratee, context, 1);
+ var value = iteratee(obj);
var low = 0, high = array.length;
while (low < high) {
- var mid = (low + high) >>> 1;
- iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
+ var mid = low + high >>> 1;
+ if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
};
- // Safely convert anything iterable into a real, live array.
+ // Safely create a real, live array from anything iterable.
_.toArray = function(obj) {
if (!obj) return [];
if (_.isArray(obj)) return slice.call(obj);
@@ -374,7 +410,18 @@
// Return the number of elements in an object.
_.size = function(obj) {
if (obj == null) return 0;
- return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
+ return obj.length === +obj.length ? obj.length : _.keys(obj).length;
+ };
+
+ // Split a collection into two arrays: one whose elements all satisfy the given
+ // predicate, and one whose elements all do not satisfy the predicate.
+ _.partition = function(obj, predicate, context) {
+ predicate = _.iteratee(predicate, context);
+ var pass = [], fail = [];
+ _.each(obj, function(value, key, obj) {
+ (predicate(value, key, obj) ? pass : fail).push(value);
+ });
+ return [pass, fail];
};
// Array Functions
@@ -385,7 +432,9 @@
// allows it to work with `_.map`.
_.first = _.head = _.take = function(array, n, guard) {
if (array == null) return void 0;
- return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
+ if (n == null || guard) return array[0];
+ if (n < 0) return [];
+ return slice.call(array, 0, n);
};
// Returns everything but the last entry of the array. Especially useful on
@@ -393,18 +442,15 @@
// the array, excluding the last N. The **guard** check allows it to work with
// `_.map`.
_.initial = function(array, n, guard) {
- return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
+ return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
};
// Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`.
_.last = function(array, n, guard) {
if (array == null) return void 0;
- if ((n != null) && !guard) {
- return slice.call(array, Math.max(array.length - n, 0));
- } else {
- return array[array.length - 1];
- }
+ if (n == null || guard) return array[array.length - 1];
+ return slice.call(array, Math.max(array.length - n, 0));
};
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
@@ -412,7 +458,7 @@
// the rest N values in the array. The **guard**
// check allows it to work with `_.map`.
_.rest = _.tail = _.drop = function(array, n, guard) {
- return slice.call(array, (n == null) || guard ? 1 : n);
+ return slice.call(array, n == null || guard ? 1 : n);
};
// Trim out all falsy values from an array.
@@ -421,20 +467,26 @@
};
// Internal implementation of a recursive `flatten` function.
- var flatten = function(input, shallow, output) {
- each(input, function(value) {
- if (_.isArray(value)) {
- shallow ? push.apply(output, value) : flatten(value, shallow, output);
+ var flatten = function(input, shallow, strict, output) {
+ if (shallow && _.every(input, _.isArray)) {
+ return concat.apply(output, input);
+ }
+ for (var i = 0, length = input.length; i < length; i++) {
+ var value = input[i];
+ if (!_.isArray(value) && !_.isArguments(value)) {
+ if (!strict) output.push(value);
+ } else if (shallow) {
+ push.apply(output, value);
} else {
- output.push(value);
+ flatten(value, shallow, strict, output);
}
- });
+ }
return output;
};
- // Return a completely flattened version of an array.
+ // Flatten out an array, either recursively (by default), or just one level.
_.flatten = function(array, shallow) {
- return flatten(array, shallow, []);
+ return flatten(array, shallow, false, []);
};
// Return a version of the array that does not contain the specified value(s).
@@ -445,86 +497,85 @@
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
- _.uniq = _.unique = function(array, isSorted, iterator, context) {
- if (_.isFunction(isSorted)) {
- context = iterator;
- iterator = isSorted;
+ _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+ if (array == null) return [];
+ if (!_.isBoolean(isSorted)) {
+ context = iteratee;
+ iteratee = isSorted;
isSorted = false;
}
- var initial = iterator ? _.map(array, iterator, context) : array;
- var results = [];
+ if (iteratee != null) iteratee = _.iteratee(iteratee, context);
+ var result = [];
var seen = [];
- each(initial, function(value, index) {
- if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
- seen.push(value);
- results.push(array[index]);
+ for (var i = 0, length = array.length; i < length; i++) {
+ var value = array[i];
+ if (isSorted) {
+ if (!i || seen !== value) result.push(value);
+ seen = value;
+ } else if (iteratee) {
+ var computed = iteratee(value, i, array);
+ if (_.indexOf(seen, computed) < 0) {
+ seen.push(computed);
+ result.push(value);
+ }
+ } else if (_.indexOf(result, value) < 0) {
+ result.push(value);
}
- });
- return results;
+ }
+ return result;
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
- return _.uniq(concat.apply(ArrayProto, arguments));
+ return _.uniq(flatten(arguments, true, true, []));
};
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
- var rest = slice.call(arguments, 1);
- return _.filter(_.uniq(array), function(item) {
- return _.every(rest, function(other) {
- return _.indexOf(other, item) >= 0;
- });
- });
+ if (array == null) return [];
+ var result = [];
+ var argsLength = arguments.length;
+ for (var i = 0, length = array.length; i < length; i++) {
+ var item = array[i];
+ if (_.contains(result, item)) continue;
+ for (var j = 1; j < argsLength; j++) {
+ if (!_.contains(arguments[j], item)) break;
+ }
+ if (j === argsLength) result.push(item);
+ }
+ return result;
};
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
- var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
- return _.filter(array, function(value){ return !_.contains(rest, value); });
+ var rest = flatten(slice.call(arguments, 1), true, true, []);
+ return _.filter(array, function(value){
+ return !_.contains(rest, value);
+ });
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
- _.zip = function() {
- var args = slice.call(arguments);
- var length = _.max(_.pluck(args, 'length'));
- var results = new Array(length);
+ _.zip = function(array) {
+ if (array == null) return [];
+ var length = _.max(arguments, 'length').length;
+ var results = Array(length);
for (var i = 0; i < length; i++) {
- results[i] = _.pluck(args, "" + i);
+ results[i] = _.pluck(arguments, i);
}
return results;
};
- // The inverse operation to `_.zip`. If given an array of pairs it
- // returns an array of the paired elements split into two left and
- // right element arrays, if given an array of triples it returns a
- // three element array and so on. For example, `_.unzip` given
- // `[['a',1],['b',2],['c',3]]` returns the array
- // [['a','b','c'],[1,2,3]].
- _.unzip = function(tuples) {
- var results = [];
- _.each(tuples, function (tuple, tupleIndex) {
- _.each(tuple, function (value, itemIndex) {
- if (results.length <= itemIndex) {
- results[itemIndex] = [];
- }
- results[itemIndex][tupleIndex] = value;
- });
- });
- return results;
- };
-
// Converts lists into objects. Pass either a single array of `[key, value]`
// pairs, or two parallel arrays of the same length -- one of keys, and one of
// the corresponding values.
_.object = function(list, values) {
if (list == null) return {};
var result = {};
- for (var i = 0, l = list.length; i < l; i++) {
+ for (var i = 0, length = list.length; i < length; i++) {
if (values) {
result[list[i]] = values[i];
} else {
@@ -534,37 +585,32 @@
return result;
};
- // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
- // we need this function. Return the position of the first occurrence of an
- // item in an array, or -1 if the item is not included in the array.
- // Delegates to **ECMAScript 5**'s native `indexOf` if available.
+ // Return the position of the first occurrence of an item in an array,
+ // or -1 if the item is not included in the array.
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) {
if (array == null) return -1;
- var i = 0, l = array.length;
+ var i = 0, length = array.length;
if (isSorted) {
if (typeof isSorted == 'number') {
- i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
+ i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
} else {
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
}
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
- for (; i < l; i++) if (array[i] === item) return i;
+ for (; i < length; i++) if (array[i] === item) return i;
return -1;
};
- // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
_.lastIndexOf = function(array, item, from) {
if (array == null) return -1;
- var hasIndex = from != null;
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
- return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
+ var idx = array.length;
+ if (typeof from == 'number') {
+ idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
}
- var i = (hasIndex ? from : array.length);
- while (i--) if (array[i] === item) return i;
+ while (--idx >= 0) if (array[idx] === item) return idx;
return -1;
};
@@ -576,15 +622,13 @@
stop = start || 0;
start = 0;
}
- step = arguments[2] || 1;
+ step = step || 1;
- var len = Math.max(Math.ceil((stop - start) / step), 0);
- var idx = 0;
- var range = new Array(len);
+ var length = Math.max(Math.ceil((stop - start) / step), 0);
+ var range = Array(length);
- while(idx < len) {
- range[idx++] = start;
- start += step;
+ for (var idx = 0; idx < length; idx++, start += step) {
+ range[idx] = start;
}
return range;
@@ -594,60 +638,76 @@
// ------------------
// Reusable constructor function for prototype setting.
- var ctor = function(){};
+ var Ctor = function(){};
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
// available.
_.bind = function(func, context) {
var args, bound;
- if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
- if (!_.isFunction(func)) throw new TypeError;
+ if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
+ if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
args = slice.call(arguments, 2);
- return bound = function() {
+ bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
- ctor.prototype = func.prototype;
- var self = new ctor;
- ctor.prototype = null;
+ Ctor.prototype = func.prototype;
+ var self = new Ctor;
+ Ctor.prototype = null;
var result = func.apply(self, args.concat(slice.call(arguments)));
- if (Object(result) === result) return result;
+ if (_.isObject(result)) return result;
return self;
};
+ return bound;
+ };
+
+ // Partially apply a function by creating a version that has had some of its
+ // arguments pre-filled, without changing its dynamic `this` context. _ acts
+ // as a placeholder, allowing any combination of arguments to be pre-filled.
+ _.partial = function(func) {
+ var boundArgs = slice.call(arguments, 1);
+ return function() {
+ var position = 0;
+ var args = boundArgs.slice();
+ for (var i = 0, length = args.length; i < length; i++) {
+ if (args[i] === _) args[i] = arguments[position++];
+ }
+ while (position < arguments.length) args.push(arguments[position++]);
+ return func.apply(this, args);
+ };
};
- // Partially apply a function by creating a version that has had some of its
- // arguments pre-filled, without changing its dynamic `this` context.
- _.partial = function(func) {
- var args = slice.call(arguments, 1);
- return function() {
- return func.apply(this, args.concat(slice.call(arguments)));
- };
- };
-
- // Bind all of an object's methods to that object. Useful for ensuring that
- // all callbacks defined on an object belong to it.
+ // Bind a number of an object's methods to that object. Remaining arguments
+ // are the method names to be bound. Useful for ensuring that all callbacks
+ // defined on an object belong to it.
_.bindAll = function(obj) {
- var funcs = slice.call(arguments, 1);
- if (funcs.length === 0) throw new Error("bindAll must be passed function names");
- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
+ var i, length = arguments.length, key;
+ if (length <= 1) throw new Error('bindAll must be passed function names');
+ for (i = 1; i < length; i++) {
+ key = arguments[i];
+ obj[key] = _.bind(obj[key], obj);
+ }
return obj;
};
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
- var memo = {};
- hasher || (hasher = _.identity);
- return function() {
- var key = hasher.apply(this, arguments);
- return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+ var memoize = function(key) {
+ var cache = memoize.cache;
+ var address = hasher ? hasher.apply(this, arguments) : key;
+ if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
+ return cache[address];
};
+ memoize.cache = {};
+ return memoize;
};
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
- return setTimeout(function(){ return func.apply(null, args); }, wait);
+ return setTimeout(function(){
+ return func.apply(null, args);
+ }, wait);
};
// Defers a function, scheduling it to run after the current call stack has
@@ -657,27 +717,34 @@
};
// Returns a function, that, when invoked, will only be triggered at most once
- // during a given window of time.
- _.throttle = function(func, wait, immediate) {
- var context, args, timeout, result;
+ // during a given window of time. Normally, the throttled function will run
+ // as much as it can, without ever going more than once per `wait` duration;
+ // but if you'd like to disable the execution on the leading edge, pass
+ // `{leading: false}`. To disable execution on the trailing edge, ditto.
+ _.throttle = function(func, wait, options) {
+ var context, args, result;
+ var timeout = null;
var previous = 0;
+ if (!options) options = {};
var later = function() {
- previous = new Date;
+ previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
+ if (!timeout) context = args = null;
};
return function() {
- var now = new Date;
- if (!previous && immediate === false) previous = now;
+ var now = _.now();
+ if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
- if (remaining <= 0) {
+ if (remaining <= 0 || remaining > wait) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
- } else if (!timeout) {
+ if (!timeout) context = args = null;
+ } else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
@@ -689,61 +756,66 @@
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
- var timeout, result;
+ var timeout, args, context, timestamp, result;
+
+ var later = function() {
+ var last = _.now() - timestamp;
+
+ if (last < wait && last > 0) {
+ timeout = setTimeout(later, wait - last);
+ } else {
+ timeout = null;
+ if (!immediate) {
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ }
+ }
+ };
+
return function() {
- var context = this, args = arguments;
- var later = function() {
- timeout = null;
- if (!immediate) result = func.apply(context, args);
- };
+ context = this;
+ args = arguments;
+ timestamp = _.now();
var callNow = immediate && !timeout;
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- if (callNow) result = func.apply(context, args);
+ if (!timeout) timeout = setTimeout(later, wait);
+ if (callNow) {
+ result = func.apply(context, args);
+ context = args = null;
+ }
+
return result;
};
};
- // Returns a function that will be executed at most one time, no matter how
- // often you call it. Useful for lazy initialization.
- _.once = function(func) {
- var ran = false, memo;
- return function() {
- if (ran) return memo;
- ran = true;
- memo = func.apply(this, arguments);
- func = null;
- return memo;
- };
- };
-
// Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
_.wrap = function(func, wrapper) {
+ return _.partial(wrapper, func);
+ };
+
+ // Returns a negated version of the passed-in predicate.
+ _.negate = function(predicate) {
return function() {
- var args = [func];
- push.apply(args, arguments);
- return wrapper.apply(this, args);
+ return !predicate.apply(this, arguments);
};
};
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
_.compose = function() {
- var funcs = arguments;
+ var args = arguments;
+ var start = args.length - 1;
return function() {
- var args = arguments;
- for (var i = funcs.length - 1; i >= 0; i--) {
- args = [funcs[i].apply(this, args)];
- }
- return args[0];
+ var i = start;
+ var result = args[start].apply(this, arguments);
+ while (i--) result = args[i].call(this, result);
+ return result;
};
};
// Returns a function that will only be executed after being called N times.
_.after = function(times, func) {
- if (times <= 0) return func();
return function() {
if (--times < 1) {
return func.apply(this, arguments);
@@ -751,13 +823,31 @@
};
};
+ // Returns a function that will only be executed before being called N times.
+ _.before = function(times, func) {
+ var memo;
+ return function() {
+ if (--times > 0) {
+ memo = func.apply(this, arguments);
+ } else {
+ func = null;
+ }
+ return memo;
+ };
+ };
+
+ // Returns a function that will be executed at most one time, no matter how
+ // often you call it. Useful for lazy initialization.
+ _.once = _.partial(_.before, 2);
+
// Object Functions
// ----------------
// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
- _.keys = nativeKeys || function(obj) {
- if (obj !== Object(obj)) throw new TypeError('Invalid object');
+ _.keys = function(obj) {
+ if (!_.isObject(obj)) return [];
+ if (nativeKeys) return nativeKeys(obj);
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys.push(key);
return keys;
@@ -765,22 +855,33 @@
// Retrieve the values of an object's properties.
_.values = function(obj) {
- var values = [];
- for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
+ var keys = _.keys(obj);
+ var length = keys.length;
+ var values = Array(length);
+ for (var i = 0; i < length; i++) {
+ values[i] = obj[keys[i]];
+ }
return values;
};
// Convert an object into a list of `[key, value]` pairs.
_.pairs = function(obj) {
- var pairs = [];
- for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
+ var keys = _.keys(obj);
+ var length = keys.length;
+ var pairs = Array(length);
+ for (var i = 0; i < length; i++) {
+ pairs[i] = [keys[i], obj[keys[i]]];
+ }
return pairs;
};
// Invert the keys and values of an object. The values must be serializable.
_.invert = function(obj) {
var result = {};
- for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
+ var keys = _.keys(obj);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ result[obj[keys[i]]] = keys[i];
+ }
return result;
};
@@ -796,45 +897,62 @@
// Extend a given object with all the properties in passed-in object(s).
_.extend = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- obj[prop] = source[prop];
+ if (!_.isObject(obj)) return obj;
+ var source, prop;
+ for (var i = 1, length = arguments.length; i < length; i++) {
+ source = arguments[i];
+ for (prop in source) {
+ if (hasOwnProperty.call(source, prop)) {
+ obj[prop] = source[prop];
}
}
- });
+ }
return obj;
};
// Return a copy of the object only containing the whitelisted properties.
- _.pick = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- each(keys, function(key) {
- if (key in obj) copy[key] = obj[key];
- });
- return copy;
+ _.pick = function(obj, iteratee, context) {
+ var result = {}, key;
+ if (obj == null) return result;
+ if (_.isFunction(iteratee)) {
+ iteratee = createCallback(iteratee, context);
+ for (key in obj) {
+ var value = obj[key];
+ if (iteratee(value, key, obj)) result[key] = value;
+ }
+ } else {
+ var keys = concat.apply([], slice.call(arguments, 1));
+ obj = new Object(obj);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ key = keys[i];
+ if (key in obj) result[key] = obj[key];
+ }
+ }
+ return result;
};
// Return a copy of the object without the blacklisted properties.
- _.omit = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- for (var key in obj) {
- if (!_.contains(keys, key)) copy[key] = obj[key];
+ _.omit = function(obj, iteratee, context) {
+ if (_.isFunction(iteratee)) {
+ iteratee = _.negate(iteratee);
+ } else {
+ var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
+ iteratee = function(value, key) {
+ return !_.contains(keys, key);
+ };
}
- return copy;
+ return _.pick(obj, iteratee, context);
};
// Fill in a given object with default properties.
_.defaults = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- if (obj[prop] === void 0) obj[prop] = source[prop];
- }
+ if (!_.isObject(obj)) return obj;
+ for (var i = 1, length = arguments.length; i < length; i++) {
+ var source = arguments[i];
+ for (var prop in source) {
+ if (obj[prop] === void 0) obj[prop] = source[prop];
}
- });
+ }
return obj;
};
@@ -855,8 +973,8 @@
// Internal recursive comparison function for `isEqual`.
var eq = function(a, b, aStack, bStack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
- // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
- if (a === b) return a !== 0 || 1 / a == 1 / b;
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+ if (a === b) return a !== 0 || 1 / a === 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
@@ -864,29 +982,27 @@
if (b instanceof _) b = b._wrapped;
// Compare `[[Class]]` names.
var className = toString.call(a);
- if (className != toString.call(b)) return false;
+ if (className !== toString.call(b)) return false;
switch (className) {
- // Strings, numbers, dates, and booleans are compared by value.
+ // Strings, numbers, regular expressions, dates, and booleans are compared by value.
+ case '[object RegExp]':
+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
case '[object String]':
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
- return a == String(b);
+ return '' + a === '' + b;
case '[object Number]':
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
- // other numeric values.
- return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
+ // `NaN`s are equivalent, but non-reflexive.
+ // Object(NaN) is equivalent to NaN
+ if (+a !== +a) return +b !== +b;
+ // An `egal` comparison is performed for other numeric values.
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
case '[object Date]':
case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
- return +a == +b;
- // RegExps are compared by their source patterns and flags.
- case '[object RegExp]':
- return a.source == b.source &&
- a.global == b.global &&
- a.multiline == b.multiline &&
- a.ignoreCase == b.ignoreCase;
+ return +a === +b;
}
if (typeof a != 'object' || typeof b != 'object') return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
@@ -895,17 +1011,29 @@
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
- if (aStack[length] == a) return bStack[length] == b;
+ if (aStack[length] === a) return bStack[length] === b;
+ }
+ // Objects with different constructors are not equivalent, but `Object`s
+ // from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (
+ aCtor !== bCtor &&
+ // Handle Object.create(x) cases
+ 'constructor' in a && 'constructor' in b &&
+ !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
+ _.isFunction(bCtor) && bCtor instanceof bCtor)
+ ) {
+ return false;
}
// Add the first object to the stack of traversed objects.
aStack.push(a);
bStack.push(b);
- var size = 0, result = true;
+ var size, result;
// Recursively compare objects and arrays.
- if (className == '[object Array]') {
+ if (className === '[object Array]') {
// Compare array lengths to determine if a deep comparison is necessary.
size = a.length;
- result = size == b.length;
+ result = size === b.length;
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
@@ -913,29 +1041,18 @@
}
}
} else {
- // Objects with different constructors are not equivalent, but `Object`s
- // from different frames are.
- var aCtor = a.constructor, bCtor = b.constructor;
- if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
- _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
- return false;
- }
// Deep compare objects.
- for (var key in a) {
- if (_.has(a, key)) {
- // Count the expected number of properties.
- size++;
- // Deep compare each member.
+ var keys = _.keys(a), key;
+ size = keys.length;
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
+ result = _.keys(b).length === size;
+ if (result) {
+ while (size--) {
+ // Deep compare each member
+ key = keys[size];
if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
}
}
- // Ensure that both objects contain the same number of properties.
- if (result) {
- for (key in b) {
- if (_.has(b, key) && !(size--)) break;
- }
- result = !size;
- }
}
// Remove the first object from the stack of traversed objects.
aStack.pop();
@@ -952,7 +1069,7 @@
// An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) {
if (obj == null) return true;
- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
+ if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
for (var key in obj) if (_.has(obj, key)) return false;
return true;
};
@@ -965,18 +1082,19 @@
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
- return toString.call(obj) == '[object Array]';
+ return toString.call(obj) === '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
- return obj === Object(obj);
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
};
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
- each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
+ _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
_['is' + name] = function(obj) {
- return toString.call(obj) == '[object ' + name + ']';
+ return toString.call(obj) === '[object ' + name + ']';
};
});
@@ -984,14 +1102,14 @@
// there isn't any inspectable "Arguments" type.
if (!_.isArguments(arguments)) {
_.isArguments = function(obj) {
- return !!(obj && _.has(obj, 'callee'));
+ return _.has(obj, 'callee');
};
}
- // Optimize `isFunction` if appropriate.
- if (typeof (/./) !== 'function') {
+ // Optimize `isFunction` if appropriate. Work around an IE 11 bug.
+ if (typeof /./ !== 'function') {
_.isFunction = function(obj) {
- return typeof obj === 'function';
+ return typeof obj == 'function' || false;
};
}
@@ -1002,12 +1120,12 @@
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
_.isNaN = function(obj) {
- return _.isNumber(obj) && obj != +obj;
+ return _.isNumber(obj) && obj !== +obj;
};
// Is a given value a boolean?
_.isBoolean = function(obj) {
- return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
};
// Is a given value equal to null?
@@ -1023,7 +1141,7 @@
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
- return hasOwnProperty.call(obj, key);
+ return obj != null && hasOwnProperty.call(obj, key);
};
// Utility Functions
@@ -1036,15 +1154,45 @@
return this;
};
- // Keep the identity function around for default iterators.
+ // Keep the identity function around for default iteratees.
_.identity = function(value) {
return value;
};
+ // Predicate-generating functions. Often useful outside of Underscore.
+ _.constant = function(value) {
+ return function() {
+ return value;
+ };
+ };
+
+ _.noop = function(){};
+
+ _.property = function(key) {
+ return function(obj) {
+ return obj[key];
+ };
+ };
+
+ // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
+ _.matches = function(attrs) {
+ var pairs = _.pairs(attrs), length = pairs.length;
+ return function(obj) {
+ if (obj == null) return !length;
+ obj = new Object(obj);
+ for (var i = 0; i < length; i++) {
+ var pair = pairs[i], key = pair[0];
+ if (pair[1] !== obj[key] || !(key in obj)) return false;
+ }
+ return true;
+ };
+ };
+
// Run a function **n** times.
- _.times = function(n, iterator, context) {
- var accum = Array(n);
- for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
+ _.times = function(n, iteratee, context) {
+ var accum = Array(Math.max(0, n));
+ iteratee = createCallback(iteratee, context, 1);
+ for (var i = 0; i < n; i++) accum[i] = iteratee(i);
return accum;
};
@@ -1057,53 +1205,45 @@
return min + Math.floor(Math.random() * (max - min + 1));
};
- // List of HTML entities for escaping.
- var entityMap = {
- escape: {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": ''',
- '/': '/'
- }
- };
- entityMap.unescape = _.invert(entityMap.escape);
-
- // Regexes containing the keys and values listed immediately above.
- var entityRegexes = {
- escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
- unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
+ // A (possibly faster) way to get the current timestamp as an integer.
+ _.now = Date.now || function() {
+ return new Date().getTime();
};
+ // List of HTML entities for escaping.
+ var escapeMap = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
+ };
+ var unescapeMap = _.invert(escapeMap);
+
// Functions for escaping and unescaping strings to/from HTML interpolation.
- _.each(['escape', 'unescape'], function(method) {
- _[method] = function(string) {
- if (string == null) return '';
- return ('' + string).replace(entityRegexes[method], function(match) {
- return entityMap[method][match];
- });
+ var createEscaper = function(map) {
+ var escaper = function(match) {
+ return map[match];
};
- });
+ // Regexes for identifying a key that needs to be escaped
+ var source = '(?:' + _.keys(map).join('|') + ')';
+ var testRegexp = RegExp(source);
+ var replaceRegexp = RegExp(source, 'g');
+ return function(string) {
+ string = string == null ? '' : '' + string;
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+ };
+ };
+ _.escape = createEscaper(escapeMap);
+ _.unescape = createEscaper(unescapeMap);
// If the value of the named `property` is a function then invoke it with the
// `object` as context; otherwise, return it.
_.result = function(object, property) {
if (object == null) return void 0;
var value = object[property];
- return _.isFunction(value) ? value.call(object) : value;
- };
-
- // Add your own custom functions to the Underscore object.
- _.mixin = function(obj) {
- each(_.functions(obj), function(name){
- var func = _[name] = obj[name];
- _.prototype[name] = function() {
- var args = [this._wrapped];
- push.apply(args, arguments);
- return result.call(this, func.apply(_, args));
- };
- });
+ return _.isFunction(value) ? object[property]() : value;
};
// Generate a unique integer id (unique within the entire client session).
@@ -1134,22 +1274,26 @@
'\\': '\\',
'\r': 'r',
'\n': 'n',
- '\t': 't',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
- var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
+ var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
+
+ var escapeChar = function(match) {
+ return '\\' + escapes[match];
+ };
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
- _.template = function(text, data, settings) {
- var render;
+ // NB: `oldSettings` only exists for backwards compatibility.
+ _.template = function(text, settings, oldSettings) {
+ if (!settings && oldSettings) settings = oldSettings;
settings = _.defaults({}, settings, _.templateSettings);
// Combine delimiters into one regular expression via alternation.
- var matcher = new RegExp([
+ var matcher = RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
@@ -1159,19 +1303,18 @@
var index = 0;
var source = "__p+='";
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
- source += text.slice(index, offset)
- .replace(escaper, function(match) { return '\\' + escapes[match]; });
+ source += text.slice(index, offset).replace(escaper, escapeChar);
+ index = offset + match.length;
if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
- }
- if (interpolate) {
+ } else if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
- }
- if (evaluate) {
+ } else if (evaluate) {
source += "';\n" + evaluate + "\n__p+='";
}
- index = offset + match.length;
+
+ // Adobe VMs need the match returned to produce the correct offest.
return match;
});
source += "';\n";
@@ -1181,29 +1324,31 @@
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
- source + "return __p;\n";
+ source + 'return __p;\n';
try {
- render = new Function(settings.variable || 'obj', '_', source);
+ var render = new Function(settings.variable || 'obj', '_', source);
} catch (e) {
e.source = source;
throw e;
}
- if (data) return render(data, _);
var template = function(data) {
return render.call(this, data, _);
};
- // Provide the compiled function source as a convenience for precompilation.
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
+ // Provide the compiled source as a convenience for precompilation.
+ var argument = settings.variable || 'obj';
+ template.source = 'function(' + argument + '){\n' + source + '}';
return template;
};
- // Add a "chain" function, which will delegate to the wrapper.
+ // Add a "chain" function. Start chaining a wrapped Underscore object.
_.chain = function(obj) {
- return _(obj).chain();
+ var instance = _(obj);
+ instance._chain = true;
+ return instance;
};
// OOP
@@ -1217,41 +1362,55 @@
return this._chain ? _(obj).chain() : obj;
};
+ // Add your own custom functions to the Underscore object.
+ _.mixin = function(obj) {
+ _.each(_.functions(obj), function(name) {
+ var func = _[name] = obj[name];
+ _.prototype[name] = function() {
+ var args = [this._wrapped];
+ push.apply(args, arguments);
+ return result.call(this, func.apply(_, args));
+ };
+ });
+ };
+
// Add all of the Underscore functions to the wrapper object.
_.mixin(_);
// Add all mutator Array functions to the wrapper.
- each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
var obj = this._wrapped;
method.apply(obj, arguments);
- if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
+ if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
return result.call(this, obj);
};
});
// Add all accessor Array functions to the wrapper.
- each(['concat', 'join', 'slice'], function(name) {
+ _.each(['concat', 'join', 'slice'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
return result.call(this, method.apply(this._wrapped, arguments));
};
});
- _.extend(_.prototype, {
+ // Extracts the result from a wrapped and chained object.
+ _.prototype.value = function() {
+ return this._wrapped;
+ };
- // Start chaining a wrapped Underscore object.
- chain: function() {
- this._chain = true;
- return this;
- },
-
- // Extracts the result from a wrapped and chained object.
- value: function() {
- return this._wrapped;
- }
-
- });
-
-}).call(this);
+ // AMD registration happens at the end for compatibility with AMD loaders
+ // that may not enforce next-turn semantics on modules. Even though general
+ // practice for AMD registration is to be anonymous, underscore registers
+ // as a named module because, like jQuery, it is a base library that is
+ // popular enough to be bundled in a third party lib, but not be part of
+ // an AMD load request. Those cases could generate an error when an
+ // anonymous define() is called outside of a loader request.
+ if (typeof define === 'function' && define.amd) {
+ define('underscore', [], function() {
+ return _;
+ });
+ }
+}.call(this));
This diff is so big that we needed to truncate the remainder.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Merged in dannon/galaxy-central/stable (pull request #602)
by commits-noreply@bitbucket.org 10 Dec '14
by commits-noreply@bitbucket.org 10 Dec '14
10 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/212e1d5e9be5/
Changeset: 212e1d5e9be5
Branch: stable
User: jmchilton
Date: 2014-12-10 17:20:55+00:00
Summary: Merged in dannon/galaxy-central/stable (pull request #602)
[STABLE] Force sanitization of form.title and form.name. Header needs more digging; we actually use html content in the field.
Affected #: 1 file
diff -r 2db0fb9594d6c315e4e0a4be70f64373cfc708f6 -r 212e1d5e9be5a9a1e12c834bd545de504753c9fe templates/form.mako
--- a/templates/form.mako
+++ b/templates/form.mako
@@ -22,7 +22,7 @@
</%def>
-<%def name="title()">${form.title}</%def>
+<%def name="title()">${form.title | h}</%def><%def name="javascripts()">
${parent.javascripts()}
@@ -53,7 +53,7 @@
%endif
<div class="form" style="margin: 1em">
- <div class="form-title">${util.unicodify( form.title )}</div>
+ <div class="form-title">${util.unicodify( form.title ) | h }</div><div class="form-body"><%
has_file_input = False
@@ -62,7 +62,7 @@
has_file_input = True
break
%>
- <form name="${form.name}" action="${form.action}" method="post"
+ <form name="${form.name | h }" action="${form.action}" method="post"
%if has_file_input:
enctype="multipart/form-data"
%endif
@@ -76,28 +76,28 @@
<div class="${cls}">
%if input.use_label:
<label>
- ${_(input.label)}:
+ ${_(input.label) | h }:
</label>
%endif
<div class="form-row-input">
%if input.type == 'textarea':
- <textarea name="${input.name}">${input.value}</textarea>
+ <textarea name="${input.name | h }">${input.value | h }</textarea>
%elif input.type == 'select':
- <select name="${input.name}">
+ <select name="${input.name | h}">
%for (name, value) in input.options:
- <option value="${value}">${name}</option>
+ <option value="${value | h }">${name | h }</option>
%endfor
</select>
%else:
- <input type="${input.type}" name="${input.name}" value="${input.value}">
+ <input type="${input.type}" name="${input.name | h }" value="${input.value | h }">
%endif
</div>
%if input.error:
- <div class="form-row-error-message">${input.error}</div>
+ <div class="form-row-error-message">${input.error | h }</div>
%endif
%if input.help:
<div class="toolParamHelp" style="clear: both;">
- ${input.help}
+ ${input.help | h}
</div>
%endif
<div style="clear: both"></div>
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/2d51d40f07ca/
Changeset: 2d51d40f07ca
Branch: stable
User: dannon
Date: 2014-12-09 19:46:03+00:00
Summary: Force sanitization of form.title and form.name. Header needs more digging; we actually use html content in the field.
Affected #: 1 file
diff -r fdc7863699d233e2b44d6d42f47dfaaa97e0d80e -r 2d51d40f07ca0d3ca266a33bf39190dfe8b9a6be templates/form.mako
--- a/templates/form.mako
+++ b/templates/form.mako
@@ -22,7 +22,7 @@
</%def>
-<%def name="title()">${form.title}</%def>
+<%def name="title()">${form.title | h}</%def><%def name="javascripts()">
${parent.javascripts()}
@@ -53,7 +53,7 @@
%endif
<div class="form" style="margin: 1em">
- <div class="form-title">${util.unicodify( form.title )}</div>
+ <div class="form-title">${util.unicodify( form.title ) | h}</div><div class="form-body"><%
has_file_input = False
@@ -62,7 +62,7 @@
has_file_input = True
break
%>
- <form name="${form.name}" action="${form.action}" method="post"
+ <form name="${form.name | h}" action="${form.action}" method="post"
%if has_file_input:
enctype="multipart/form-data"
%endif
https://bitbucket.org/galaxy/galaxy-central/commits/7adac1842adf/
Changeset: 7adac1842adf
Branch: stable
User: dannon
Date: 2014-12-09 20:44:08+00:00
Summary: Additionally sanitize form input fields (label, name, etc.)
Affected #: 1 file
diff -r 2d51d40f07ca0d3ca266a33bf39190dfe8b9a6be -r 7adac1842adf8db15183baff73e971aeab3537a9 templates/form.mako
--- a/templates/form.mako
+++ b/templates/form.mako
@@ -53,7 +53,7 @@
%endif
<div class="form" style="margin: 1em">
- <div class="form-title">${util.unicodify( form.title ) | h}</div>
+ <div class="form-title">${util.unicodify( form.title ) | h }</div><div class="form-body"><%
has_file_input = False
@@ -62,7 +62,7 @@
has_file_input = True
break
%>
- <form name="${form.name | h}" action="${form.action}" method="post"
+ <form name="${form.name | h }" action="${form.action}" method="post"
%if has_file_input:
enctype="multipart/form-data"
%endif
@@ -76,28 +76,28 @@
<div class="${cls}">
%if input.use_label:
<label>
- ${_(input.label)}:
+ ${_(input.label) | h }:
</label>
%endif
<div class="form-row-input">
%if input.type == 'textarea':
- <textarea name="${input.name}">${input.value}</textarea>
+ <textarea name="${input.name | h }">${input.value | h }</textarea>
%elif input.type == 'select':
- <select name="${input.name}">
+ <select name="${input.name | h}">
%for (name, value) in input.options:
- <option value="${value}">${name}</option>
+ <option value="${value | h }">${name | h }</option>
%endfor
</select>
%else:
- <input type="${input.type}" name="${input.name}" value="${input.value}">
+ <input type="${input.type}" name="${input.name | h }" value="${input.value | h }">
%endif
</div>
%if input.error:
- <div class="form-row-error-message">${input.error}</div>
+ <div class="form-row-error-message">${input.error | h }</div>
%endif
%if input.help:
<div class="toolParamHelp" style="clear: both;">
- ${input.help}
+ ${input.help | h}
</div>
%endif
<div style="clear: both"></div>
https://bitbucket.org/galaxy/galaxy-central/commits/212e1d5e9be5/
Changeset: 212e1d5e9be5
Branch: stable
User: jmchilton
Date: 2014-12-10 17:20:55+00:00
Summary: Merged in dannon/galaxy-central/stable (pull request #602)
[STABLE] Force sanitization of form.title and form.name. Header needs more digging; we actually use html content in the field.
Affected #: 1 file
diff -r 2db0fb9594d6c315e4e0a4be70f64373cfc708f6 -r 212e1d5e9be5a9a1e12c834bd545de504753c9fe templates/form.mako
--- a/templates/form.mako
+++ b/templates/form.mako
@@ -22,7 +22,7 @@
</%def>
-<%def name="title()">${form.title}</%def>
+<%def name="title()">${form.title | h}</%def><%def name="javascripts()">
${parent.javascripts()}
@@ -53,7 +53,7 @@
%endif
<div class="form" style="margin: 1em">
- <div class="form-title">${util.unicodify( form.title )}</div>
+ <div class="form-title">${util.unicodify( form.title ) | h }</div><div class="form-body"><%
has_file_input = False
@@ -62,7 +62,7 @@
has_file_input = True
break
%>
- <form name="${form.name}" action="${form.action}" method="post"
+ <form name="${form.name | h }" action="${form.action}" method="post"
%if has_file_input:
enctype="multipart/form-data"
%endif
@@ -76,28 +76,28 @@
<div class="${cls}">
%if input.use_label:
<label>
- ${_(input.label)}:
+ ${_(input.label) | h }:
</label>
%endif
<div class="form-row-input">
%if input.type == 'textarea':
- <textarea name="${input.name}">${input.value}</textarea>
+ <textarea name="${input.name | h }">${input.value | h }</textarea>
%elif input.type == 'select':
- <select name="${input.name}">
+ <select name="${input.name | h}">
%for (name, value) in input.options:
- <option value="${value}">${name}</option>
+ <option value="${value | h }">${name | h }</option>
%endfor
</select>
%else:
- <input type="${input.type}" name="${input.name}" value="${input.value}">
+ <input type="${input.type}" name="${input.name | h }" value="${input.value | h }">
%endif
</div>
%if input.error:
- <div class="form-row-error-message">${input.error}</div>
+ <div class="form-row-error-message">${input.error | h }</div>
%endif
%if input.help:
<div class="toolParamHelp" style="clear: both;">
- ${input.help}
+ ${input.help | h}
</div>
%endif
<div style="clear: both"></div>
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/7eeb2a0f5a97/
Changeset: 7eeb2a0f5a97
User: jmchilton
Date: 2014-12-10 16:49:50+00:00
Summary: force_history_refresh does nothing so I am just setting it False in tool.
(TODO: Update planemo linter to mark this as a problem.)
Affected #: 1 file
diff -r 01a3ff6a376c4b95ca540bc120b5aab47920fd39 -r 7eeb2a0f5a977d88c506bf1365c8bb46b5897354 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1410,10 +1410,8 @@
self.version = "1.0.0"
# Support multi-byte tools
self.is_multi_byte = string_as_bool( root.get( "is_multi_byte", False ) )
- # Force history to fully refresh after job execution for this tool.
- # Useful i.e. when an indeterminate number of outputs are created by
- # a tool.
- self.force_history_refresh = string_as_bool( root.get( 'force_history_refresh', 'False' ) )
+ # Legacy feature, ignored by UI.
+ self.force_history_refresh = False
self.display_interface = string_as_bool( root.get( 'display_interface', str( self.display_interface ) ) )
self.require_login = string_as_bool( root.get( 'require_login', str( self.require_login ) ) )
# Load input translator, used by datasource tools to change names/values of incoming parameters
https://bitbucket.org/galaxy/galaxy-central/commits/05533cd3509f/
Changeset: 05533cd3509f
User: jmchilton
Date: 2014-12-10 16:49:50+00:00
Summary: Small PEP-8 fix for Tool.parse_inputs.
Affected #: 1 file
diff -r 7eeb2a0f5a977d88c506bf1365c8bb46b5897354 -r 05533cd3509f1e23f514fc5190467580824f0b37 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -1580,11 +1580,11 @@
# template.
if self.nginx_upload and self.app.config.nginx_upload_path:
if '?' in urllib.unquote_plus( self.action ):
- raise Exception( 'URL parameters in a non-default tool action can not be used ' \
- 'in conjunction with nginx upload. Please convert them to ' \
+ raise Exception( 'URL parameters in a non-default tool action can not be used '
+ 'in conjunction with nginx upload. Please convert them to '
'hidden POST parameters' )
self.action = (self.app.config.nginx_upload_path + '?nginx_redir=',
- urllib.unquote_plus(self.action))
+ urllib.unquote_plus(self.action))
self.target = input_elem.get( "target", self.target )
self.method = input_elem.get( "method", self.method )
# Parse the actual parameters
https://bitbucket.org/galaxy/galaxy-central/commits/d66ad58a40e3/
Changeset: d66ad58a40e3
User: jmchilton
Date: 2014-12-10 16:49:50+00:00
Summary: Unit testing explicitly related to parsing of XML for parameters.
Cleans up some existing tests and does some de-duplication as well.
Affected #: 4 files
diff -r 05533cd3509f1e23f514fc5190467580824f0b37 -r d66ad58a40e31defb6de0eb8b8b543b7e0f26ae5 test/unit/tools/test_column_parameters.py
--- a/test/unit/tools/test_column_parameters.py
+++ b/test/unit/tools/test_column_parameters.py
@@ -2,16 +2,12 @@
test_select_parameters.py.
"""
-from unittest import TestCase
-from galaxy.tools.parameters import basic
from galaxy.util import bunch
from galaxy import model
-from elementtree.ElementTree import XML
+from .test_parameter_parsing import BaseParameterTestCase
-import tools_support
-
-class DataColumnParameterTestCase( TestCase, tools_support.UsesApp ):
+class DataColumnParameterTestCase( BaseParameterTestCase ):
def test_not_optional_by_default(self):
assert not self.__param_optional()
@@ -62,11 +58,7 @@
self.assertEqual( '2', self.param.get_initial_value( self.trans, { "input_tsv": self.build_ready_hda() } ) )
def setUp( self ):
- self.setup_app( mock_model=False )
- self.mock_tool = bunch.Bunch(
- app=self.app,
- tool_type="default",
- )
+ super(DataColumnParameterTestCase, self).setUp()
self.test_history = model.History()
self.app.model.context.add( self.test_history )
self.app.model.context.flush()
@@ -105,8 +97,8 @@
if self.set_data_ref:
data_ref_text = 'data_ref="input_tsv"'
template_xml = '''<param name="my_name" type="%s" %s %s %s %s></param>'''
- self.param_xml = XML( template_xml % ( self.type, data_ref_text, multi_text, optional_text, self.other_attributes ) )
- self._param = basic.ColumnListParameter( self.mock_tool, self.param_xml )
+ param_str = template_xml % ( self.type, data_ref_text, multi_text, optional_text, self.other_attributes )
+ self._param = self._parameter_for( xml=param_str )
self._param.ref_input = bunch.Bunch(formats=[model.datatypes_registry.get_datatype_by_extension("tabular")])
return self._param
diff -r 05533cd3509f1e23f514fc5190467580824f0b37 -r d66ad58a40e31defb6de0eb8b8b543b7e0f26ae5 test/unit/tools/test_data_parameters.py
--- a/test/unit/tools/test_data_parameters.py
+++ b/test/unit/tools/test_data_parameters.py
@@ -1,15 +1,10 @@
-from unittest import TestCase
-
from galaxy import model
from galaxy.util import bunch
-from galaxy.tools.parameters import basic
-from elementtree.ElementTree import XML
+from .test_parameter_parsing import BaseParameterTestCase
-import tools_support
-
-class DataToolParameterTestCase( TestCase, tools_support.UsesApp ):
+class DataToolParameterTestCase( BaseParameterTestCase ):
def test_to_python_none_values( self ):
assert None is self.param.to_python( None, self.app )
@@ -149,11 +144,7 @@
return hda
def setUp( self ):
- self.setup_app( mock_model=False )
- self.mock_tool = bunch.Bunch(
- app=self.app,
- tool_type="default",
- )
+ super(DataToolParameterTestCase, self).setUp()
self.test_history = model.History()
self.app.model.context.add( self.test_history )
self.app.model.context.flush()
@@ -187,8 +178,8 @@
if self.optional:
optional_text = 'optional="True"'
template_xml = '''<param name="data2" type="data" ext="txt" %s %s></param>'''
- self.param_xml = XML( template_xml % ( multi_text, optional_text ) )
- self._param = basic.DataToolParameter( self.mock_tool, self.param_xml )
+ param_str = template_xml % ( multi_text, optional_text )
+ self._param = self._parameter_for( tool=self.mock_tool, xml=param_str )
return self._param
diff -r 05533cd3509f1e23f514fc5190467580824f0b37 -r d66ad58a40e31defb6de0eb8b8b543b7e0f26ae5 test/unit/tools/test_parameter_parsing.py
--- /dev/null
+++ b/test/unit/tools/test_parameter_parsing.py
@@ -0,0 +1,283 @@
+from unittest import TestCase
+
+from galaxy.tools.parameters import basic
+from galaxy.util import bunch
+from elementtree.ElementTree import XML
+
+import tools_support
+
+
+class BaseParameterTestCase( TestCase, tools_support.UsesApp ):
+
+ def setUp(self):
+ self.setup_app( mock_model=False )
+ self.mock_tool = bunch.Bunch(
+ app=self.app,
+ tool_type="default",
+ )
+
+ def _parameter_for(self, **kwds):
+ content = kwds["xml"]
+ param_xml = XML( content )
+ return basic.ToolParameter.build( self.mock_tool, param_xml )
+
+
+class ParameterParsingTestCase( BaseParameterTestCase ):
+ """ Test the parsing of XML for most parameter types - in many
+ ways these are not very good tests since they break the abstraction
+ established by the tools. The docs tests in basic.py are better but
+ largely rely on HTML stuff we are moving to the client side so they
+ those tests may need to be updated anyway.
+
+ It occurs to me that rewriting this stuff to test to_dict would
+ be much better - since that is a public API of the the tools.
+ """
+
+ def test_parse_help_and_label(self):
+ param = self._parameter_for(xml="""
+ <param type="text" name="texti" size="8" value="mydefault" label="x" help="y" />
+ """)
+ assert param.label == "x"
+ assert param.help == "y"
+
+ param = self._parameter_for(xml="""
+ <param type="text" name="texti" size="8" value="mydefault">
+ <label>x2</label>
+ <help>y2</help>
+ </param>
+ """)
+ assert param.label == "x2"
+ assert param.help == "y2"
+
+ def test_parse_sanitizers(self):
+ param = self._parameter_for(xml="""
+ <param type="text" name="texti" size="8" value="mydefault">
+ <sanitizer invalid_char="">
+ <valid initial="string.digits"><add value=","/></valid>
+ </sanitizer>
+ </param>
+ """)
+ sanitizer = param.sanitizer
+ assert sanitizer is not None
+ assert sanitizer.sanitize_param("a") == ""
+ assert sanitizer.sanitize_param(",") == ","
+
+ def test_parse_optional(self):
+ param = self._parameter_for(xml="""
+ <param type="text" name="texti" size="8" value="mydefault" />
+ """)
+ assert param.optional is False
+
+ param = self._parameter_for(xml="""
+ <param type="text" name="texti" size="8" value="mydefault" optional="true" />
+ """)
+ assert param.optional is True
+
+ def test_parse_validators(self):
+ param = self._parameter_for(xml="""
+ <param type="text" name="texti" size="8" value="mydefault">
+ <validator type="unspecified_build" message="no genome?" />
+ </param>
+ """)
+ assert param.validators[0].message == "no genome?"
+
+ def test_text_params(self):
+ param = self._parameter_for(xml="""
+ <param type="text" name="texti" size="8" value="mydefault" />
+ """)
+ assert param.size == "8"
+ assert param.value == "mydefault"
+ assert param.type == "text"
+ assert not param.area
+
+ def test_text_area_params(self):
+ param = self._parameter_for(xml="""
+ <param type="text" name="textarea" area="true" />
+ """)
+ assert param.size is None
+ assert param.value is None
+ assert param.type == "text"
+ assert param.area
+
+ def test_integer_params(self):
+ param = self._parameter_for(xml="""
+ <param type="integer" name="intp" min="8" max="9" value="9" />
+ """)
+ assert param.name == "intp"
+ assert param.value == "9"
+ assert param.type == "integer"
+ param.validate( 8 )
+ self.assertRaises(Exception, lambda: param.validate( 10 ))
+
+ def test_float_params(self):
+ param = self._parameter_for(xml="""
+ <param type="float" name="floatp" min="7.8" max="9.5" value="9" />
+ """)
+ assert param.name == "floatp"
+ assert param.value == "9"
+ assert param.type == "float"
+ param.validate( 8.1 )
+ self.assertRaises(Exception, lambda: param.validate( 10.0 ))
+
+ def test_boolean_params(self):
+ param = self._parameter_for(xml="""
+ <param type="boolean" name="boolp" />
+ """)
+ assert param.name == "boolp"
+ assert param.truevalue == "true"
+ assert param.falsevalue == "false"
+ assert param.type == "boolean"
+
+ param = self._parameter_for(xml="""
+ <param type="boolean" name="boolp" truevalue="t" falsevalue="f" />
+ """)
+ assert param.truevalue == "t"
+ assert param.falsevalue == "f"
+
+ def test_file_params(self):
+ param = self._parameter_for(xml="""
+ <param type="file" name="filep" ajax-upload="true" />
+ """)
+ assert param.name == "filep"
+ assert param.type == "file"
+ assert param.ajax
+
+ def test_ftpfile_params(self):
+ param = self._parameter_for(xml="""
+ <param type="ftpfile" name="ftpfilep" />
+ """)
+ assert param.name == "ftpfilep"
+ assert param.type == "ftpfile"
+
+ def test_hidden(self):
+ param = self._parameter_for(xml="""
+ <param name="hiddenp" type="hidden" value="a hidden value" />
+ """)
+ assert param.name == "hiddenp"
+ assert param.type == "hidden"
+ assert param.value == "a hidden value"
+
+ def test_base_url(self):
+ param = self._parameter_for(xml="""
+ <param name="urlp" type="baseurl" value="http://twitter.com/" />
+ """)
+ assert param.name == "urlp"
+ assert param.type == "baseurl"
+ assert param.value == "http://twitter.com/"
+
+ param = self._parameter_for(xml="""
+ <param name="urlp" type="baseurl" />
+ """)
+ assert param.value == ""
+
+ def test_select_static(self):
+ param = self._parameter_for(xml="""
+ <param name="selectp" type="select" multiple="true">
+ <option value="a">A</option>
+ <option value="b" selected="true">B</option>
+ </param>
+ """)
+ assert param.multiple is True
+ assert param.name == "selectp"
+ assert param.type == "select"
+
+ assert param.options is None
+ assert param.dynamic_options is None
+ assert not param.is_dynamic
+
+ options = param.static_options
+ assert options[0][0] == "A"
+ assert options[0][1] == "a"
+ assert not options[0][2]
+
+ assert options[1][0] == "B"
+ assert options[1][1] == "b"
+ assert options[1][2]
+
+ def test_select_dynamic(self):
+ param = self._parameter_for(xml="""
+ <param name="selectp" type="select" dynamic_options="cow">
+ </param>
+ """)
+ assert param.multiple is False
+ assert param.options is None
+ assert param.dynamic_options == "cow"
+ ## This should be None or something - not undefined.
+ # assert not param.static_options
+ assert param.is_dynamic
+
+ def test_select_options_from(self):
+ param = self._parameter_for(xml="""
+ <param name="selectp" type="select">
+ <options from_data_table="cow">
+ </options>
+ </param>
+ """)
+ assert param.dynamic_options is None
+ assert param.is_dynamic
+
+ # More detailed tests of dynamic options should be placed
+ # in test_select_parameters.
+ assert param.options.missing_tool_data_table_name == "cow"
+
+ def test_genome_build(self):
+ param = self._parameter_for(xml="""
+ <param name="genomep" type="genomebuild">
+ </param>
+ """)
+ assert param.type == "genomebuild"
+ assert param.name == "genomep"
+ assert param.static_options
+
+ # Column and Data have sufficient test coverage in
+ # other modules.
+ def test_drilldown(self):
+ param = self._parameter_for(xml="""
+ <param name="some_name" type="drill_down" display="checkbox" hierarchy="recurse" multiple="true">
+ <options>
+ <option name="Heading 1" value="heading1">
+ <option name="Option 1" value="option1"/>
+ <option name="Option 2" value="option2"/>
+ <option name="Heading 1" value="heading1">
+ <option name="Option 3" value="option3"/>
+ <option name="Option 4" value="option4"/>
+ </option>
+ </option>
+ <option name="Option 5" value="option5"/>
+ </options>
+ </param>
+ """)
+ assert param.type == "drill_down"
+ assert param.name == "some_name"
+ assert param.options
+
+ heading1 = param.options[0]
+ assert heading1["selected"] is False
+ assert heading1["name"] == "Heading 1"
+ assert heading1["value"] == "heading1"
+ option1 = heading1["options"][0]
+ assert option1["selected"] is False
+ assert option1["name"] == "Option 1"
+ assert option1["value"] == "option1"
+
+ option5 = param.options[1]
+ assert option5["selected"] is False
+ assert option5["name"] == "Option 5"
+ assert option5["value"] == "option5"
+ assert len(option5["options"]) == 0
+
+ def test_tool_collection(self):
+ param = self._parameter_for(xml="""
+ <param name="datac" type="data_collection" collection_type="list" format="txt">
+ </param>
+ """)
+ assert param.type == "data_collection"
+ assert param.collection_type == "list"
+
+ def test_library(self):
+ param = self._parameter_for(xml="""
+ <param name="libraryp" type="library_data">
+ </param>
+ """)
+ assert param.type == "library_data"
+ assert param.name == "libraryp"
diff -r 05533cd3509f1e23f514fc5190467580824f0b37 -r d66ad58a40e31defb6de0eb8b8b543b7e0f26ae5 test/unit/tools/test_select_parameters.py
--- a/test/unit/tools/test_select_parameters.py
+++ b/test/unit/tools/test_select_parameters.py
@@ -1,13 +1,11 @@
-from unittest import TestCase
from galaxy.util import bunch
from galaxy import model
from galaxy.tools.parameters import basic
-from elementtree.ElementTree import XML
-import tools_support
+from .test_parameter_parsing import BaseParameterTestCase
-class SelectToolParameterTestCase( TestCase, tools_support.UsesApp ):
+class SelectToolParameterTestCase( BaseParameterTestCase ):
def test_dep_dummy_datasets_need_late_validation( self ):
self.options_xml = '''<options><filter type="data_meta" ref="input_bam" key="dbkey"/></options>'''
@@ -51,11 +49,7 @@
# TODO: Good deal of overlap here with DataToolParameterTestCase,
# refactor.
def setUp( self ):
- self.setup_app( mock_model=False )
- self.mock_tool = bunch.Bunch(
- app=self.app,
- tool_type="default",
- )
+ super(SelectToolParameterTestCase, self).setUp()
self.test_history = model.History()
self.app.model.context.add( self.test_history )
self.app.model.context.flush()
@@ -88,8 +82,8 @@
if self.set_data_ref:
data_ref_text = 'data_ref="input_bam"'
template_xml = '''<param name="my_name" type="%s" %s %s %s>%s</param>'''
- self.param_xml = XML( template_xml % ( self.type, data_ref_text, multi_text, optional_text, options_text ) )
- self._param = basic.SelectToolParameter( self.mock_tool, self.param_xml )
+ param_str = template_xml % ( self.type, data_ref_text, multi_text, optional_text, options_text )
+ self._param = self._parameter_for( xml=param_str )
return self._param
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: Hide current version from version selector
by commits-noreply@bitbucket.org 10 Dec '14
by commits-noreply@bitbucket.org 10 Dec '14
10 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/01a3ff6a376c/
Changeset: 01a3ff6a376c
User: guerler
Date: 2014-12-10 16:42:34+00:00
Summary: ToolForm: Hide current version from version selector
Affected #: 3 files
diff -r 4f46caf59f6c6a8a5dd03a425cc2656f91198fe1 -r 01a3ff6a376c4b95ca540bc120b5aab47920fd39 client/galaxy/scripts/mvc/tools/tools-form.js
--- a/client/galaxy/scripts/mvc/tools/tools-form.js
+++ b/client/galaxy/scripts/mvc/tools/tools-form.js
@@ -342,20 +342,23 @@
});
if (options.versions && options.versions.length > 1) {
for (var i in options.versions) {
- versions_button.addMenu({
- title : 'Switch to ' + options.versions[i],
- version : options.versions[i],
- icon : 'fa-cube',
- onclick : function() {
- // here we update the tool version (some tools encode the version also in the id)
- options.id = options.id.replace(options.version, this.version);
- options.version = this.version;
-
- // rebuild the model and form
- self.deferred.reset();
- self.deferred.execute(function(){self._buildModel()});
- }
- });
+ var version = options.versions[i];
+ if (version != options.version) {
+ versions_button.addMenu({
+ title : 'Switch to ' + version,
+ version : version,
+ icon : 'fa-cube',
+ onclick : function() {
+ // here we update the tool version (some tools encode the version also in the id)
+ options.id = options.id.replace(options.version, this.version);
+ options.version = this.version;
+
+ // rebuild the model and form
+ self.deferred.reset();
+ self.deferred.execute(function(){self._buildModel()});
+ }
+ });
+ }
}
} else {
versions_button.$el.hide();
diff -r 4f46caf59f6c6a8a5dd03a425cc2656f91198fe1 -r 01a3ff6a376c4b95ca540bc120b5aab47920fd39 static/scripts/mvc/tools/tools-form.js
--- a/static/scripts/mvc/tools/tools-form.js
+++ b/static/scripts/mvc/tools/tools-form.js
@@ -342,20 +342,23 @@
});
if (options.versions && options.versions.length > 1) {
for (var i in options.versions) {
- versions_button.addMenu({
- title : 'Switch to ' + options.versions[i],
- version : options.versions[i],
- icon : 'fa-cube',
- onclick : function() {
- // here we update the tool version (some tools encode the version also in the id)
- options.id = options.id.replace(options.version, this.version);
- options.version = this.version;
-
- // rebuild the model and form
- self.deferred.reset();
- self.deferred.execute(function(){self._buildModel()});
- }
- });
+ var version = options.versions[i];
+ if (version != options.version) {
+ versions_button.addMenu({
+ title : 'Switch to ' + version,
+ version : version,
+ icon : 'fa-cube',
+ onclick : function() {
+ // here we update the tool version (some tools encode the version also in the id)
+ options.id = options.id.replace(options.version, this.version);
+ options.version = this.version;
+
+ // rebuild the model and form
+ self.deferred.reset();
+ self.deferred.execute(function(){self._buildModel()});
+ }
+ });
+ }
}
} else {
versions_button.$el.hide();
diff -r 4f46caf59f6c6a8a5dd03a425cc2656f91198fe1 -r 01a3ff6a376c4b95ca540bc120b5aab47920fd39 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(["utils/utils","utils/deferred","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-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,j,h,m,k,a,e,d,f,l,c,g){var b=Backbone.View.extend({container:"body",initialize:function(o){console.debug(o);var n=this;var p=parent.Galaxy;if(p&&p.modal){this.modal=p.modal}else{this.modal=new m.Modal.View()}if(p&&p.currUser){this.is_admin=p.currUser.get("is_admin")}else{this.is_admin=false}this.options=o;this.deferred=new j();this.setElement("<div/>");$(this.container).append(this.$el);this._buildForm()},reciept:function(n){$(this.container).empty();$(this.container).append(n)},reset:function(){for(var n in this.element_list){this.element_list[n].reset()}},rebuild:function(){this.tree.refresh();console.debug("tools-form::rebuild() - Rebuilding data structures.")},refresh:function(){if(this.is_dynamic){var n=this;this.deferred.reset();this.deferred.execute(function(){n._updateModel()})}},_buildModel:function(){var n=this;var o=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){o+="job_id="+this.options.job_id}else{if(this.options.dataset_id){o+="dataset_id="+this.options.dataset_id}else{o+="tool_version="+this.options.version+"&";var q=top.location.href;var r=q.indexOf("?");if(q.indexOf("tool_id=")!=-1&&r!==-1){o+=q.slice(r+1)}}}var p=this.deferred.register();i.request({type:"GET",url:o,success:function(s){n.options=s;n._buildForm();n.message.update({status:"success",message:"Now you are using '"+n.options.name+"' version "+n.options.version+".",persistent:false});n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(s)},error:function(s){n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(s);var t=s.error||"Uncaught error.";n.modal.show({title:"Tool cannot be executed",body:t,buttons:{Close:function(){n.modal.hide()}}})}})},_updateModel:function(){var n=this;var o=this.tree.finalize({data:function(s){if(s.values.length>0&&s.values[0]&&s.values[0].src==="hda"){return n.content.get({id:s.values[0].id,src:"hda"}).id_uncoded}return null}});console.debug("tools-form::_refreshForm() - Refreshing states.");console.debug(o);function r(v){for(var t in n.input_list){var u=n.field_list[t];var s=n.input_list[t];if(s.is_dynamic&&u.wait&&u.unwait){if(v){u.wait()}else{u.unwait()}}}}r(true);var q=this.deferred.register();var p=galaxy_config.root+"api/tools/"+this.options.id+"/build?tool_version="+this.options.version;i.request({type:"GET",url:p,data:o,success:function(s){n._updateForm(s);r(false);n.deferred.done(q);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(s)},error:function(s){n.deferred.done(q);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(s)}})},_updateForm:function(n){var o=this;this.tree.matchModel(n,function(q,u){var p=o.input_list[q];if(p&&p.options){if(!_.isEqual(p.options,u.options)){p.options=u.options;var v=o.field_list[q];if(v.update){var t=[];if((["data","data_collection","drill_down"]).indexOf(p.type)!=-1){t=p.options}else{for(var s in u.options){var r=u.options[s];if(r.length>2){t.push({label:r[0],value:r[1]})}}}v.update(t);v.trigger("change");console.debug("Updating options for "+q)}}}})},_buildForm:function(){var w=this;this.field_list={};this.input_list={};this.element_list={};this.tree=new c(this);this.job_handler=new g(this);this.content=new f(this);var x=this.options;this.message=new m.Message();var n="This tool requires ";for(var r in x.requirements){var v=x.requirements[r];n+=v.name;if(v.version){n+=" (Version "+v.version+")"}if(r<x.requirements.length-2){n+=", "}if(r==x.requirements.length-2){n+=" and "}}n+=".";var t=new m.ButtonIcon({icon:"fa-info-circle",title:"Requirements",tooltip:"Display tool requirements",onclick:function(){if(!this.visible){this.visible=true;w.message.update({persistent:true,message:n,status:"warning"})}else{this.visible=false;w.message.update({message:""})}}});if(!x.requirements||x.requirements.length==0){t.$el.hide()}var p=new m.ButtonMenu({icon:"fa-cubes",title:"Versions",tooltip:"Select another tool version"});if(x.versions&&x.versions.length>1){for(var r in x.versions){p.addMenu({title:"Switch to "+x.versions[r],version:x.versions[r],icon:"fa-cube",onclick:function(){x.id=x.id.replace(x.version,this.version);x.version=this.version;w.deferred.reset();w.deferred.execute(function(){w._buildModel()})}})}}else{p.$el.hide()}var s=new m.ButtonMenu({icon:"fa-gear",title:"Options",tooltip:"View available options"});if(x.biostar_url){s.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(x.biostar_url+"/p/new/post/")}});s.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(x.biostar_url+"/t/"+x.id+"/")}})}s.addMenu({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",window.location.origin+galaxy_config.root+"root?tool_id="+x.id)}});if(this.is_admin){s.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+x.id+"/download"}})}this.section=new l.View(w,{inputs:x.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+x.name+"</b> "+x.description+" (Version "+x.version+")",cls:"ui-portlet-slim",operations:{requirements:t,menu:s,versions:p},buttons:{execute:new m.Button({icon:"fa-check",tooltip:"Execute: "+x.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){w.job_handler.submit()}})}});this.$el.empty();this.$el.append(this.portlet.$el);if(x.help!=""){this.$el.append(d.help(x.help))}if(x.citations){var u=$("<div/>");var o=new k.ToolCitationCollection();o.tool_id=x.id;var q=new a.CitationListView({el:u,collection:o});q.render();o.fetch();this.$el.append(u)}this.portlet.append(this.message.$el,true);this.portlet.append(this.section.$el);this.rebuild();if(x.message){this.message.update({persistent:true,status:"warning",message:x.message})}}});return{View:b}});
\ No newline at end of file
+define(["utils/utils","utils/deferred","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-content","mvc/tools/tools-section","mvc/tools/tools-tree","mvc/tools/tools-jobs"],function(i,j,h,m,k,a,e,d,f,l,c,g){var b=Backbone.View.extend({container:"body",initialize:function(o){console.debug(o);var n=this;var p=parent.Galaxy;if(p&&p.modal){this.modal=p.modal}else{this.modal=new m.Modal.View()}if(p&&p.currUser){this.is_admin=p.currUser.get("is_admin")}else{this.is_admin=false}this.options=o;this.deferred=new j();this.setElement("<div/>");$(this.container).append(this.$el);this._buildForm()},reciept:function(n){$(this.container).empty();$(this.container).append(n)},reset:function(){for(var n in this.element_list){this.element_list[n].reset()}},rebuild:function(){this.tree.refresh();console.debug("tools-form::rebuild() - Rebuilding data structures.")},refresh:function(){if(this.is_dynamic){var n=this;this.deferred.reset();this.deferred.execute(function(){n._updateModel()})}},_buildModel:function(){var n=this;var o=galaxy_config.root+"api/tools/"+this.options.id+"/build?";if(this.options.job_id){o+="job_id="+this.options.job_id}else{if(this.options.dataset_id){o+="dataset_id="+this.options.dataset_id}else{o+="tool_version="+this.options.version+"&";var q=top.location.href;var r=q.indexOf("?");if(q.indexOf("tool_id=")!=-1&&r!==-1){o+=q.slice(r+1)}}}var p=this.deferred.register();i.request({type:"GET",url:o,success:function(s){n.options=s;n._buildForm();n.message.update({status:"success",message:"Now you are using '"+n.options.name+"' version "+n.options.version+".",persistent:false});n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model ready.");console.debug(s)},error:function(s){n.deferred.done(p);console.debug("tools-form::initialize() - Initial tool model request failed.");console.debug(s);var t=s.error||"Uncaught error.";n.modal.show({title:"Tool cannot be executed",body:t,buttons:{Close:function(){n.modal.hide()}}})}})},_updateModel:function(){var n=this;var o=this.tree.finalize({data:function(s){if(s.values.length>0&&s.values[0]&&s.values[0].src==="hda"){return n.content.get({id:s.values[0].id,src:"hda"}).id_uncoded}return null}});console.debug("tools-form::_refreshForm() - Refreshing states.");console.debug(o);function r(v){for(var t in n.input_list){var u=n.field_list[t];var s=n.input_list[t];if(s.is_dynamic&&u.wait&&u.unwait){if(v){u.wait()}else{u.unwait()}}}}r(true);var q=this.deferred.register();var p=galaxy_config.root+"api/tools/"+this.options.id+"/build?tool_version="+this.options.version;i.request({type:"GET",url:p,data:o,success:function(s){n._updateForm(s);r(false);n.deferred.done(q);console.debug("tools-form::_refreshForm() - States refreshed.");console.debug(s)},error:function(s){n.deferred.done(q);console.debug("tools-form::_refreshForm() - Refresh request failed.");console.debug(s)}})},_updateForm:function(n){var o=this;this.tree.matchModel(n,function(q,u){var p=o.input_list[q];if(p&&p.options){if(!_.isEqual(p.options,u.options)){p.options=u.options;var v=o.field_list[q];if(v.update){var t=[];if((["data","data_collection","drill_down"]).indexOf(p.type)!=-1){t=p.options}else{for(var s in u.options){var r=u.options[s];if(r.length>2){t.push({label:r[0],value:r[1]})}}}v.update(t);v.trigger("change");console.debug("Updating options for "+q)}}}})},_buildForm:function(){var x=this;this.field_list={};this.input_list={};this.element_list={};this.tree=new c(this);this.job_handler=new g(this);this.content=new f(this);var y=this.options;this.message=new m.Message();var n="This tool requires ";for(var r in y.requirements){var w=y.requirements[r];n+=w.name;if(w.version){n+=" (Version "+w.version+")"}if(r<y.requirements.length-2){n+=", "}if(r==y.requirements.length-2){n+=" and "}}n+=".";var t=new m.ButtonIcon({icon:"fa-info-circle",title:"Requirements",tooltip:"Display tool requirements",onclick:function(){if(!this.visible){this.visible=true;x.message.update({persistent:true,message:n,status:"warning"})}else{this.visible=false;x.message.update({message:""})}}});if(!y.requirements||y.requirements.length==0){t.$el.hide()}var p=new m.ButtonMenu({icon:"fa-cubes",title:"Versions",tooltip:"Select another tool version"});if(y.versions&&y.versions.length>1){for(var r in y.versions){var u=y.versions[r];if(u!=y.version){p.addMenu({title:"Switch to "+u,version:u,icon:"fa-cube",onclick:function(){y.id=y.id.replace(y.version,this.version);y.version=this.version;x.deferred.reset();x.deferred.execute(function(){x._buildModel()})}})}}}else{p.$el.hide()}var s=new m.ButtonMenu({icon:"fa-gear",title:"Options",tooltip:"View available options"});if(y.biostar_url){s.addMenu({icon:"fa-question-circle",title:"Question?",tooltip:"Ask a question about this tool (Biostar)",onclick:function(){window.open(y.biostar_url+"/p/new/post/")}});s.addMenu({icon:"fa-search",title:"Search",tooltip:"Search help for this tool (Biostar)",onclick:function(){window.open(y.biostar_url+"/t/"+y.id+"/")}})}s.addMenu({icon:"fa-share",title:"Share",tooltip:"Share this tool",onclick:function(){prompt("Copy to clipboard: Ctrl+C, Enter",window.location.origin+galaxy_config.root+"root?tool_id="+y.id)}});if(this.is_admin){s.addMenu({icon:"fa-download",title:"Download",tooltip:"Download this tool",onclick:function(){window.location.href=galaxy_config.root+"api/tools/"+y.id+"/download"}})}this.section=new l.View(x,{inputs:y.inputs,cls:"ui-table-plain"});if(this.incompatible){this.$el.hide();$("#tool-form-classic").show();return}this.portlet=new h.View({icon:"fa-wrench",title:"<b>"+y.name+"</b> "+y.description+" (Version "+y.version+")",cls:"ui-portlet-slim",operations:{requirements:t,menu:s,versions:p},buttons:{execute:new m.Button({icon:"fa-check",tooltip:"Execute: "+y.name,title:"Execute",cls:"btn btn-primary",floating:"clear",onclick:function(){x.job_handler.submit()}})}});this.$el.empty();this.$el.append(this.portlet.$el);if(y.help!=""){this.$el.append(d.help(y.help))}if(y.citations){var v=$("<div/>");var o=new k.ToolCitationCollection();o.tool_id=y.id;var q=new a.CitationListView({el:v,collection:o});q.render();o.fetch();this.$el.append(v)}this.portlet.append(this.message.$el,true);this.portlet.append(this.section.$el);this.rebuild();if(y.message){this.message.update({persistent:true,status:"warning",message:y.message})}}});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: guerler: ToolForm: Activate tool form
by commits-noreply@bitbucket.org 10 Dec '14
by commits-noreply@bitbucket.org 10 Dec '14
10 Dec '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/4f46caf59f6c/
Changeset: 4f46caf59f6c
User: guerler
Date: 2014-12-10 16:02:50+00:00
Summary: ToolForm: Activate tool form
Affected #: 1 file
diff -r eca8b8ed910366a2f72b778ace674e3126832e66 -r 4f46caf59f6c6a8a5dd03a425cc2656f91198fe1 templates/webapps/galaxy/tool_form.mako
--- a/templates/webapps/galaxy/tool_form.mako
+++ b/templates/webapps/galaxy/tool_form.mako
@@ -4,7 +4,7 @@
${h.css('base', 'jquery-ui/smoothness/jquery-ui')}
## skip new tool form code if disabled
-%if trans.app.config.get('toolform_upgrade', False):
+##%if trans.app.config.get('toolform_upgrade', False):
<%
## TEMPORARY: create tool dictionary in mako while both tool forms are in use.
## This avoids making two separate requests since the classic form requires the mako anyway.
@@ -28,9 +28,9 @@
});
</script><div id="tool-form-classic" style="display: none;">
-%else:
- <div id="tool-form-classic">
-%endif
+##%else:
+## <div id="tool-form-classic">
+##%endif
<%namespace file="/message.mako" import="render_msg" /><%namespace file="/base_panels.mako" import="overlay" />
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