Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
todomvc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Sven Franck
todomvc
Commits
e80de6d1
Commit
e80de6d1
authored
Dec 14, 2014
by
Pascal Hartig
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Backbone: Update jQuery, localStorage plugin
parent
f6786e58
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
582 additions
and
9305 deletions
+582
-9305
examples/backbone/bower.json
examples/backbone/bower.json
+2
-2
examples/backbone/bower_components/backbone.localStorage/backbone.localStorage.js
...components/backbone.localStorage/backbone.localStorage.js
+83
-49
examples/backbone/bower_components/jquery/jquery.js
examples/backbone/bower_components/jquery/jquery.js
+0
-8829
examples/backbone/bower_components/underscore/underscore.js
examples/backbone/bower_components/underscore/underscore.js
+496
-424
examples/backbone/index.html
examples/backbone/index.html
+1
-1
No files found.
examples/backbone/bower.json
View file @
e80de6d1
...
@@ -3,8 +3,8 @@
...
@@ -3,8 +3,8 @@
"version"
:
"0.0.0"
,
"version"
:
"0.0.0"
,
"dependencies"
:
{
"dependencies"
:
{
"backbone"
:
"~1.1.1"
,
"backbone"
:
"~1.1.1"
,
"underscore"
:
"~1.
6
.0"
,
"underscore"
:
"~1.
7
.0"
,
"jquery"
:
"~2.
0
.0"
,
"jquery"
:
"~2.
1
.0"
,
"todomvc-common"
:
"~0.3.0"
,
"todomvc-common"
:
"~0.3.0"
,
"backbone.localStorage"
:
"~1.1.0"
"backbone.localStorage"
:
"~1.1.0"
}
}
...
...
examples/backbone/bower_components/backbone.localStorage/backbone.localStorage.js
View file @
e80de6d1
/**
/**
* Backbone localStorage Adapter
* Backbone localStorage Adapter
* Version 1.1.
7
* Version 1.1.
14
*
*
* https://github.com/jeromegn/Backbone.localStorage
* https://github.com/jeromegn/Backbone.localStorage
*/
*/
(
function
(
root
,
factory
)
{
(
function
(
root
,
factory
)
{
if
(
typeof
exports
===
'
object
'
&&
typeof
require
===
'
function
'
)
{
if
(
typeof
exports
===
'
object
'
&&
typeof
require
===
'
function
'
)
{
module
.
exports
=
factory
(
require
(
"
underscore
"
),
require
(
"
backbone
"
));
module
.
exports
=
factory
(
require
(
"
backbone
"
));
}
else
if
(
typeof
define
===
"
function
"
&&
define
.
amd
)
{
}
else
if
(
typeof
define
===
"
function
"
&&
define
.
amd
)
{
// AMD. Register as an anonymous module.
// AMD. Register as an anonymous module.
define
([
"
underscore
"
,
"
backbone
"
],
function
(
_
,
Backbone
)
{
define
([
"
backbone
"
],
function
(
Backbone
)
{
// Use global variables if the locals are undefined.
// Use global variables if the locals are undefined.
return
factory
(
_
||
root
.
_
,
Backbone
||
root
.
Backbone
);
return
factory
(
Backbone
||
root
.
Backbone
);
});
});
}
else
{
}
else
{
// RequireJS isn't being used. Assume underscore and backbone are loaded in <script> tags
factory
(
Backbone
);
factory
(
_
,
Backbone
);
}
}
}(
this
,
function
(
Backbone
)
{
}(
this
,
function
(
_
,
Backbone
)
{
// A simple module to replace `Backbone.sync` with *localStorage*-based
// A simple module to replace `Backbone.sync` with *localStorage*-based
// persistence. Models are given GUIDS, and saved into a JSON object. Simple
// persistence. Models are given GUIDS, and saved into a JSON object. Simple
// as that.
// as that.
// Hold reference to Underscore.js and Backbone.js in the closure in order
// to make things work even if they are removed from the global namespace
// Generate four random hex digits.
// Generate four random hex digits.
function
S4
()
{
function
S4
()
{
return
(((
1
+
Math
.
random
())
*
0x10000
)
|
0
).
toString
(
16
).
substring
(
1
);
return
(((
1
+
Math
.
random
())
*
0x10000
)
|
0
).
toString
(
16
).
substring
(
1
);
...
@@ -35,19 +31,49 @@ function guid() {
...
@@ -35,19 +31,49 @@ function guid() {
return
(
S4
()
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
S4
()
+
S4
());
return
(
S4
()
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
S4
()
+
S4
());
};
};
function
isObject
(
item
)
{
return
item
===
Object
(
item
);
}
function
contains
(
array
,
item
)
{
var
i
=
array
.
length
;
while
(
i
--
)
if
(
array
[
i
]
===
item
)
return
true
;
return
false
;
}
function
extend
(
obj
,
props
)
{
for
(
var
key
in
props
)
obj
[
key
]
=
props
[
key
]
return
obj
;
}
function
result
(
object
,
property
)
{
if
(
object
==
null
)
return
void
0
;
var
value
=
object
[
property
];
return
(
typeof
value
===
'
function
'
)
?
object
[
property
]()
:
value
;
}
// Our Store is represented by a single JS object in *localStorage*. Create it
// Our Store is represented by a single JS object in *localStorage*. Create it
// with a meaningful name, like the name you'd give a table.
// with a meaningful name, like the name you'd give a table.
// window.Store is deprectated, use Backbone.LocalStorage instead
// window.Store is deprectated, use Backbone.LocalStorage instead
Backbone
.
LocalStorage
=
window
.
Store
=
function
(
name
)
{
Backbone
.
LocalStorage
=
window
.
Store
=
function
(
name
,
serializer
)
{
if
(
!
this
.
localStorage
)
{
if
(
!
this
.
localStorage
)
{
throw
"
Backbone.localStorage: Environment does not support localStorage.
"
throw
"
Backbone.localStorage: Environment does not support localStorage.
"
}
}
this
.
name
=
name
;
this
.
name
=
name
;
this
.
serializer
=
serializer
||
{
serialize
:
function
(
item
)
{
return
isObject
(
item
)
?
JSON
.
stringify
(
item
)
:
item
;
},
// fix for "illegal access" error on Android when JSON.parse is passed null
deserialize
:
function
(
data
)
{
return
data
&&
JSON
.
parse
(
data
);
}
};
var
store
=
this
.
localStorage
().
getItem
(
this
.
name
);
var
store
=
this
.
localStorage
().
getItem
(
this
.
name
);
this
.
records
=
(
store
&&
store
.
split
(
"
,
"
))
||
[];
this
.
records
=
(
store
&&
store
.
split
(
"
,
"
))
||
[];
};
};
_
.
extend
(
Backbone
.
LocalStorage
.
prototype
,
{
extend
(
Backbone
.
LocalStorage
.
prototype
,
{
// Save the current state of the **Store** to *localStorage*.
// Save the current state of the **Store** to *localStorage*.
save
:
function
()
{
save
:
function
()
{
...
@@ -57,11 +83,11 @@ _.extend(Backbone.LocalStorage.prototype, {
...
@@ -57,11 +83,11 @@ _.extend(Backbone.LocalStorage.prototype, {
// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
// have an id of it's own.
// have an id of it's own.
create
:
function
(
model
)
{
create
:
function
(
model
)
{
if
(
!
model
.
id
)
{
if
(
!
model
.
id
&&
model
.
id
!==
0
)
{
model
.
id
=
guid
();
model
.
id
=
guid
();
model
.
set
(
model
.
idAttribute
,
model
.
id
);
model
.
set
(
model
.
idAttribute
,
model
.
id
);
}
}
this
.
localStorage
().
setItem
(
this
.
name
+
"
-
"
+
model
.
id
,
JSON
.
stringify
(
model
));
this
.
localStorage
().
setItem
(
this
.
_itemName
(
model
.
id
),
this
.
serializer
.
serialize
(
model
));
this
.
records
.
push
(
model
.
id
.
toString
());
this
.
records
.
push
(
model
.
id
.
toString
());
this
.
save
();
this
.
save
();
return
this
.
find
(
model
);
return
this
.
find
(
model
);
...
@@ -69,36 +95,40 @@ _.extend(Backbone.LocalStorage.prototype, {
...
@@ -69,36 +95,40 @@ _.extend(Backbone.LocalStorage.prototype, {
// Update a model by replacing its copy in `this.data`.
// Update a model by replacing its copy in `this.data`.
update
:
function
(
model
)
{
update
:
function
(
model
)
{
this
.
localStorage
().
setItem
(
this
.
name
+
"
-
"
+
model
.
id
,
JSON
.
stringify
(
model
));
this
.
localStorage
().
setItem
(
this
.
_itemName
(
model
.
id
),
this
.
serializer
.
serialize
(
model
));
if
(
!
_
.
include
(
this
.
records
,
model
.
id
.
toString
()))
var
modelId
=
model
.
id
.
toString
();
this
.
records
.
push
(
model
.
id
.
toString
());
this
.
save
();
if
(
!
contains
(
this
.
records
,
modelId
))
{
this
.
records
.
push
(
modelId
);
this
.
save
();
}
return
this
.
find
(
model
);
return
this
.
find
(
model
);
},
},
// Retrieve a model from `this.data` by id.
// Retrieve a model from `this.data` by id.
find
:
function
(
model
)
{
find
:
function
(
model
)
{
return
this
.
jsonData
(
this
.
localStorage
().
getItem
(
this
.
name
+
"
-
"
+
model
.
id
));
return
this
.
serializer
.
deserialize
(
this
.
localStorage
().
getItem
(
this
.
_itemName
(
model
.
id
)
));
},
},
// Return the array of all models currently in storage.
// Return the array of all models currently in storage.
findAll
:
function
()
{
findAll
:
function
()
{
// Lodash removed _#chain in v1.0.0-rc.1
var
result
=
[];
return
(
_
.
chain
||
_
)(
this
.
records
)
for
(
var
i
=
0
,
id
,
data
;
i
<
this
.
records
.
length
;
i
++
)
{
.
map
(
function
(
id
){
id
=
this
.
records
[
i
];
return
this
.
jsonData
(
this
.
localStorage
().
getItem
(
this
.
name
+
"
-
"
+
id
));
data
=
this
.
serializer
.
deserialize
(
this
.
localStorage
().
getItem
(
this
.
_itemName
(
id
)
));
},
this
)
if
(
data
!=
null
)
result
.
push
(
data
);
.
compact
()
}
.
value
()
;
return
result
;
},
},
// Delete a model from `this.data`, returning it.
// Delete a model from `this.data`, returning it.
destroy
:
function
(
model
)
{
destroy
:
function
(
model
)
{
if
(
model
.
isNew
())
this
.
localStorage
().
removeItem
(
this
.
_itemName
(
model
.
id
));
return
false
var
modelId
=
model
.
id
.
toString
();
this
.
localStorage
().
removeItem
(
this
.
name
+
"
-
"
+
model
.
id
);
for
(
var
i
=
0
,
id
;
i
<
this
.
records
.
length
;
i
++
)
{
this
.
records
=
_
.
reject
(
this
.
records
,
function
(
id
){
if
(
this
.
records
[
i
]
===
modelId
)
{
return
id
===
model
.
id
.
toString
();
this
.
records
.
splice
(
i
,
1
);
});
}
}
this
.
save
();
this
.
save
();
return
model
;
return
model
;
},
},
...
@@ -107,11 +137,6 @@ _.extend(Backbone.LocalStorage.prototype, {
...
@@ -107,11 +137,6 @@ _.extend(Backbone.LocalStorage.prototype, {
return
localStorage
;
return
localStorage
;
},
},
// fix for "illegal access" error on Android when JSON.parse is passed null
jsonData
:
function
(
data
)
{
return
data
&&
JSON
.
parse
(
data
);
},
// Clear localStorage for specific collection.
// Clear localStorage for specific collection.
_clear
:
function
()
{
_clear
:
function
()
{
var
local
=
this
.
localStorage
(),
var
local
=
this
.
localStorage
(),
...
@@ -120,11 +145,12 @@ _.extend(Backbone.LocalStorage.prototype, {
...
@@ -120,11 +145,12 @@ _.extend(Backbone.LocalStorage.prototype, {
// Remove id-tracking item (e.g., "foo").
// Remove id-tracking item (e.g., "foo").
local
.
removeItem
(
this
.
name
);
local
.
removeItem
(
this
.
name
);
// Lodash removed _#chain in v1.0.0-rc.1
// Match all data items (e.g., "foo-ID") and remove.
// Match all data items (e.g., "foo-ID") and remove.
(
_
.
chain
||
_
)(
local
).
keys
()
for
(
var
k
in
local
)
{
.
filter
(
function
(
k
)
{
return
itemRe
.
test
(
k
);
})
if
(
itemRe
.
test
(
k
))
{
.
each
(
function
(
k
)
{
local
.
removeItem
(
k
);
});
local
.
removeItem
(
k
);
}
}
this
.
records
.
length
=
0
;
this
.
records
.
length
=
0
;
},
},
...
@@ -132,6 +158,10 @@ _.extend(Backbone.LocalStorage.prototype, {
...
@@ -132,6 +158,10 @@ _.extend(Backbone.LocalStorage.prototype, {
// Size of localStorage.
// Size of localStorage.
_storageSize
:
function
()
{
_storageSize
:
function
()
{
return
this
.
localStorage
().
length
;
return
this
.
localStorage
().
length
;
},
_itemName
:
function
(
id
)
{
return
this
.
name
+
"
-
"
+
id
;
}
}
});
});
...
@@ -140,9 +170,13 @@ _.extend(Backbone.LocalStorage.prototype, {
...
@@ -140,9 +170,13 @@ _.extend(Backbone.LocalStorage.prototype, {
// *localStorage* property, which should be an instance of `Store`.
// *localStorage* property, which should be an instance of `Store`.
// window.Store.sync and Backbone.localSync is deprecated, use Backbone.LocalStorage.sync instead
// window.Store.sync and Backbone.localSync is deprecated, use Backbone.LocalStorage.sync instead
Backbone
.
LocalStorage
.
sync
=
window
.
Store
.
sync
=
Backbone
.
localSync
=
function
(
method
,
model
,
options
)
{
Backbone
.
LocalStorage
.
sync
=
window
.
Store
.
sync
=
Backbone
.
localSync
=
function
(
method
,
model
,
options
)
{
var
store
=
model
.
localStorage
||
model
.
collection
.
localStorage
;
var
store
=
result
(
model
,
'
localStorage
'
)
||
result
(
model
.
collection
,
'
localStorage
'
)
;
var
resp
,
errorMessage
,
syncDfd
=
Backbone
.
$
.
Deferred
&&
Backbone
.
$
.
Deferred
();
//If $ is having Deferred - use it.
var
resp
,
errorMessage
;
//If $ is having Deferred - use it.
var
syncDfd
=
Backbone
.
$
?
(
Backbone
.
$
.
Deferred
&&
Backbone
.
$
.
Deferred
())
:
(
Backbone
.
Deferred
&&
Backbone
.
Deferred
());
try
{
try
{
...
...
examples/backbone/bower_components/jquery/jquery.js
deleted
100755 → 0
View file @
f6786e58
This source diff could not be displayed because it is too large. You can
view the blob
instead.
examples/backbone/bower_components/underscore/underscore.js
View file @
e80de6d1
// Underscore.js 1.
6
.0
// Underscore.js 1.
7
.0
// http://underscorejs.org
// http://underscorejs.org
// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Underscore may be freely distributed under the MIT license.
// Underscore may be freely distributed under the MIT license.
...
@@ -14,9 +14,6 @@
...
@@ -14,9 +14,6 @@
// Save the previous value of the `_` variable.
// Save the previous value of the `_` variable.
var
previousUnderscore
=
root
.
_
;
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:
// Save bytes in the minified (but not gzipped) version:
var
ArrayProto
=
Array
.
prototype
,
ObjProto
=
Object
.
prototype
,
FuncProto
=
Function
.
prototype
;
var
ArrayProto
=
Array
.
prototype
,
ObjProto
=
Object
.
prototype
,
FuncProto
=
Function
.
prototype
;
...
@@ -31,15 +28,6 @@
...
@@ -31,15 +28,6 @@
// All **ECMAScript 5** native function implementations that we hope to use
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
// are declared here.
var
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
,
nativeIsArray
=
Array
.
isArray
,
nativeKeys
=
Object
.
keys
,
nativeKeys
=
Object
.
keys
,
nativeBind
=
FuncProto
.
bind
;
nativeBind
=
FuncProto
.
bind
;
...
@@ -53,8 +41,7 @@
...
@@ -53,8 +41,7 @@
// Export the Underscore object for **Node.js**, with
// Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in
// backwards-compatibility for the old `require()` API. If we're in
// the browser, add `_` as a global object via a string identifier,
// the browser, add `_` as a global object.
// for Closure Compiler "advanced" mode.
if
(
typeof
exports
!==
'
undefined
'
)
{
if
(
typeof
exports
!==
'
undefined
'
)
{
if
(
typeof
module
!==
'
undefined
'
&&
module
.
exports
)
{
if
(
typeof
module
!==
'
undefined
'
&&
module
.
exports
)
{
exports
=
module
.
exports
=
_
;
exports
=
module
.
exports
=
_
;
...
@@ -65,98 +52,125 @@
...
@@ -65,98 +52,125 @@
}
}
// Current version.
// Current version.
_
.
VERSION
=
'
1.6.0
'
;
_
.
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
// Collection Functions
// --------------------
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
// The cornerstone, an `each` implementation, aka `forEach`.
// Handles
objects with the built-in `forEach`, arrays, and raw objects.
// Handles
raw objects in addition to array-likes. Treats all
//
Delegates to **ECMAScript 5**'s native `forEach` if availabl
e.
//
sparse array-likes as if they were dens
e.
var
each
=
_
.
each
=
_
.
forEach
=
function
(
obj
,
iterator
,
context
)
{
_
.
each
=
_
.
forEach
=
function
(
obj
,
iteratee
,
context
)
{
if
(
obj
==
null
)
return
obj
;
if
(
obj
==
null
)
return
obj
;
i
f
(
nativeForEach
&&
obj
.
forEach
===
nativeForEach
)
{
i
teratee
=
createCallback
(
iteratee
,
context
);
obj
.
forEach
(
iterator
,
context
)
;
var
i
,
length
=
obj
.
length
;
}
else
if
(
obj
.
length
===
+
obj
.
length
)
{
if
(
length
===
+
length
)
{
for
(
var
i
=
0
,
length
=
obj
.
length
;
i
<
length
;
i
++
)
{
for
(
i
=
0
;
i
<
length
;
i
++
)
{
i
f
(
iterator
.
call
(
context
,
obj
[
i
],
i
,
obj
)
===
breaker
)
return
;
i
teratee
(
obj
[
i
],
i
,
obj
)
;
}
}
}
else
{
}
else
{
var
keys
=
_
.
keys
(
obj
);
var
keys
=
_
.
keys
(
obj
);
for
(
var
i
=
0
,
length
=
keys
.
length
;
i
<
length
;
i
++
)
{
for
(
i
=
0
,
length
=
keys
.
length
;
i
<
length
;
i
++
)
{
i
f
(
iterator
.
call
(
context
,
obj
[
keys
[
i
]],
keys
[
i
],
obj
)
===
breaker
)
return
;
i
teratee
(
obj
[
keys
[
i
]],
keys
[
i
],
obj
)
;
}
}
}
}
return
obj
;
return
obj
;
};
};
// Return the results of applying the iterator to each element.
// Return the results of applying the iteratee to each element.
// Delegates to **ECMAScript 5**'s native `map` if available.
_
.
map
=
_
.
collect
=
function
(
obj
,
iteratee
,
context
)
{
_
.
map
=
_
.
collect
=
function
(
obj
,
iterator
,
context
)
{
if
(
obj
==
null
)
return
[];
var
results
=
[];
iteratee
=
_
.
iteratee
(
iteratee
,
context
);
if
(
obj
==
null
)
return
results
;
var
keys
=
obj
.
length
!==
+
obj
.
length
&&
_
.
keys
(
obj
),
if
(
nativeMap
&&
obj
.
map
===
nativeMap
)
return
obj
.
map
(
iterator
,
context
);
length
=
(
keys
||
obj
).
length
,
each
(
obj
,
function
(
value
,
index
,
list
)
{
results
=
Array
(
length
),
results
.
push
(
iterator
.
call
(
context
,
value
,
index
,
list
));
currentKey
;
});
for
(
var
index
=
0
;
index
<
length
;
index
++
)
{
currentKey
=
keys
?
keys
[
index
]
:
index
;
results
[
index
]
=
iteratee
(
obj
[
currentKey
],
currentKey
,
obj
);
}
return
results
;
return
results
;
};
};
var
reduceError
=
'
Reduce of empty array with no initial value
'
;
var
reduceError
=
'
Reduce of empty array with no initial value
'
;
// **Reduce** builds up a single result from a list of values, aka `inject`,
// **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
// or `foldl`.
_
.
reduce
=
_
.
foldl
=
_
.
inject
=
function
(
obj
,
iterator
,
memo
,
context
)
{
_
.
reduce
=
_
.
foldl
=
_
.
inject
=
function
(
obj
,
iteratee
,
memo
,
context
)
{
var
initial
=
arguments
.
length
>
2
;
if
(
obj
==
null
)
obj
=
[];
if
(
obj
==
null
)
obj
=
[];
if
(
nativeReduce
&&
obj
.
reduce
===
nativeReduce
)
{
iteratee
=
createCallback
(
iteratee
,
context
,
4
);
if
(
context
)
iterator
=
_
.
bind
(
iterator
,
context
);
var
keys
=
obj
.
length
!==
+
obj
.
length
&&
_
.
keys
(
obj
),
return
initial
?
obj
.
reduce
(
iterator
,
memo
)
:
obj
.
reduce
(
iterator
);
length
=
(
keys
||
obj
).
length
,
index
=
0
,
currentKey
;
if
(
arguments
.
length
<
3
)
{
if
(
!
length
)
throw
new
TypeError
(
reduceError
);
memo
=
obj
[
keys
?
keys
[
index
++
]
:
index
++
];
}
for
(;
index
<
length
;
index
++
)
{
currentKey
=
keys
?
keys
[
index
]
:
index
;
memo
=
iteratee
(
memo
,
obj
[
currentKey
],
currentKey
,
obj
);
}
}
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
);
return
memo
;
return
memo
;
};
};
// The right-associative version of reduce, also known as `foldr`.
// The right-associative version of reduce, also known as `foldr`.
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
_
.
reduceRight
=
_
.
foldr
=
function
(
obj
,
iteratee
,
memo
,
context
)
{
_
.
reduceRight
=
_
.
foldr
=
function
(
obj
,
iterator
,
memo
,
context
)
{
var
initial
=
arguments
.
length
>
2
;
if
(
obj
==
null
)
obj
=
[];
if
(
obj
==
null
)
obj
=
[];
if
(
nativeReduceRight
&&
obj
.
reduceRight
===
nativeReduceRight
)
{
iteratee
=
createCallback
(
iteratee
,
context
,
4
);
if
(
context
)
iterator
=
_
.
bind
(
iterator
,
context
);
var
keys
=
obj
.
length
!==
+
obj
.
length
&&
_
.
keys
(
obj
),
return
initial
?
obj
.
reduceRight
(
iterator
,
memo
)
:
obj
.
reduceRight
(
iterator
);
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
;
while
(
index
--
)
{
if
(
length
!==
+
length
)
{
currentKey
=
keys
?
keys
[
index
]
:
index
;
var
keys
=
_
.
keys
(
obj
);
memo
=
iteratee
(
memo
,
obj
[
currentKey
],
currentKey
,
obj
);
length
=
keys
.
length
;
}
}
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
memo
;
};
};
// Return the first value which passes a truth test. Aliased as `detect`.
// Return the first value which passes a truth test. Aliased as `detect`.
_
.
find
=
_
.
detect
=
function
(
obj
,
predicate
,
context
)
{
_
.
find
=
_
.
detect
=
function
(
obj
,
predicate
,
context
)
{
var
result
;
var
result
;
any
(
obj
,
function
(
value
,
index
,
list
)
{
predicate
=
_
.
iteratee
(
predicate
,
context
);
if
(
predicate
.
call
(
context
,
value
,
index
,
list
))
{
_
.
some
(
obj
,
function
(
value
,
index
,
list
)
{
if
(
predicate
(
value
,
index
,
list
))
{
result
=
value
;
result
=
value
;
return
true
;
return
true
;
}
}
...
@@ -165,61 +179,58 @@
...
@@ -165,61 +179,58 @@
};
};
// Return all the elements that pass a truth test.
// Return all the elements that pass a truth test.
// Delegates to **ECMAScript 5**'s native `filter` if available.
// Aliased as `select`.
// Aliased as `select`.
_
.
filter
=
_
.
select
=
function
(
obj
,
predicate
,
context
)
{
_
.
filter
=
_
.
select
=
function
(
obj
,
predicate
,
context
)
{
var
results
=
[];
var
results
=
[];
if
(
obj
==
null
)
return
results
;
if
(
obj
==
null
)
return
results
;
if
(
nativeFilter
&&
obj
.
filter
===
nativeFilter
)
return
obj
.
filter
(
predicate
,
context
);
predicate
=
_
.
iteratee
(
predicate
,
context
);
each
(
obj
,
function
(
value
,
index
,
list
)
{
_
.
each
(
obj
,
function
(
value
,
index
,
list
)
{
if
(
predicate
.
call
(
context
,
value
,
index
,
list
))
results
.
push
(
value
);
if
(
predicate
(
value
,
index
,
list
))
results
.
push
(
value
);
});
});
return
results
;
return
results
;
};
};
// Return all the elements for which a truth test fails.
// Return all the elements for which a truth test fails.
_
.
reject
=
function
(
obj
,
predicate
,
context
)
{
_
.
reject
=
function
(
obj
,
predicate
,
context
)
{
return
_
.
filter
(
obj
,
function
(
value
,
index
,
list
)
{
return
_
.
filter
(
obj
,
_
.
negate
(
_
.
iteratee
(
predicate
)),
context
);
return
!
predicate
.
call
(
context
,
value
,
index
,
list
);
},
context
);
};
};
// Determine whether all of the elements match a truth test.
// Determine whether all of the elements match a truth test.
// Delegates to **ECMAScript 5**'s native `every` if available.
// Aliased as `all`.
// Aliased as `all`.
_
.
every
=
_
.
all
=
function
(
obj
,
predicate
,
context
)
{
_
.
every
=
_
.
all
=
function
(
obj
,
predicate
,
context
)
{
predicate
||
(
predicate
=
_
.
identity
);
if
(
obj
==
null
)
return
true
;
var
result
=
true
;
predicate
=
_
.
iteratee
(
predicate
,
context
);
if
(
obj
==
null
)
return
result
;
var
keys
=
obj
.
length
!==
+
obj
.
length
&&
_
.
keys
(
obj
),
if
(
nativeEvery
&&
obj
.
every
===
nativeEvery
)
return
obj
.
every
(
predicate
,
context
);
length
=
(
keys
||
obj
).
length
,
each
(
obj
,
function
(
value
,
index
,
list
)
{
index
,
currentKey
;
if
(
!
(
result
=
result
&&
predicate
.
call
(
context
,
value
,
index
,
list
)))
return
breaker
;
for
(
index
=
0
;
index
<
length
;
index
++
)
{
});
currentKey
=
keys
?
keys
[
index
]
:
index
;
return
!!
result
;
if
(
!
predicate
(
obj
[
currentKey
],
currentKey
,
obj
))
return
false
;
}
return
true
;
};
};
// Determine if at least one element in the object matches a truth test.
// 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`.
// Aliased as `any`.
var
any
=
_
.
some
=
_
.
any
=
function
(
obj
,
predicate
,
context
)
{
_
.
some
=
_
.
any
=
function
(
obj
,
predicate
,
context
)
{
predicate
||
(
predicate
=
_
.
identity
);
if
(
obj
==
null
)
return
false
;
var
result
=
false
;
predicate
=
_
.
iteratee
(
predicate
,
context
);
if
(
obj
==
null
)
return
result
;
var
keys
=
obj
.
length
!==
+
obj
.
length
&&
_
.
keys
(
obj
),
if
(
nativeSome
&&
obj
.
some
===
nativeSome
)
return
obj
.
some
(
predicate
,
context
);
length
=
(
keys
||
obj
).
length
,
each
(
obj
,
function
(
value
,
index
,
list
)
{
index
,
currentKey
;
if
(
result
||
(
result
=
predicate
.
call
(
context
,
value
,
index
,
list
)))
return
breaker
;
for
(
index
=
0
;
index
<
length
;
index
++
)
{
});
currentKey
=
keys
?
keys
[
index
]
:
index
;
return
!!
result
;
if
(
predicate
(
obj
[
currentKey
],
currentKey
,
obj
))
return
true
;
}
return
false
;
};
};
// Determine if the array or object contains a given value (using `===`).
// Determine if the array or object contains a given value (using `===`).
// Aliased as `include`.
// Aliased as `include`.
_
.
contains
=
_
.
include
=
function
(
obj
,
target
)
{
_
.
contains
=
_
.
include
=
function
(
obj
,
target
)
{
if
(
obj
==
null
)
return
false
;
if
(
obj
==
null
)
return
false
;
if
(
nativeIndexOf
&&
obj
.
indexOf
===
nativeIndexOf
)
return
obj
.
indexOf
(
target
)
!=
-
1
;
if
(
obj
.
length
!==
+
obj
.
length
)
obj
=
_
.
values
(
obj
);
return
any
(
obj
,
function
(
value
)
{
return
_
.
indexOf
(
obj
,
target
)
>=
0
;
return
value
===
target
;
});
};
};
// Invoke a method (with arguments) on every item in a collection.
// Invoke a method (with arguments) on every item in a collection.
...
@@ -248,51 +259,67 @@
...
@@ -248,51 +259,67 @@
return
_
.
find
(
obj
,
_
.
matches
(
attrs
));
return
_
.
find
(
obj
,
_
.
matches
(
attrs
));
};
};
// Return the maximum element or (element-based computation).
// Return the maximum element (or element-based computation).
// Can't optimize arrays of integers longer than 65,535 elements.
_
.
max
=
function
(
obj
,
iteratee
,
context
)
{
// See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
var
result
=
-
Infinity
,
lastComputed
=
-
Infinity
,
_
.
max
=
function
(
obj
,
iterator
,
context
)
{
value
,
computed
;
if
(
!
iterator
&&
_
.
isArray
(
obj
)
&&
obj
[
0
]
===
+
obj
[
0
]
&&
obj
.
length
<
65535
)
{
if
(
iteratee
==
null
&&
obj
!=
null
)
{
return
Math
.
max
.
apply
(
Math
,
obj
);
obj
=
obj
.
length
===
+
obj
.
length
?
obj
:
_
.
values
(
obj
);
}
for
(
var
i
=
0
,
length
=
obj
.
length
;
i
<
length
;
i
++
)
{
var
result
=
-
Infinity
,
lastComputed
=
-
Infinity
;
value
=
obj
[
i
];
each
(
obj
,
function
(
value
,
index
,
list
)
{
if
(
value
>
result
)
{
var
computed
=
iterator
?
iterator
.
call
(
context
,
value
,
index
,
list
)
:
value
;
result
=
value
;
if
(
computed
>
lastComputed
)
{
}
result
=
value
;
lastComputed
=
computed
;
}
}
});
}
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
;
}
});
}
return
result
;
return
result
;
};
};
// Return the minimum element (or element-based computation).
// Return the minimum element (or element-based computation).
_
.
min
=
function
(
obj
,
iterat
or
,
context
)
{
_
.
min
=
function
(
obj
,
iterat
ee
,
context
)
{
if
(
!
iterator
&&
_
.
isArray
(
obj
)
&&
obj
[
0
]
===
+
obj
[
0
]
&&
obj
.
length
<
65535
)
{
var
result
=
Infinity
,
lastComputed
=
Infinity
,
return
Math
.
min
.
apply
(
Math
,
obj
)
;
value
,
computed
;
}
if
(
iteratee
==
null
&&
obj
!=
null
)
{
var
result
=
Infinity
,
lastComputed
=
Infinity
;
obj
=
obj
.
length
===
+
obj
.
length
?
obj
:
_
.
values
(
obj
)
;
each
(
obj
,
function
(
value
,
index
,
list
)
{
for
(
var
i
=
0
,
length
=
obj
.
length
;
i
<
length
;
i
++
)
{
var
computed
=
iterator
?
iterator
.
call
(
context
,
value
,
index
,
list
)
:
value
;
value
=
obj
[
i
]
;
if
(
computed
<
lastComputed
)
{
if
(
value
<
result
)
{
result
=
value
;
result
=
value
;
lastComputed
=
computed
;
}
}
}
});
}
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
;
}
});
}
return
result
;
return
result
;
};
};
// Shuffle a
n array
, using the modern version of the
// Shuffle a
collection
, using the modern version of the
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
// [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
_
.
shuffle
=
function
(
obj
)
{
_
.
shuffle
=
function
(
obj
)
{
var
rand
;
var
set
=
obj
&&
obj
.
length
===
+
obj
.
length
?
obj
:
_
.
values
(
obj
)
;
var
index
=
0
;
var
length
=
set
.
length
;
var
shuffled
=
[]
;
var
shuffled
=
Array
(
length
)
;
each
(
obj
,
function
(
value
)
{
for
(
var
index
=
0
,
rand
;
index
<
length
;
index
++
)
{
rand
=
_
.
random
(
index
++
);
rand
=
_
.
random
(
0
,
index
);
shuffled
[
index
-
1
]
=
shuffled
[
rand
];
if
(
rand
!==
index
)
shuffled
[
index
]
=
shuffled
[
rand
];
shuffled
[
rand
]
=
value
;
shuffled
[
rand
]
=
set
[
index
]
;
}
);
}
return
shuffled
;
return
shuffled
;
};
};
...
@@ -307,21 +334,14 @@
...
@@ -307,21 +334,14 @@
return
_
.
shuffle
(
obj
).
slice
(
0
,
Math
.
max
(
0
,
n
));
return
_
.
shuffle
(
obj
).
slice
(
0
,
Math
.
max
(
0
,
n
));
};
};
// An internal function to generate lookup iterators.
// Sort the object's values by a criterion produced by an iteratee.
var
lookupIterator
=
function
(
value
)
{
_
.
sortBy
=
function
(
obj
,
iteratee
,
context
)
{
if
(
value
==
null
)
return
_
.
identity
;
iteratee
=
_
.
iteratee
(
iteratee
,
context
);
if
(
_
.
isFunction
(
value
))
return
value
;
return
_
.
property
(
value
);
};
// Sort the object's values by a criterion produced by an iterator.
_
.
sortBy
=
function
(
obj
,
iterator
,
context
)
{
iterator
=
lookupIterator
(
iterator
);
return
_
.
pluck
(
_
.
map
(
obj
,
function
(
value
,
index
,
list
)
{
return
_
.
pluck
(
_
.
map
(
obj
,
function
(
value
,
index
,
list
)
{
return
{
return
{
value
:
value
,
value
:
value
,
index
:
index
,
index
:
index
,
criteria
:
iterat
or
.
call
(
context
,
value
,
index
,
list
)
criteria
:
iterat
ee
(
value
,
index
,
list
)
};
};
}).
sort
(
function
(
left
,
right
)
{
}).
sort
(
function
(
left
,
right
)
{
var
a
=
left
.
criteria
;
var
a
=
left
.
criteria
;
...
@@ -336,12 +356,12 @@
...
@@ -336,12 +356,12 @@
// An internal function used for aggregate "group by" operations.
// An internal function used for aggregate "group by" operations.
var
group
=
function
(
behavior
)
{
var
group
=
function
(
behavior
)
{
return
function
(
obj
,
iterat
or
,
context
)
{
return
function
(
obj
,
iterat
ee
,
context
)
{
var
result
=
{};
var
result
=
{};
iterat
or
=
lookupIterator
(
iterator
);
iterat
ee
=
_
.
iteratee
(
iteratee
,
context
);
each
(
obj
,
function
(
value
,
index
)
{
_
.
each
(
obj
,
function
(
value
,
index
)
{
var
key
=
iterat
or
.
call
(
context
,
value
,
index
,
obj
);
var
key
=
iterat
ee
(
value
,
index
,
obj
);
behavior
(
result
,
key
,
value
);
behavior
(
result
,
value
,
key
);
});
});
return
result
;
return
result
;
};
};
...
@@ -349,32 +369,32 @@
...
@@ -349,32 +369,32 @@
// Groups the object's values by a criterion. Pass either a string attribute
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
// to group by, or a function that returns the criterion.
_
.
groupBy
=
group
(
function
(
result
,
key
,
value
)
{
_
.
groupBy
=
group
(
function
(
result
,
value
,
key
)
{
_
.
has
(
result
,
key
)
?
result
[
key
].
push
(
value
)
:
result
[
key
]
=
[
value
];
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
// Indexes the object's values by a criterion, similar to `groupBy`, but for
// when you know that your index values will be unique.
// when you know that your index values will be unique.
_
.
indexBy
=
group
(
function
(
result
,
key
,
value
)
{
_
.
indexBy
=
group
(
function
(
result
,
value
,
key
)
{
result
[
key
]
=
value
;
result
[
key
]
=
value
;
});
});
// Counts instances of an object that group by a certain criterion. Pass
// 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
// either a string attribute to count by, or a function that returns the
// criterion.
// criterion.
_
.
countBy
=
group
(
function
(
result
,
key
)
{
_
.
countBy
=
group
(
function
(
result
,
value
,
key
)
{
_
.
has
(
result
,
key
)
?
result
[
key
]
++
:
result
[
key
]
=
1
;
if
(
_
.
has
(
result
,
key
))
result
[
key
]
++
;
else
result
[
key
]
=
1
;
});
});
// Use a comparator function to figure out the smallest index at which
// 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.
// an object should be inserted so as to maintain order. Uses binary search.
_
.
sortedIndex
=
function
(
array
,
obj
,
iterat
or
,
context
)
{
_
.
sortedIndex
=
function
(
array
,
obj
,
iterat
ee
,
context
)
{
iterat
or
=
lookupIterator
(
iterator
);
iterat
ee
=
_
.
iteratee
(
iteratee
,
context
,
1
);
var
value
=
iterat
or
.
call
(
context
,
obj
);
var
value
=
iterat
ee
(
obj
);
var
low
=
0
,
high
=
array
.
length
;
var
low
=
0
,
high
=
array
.
length
;
while
(
low
<
high
)
{
while
(
low
<
high
)
{
var
mid
=
(
low
+
high
)
>>>
1
;
var
mid
=
low
+
high
>>>
1
;
i
terator
.
call
(
context
,
array
[
mid
])
<
value
?
low
=
mid
+
1
:
high
=
mid
;
i
f
(
iteratee
(
array
[
mid
])
<
value
)
low
=
mid
+
1
;
else
high
=
mid
;
}
}
return
low
;
return
low
;
};
};
...
@@ -390,7 +410,18 @@
...
@@ -390,7 +410,18 @@
// Return the number of elements in an object.
// Return the number of elements in an object.
_
.
size
=
function
(
obj
)
{
_
.
size
=
function
(
obj
)
{
if
(
obj
==
null
)
return
0
;
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
// Array Functions
...
@@ -401,7 +432,7 @@
...
@@ -401,7 +432,7 @@
// allows it to work with `_.map`.
// allows it to work with `_.map`.
_
.
first
=
_
.
head
=
_
.
take
=
function
(
array
,
n
,
guard
)
{
_
.
first
=
_
.
head
=
_
.
take
=
function
(
array
,
n
,
guard
)
{
if
(
array
==
null
)
return
void
0
;
if
(
array
==
null
)
return
void
0
;
if
(
(
n
==
null
)
||
guard
)
return
array
[
0
];
if
(
n
==
null
||
guard
)
return
array
[
0
];
if
(
n
<
0
)
return
[];
if
(
n
<
0
)
return
[];
return
slice
.
call
(
array
,
0
,
n
);
return
slice
.
call
(
array
,
0
,
n
);
};
};
...
@@ -411,14 +442,14 @@
...
@@ -411,14 +442,14 @@
// the array, excluding the last N. The **guard** check allows it to work with
// the array, excluding the last N. The **guard** check allows it to work with
// `_.map`.
// `_.map`.
_
.
initial
=
function
(
array
,
n
,
guard
)
{
_
.
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
// 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`.
// values in the array. The **guard** check allows it to work with `_.map`.
_
.
last
=
function
(
array
,
n
,
guard
)
{
_
.
last
=
function
(
array
,
n
,
guard
)
{
if
(
array
==
null
)
return
void
0
;
if
(
array
==
null
)
return
void
0
;
if
(
(
n
==
null
)
||
guard
)
return
array
[
array
.
length
-
1
];
if
(
n
==
null
||
guard
)
return
array
[
array
.
length
-
1
];
return
slice
.
call
(
array
,
Math
.
max
(
array
.
length
-
n
,
0
));
return
slice
.
call
(
array
,
Math
.
max
(
array
.
length
-
n
,
0
));
};
};
...
@@ -427,7 +458,7 @@
...
@@ -427,7 +458,7 @@
// the rest N values in the array. The **guard**
// the rest N values in the array. The **guard**
// check allows it to work with `_.map`.
// check allows it to work with `_.map`.
_
.
rest
=
_
.
tail
=
_
.
drop
=
function
(
array
,
n
,
guard
)
{
_
.
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.
// Trim out all falsy values from an array.
...
@@ -436,23 +467,26 @@
...
@@ -436,23 +467,26 @@
};
};
// Internal implementation of a recursive `flatten` function.
// Internal implementation of a recursive `flatten` function.
var
flatten
=
function
(
input
,
shallow
,
output
)
{
var
flatten
=
function
(
input
,
shallow
,
strict
,
output
)
{
if
(
shallow
&&
_
.
every
(
input
,
_
.
isArray
))
{
if
(
shallow
&&
_
.
every
(
input
,
_
.
isArray
))
{
return
concat
.
apply
(
output
,
input
);
return
concat
.
apply
(
output
,
input
);
}
}
each
(
input
,
function
(
value
)
{
for
(
var
i
=
0
,
length
=
input
.
length
;
i
<
length
;
i
++
)
{
if
(
_
.
isArray
(
value
)
||
_
.
isArguments
(
value
))
{
var
value
=
input
[
i
];
shallow
?
push
.
apply
(
output
,
value
)
:
flatten
(
value
,
shallow
,
output
);
if
(
!
_
.
isArray
(
value
)
&&
!
_
.
isArguments
(
value
))
{
if
(
!
strict
)
output
.
push
(
value
);
}
else
if
(
shallow
)
{
push
.
apply
(
output
,
value
);
}
else
{
}
else
{
output
.
push
(
value
);
flatten
(
value
,
shallow
,
strict
,
output
);
}
}
}
);
}
return
output
;
return
output
;
};
};
// Flatten out an array, either recursively (by default), or just one level.
// Flatten out an array, either recursively (by default), or just one level.
_
.
flatten
=
function
(
array
,
shallow
)
{
_
.
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).
// Return a version of the array that does not contain the specified value(s).
...
@@ -460,68 +494,77 @@
...
@@ -460,68 +494,77 @@
return
_
.
difference
(
array
,
slice
.
call
(
arguments
,
1
));
return
_
.
difference
(
array
,
slice
.
call
(
arguments
,
1
));
};
};
// Split an array into two arrays: one whose elements all satisfy the given
// predicate, and one whose elements all do not satisfy the predicate.
_
.
partition
=
function
(
array
,
predicate
)
{
var
pass
=
[],
fail
=
[];
each
(
array
,
function
(
elem
)
{
(
predicate
(
elem
)
?
pass
:
fail
).
push
(
elem
);
});
return
[
pass
,
fail
];
};
// Produce a duplicate-free version of the array. If the array has already
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
// Aliased as `unique`.
_
.
uniq
=
_
.
unique
=
function
(
array
,
isSorted
,
iterator
,
context
)
{
_
.
uniq
=
_
.
unique
=
function
(
array
,
isSorted
,
iteratee
,
context
)
{
if
(
_
.
isFunction
(
isSorted
))
{
if
(
array
==
null
)
return
[];
context
=
iterator
;
if
(
!
_
.
isBoolean
(
isSorted
))
{
iterator
=
isSorted
;
context
=
iteratee
;
iteratee
=
isSorted
;
isSorted
=
false
;
isSorted
=
false
;
}
}
var
initial
=
iterator
?
_
.
map
(
array
,
iterator
,
context
)
:
array
;
if
(
iteratee
!=
null
)
iteratee
=
_
.
iteratee
(
iteratee
,
context
)
;
var
result
s
=
[];
var
result
=
[];
var
seen
=
[];
var
seen
=
[];
each
(
initial
,
function
(
value
,
index
)
{
for
(
var
i
=
0
,
length
=
array
.
length
;
i
<
length
;
i
++
)
{
if
(
isSorted
?
(
!
index
||
seen
[
seen
.
length
-
1
]
!==
value
)
:
!
_
.
contains
(
seen
,
value
))
{
var
value
=
array
[
i
];
seen
.
push
(
value
);
if
(
isSorted
)
{
results
.
push
(
array
[
index
]);
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
result
s
;
return
result
;
};
};
// Produce an array that contains the union: each distinct element from all of
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
// the passed-in arrays.
_
.
union
=
function
()
{
_
.
union
=
function
()
{
return
_
.
uniq
(
_
.
flatten
(
arguments
,
true
));
return
_
.
uniq
(
flatten
(
arguments
,
true
,
true
,
[]
));
};
};
// Produce an array that contains every item shared between all the
// Produce an array that contains every item shared between all the
// passed-in arrays.
// passed-in arrays.
_
.
intersection
=
function
(
array
)
{
_
.
intersection
=
function
(
array
)
{
var
rest
=
slice
.
call
(
arguments
,
1
);
if
(
array
==
null
)
return
[];
return
_
.
filter
(
_
.
uniq
(
array
),
function
(
item
)
{
var
result
=
[];
return
_
.
every
(
rest
,
function
(
other
)
{
var
argsLength
=
arguments
.
length
;
return
_
.
contains
(
other
,
item
);
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.
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
// Only the elements present in just the first array will remain.
_
.
difference
=
function
(
array
)
{
_
.
difference
=
function
(
array
)
{
var
rest
=
concat
.
apply
(
ArrayProto
,
slice
.
call
(
arguments
,
1
));
var
rest
=
flatten
(
slice
.
call
(
arguments
,
1
),
true
,
true
,
[]);
return
_
.
filter
(
array
,
function
(
value
){
return
!
_
.
contains
(
rest
,
value
);
});
return
_
.
filter
(
array
,
function
(
value
){
return
!
_
.
contains
(
rest
,
value
);
});
};
};
// Zip together multiple lists into a single array -- elements that share
// Zip together multiple lists into a single array -- elements that share
// an index go together.
// an index go together.
_
.
zip
=
function
()
{
_
.
zip
=
function
(
array
)
{
var
length
=
_
.
max
(
_
.
pluck
(
arguments
,
'
length
'
).
concat
(
0
));
if
(
array
==
null
)
return
[];
var
results
=
new
Array
(
length
);
var
length
=
_
.
max
(
arguments
,
'
length
'
).
length
;
var
results
=
Array
(
length
);
for
(
var
i
=
0
;
i
<
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
length
;
i
++
)
{
results
[
i
]
=
_
.
pluck
(
arguments
,
''
+
i
);
results
[
i
]
=
_
.
pluck
(
arguments
,
i
);
}
}
return
results
;
return
results
;
};
};
...
@@ -542,10 +585,8 @@
...
@@ -542,10 +585,8 @@
return
result
;
return
result
;
};
};
// If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
// Return the position of the first occurrence of an item in an array,
// we need this function. Return the position of the first occurrence of an
// or -1 if the item is not included in the array.
// item in an array, or -1 if the item is not included in the array.
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
// If the array is large and already in sort order, pass `true`
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
// for **isSorted** to use binary search.
_
.
indexOf
=
function
(
array
,
item
,
isSorted
)
{
_
.
indexOf
=
function
(
array
,
item
,
isSorted
)
{
...
@@ -553,26 +594,23 @@
...
@@ -553,26 +594,23 @@
var
i
=
0
,
length
=
array
.
length
;
var
i
=
0
,
length
=
array
.
length
;
if
(
isSorted
)
{
if
(
isSorted
)
{
if
(
typeof
isSorted
==
'
number
'
)
{
if
(
typeof
isSorted
==
'
number
'
)
{
i
=
(
isSorted
<
0
?
Math
.
max
(
0
,
length
+
isSorted
)
:
isSorted
)
;
i
=
isSorted
<
0
?
Math
.
max
(
0
,
length
+
isSorted
)
:
isSorted
;
}
else
{
}
else
{
i
=
_
.
sortedIndex
(
array
,
item
);
i
=
_
.
sortedIndex
(
array
,
item
);
return
array
[
i
]
===
item
?
i
:
-
1
;
return
array
[
i
]
===
item
?
i
:
-
1
;
}
}
}
}
if
(
nativeIndexOf
&&
array
.
indexOf
===
nativeIndexOf
)
return
array
.
indexOf
(
item
,
isSorted
);
for
(;
i
<
length
;
i
++
)
if
(
array
[
i
]
===
item
)
return
i
;
for
(;
i
<
length
;
i
++
)
if
(
array
[
i
]
===
item
)
return
i
;
return
-
1
;
return
-
1
;
};
};
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
_
.
lastIndexOf
=
function
(
array
,
item
,
from
)
{
_
.
lastIndexOf
=
function
(
array
,
item
,
from
)
{
if
(
array
==
null
)
return
-
1
;
if
(
array
==
null
)
return
-
1
;
var
hasIndex
=
from
!=
null
;
var
idx
=
array
.
length
;
if
(
nativeLastIndexOf
&&
array
.
lastIndexOf
===
nativeLastIndexOf
)
{
if
(
typeof
from
==
'
number
'
)
{
return
hasIndex
?
array
.
lastIndexOf
(
item
,
from
)
:
array
.
lastIndexOf
(
item
);
idx
=
from
<
0
?
idx
+
from
+
1
:
Math
.
min
(
idx
,
from
+
1
);
}
}
var
i
=
(
hasIndex
?
from
:
array
.
length
);
while
(
--
idx
>=
0
)
if
(
array
[
idx
]
===
item
)
return
idx
;
while
(
i
--
)
if
(
array
[
i
]
===
item
)
return
i
;
return
-
1
;
return
-
1
;
};
};
...
@@ -584,15 +622,13 @@
...
@@ -584,15 +622,13 @@
stop
=
start
||
0
;
stop
=
start
||
0
;
start
=
0
;
start
=
0
;
}
}
step
=
arguments
[
2
]
||
1
;
step
=
step
||
1
;
var
length
=
Math
.
max
(
Math
.
ceil
((
stop
-
start
)
/
step
),
0
);
var
length
=
Math
.
max
(
Math
.
ceil
((
stop
-
start
)
/
step
),
0
);
var
idx
=
0
;
var
range
=
Array
(
length
);
var
range
=
new
Array
(
length
);
while
(
idx
<
length
)
{
for
(
var
idx
=
0
;
idx
<
length
;
idx
++
,
start
+=
step
)
{
range
[
idx
++
]
=
start
;
range
[
idx
]
=
start
;
start
+=
step
;
}
}
return
range
;
return
range
;
...
@@ -602,7 +638,7 @@
...
@@ -602,7 +638,7 @@
// ------------------
// ------------------
// Reusable constructor function for prototype setting.
// Reusable constructor function for prototype setting.
var
c
tor
=
function
(){};
var
C
tor
=
function
(){};
// Create a function bound to a given object (assigning `this`, and arguments,
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
...
@@ -610,17 +646,18 @@
...
@@ -610,17 +646,18 @@
_
.
bind
=
function
(
func
,
context
)
{
_
.
bind
=
function
(
func
,
context
)
{
var
args
,
bound
;
var
args
,
bound
;
if
(
nativeBind
&&
func
.
bind
===
nativeBind
)
return
nativeBind
.
apply
(
func
,
slice
.
call
(
arguments
,
1
));
if
(
nativeBind
&&
func
.
bind
===
nativeBind
)
return
nativeBind
.
apply
(
func
,
slice
.
call
(
arguments
,
1
));
if
(
!
_
.
isFunction
(
func
))
throw
new
TypeError
;
if
(
!
_
.
isFunction
(
func
))
throw
new
TypeError
(
'
Bind must be called on a function
'
)
;
args
=
slice
.
call
(
arguments
,
2
);
args
=
slice
.
call
(
arguments
,
2
);
return
bound
=
function
()
{
bound
=
function
()
{
if
(
!
(
this
instanceof
bound
))
return
func
.
apply
(
context
,
args
.
concat
(
slice
.
call
(
arguments
)));
if
(
!
(
this
instanceof
bound
))
return
func
.
apply
(
context
,
args
.
concat
(
slice
.
call
(
arguments
)));
c
tor
.
prototype
=
func
.
prototype
;
C
tor
.
prototype
=
func
.
prototype
;
var
self
=
new
c
tor
;
var
self
=
new
C
tor
;
c
tor
.
prototype
=
null
;
C
tor
.
prototype
=
null
;
var
result
=
func
.
apply
(
self
,
args
.
concat
(
slice
.
call
(
arguments
)));
var
result
=
func
.
apply
(
self
,
args
.
concat
(
slice
.
call
(
arguments
)));
if
(
Object
(
result
)
===
result
)
return
result
;
if
(
_
.
isObject
(
result
)
)
return
result
;
return
self
;
return
self
;
};
};
return
bound
;
};
};
// Partially apply a function by creating a version that has had some of its
// Partially apply a function by creating a version that has had some of its
...
@@ -643,27 +680,34 @@
...
@@ -643,27 +680,34 @@
// are the method names to be bound. Useful for ensuring that all callbacks
// are the method names to be bound. Useful for ensuring that all callbacks
// defined on an object belong to it.
// defined on an object belong to it.
_
.
bindAll
=
function
(
obj
)
{
_
.
bindAll
=
function
(
obj
)
{
var
funcs
=
slice
.
call
(
arguments
,
1
);
var
i
,
length
=
arguments
.
length
,
key
;
if
(
funcs
.
length
===
0
)
throw
new
Error
(
'
bindAll must be passed function names
'
);
if
(
length
<=
1
)
throw
new
Error
(
'
bindAll must be passed function names
'
);
each
(
funcs
,
function
(
f
)
{
obj
[
f
]
=
_
.
bind
(
obj
[
f
],
obj
);
});
for
(
i
=
1
;
i
<
length
;
i
++
)
{
key
=
arguments
[
i
];
obj
[
key
]
=
_
.
bind
(
obj
[
key
],
obj
);
}
return
obj
;
return
obj
;
};
};
// Memoize an expensive function by storing its results.
// Memoize an expensive function by storing its results.
_
.
memoize
=
function
(
func
,
hasher
)
{
_
.
memoize
=
function
(
func
,
hasher
)
{
var
memo
=
{};
var
memo
ize
=
function
(
key
)
{
hasher
||
(
hasher
=
_
.
identity
)
;
var
cache
=
memoize
.
cache
;
return
function
()
{
var
address
=
hasher
?
hasher
.
apply
(
this
,
arguments
)
:
key
;
var
key
=
hasher
.
apply
(
this
,
arguments
);
if
(
!
_
.
has
(
cache
,
address
))
cache
[
address
]
=
func
.
apply
(
this
,
arguments
);
return
_
.
has
(
memo
,
key
)
?
memo
[
key
]
:
(
memo
[
key
]
=
func
.
apply
(
this
,
arguments
))
;
return
cache
[
address
]
;
};
};
memoize
.
cache
=
{};
return
memoize
;
};
};
// Delays a function for the given number of milliseconds, and then calls
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
// it with the arguments supplied.
_
.
delay
=
function
(
func
,
wait
)
{
_
.
delay
=
function
(
func
,
wait
)
{
var
args
=
slice
.
call
(
arguments
,
2
);
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
// Defers a function, scheduling it to run after the current call stack has
...
@@ -681,12 +725,12 @@
...
@@ -681,12 +725,12 @@
var
context
,
args
,
result
;
var
context
,
args
,
result
;
var
timeout
=
null
;
var
timeout
=
null
;
var
previous
=
0
;
var
previous
=
0
;
options
||
(
options
=
{})
;
if
(
!
options
)
options
=
{}
;
var
later
=
function
()
{
var
later
=
function
()
{
previous
=
options
.
leading
===
false
?
0
:
_
.
now
();
previous
=
options
.
leading
===
false
?
0
:
_
.
now
();
timeout
=
null
;
timeout
=
null
;
result
=
func
.
apply
(
context
,
args
);
result
=
func
.
apply
(
context
,
args
);
context
=
args
=
null
;
if
(
!
timeout
)
context
=
args
=
null
;
};
};
return
function
()
{
return
function
()
{
var
now
=
_
.
now
();
var
now
=
_
.
now
();
...
@@ -694,12 +738,12 @@
...
@@ -694,12 +738,12 @@
var
remaining
=
wait
-
(
now
-
previous
);
var
remaining
=
wait
-
(
now
-
previous
);
context
=
this
;
context
=
this
;
args
=
arguments
;
args
=
arguments
;
if
(
remaining
<=
0
)
{
if
(
remaining
<=
0
||
remaining
>
wait
)
{
clearTimeout
(
timeout
);
clearTimeout
(
timeout
);
timeout
=
null
;
timeout
=
null
;
previous
=
now
;
previous
=
now
;
result
=
func
.
apply
(
context
,
args
);
result
=
func
.
apply
(
context
,
args
);
context
=
args
=
null
;
if
(
!
timeout
)
context
=
args
=
null
;
}
else
if
(
!
timeout
&&
options
.
trailing
!==
false
)
{
}
else
if
(
!
timeout
&&
options
.
trailing
!==
false
)
{
timeout
=
setTimeout
(
later
,
remaining
);
timeout
=
setTimeout
(
later
,
remaining
);
}
}
...
@@ -716,13 +760,14 @@
...
@@ -716,13 +760,14 @@
var
later
=
function
()
{
var
later
=
function
()
{
var
last
=
_
.
now
()
-
timestamp
;
var
last
=
_
.
now
()
-
timestamp
;
if
(
last
<
wait
)
{
if
(
last
<
wait
&&
last
>
0
)
{
timeout
=
setTimeout
(
later
,
wait
-
last
);
timeout
=
setTimeout
(
later
,
wait
-
last
);
}
else
{
}
else
{
timeout
=
null
;
timeout
=
null
;
if
(
!
immediate
)
{
if
(
!
immediate
)
{
result
=
func
.
apply
(
context
,
args
);
result
=
func
.
apply
(
context
,
args
);
context
=
args
=
null
;
if
(
!
timeout
)
context
=
args
=
null
;
}
}
}
}
};
};
...
@@ -732,9 +777,7 @@
...
@@ -732,9 +777,7 @@
args
=
arguments
;
args
=
arguments
;
timestamp
=
_
.
now
();
timestamp
=
_
.
now
();
var
callNow
=
immediate
&&
!
timeout
;
var
callNow
=
immediate
&&
!
timeout
;
if
(
!
timeout
)
{
if
(
!
timeout
)
timeout
=
setTimeout
(
later
,
wait
);
timeout
=
setTimeout
(
later
,
wait
);
}
if
(
callNow
)
{
if
(
callNow
)
{
result
=
func
.
apply
(
context
,
args
);
result
=
func
.
apply
(
context
,
args
);
context
=
args
=
null
;
context
=
args
=
null
;
...
@@ -744,19 +787,6 @@
...
@@ -744,19 +787,6 @@
};
};
};
};
// 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,
// Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
// conditionally execute the original function.
...
@@ -764,16 +794,23 @@
...
@@ -764,16 +794,23 @@
return
_
.
partial
(
wrapper
,
func
);
return
_
.
partial
(
wrapper
,
func
);
};
};
// Returns a negated version of the passed-in predicate.
_
.
negate
=
function
(
predicate
)
{
return
function
()
{
return
!
predicate
.
apply
(
this
,
arguments
);
};
};
// Returns a function that is the composition of a list of functions, each
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
// consuming the return value of the function that follows.
_
.
compose
=
function
()
{
_
.
compose
=
function
()
{
var
funcs
=
arguments
;
var
args
=
arguments
;
var
start
=
args
.
length
-
1
;
return
function
()
{
return
function
()
{
var
args
=
arguments
;
var
i
=
start
;
for
(
var
i
=
funcs
.
length
-
1
;
i
>=
0
;
i
--
)
{
var
result
=
args
[
start
].
apply
(
this
,
arguments
);
args
=
[
funcs
[
i
].
apply
(
this
,
args
)];
while
(
i
--
)
result
=
args
[
i
].
call
(
this
,
result
);
}
return
result
;
return
args
[
0
];
};
};
};
};
...
@@ -786,6 +823,23 @@
...
@@ -786,6 +823,23 @@
};
};
};
};
// 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
// Object Functions
// ----------------
// ----------------
...
@@ -803,7 +857,7 @@
...
@@ -803,7 +857,7 @@
_
.
values
=
function
(
obj
)
{
_
.
values
=
function
(
obj
)
{
var
keys
=
_
.
keys
(
obj
);
var
keys
=
_
.
keys
(
obj
);
var
length
=
keys
.
length
;
var
length
=
keys
.
length
;
var
values
=
new
Array
(
length
);
var
values
=
Array
(
length
);
for
(
var
i
=
0
;
i
<
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
length
;
i
++
)
{
values
[
i
]
=
obj
[
keys
[
i
]];
values
[
i
]
=
obj
[
keys
[
i
]];
}
}
...
@@ -814,7 +868,7 @@
...
@@ -814,7 +868,7 @@
_
.
pairs
=
function
(
obj
)
{
_
.
pairs
=
function
(
obj
)
{
var
keys
=
_
.
keys
(
obj
);
var
keys
=
_
.
keys
(
obj
);
var
length
=
keys
.
length
;
var
length
=
keys
.
length
;
var
pairs
=
new
Array
(
length
);
var
pairs
=
Array
(
length
);
for
(
var
i
=
0
;
i
<
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
length
;
i
++
)
{
pairs
[
i
]
=
[
keys
[
i
],
obj
[
keys
[
i
]]];
pairs
[
i
]
=
[
keys
[
i
],
obj
[
keys
[
i
]]];
}
}
...
@@ -843,45 +897,62 @@
...
@@ -843,45 +897,62 @@
// Extend a given object with all the properties in passed-in object(s).
// Extend a given object with all the properties in passed-in object(s).
_
.
extend
=
function
(
obj
)
{
_
.
extend
=
function
(
obj
)
{
each
(
slice
.
call
(
arguments
,
1
),
function
(
source
)
{
if
(
!
_
.
isObject
(
obj
))
return
obj
;
if
(
source
)
{
var
source
,
prop
;
for
(
var
prop
in
source
)
{
for
(
var
i
=
1
,
length
=
arguments
.
length
;
i
<
length
;
i
++
)
{
obj
[
prop
]
=
source
[
prop
];
source
=
arguments
[
i
];
for
(
prop
in
source
)
{
if
(
hasOwnProperty
.
call
(
source
,
prop
))
{
obj
[
prop
]
=
source
[
prop
];
}
}
}
}
}
);
}
return
obj
;
return
obj
;
};
};
// Return a copy of the object only containing the whitelisted properties.
// Return a copy of the object only containing the whitelisted properties.
_
.
pick
=
function
(
obj
)
{
_
.
pick
=
function
(
obj
,
iteratee
,
context
)
{
var
copy
=
{};
var
result
=
{},
key
;
var
keys
=
concat
.
apply
(
ArrayProto
,
slice
.
call
(
arguments
,
1
));
if
(
obj
==
null
)
return
result
;
each
(
keys
,
function
(
key
)
{
if
(
_
.
isFunction
(
iteratee
))
{
if
(
key
in
obj
)
copy
[
key
]
=
obj
[
key
];
iteratee
=
createCallback
(
iteratee
,
context
);
});
for
(
key
in
obj
)
{
return
copy
;
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.
// Return a copy of the object without the blacklisted properties.
_
.
omit
=
function
(
obj
)
{
_
.
omit
=
function
(
obj
,
iteratee
,
context
)
{
var
copy
=
{};
if
(
_
.
isFunction
(
iteratee
))
{
var
keys
=
concat
.
apply
(
ArrayProto
,
slice
.
call
(
arguments
,
1
));
iteratee
=
_
.
negate
(
iteratee
);
for
(
var
key
in
obj
)
{
}
else
{
if
(
!
_
.
contains
(
keys
,
key
))
copy
[
key
]
=
obj
[
key
];
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.
// Fill in a given object with default properties.
_
.
defaults
=
function
(
obj
)
{
_
.
defaults
=
function
(
obj
)
{
each
(
slice
.
call
(
arguments
,
1
),
function
(
source
)
{
if
(
!
_
.
isObject
(
obj
))
return
obj
;
if
(
source
)
{
for
(
var
i
=
1
,
length
=
arguments
.
length
;
i
<
length
;
i
++
)
{
for
(
var
prop
in
source
)
{
var
source
=
arguments
[
i
];
if
(
obj
[
prop
]
===
void
0
)
obj
[
prop
]
=
source
[
prop
];
for
(
var
prop
in
source
)
{
}
if
(
obj
[
prop
]
===
void
0
)
obj
[
prop
]
=
source
[
prop
];
}
}
}
);
}
return
obj
;
return
obj
;
};
};
...
@@ -903,7 +974,7 @@
...
@@ -903,7 +974,7 @@
var
eq
=
function
(
a
,
b
,
aStack
,
bStack
)
{
var
eq
=
function
(
a
,
b
,
aStack
,
bStack
)
{
// Identical objects are equal. `0 === -0`, but they aren't identical.
// 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).
// See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
if
(
a
===
b
)
return
a
!==
0
||
1
/
a
==
1
/
b
;
if
(
a
===
b
)
return
a
!==
0
||
1
/
a
==
=
1
/
b
;
// A strict comparison is necessary because `null == undefined`.
// A strict comparison is necessary because `null == undefined`.
if
(
a
==
null
||
b
==
null
)
return
a
===
b
;
if
(
a
==
null
||
b
==
null
)
return
a
===
b
;
// Unwrap any wrapped objects.
// Unwrap any wrapped objects.
...
@@ -911,29 +982,27 @@
...
@@ -911,29 +982,27 @@
if
(
b
instanceof
_
)
b
=
b
.
_wrapped
;
if
(
b
instanceof
_
)
b
=
b
.
_wrapped
;
// Compare `[[Class]]` names.
// Compare `[[Class]]` names.
var
className
=
toString
.
call
(
a
);
var
className
=
toString
.
call
(
a
);
if
(
className
!=
toString
.
call
(
b
))
return
false
;
if
(
className
!=
=
toString
.
call
(
b
))
return
false
;
switch
(
className
)
{
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]
'
:
case
'
[object String]
'
:
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
// equivalent to `new String("5")`.
return
a
==
String
(
b
)
;
return
''
+
a
===
''
+
b
;
case
'
[object Number]
'
:
case
'
[object Number]
'
:
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
// `NaN`s are equivalent, but non-reflexive.
// other numeric values.
// Object(NaN) is equivalent to NaN
return
a
!=
+
a
?
b
!=
+
b
:
(
a
==
0
?
1
/
a
==
1
/
b
:
a
==
+
b
);
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 Date]
'
:
case
'
[object Boolean]
'
:
case
'
[object Boolean]
'
:
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
// of `NaN` are not equivalent.
return
+
a
==
+
b
;
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
;
}
}
if
(
typeof
a
!=
'
object
'
||
typeof
b
!=
'
object
'
)
return
false
;
if
(
typeof
a
!=
'
object
'
||
typeof
b
!=
'
object
'
)
return
false
;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// Assume equality for cyclic structures. The algorithm for detecting cyclic
...
@@ -942,25 +1011,29 @@
...
@@ -942,25 +1011,29 @@
while
(
length
--
)
{
while
(
length
--
)
{
// Linear search. Performance is inversely proportional to the number of
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
// 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
// Objects with different constructors are not equivalent, but `Object`s
// from different frames are.
// from different frames are.
var
aCtor
=
a
.
constructor
,
bCtor
=
b
.
constructor
;
var
aCtor
=
a
.
constructor
,
bCtor
=
b
.
constructor
;
if
(
aCtor
!==
bCtor
&&
!
(
_
.
isFunction
(
aCtor
)
&&
(
aCtor
instanceof
aCtor
)
&&
if
(
_
.
isFunction
(
bCtor
)
&&
(
bCtor
instanceof
bCtor
))
aCtor
!==
bCtor
&&
&&
(
'
constructor
'
in
a
&&
'
constructor
'
in
b
))
{
// Handle Object.create(x) cases
'
constructor
'
in
a
&&
'
constructor
'
in
b
&&
!
(
_
.
isFunction
(
aCtor
)
&&
aCtor
instanceof
aCtor
&&
_
.
isFunction
(
bCtor
)
&&
bCtor
instanceof
bCtor
)
)
{
return
false
;
return
false
;
}
}
// Add the first object to the stack of traversed objects.
// Add the first object to the stack of traversed objects.
aStack
.
push
(
a
);
aStack
.
push
(
a
);
bStack
.
push
(
b
);
bStack
.
push
(
b
);
var
size
=
0
,
result
=
true
;
var
size
,
result
;
// Recursively compare objects and arrays.
// Recursively compare objects and arrays.
if
(
className
==
'
[object Array]
'
)
{
if
(
className
==
=
'
[object Array]
'
)
{
// Compare array lengths to determine if a deep comparison is necessary.
// Compare array lengths to determine if a deep comparison is necessary.
size
=
a
.
length
;
size
=
a
.
length
;
result
=
size
==
b
.
length
;
result
=
size
==
=
b
.
length
;
if
(
result
)
{
if
(
result
)
{
// Deep compare the contents, ignoring non-numeric properties.
// Deep compare the contents, ignoring non-numeric properties.
while
(
size
--
)
{
while
(
size
--
)
{
...
@@ -969,20 +1042,16 @@
...
@@ -969,20 +1042,16 @@
}
}
}
else
{
}
else
{
// Deep compare objects.
// Deep compare objects.
for
(
var
key
in
a
)
{
var
keys
=
_
.
keys
(
a
),
key
;
if
(
_
.
has
(
a
,
key
))
{
size
=
keys
.
length
;
// Count the expected number of properties.
// Ensure that both objects contain the same number of properties before comparing deep equality.
size
++
;
result
=
_
.
keys
(
b
).
length
===
size
;
// Deep compare each member.
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
)
{
if
(
result
)
{
for
(
key
in
b
)
{
while
(
size
--
)
{
if
(
_
.
has
(
b
,
key
)
&&
!
(
size
--
))
break
;
// Deep compare each member
key
=
keys
[
size
];
if
(
!
(
result
=
_
.
has
(
b
,
key
)
&&
eq
(
a
[
key
],
b
[
key
],
aStack
,
bStack
)))
break
;
}
}
result
=
!
size
;
}
}
}
}
// Remove the first object from the stack of traversed objects.
// Remove the first object from the stack of traversed objects.
...
@@ -1000,7 +1069,7 @@
...
@@ -1000,7 +1069,7 @@
// An "empty" object has no enumerable own-properties.
// An "empty" object has no enumerable own-properties.
_
.
isEmpty
=
function
(
obj
)
{
_
.
isEmpty
=
function
(
obj
)
{
if
(
obj
==
null
)
return
true
;
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
;
for
(
var
key
in
obj
)
if
(
_
.
has
(
obj
,
key
))
return
false
;
return
true
;
return
true
;
};
};
...
@@ -1013,18 +1082,19 @@
...
@@ -1013,18 +1082,19 @@
// Is a given value an array?
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
// Delegates to ECMA5's native Array.isArray
_
.
isArray
=
nativeIsArray
||
function
(
obj
)
{
_
.
isArray
=
nativeIsArray
||
function
(
obj
)
{
return
toString
.
call
(
obj
)
==
'
[object Array]
'
;
return
toString
.
call
(
obj
)
==
=
'
[object Array]
'
;
};
};
// Is a given variable an object?
// Is a given variable an object?
_
.
isObject
=
function
(
obj
)
{
_
.
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.
// 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
)
{
_
[
'
is
'
+
name
]
=
function
(
obj
)
{
return
toString
.
call
(
obj
)
==
'
[object
'
+
name
+
'
]
'
;
return
toString
.
call
(
obj
)
==
=
'
[object
'
+
name
+
'
]
'
;
};
};
});
});
...
@@ -1032,14 +1102,14 @@
...
@@ -1032,14 +1102,14 @@
// there isn't any inspectable "Arguments" type.
// there isn't any inspectable "Arguments" type.
if
(
!
_
.
isArguments
(
arguments
))
{
if
(
!
_
.
isArguments
(
arguments
))
{
_
.
isArguments
=
function
(
obj
)
{
_
.
isArguments
=
function
(
obj
)
{
return
!!
(
obj
&&
_
.
has
(
obj
,
'
callee
'
)
);
return
_
.
has
(
obj
,
'
callee
'
);
};
};
}
}
// Optimize `isFunction` if appropriate.
// Optimize `isFunction` if appropriate.
Work around an IE 11 bug.
if
(
typeof
(
/./
)
!==
'
function
'
)
{
if
(
typeof
/./
!==
'
function
'
)
{
_
.
isFunction
=
function
(
obj
)
{
_
.
isFunction
=
function
(
obj
)
{
return
typeof
obj
==
=
'
function
'
;
return
typeof
obj
==
'
function
'
||
false
;
};
};
}
}
...
@@ -1050,12 +1120,12 @@
...
@@ -1050,12 +1120,12 @@
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
_
.
isNaN
=
function
(
obj
)
{
_
.
isNaN
=
function
(
obj
)
{
return
_
.
isNumber
(
obj
)
&&
obj
!=
+
obj
;
return
_
.
isNumber
(
obj
)
&&
obj
!=
=
+
obj
;
};
};
// Is a given value a boolean?
// Is a given value a boolean?
_
.
isBoolean
=
function
(
obj
)
{
_
.
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?
// Is a given value equal to null?
...
@@ -1071,7 +1141,7 @@
...
@@ -1071,7 +1141,7 @@
// Shortcut function for checking if an object has a given property directly
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
// on itself (in other words, not on a prototype).
_
.
has
=
function
(
obj
,
key
)
{
_
.
has
=
function
(
obj
,
key
)
{
return
hasOwnProperty
.
call
(
obj
,
key
);
return
obj
!=
null
&&
hasOwnProperty
.
call
(
obj
,
key
);
};
};
// Utility Functions
// Utility Functions
...
@@ -1084,17 +1154,19 @@
...
@@ -1084,17 +1154,19 @@
return
this
;
return
this
;
};
};
// Keep the identity function around for default iterat
or
s.
// Keep the identity function around for default iterat
ee
s.
_
.
identity
=
function
(
value
)
{
_
.
identity
=
function
(
value
)
{
return
value
;
return
value
;
};
};
_
.
constant
=
function
(
value
)
{
_
.
constant
=
function
(
value
)
{
return
function
()
{
return
function
()
{
return
value
;
return
value
;
};
};
};
};
_
.
noop
=
function
(){};
_
.
property
=
function
(
key
)
{
_
.
property
=
function
(
key
)
{
return
function
(
obj
)
{
return
function
(
obj
)
{
return
obj
[
key
];
return
obj
[
key
];
...
@@ -1103,20 +1175,23 @@
...
@@ -1103,20 +1175,23 @@
// Returns a predicate for checking whether an object has a given set of `key:value` pairs.
// Returns a predicate for checking whether an object has a given set of `key:value` pairs.
_
.
matches
=
function
(
attrs
)
{
_
.
matches
=
function
(
attrs
)
{
var
pairs
=
_
.
pairs
(
attrs
),
length
=
pairs
.
length
;
return
function
(
obj
)
{
return
function
(
obj
)
{
if
(
obj
===
attrs
)
return
true
;
//avoid comparing an object to itself.
if
(
obj
==
null
)
return
!
length
;
for
(
var
key
in
attrs
)
{
obj
=
new
Object
(
obj
);
if
(
attrs
[
key
]
!==
obj
[
key
])
for
(
var
i
=
0
;
i
<
length
;
i
++
)
{
return
false
;
var
pair
=
pairs
[
i
],
key
=
pair
[
0
];
if
(
pair
[
1
]
!==
obj
[
key
]
||
!
(
key
in
obj
))
return
false
;
}
}
return
true
;
return
true
;
}
}
;
};
};
// Run a function **n** times.
// Run a function **n** times.
_
.
times
=
function
(
n
,
iterat
or
,
context
)
{
_
.
times
=
function
(
n
,
iterat
ee
,
context
)
{
var
accum
=
Array
(
Math
.
max
(
0
,
n
));
var
accum
=
Array
(
Math
.
max
(
0
,
n
));
for
(
var
i
=
0
;
i
<
n
;
i
++
)
accum
[
i
]
=
iterator
.
call
(
context
,
i
);
iteratee
=
createCallback
(
iteratee
,
context
,
1
);
for
(
var
i
=
0
;
i
<
n
;
i
++
)
accum
[
i
]
=
iteratee
(
i
);
return
accum
;
return
accum
;
};
};
...
@@ -1130,54 +1205,44 @@
...
@@ -1130,54 +1205,44 @@
};
};
// A (possibly faster) way to get the current timestamp as an integer.
// A (possibly faster) way to get the current timestamp as an integer.
_
.
now
=
Date
.
now
||
function
()
{
return
new
Date
().
getTime
();
};
_
.
now
=
Date
.
now
||
function
()
{
return
new
Date
().
getTime
();
// List of HTML entities for escaping.
var
entityMap
=
{
escape
:
{
'
&
'
:
'
&
'
,
'
<
'
:
'
<
'
,
'
>
'
:
'
>
'
,
'
"
'
:
'
"
'
,
"
'
"
:
'
'
'
}
};
};
entityMap
.
unescape
=
_
.
invert
(
entityMap
.
escape
);
// Regexes containing the keys and values listed immediately above.
// List of HTML entities for escaping.
var
entityRegexes
=
{
var
escapeMap
=
{
escape
:
new
RegExp
(
'
[
'
+
_
.
keys
(
entityMap
.
escape
).
join
(
''
)
+
'
]
'
,
'
g
'
),
'
&
'
:
'
&
'
,
unescape
:
new
RegExp
(
'
(
'
+
_
.
keys
(
entityMap
.
unescape
).
join
(
'
|
'
)
+
'
)
'
,
'
g
'
)
'
<
'
:
'
<
'
,
'
>
'
:
'
>
'
,
'
"
'
:
'
"
'
,
"
'
"
:
'
'
'
,
'
`
'
:
'
`
'
};
};
var
unescapeMap
=
_
.
invert
(
escapeMap
);
// Functions for escaping and unescaping strings to/from HTML interpolation.
// Functions for escaping and unescaping strings to/from HTML interpolation.
_
.
each
([
'
escape
'
,
'
unescape
'
],
function
(
method
)
{
var
createEscaper
=
function
(
map
)
{
_
[
method
]
=
function
(
string
)
{
var
escaper
=
function
(
match
)
{
if
(
string
==
null
)
return
''
;
return
map
[
match
];
return
(
''
+
string
).
replace
(
entityRegexes
[
method
],
function
(
match
)
{
return
entityMap
[
method
][
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
// If the value of the named `property` is a function then invoke it with the
// `object` as context; otherwise, return it.
// `object` as context; otherwise, return it.
_
.
result
=
function
(
object
,
property
)
{
_
.
result
=
function
(
object
,
property
)
{
if
(
object
==
null
)
return
void
0
;
if
(
object
==
null
)
return
void
0
;
var
value
=
object
[
property
];
var
value
=
object
[
property
];
return
_
.
isFunction
(
value
)
?
value
.
call
(
object
)
:
value
;
return
_
.
isFunction
(
value
)
?
object
[
property
]()
:
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
));
};
});
};
};
// Generate a unique integer id (unique within the entire client session).
// Generate a unique integer id (unique within the entire client session).
...
@@ -1208,22 +1273,26 @@
...
@@ -1208,22 +1273,26 @@
'
\\
'
:
'
\\
'
,
'
\\
'
:
'
\\
'
,
'
\r
'
:
'
r
'
,
'
\r
'
:
'
r
'
,
'
\n
'
:
'
n
'
,
'
\n
'
:
'
n
'
,
'
\t
'
:
'
t
'
,
'
\
u2028
'
:
'
u2028
'
,
'
\
u2028
'
:
'
u2028
'
,
'
\
u2029
'
:
'
u2029
'
'
\
u2029
'
:
'
u2029
'
};
};
var
escaper
=
/
\\
|'|
\r
|
\n
|
\t
|
\u
2028|
\u
2029/g
;
var
escaper
=
/
\\
|'|
\r
|
\n
|
\u
2028|
\u
2029/g
;
var
escapeChar
=
function
(
match
)
{
return
'
\\
'
+
escapes
[
match
];
};
// JavaScript micro-templating, similar to John Resig's implementation.
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
// and correctly escapes quotes within interpolated code.
_
.
template
=
function
(
text
,
data
,
settings
)
{
// NB: `oldSettings` only exists for backwards compatibility.
var
render
;
_
.
template
=
function
(
text
,
settings
,
oldSettings
)
{
if
(
!
settings
&&
oldSettings
)
settings
=
oldSettings
;
settings
=
_
.
defaults
({},
settings
,
_
.
templateSettings
);
settings
=
_
.
defaults
({},
settings
,
_
.
templateSettings
);
// Combine delimiters into one regular expression via alternation.
// Combine delimiters into one regular expression via alternation.
var
matcher
=
new
RegExp
([
var
matcher
=
RegExp
([
(
settings
.
escape
||
noMatch
).
source
,
(
settings
.
escape
||
noMatch
).
source
,
(
settings
.
interpolate
||
noMatch
).
source
,
(
settings
.
interpolate
||
noMatch
).
source
,
(
settings
.
evaluate
||
noMatch
).
source
(
settings
.
evaluate
||
noMatch
).
source
...
@@ -1233,19 +1302,18 @@
...
@@ -1233,19 +1302,18 @@
var
index
=
0
;
var
index
=
0
;
var
source
=
"
__p+='
"
;
var
source
=
"
__p+='
"
;
text
.
replace
(
matcher
,
function
(
match
,
escape
,
interpolate
,
evaluate
,
offset
)
{
text
.
replace
(
matcher
,
function
(
match
,
escape
,
interpolate
,
evaluate
,
offset
)
{
source
+=
text
.
slice
(
index
,
offset
)
source
+=
text
.
slice
(
index
,
offset
)
.
replace
(
escaper
,
escapeChar
);
.
replace
(
escaper
,
function
(
match
)
{
return
'
\\
'
+
escapes
[
match
];
})
;
index
=
offset
+
match
.
length
;
if
(
escape
)
{
if
(
escape
)
{
source
+=
"
'+
\n
((__t=(
"
+
escape
+
"
))==null?'':_.escape(__t))+
\n
'
"
;
source
+=
"
'+
\n
((__t=(
"
+
escape
+
"
))==null?'':_.escape(__t))+
\n
'
"
;
}
}
else
if
(
interpolate
)
{
if
(
interpolate
)
{
source
+=
"
'+
\n
((__t=(
"
+
interpolate
+
"
))==null?'':__t)+
\n
'
"
;
source
+=
"
'+
\n
((__t=(
"
+
interpolate
+
"
))==null?'':__t)+
\n
'
"
;
}
}
else
if
(
evaluate
)
{
if
(
evaluate
)
{
source
+=
"
';
\n
"
+
evaluate
+
"
\n
__p+='
"
;
source
+=
"
';
\n
"
+
evaluate
+
"
\n
__p+='
"
;
}
}
index
=
offset
+
match
.
length
;
// Adobe VMs need the match returned to produce the correct offest.
return
match
;
return
match
;
});
});
source
+=
"
';
\n
"
;
source
+=
"
';
\n
"
;
...
@@ -1255,29 +1323,31 @@
...
@@ -1255,29 +1323,31 @@
source
=
"
var __t,__p='',__j=Array.prototype.join,
"
+
source
=
"
var __t,__p='',__j=Array.prototype.join,
"
+
"
print=function(){__p+=__j.call(arguments,'');};
\n
"
+
"
print=function(){__p+=__j.call(arguments,'');};
\n
"
+
source
+
"
return __p;
\n
"
;
source
+
'
return __p;
\n
'
;
try
{
try
{
render
=
new
Function
(
settings
.
variable
||
'
obj
'
,
'
_
'
,
source
);
var
render
=
new
Function
(
settings
.
variable
||
'
obj
'
,
'
_
'
,
source
);
}
catch
(
e
)
{
}
catch
(
e
)
{
e
.
source
=
source
;
e
.
source
=
source
;
throw
e
;
throw
e
;
}
}
if
(
data
)
return
render
(
data
,
_
);
var
template
=
function
(
data
)
{
var
template
=
function
(
data
)
{
return
render
.
call
(
this
,
data
,
_
);
return
render
.
call
(
this
,
data
,
_
);
};
};
// Provide the compiled function source as a convenience for precompilation.
// Provide the compiled source as a convenience for precompilation.
template
.
source
=
'
function(
'
+
(
settings
.
variable
||
'
obj
'
)
+
'
){
\n
'
+
source
+
'
}
'
;
var
argument
=
settings
.
variable
||
'
obj
'
;
template
.
source
=
'
function(
'
+
argument
+
'
){
\n
'
+
source
+
'
}
'
;
return
template
;
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
)
{
_
.
chain
=
function
(
obj
)
{
return
_
(
obj
).
chain
();
var
instance
=
_
(
obj
);
instance
.
_chain
=
true
;
return
instance
;
};
};
// OOP
// OOP
...
@@ -1291,42 +1361,44 @@
...
@@ -1291,42 +1361,44 @@
return
this
.
_chain
?
_
(
obj
).
chain
()
:
obj
;
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.
// Add all of the Underscore functions to the wrapper object.
_
.
mixin
(
_
);
_
.
mixin
(
_
);
// Add all mutator Array functions to the wrapper.
// 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
];
var
method
=
ArrayProto
[
name
];
_
.
prototype
[
name
]
=
function
()
{
_
.
prototype
[
name
]
=
function
()
{
var
obj
=
this
.
_wrapped
;
var
obj
=
this
.
_wrapped
;
method
.
apply
(
obj
,
arguments
);
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
);
return
result
.
call
(
this
,
obj
);
};
};
});
});
// Add all accessor Array functions to the wrapper.
// Add all accessor Array functions to the wrapper.
each
([
'
concat
'
,
'
join
'
,
'
slice
'
],
function
(
name
)
{
_
.
each
([
'
concat
'
,
'
join
'
,
'
slice
'
],
function
(
name
)
{
var
method
=
ArrayProto
[
name
];
var
method
=
ArrayProto
[
name
];
_
.
prototype
[
name
]
=
function
()
{
_
.
prototype
[
name
]
=
function
()
{
return
result
.
call
(
this
,
method
.
apply
(
this
.
_wrapped
,
arguments
));
return
result
.
call
(
this
,
method
.
apply
(
this
.
_wrapped
,
arguments
));
};
};
});
});
_
.
extend
(
_
.
prototype
,
{
// Extracts the result from a wrapped and chained object.
_
.
prototype
.
value
=
function
()
{
// Start chaining a wrapped Underscore object.
return
this
.
_wrapped
;
chain
:
function
()
{
};
this
.
_chain
=
true
;
return
this
;
},
// Extracts the result from a wrapped and chained object.
value
:
function
()
{
return
this
.
_wrapped
;
}
});
// AMD registration happens at the end for compatibility with AMD loaders
// AMD registration happens at the end for compatibility with AMD loaders
// that may not enforce next-turn semantics on modules. Even though general
// that may not enforce next-turn semantics on modules. Even though general
...
@@ -1340,4 +1412,4 @@
...
@@ -1340,4 +1412,4 @@
return
_
;
return
_
;
});
});
}
}
}
).
call
(
this
);
}
.
call
(
this
)
);
examples/backbone/index.html
View file @
e80de6d1
...
@@ -49,7 +49,7 @@
...
@@ -49,7 +49,7 @@
<%
}
%>
<%
}
%>
</script>
</script>
<script
src=
"bower_components/todomvc-common/base.js"
></script>
<script
src=
"bower_components/todomvc-common/base.js"
></script>
<script
src=
"bower_components/jquery/jquery.js"
></script>
<script
src=
"bower_components/jquery/
dist/
jquery.js"
></script>
<script
src=
"bower_components/underscore/underscore.js"
></script>
<script
src=
"bower_components/underscore/underscore.js"
></script>
<script
src=
"bower_components/backbone/backbone.js"
></script>
<script
src=
"bower_components/backbone/backbone.js"
></script>
<script
src=
"bower_components/backbone.localStorage/backbone.localStorage.js"
></script>
<script
src=
"bower_components/backbone.localStorage/backbone.localStorage.js"
></script>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment