mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-31 23:37:49 +00:00
Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e9cbccde6 | ||
|
|
a0cb8ec124 | ||
|
|
21217dfda3 | ||
|
|
25ba18e570 | ||
|
|
a210377f35 | ||
|
|
07b9ca457f | ||
|
|
5f1372d39c | ||
|
|
01b84c79f0 | ||
|
|
4017443b1e | ||
|
|
fd2a17d244 | ||
|
|
126804f7c3 | ||
|
|
5167bbf59e | ||
|
|
8bcdfa2793 | ||
|
|
2f9cb6a91e | ||
|
|
662be14535 | ||
|
|
d6d065cd61 | ||
|
|
ac7f045708 | ||
|
|
ffe02ad7bf | ||
|
|
db1a87d10c | ||
|
|
4bae41ffd8 | ||
|
|
be36fb979f | ||
|
|
0f66d763e0 | ||
|
|
06f4743f51 | ||
|
|
9cc11b8774 | ||
|
|
de821e55ae | ||
|
|
463b5c6e49 | ||
|
|
65ab5fdb34 | ||
|
|
d2f7a035b3 | ||
|
|
bc0b924283 | ||
|
|
56ad6af5b2 | ||
|
|
c50bb3a5a9 | ||
|
|
d993a62263 | ||
|
|
82bc52b909 | ||
|
|
f31598f916 | ||
|
|
6a9efd8ac6 | ||
|
|
a9dddb6066 | ||
|
|
40cf5c99ef | ||
|
|
42f58cbbb3 | ||
|
|
fd9c780015 | ||
|
|
383b92b207 | ||
|
|
7036ed5e2f | ||
|
|
30666aa111 | ||
|
|
9614d68baa | ||
|
|
c25fb4c743 | ||
|
|
09d5222b1f | ||
|
|
426ca78bf7 | ||
|
|
a77a0945fe | ||
|
|
5311a0f903 | ||
|
|
d421656be8 | ||
|
|
04459eaa50 | ||
|
|
3beda8eea0 | ||
|
|
5e894be06b | ||
|
|
bc8f93b596 | ||
|
|
2fb93bac99 | ||
|
|
d0c94c1aef | ||
|
|
77242bfb95 | ||
|
|
5d2d86bffc | ||
|
|
8492c13e72 | ||
|
|
e4eb5dadda | ||
|
|
8532dc4b75 | ||
|
|
1ca26ce676 | ||
|
|
d8e3e823a7 | ||
|
|
473dd7660b | ||
|
|
5afeed56ef | ||
|
|
b91b04f652 | ||
|
|
25de44a23d | ||
|
|
00cfb95971 | ||
|
|
f4ba0e1191 | ||
|
|
6499643769 | ||
|
|
f85287a444 | ||
|
|
483bc9ad87 | ||
|
|
93b89a93c1 | ||
|
|
10064c046c | ||
|
|
a5aecb9d0e | ||
|
|
de1e889f1d | ||
|
|
16f89b40c3 | ||
|
|
0e387d2cda | ||
|
|
837c15e4f9 | ||
|
|
ae7e353169 | ||
|
|
6c1bbd2344 | ||
|
|
27247e8e56 | ||
|
|
08249d78ea | ||
|
|
827091e522 | ||
|
|
13d901bf8d | ||
|
|
e69bdabc99 | ||
|
|
e8d19265e4 | ||
|
|
49e3a49dc5 | ||
|
|
82a7c01898 | ||
|
|
c0d7dbf639 | ||
|
|
569caa0bf2 | ||
|
|
f88ea1ee7d | ||
|
|
d5a8fa0b97 | ||
|
|
3f8f96edea | ||
|
|
04fb4aff28 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
*.custom.*
|
||||
.DS_Store
|
||||
dist/
|
||||
node_modules/
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
*.custom.*
|
||||
.*
|
||||
dist/
|
||||
build.js
|
||||
index.js
|
||||
build/
|
||||
doc/*.php
|
||||
node_modules/
|
||||
perf/*.sh
|
||||
test/*.sh
|
||||
test/test-build.js
|
||||
test/template/
|
||||
vendor/closure-compiler
|
||||
vendor/docdown
|
||||
vendor/uglifyjs
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
*.custom.*
|
||||
.*
|
||||
dist/
|
||||
doc/*.php
|
||||
node_modules/
|
||||
perf/*.html
|
||||
|
||||
4
.travis.yml
Normal file
4
.travis.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.6
|
||||
- 0.8
|
||||
159
README.md
159
README.md
@@ -1,15 +1,17 @@
|
||||
# Lo-Dash <sup>v0.7.0</sup>
|
||||
# Lo-Dash <sup>v0.8.1</sup>
|
||||
[](http://travis-ci.org/bestiejs/lodash)
|
||||
|
||||
A drop-in replacement<sup>[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer)</sup> for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues-20), and [additional features](https://github.com/bestiejs/lodash#features).
|
||||
A drop-in replacement<sup>[*](https://github.com/bestiejs/lodash/wiki/Drop-in-Disclaimer)</sup> for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), delivering [performance](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#resolved-underscorejs-issues), and [additional features](http://lodash.com/#features).
|
||||
|
||||
Lo-Dash’s performance is gained by avoiding slower native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls.
|
||||
|
||||
## Download
|
||||
|
||||
* [Development source](https://raw.github.com/bestiejs/lodash/v0.7.0/lodash.js)
|
||||
* [Production source](https://raw.github.com/bestiejs/lodash/v0.7.0/lodash.min.js)
|
||||
* CDN copies of ≤ [v0.7.0](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.7.0/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/)
|
||||
* For optimal performance, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need
|
||||
* [Development build](https://raw.github.com/bestiejs/lodash/v0.8.1/lodash.js)
|
||||
* [Production build](https://raw.github.com/bestiejs/lodash/v0.8.1/lodash.min.js)
|
||||
* [Underscore build](https://raw.github.com/bestiejs/lodash/v0.8.1/lodash.underscore.min.js) tailored for projects already using Underscore
|
||||
* CDN copies of ≤ [v0.8.1](http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.8.1/lodash.min.js) are available on [cdnjs](http://cdnjs.com/) thanks to [CloudFlare](http://www.cloudflare.com/)
|
||||
* For optimal file size, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need
|
||||
|
||||
## Dive in
|
||||
|
||||
@@ -32,32 +34,21 @@ For more information check out these screencasts over Lo-Dash:
|
||||
## Features
|
||||
|
||||
* AMD loader support ([RequireJS](http://requirejs.org/), [curl.js](https://github.com/cujojs/curl), etc.)
|
||||
* [_.bind](http://lodash.com/docs#bind) supports *“lazy”* binding
|
||||
* [_.clone](http://lodash.com/docs#clone) supports *“deep”* cloning
|
||||
* [_.countBy](http://lodash.com/docs#countBy) as a companion function for [_.groupBy](http://lodash.com/docs#groupBy) and [_.sortBy](http://lodash.com/docs#sortBy)
|
||||
* [_.debounce](http://lodash.com/docs#debounce)’ed functions match [_.throttle](http://lodash.com/docs#throttle)’ed functions’ return value behavior
|
||||
* [_.forEach](http://lodash.com/docs#forEach) is chainable and supports exiting iteration early
|
||||
* [_.forIn](http://lodash.com/docs#forIn) for iterating over an object’s own and inherited properties
|
||||
* [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an object’s own properties
|
||||
* [_.indexOf](http://lodash.com/docs#indexOf) and [_.lastIndexOf](http://lodash.com/docs#lastIndexOf) accept a `fromIndex` argument
|
||||
* [_.invert](http://lodash.com/docs#invert) to create inverted objects
|
||||
* [_.lateBind](http://lodash.com/docs#lateBind) for late binding
|
||||
* [_.merge](http://lodash.com/docs#merge) for a *“deep”* [_.extend](http://lodash.com/docs#extend)
|
||||
* [_.object](http://lodash.com/docs#object) and [_.pairs](http://lodash.com/docs#pairs) for composing objects
|
||||
* [_.omit](http://lodash.com/docs#omit) for the inverse functionality of [_.pick](http://lodash.com/docs#pick)
|
||||
* [_.partial](http://lodash.com/docs#partial) for partial application without `this` binding
|
||||
* [_.pick](http://lodash.com/docs#pick) and [_.omit](http://lodash.com/docs#omit) accept `callback` and `thisArg` arguments
|
||||
* [_.random](http://lodash.com/docs#random) for generating random numbers within a given range
|
||||
* [_.sortBy](http://lodash.com/docs#sortBy) performs a [stable](http://en.wikipedia.org/wiki/Sorting_algorithm#Stability) sort
|
||||
* [_.template](http://lodash.com/docs#template) utilizes [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier debugging
|
||||
* [_.unescape](http://lodash.com/docs#unescape) to unescape strings escaped by [_.escape](http://lodash.com/docs#escape)
|
||||
* [_.where](http://lodash.com/docs#where) for filtering collections by contained properties
|
||||
* [_.countBy](http://lodash.com/docs#countBy), [_.groupBy](http://lodash.com/docs#groupBy), [_.sortedIndex](http://lodash.com/docs#sortedIndex), and [_.uniq](http://lodash.com/docs#uniq) accept a `thisArg` argument
|
||||
* [_.contains](http://lodash.com/docs#contains), [_.size](http://lodash.com/docs#size), [_.toArray](http://lodash.com/docs#toArray),
|
||||
[and more…](http://lodash.com/docs "_.countBy, _.every, _.filter, _.find, _.forEach, _.groupBy, _.invoke, _.map, _.pluck, _.reduce, _.reduceRight, _.reject, _.some, _.sortBy, _.where") accept strings
|
||||
|
||||
## Support
|
||||
|
||||
Lo-Dash has been tested in at least Chrome 5-21, Firefox 1-15, IE 6-9, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.8.8, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5.
|
||||
Lo-Dash has been tested in at least Chrome 5-22, Firefox 1-15, IE 6-10, Opera 9.25-12, Safari 3-6, Node.js 0.4.8-0.8.11, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5.
|
||||
|
||||
## Custom builds
|
||||
|
||||
@@ -89,7 +80,7 @@ lodash mobile
|
||||
lodash strict
|
||||
```
|
||||
|
||||
* Underscore builds, with iteration fixes removed and only Underscore’s API, may be created using the `underscore` modifier argument.
|
||||
* Underscore builds, tailored for projects already using Underscore, may be created using the `underscore` modifier argument.
|
||||
```bash
|
||||
lodash underscore
|
||||
```
|
||||
@@ -97,23 +88,17 @@ lodash underscore
|
||||
Custom builds may be created using the following commands:
|
||||
|
||||
* Use the `category` argument to pass comma separated categories of methods to include in the build.<br>
|
||||
Valid categories are *“arrays”*, *“chaining”*, *“collections”*, *“functions”*, *“objects”*, and *“utilities”*.
|
||||
Valid categories (case-insensitive) are *“arrays”*, *“chaining”*, *“collections”*, *“functions”*, *“objects”*, and *“utilities”*.
|
||||
```bash
|
||||
lodash category=collections,functions
|
||||
lodash category="collections, functions"
|
||||
```
|
||||
|
||||
* Use the `exclude` argument to pass comma separated names of methods to exclude from the build.
|
||||
```bash
|
||||
lodash exclude=union,uniq,zip
|
||||
lodash exclude="union, uniq, zip"
|
||||
```
|
||||
|
||||
* Use the `exports` argument to pass comma separated names of ways to export the `LoDash` function.<br>
|
||||
Valid exports are *“amd”*, *“commonjs”*, *“global”*, *“node”*, and *“none”*.
|
||||
Valid exports are *“amd”*, *“commonjs”*, *“global”*, *“node”*, and *“none”*.
|
||||
```bash
|
||||
lodash exports=amd,commonjs,node
|
||||
lodash include="amd, commonjs, node"
|
||||
lodash exports="amd, commonjs, node"
|
||||
```
|
||||
|
||||
* Use the `iife` argument to specify code to replace the immediately-invoked function expression that wraps Lo-Dash.
|
||||
@@ -121,31 +106,49 @@ lodash include="amd, commonjs, node"
|
||||
lodash iife="!function(window,undefined){%output%}(this)"
|
||||
```
|
||||
|
||||
* Use the `include` argument to pass comma separated names of methods to include in the build.
|
||||
* Use the `include` argument to pass comma separated method/category names to include in the build.
|
||||
```bash
|
||||
lodash include=each,filter,map
|
||||
lodash include="each, filter, map"
|
||||
```
|
||||
|
||||
All arguments, except `exclude` with `include` and `legacy` with `csp`/`mobile`, may be combined.
|
||||
|
||||
* Use the `minus` argument to pass comma separated method/category names to remove from those included in the build.
|
||||
```bash
|
||||
lodash backbone legacy exports=global category=utilities exclude=first,last
|
||||
lodash -s underscore mobile strict exports=amd category=functions include=pick,uniq
|
||||
lodash underscore minus=result,shuffle
|
||||
lodash underscore minus="result, shuffle"
|
||||
```
|
||||
|
||||
* Use the `plus` argument to pass comma separated method/category names to add to those included in the build.
|
||||
```bash
|
||||
lodash backbone plus=random,template
|
||||
lodash backbone plus="random, template"
|
||||
```
|
||||
|
||||
* Use the `template` argument to pass the file path pattern used to match template files to precompile
|
||||
```bash
|
||||
lodash template="./*.jst"
|
||||
```
|
||||
|
||||
* Use the `settings` argument to pass the template settings used when precompiling templates
|
||||
```bash
|
||||
lodash settings="{interpolate:/\\{\\{([\\s\\S]+?)\\}\\}/g}"
|
||||
```
|
||||
|
||||
All arguments, except `legacy` with `csp` or `mobile`, may be combined.<br>
|
||||
Unless specified by `-o` or `--output`, all files created are saved to the current working directory.
|
||||
|
||||
The following options are also supported:
|
||||
|
||||
* `-c`, `--stdout` Write output to standard output
|
||||
* `-h`, `--help` Display help information
|
||||
* `-o`, `--output` Write output to a given path/filename
|
||||
* `-s`, `--silent` Skip status updates normally logged to the console
|
||||
* `-V`, `--version` Output current version of Lo-Dash
|
||||
* `-c`, `--stdout` Write output to standard output
|
||||
* `-d`, `--debug` Write only the debug output
|
||||
* `-h`, `--help` Display help information
|
||||
* `-m`, `--minify` Write only the minified output
|
||||
* `-o`, `--output` Write output to a given path/filename
|
||||
* `-s`, `--silent` Skip status updates normally logged to the console
|
||||
* `-V`, `--version` Output current version of Lo-Dash
|
||||
|
||||
The `lodash` command-line utility is available when Lo-Dash is installed as a global package (i.e. `npm install -g lodash`).
|
||||
|
||||
Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`.
|
||||
|
||||
## Installation and usage
|
||||
|
||||
In browsers:
|
||||
@@ -192,43 +195,32 @@ require({
|
||||
});
|
||||
```
|
||||
|
||||
## Resolved Underscore.js issues <sup>(20+)</sup>
|
||||
## Resolved Underscore.js issues
|
||||
|
||||
* Allow iteration of objects with a `length` property [[#148](https://github.com/documentcloud/underscore/issues/148), [#154](https://github.com/documentcloud/underscore/issues/154), [#252](https://github.com/documentcloud/underscore/issues/252), [#448](https://github.com/documentcloud/underscore/issues/448), [#659](https://github.com/documentcloud/underscore/issues/659), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L543-549)]
|
||||
* Ensure array-like objects with invalid `length` properties are treated like regular objects [[#741](https://github.com/documentcloud/underscore/issues/741), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L491-501)]
|
||||
* Ensure *“Arrays”*, *“Collections”*, and *“Objects”* methods don’t error when passed falsey arguments [[#650](https://github.com/documentcloud/underscore/pull/650), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1719-1754)]
|
||||
* Ensure *“Collections”* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L503-520)]
|
||||
* Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L554-579)]
|
||||
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [#742](https://github.com/documentcloud/underscore/issues/742), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L134-140)]
|
||||
* Register as an AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L118-132)]
|
||||
* `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L223-234)]
|
||||
* `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L289-298)]
|
||||
* `_.countBy` and `_.groupBy` should only add values to own, not inherited, properties [[#736](https://github.com/documentcloud/underscore/issues/736), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L306-313)]
|
||||
* `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [#718](https://github.com/documentcloud/underscore/issues/718), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L946-968)]
|
||||
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L486-489)]
|
||||
* `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L581-600)]
|
||||
* `_.isElement` should use strict equality for its duck type check [[#734](https://github.com/documentcloud/underscore/issues/734), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L696-705)]
|
||||
* `_.isEmpty` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L732-737)]
|
||||
* `_.isEqual` should return `true` for like-objects from different documents [[#733](https://github.com/documentcloud/underscore/issues/733), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L784-795)]
|
||||
* `_.isEqual` should use custom `isEqual` methods before checking strict equality [[#748](https://github.com/documentcloud/underscore/issues/748), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L758-761)]
|
||||
* `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L803-815)]
|
||||
* `_.isNaN(new Number(NaN))` should return `true` [[#749](https://github.com/documentcloud/underscore/issues/749), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L823-825)]
|
||||
* `_.keys` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L879-881)]
|
||||
* `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1222-1225)]
|
||||
* `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1257-1271)]
|
||||
* `_.sortedIndex` should support arrays with high `length` values [[#735](https://github.com/documentcloud/underscore/issues/735), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1404-1413)]
|
||||
* `_.throttle` should work when called in a loop [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1534-1544)]
|
||||
* `_.toArray` uses custom `toArray` methods of arrays and strings [[#747](https://github.com/documentcloud/underscore/issues/747), [test](https://github.com/bestiejs/lodash/blob/v0.7.0/test/test.js#L1571-1579)]
|
||||
* Add AMD loader support [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L118-140)]
|
||||
* Allow iteration of objects with a `length` property [[#799](https://github.com/documentcloud/underscore/pull/799), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L510-516)]
|
||||
* Ensure *“Arrays”*, *“Collections”*, and *“Objects”* methods don’t error when passed falsey arguments [[#650](https://github.com/documentcloud/underscore/pull/650), [#803](https://github.com/documentcloud/underscore/issues/803), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L1729-1764)]
|
||||
* Ensure *“Collections”* methods allow string `collection` arguments [[#247](https://github.com/documentcloud/underscore/issues/247), [#276](https://github.com/documentcloud/underscore/issues/276), [#561](https://github.com/documentcloud/underscore/pull/561), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L470-487)]
|
||||
* Fix cross-browser object iteration bugs [[#60](https://github.com/documentcloud/underscore/issues/60), [#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L526-546)]
|
||||
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [#742](https://github.com/documentcloud/underscore/issues/742), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L142-148)]
|
||||
* `_.clone` should allow `deep` cloning [[#595](https://github.com/documentcloud/underscore/pull/595), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L215-224)]
|
||||
* `_.contains` should work with strings [[#667](https://github.com/documentcloud/underscore/pull/667), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L267-276)]
|
||||
* `_.extend` should recursively extend objects [[#379](https://github.com/documentcloud/underscore/pull/379), [#718](https://github.com/documentcloud/underscore/issues/718), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L955-977)]
|
||||
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L465-468)]
|
||||
* `_.forEach` should allow exiting iteration early [[#211](https://github.com/documentcloud/underscore/issues/211), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L553-570)]
|
||||
* `_.isEmpty` should support jQuery/MooTools DOM query collections [[#690](https://github.com/documentcloud/underscore/pull/690), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L712-717)]
|
||||
* `_.isObject` should avoid V8 bug [#2291](http://code.google.com/p/v8/issues/detail?id=2291) [[#605](https://github.com/documentcloud/underscore/issues/605), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L772-784)]
|
||||
* `_.keys` should work with `arguments` objects cross-browser [[#396](https://github.com/documentcloud/underscore/issues/396), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L865-867)]
|
||||
* `_.range` should coerce arguments to numbers [[#634](https://github.com/documentcloud/underscore/issues/634), [#683](https://github.com/documentcloud/underscore/issues/683), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L1231-1234)]
|
||||
* `_.throttle` should work when called in a loop [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/v0.8.1/test/test.js#L1549-1559)]
|
||||
|
||||
## Optimized methods <sup>(50+)</sup>
|
||||
|
||||
* `_.bind`
|
||||
* `_.bindAll`
|
||||
* `_.clone`
|
||||
* `_.compact`
|
||||
* `_.contains`, `_.include`
|
||||
* `_.defaults`
|
||||
* `_.defer`
|
||||
* `_.difference`
|
||||
* `_.each`
|
||||
* `_.every`, `_.all`
|
||||
@@ -245,7 +237,6 @@ require({
|
||||
* `_.invoke`
|
||||
* `_.isArguments`
|
||||
* `_.isDate`
|
||||
* `_.isEmpty`
|
||||
* `_.isFinite`
|
||||
* `_.isFunction`
|
||||
* `_.isObject`
|
||||
@@ -272,11 +263,11 @@ require({
|
||||
* `_.sortedIndex`
|
||||
* `_.template`
|
||||
* `_.throttle`
|
||||
* `_.times`
|
||||
* `_.toArray`
|
||||
* `_.union`
|
||||
* `_.uniq`, `_.unique`
|
||||
* `_.values`
|
||||
* `_.where`
|
||||
* `_.without`
|
||||
* `_.wrap`
|
||||
* `_.zip`
|
||||
@@ -284,30 +275,10 @@ require({
|
||||
|
||||
## Release Notes
|
||||
|
||||
### <sup>v0.7.0</sup>
|
||||
### <sup>v0.8.1</sup>
|
||||
|
||||
#### Compatibility Warnings ####
|
||||
|
||||
* Renamed `_.zipObject` to `_.object`
|
||||
* Replaced `_.drop` with `_.omit`
|
||||
* Made `_.drop` alias `_.rest`
|
||||
|
||||
#### Changes ####
|
||||
|
||||
* Added [_.invert](http://lodash.com/docs#invert), [_.pairs](http://lodash.com/docs#pairs), and [_.random](http://lodash.com/docs#random)
|
||||
* Added `_.result` to the `backbone` build
|
||||
* Added `exports`, `iife`, `-c`/`--stdout`, `-o`/`--output`, and `-s`/`--silent` build options
|
||||
* Ensured `isPlainObject` works with objects from other documements
|
||||
* Ensured `_.isEqual` compares values with circular references correctly
|
||||
* Ensured `_.merge` work with four or more arguments
|
||||
* Ensured `_.sortBy` performs a stable sort for `undefined` values
|
||||
* Ensured `_.template` works with "interpolate" delimiters containing ternary operators
|
||||
* Ensured the production build works in Node.js
|
||||
* Ensured template delimiters are tokenized correctly
|
||||
* Made pseudo private properties `_chain` and `_wrapped` double-underscored to avoid conflicts
|
||||
* Made `minify.js` support `underscore.js`
|
||||
* Reduced the size of `mobile` and `underscore` builds
|
||||
* Simplified `_.isEqual` and `_.size`
|
||||
* Made `underscore` build include deep clone when `clone` is requested via `include` or `plus`
|
||||
* Reverted removal of first argument falsey checks from methods
|
||||
|
||||
The full changelog is available [here](https://github.com/bestiejs/lodash/wiki/Changelog).
|
||||
|
||||
|
||||
112
build/minify.js
112
build/minify.js
@@ -9,18 +9,15 @@
|
||||
spawn = require('child_process').spawn;
|
||||
|
||||
/** The directory that is the base of the repository */
|
||||
var basePath = path.join(__dirname, '../');
|
||||
var basePath = fs.realpathSync(path.join(__dirname, '..'));
|
||||
|
||||
/** The directory where the Closure Compiler is located */
|
||||
var closurePath = path.join(basePath, 'vendor', 'closure-compiler', 'compiler.jar');
|
||||
|
||||
/** The distribution directory */
|
||||
var distPath = path.join(basePath, 'dist');
|
||||
|
||||
/** Load other modules */
|
||||
var preprocess = require(path.join(__dirname, 'pre-compile')),
|
||||
postprocess = require(path.join(__dirname, 'post-compile')),
|
||||
uglifyJS = require(path.join(basePath, 'vendor', 'uglifyjs', 'uglify-js'));
|
||||
var preprocess = require('./pre-compile'),
|
||||
postprocess = require('./post-compile'),
|
||||
uglifyJS = require('../vendor/uglifyjs/uglify-js');
|
||||
|
||||
/** Closure Compiler command-line options */
|
||||
var closureOptions = [
|
||||
@@ -37,31 +34,38 @@
|
||||
* The exposed `minify` function minifies a given Lo-Dash `source` and invokes
|
||||
* the `onComplete` callback when finished.
|
||||
*
|
||||
* @param {Array|String} source The array of command-line arguments or the
|
||||
* source to minify.
|
||||
* @param {Object} options The options object containing `onComplete`,
|
||||
* `silent`, and `workingName`.
|
||||
* @param {Array|String} [source=''] The source to minify or array of commands.
|
||||
* @param {Object} [options={}] The options object.
|
||||
*/
|
||||
function minify(source, options) {
|
||||
source || (source = '');
|
||||
options || (options = {});
|
||||
|
||||
// juggle arguments
|
||||
if (Array.isArray(source)) {
|
||||
// convert the command-line arguments to an options object
|
||||
// convert commands to an options object
|
||||
options = source;
|
||||
|
||||
var filePath = options[options.length - 1],
|
||||
dirPath = path.dirname(filePath),
|
||||
workingName = path.basename(filePath, '.js') + '.min',
|
||||
outputPath = path.join(dirPath, workingName + '.js'),
|
||||
isSilent = options.indexOf('-s') > -1 || options.indexOf('--silent') > -1;
|
||||
isSilent = options.indexOf('-s') > -1 || options.indexOf('--silent') > -1,
|
||||
isTemplate = options.indexOf('-t') > -1 || options.indexOf('--template') > -1,
|
||||
outputPath = path.join(path.dirname(filePath), path.basename(filePath, '.js') + '.min.js');
|
||||
|
||||
outputPath = options.reduce(function(result, value, index) {
|
||||
if (/-o|--output/.test(value)) {
|
||||
result = options[index + 1];
|
||||
result = path.join(fs.realpathSync(path.dirname(result)), path.basename(result));
|
||||
}
|
||||
return result;
|
||||
}, outputPath);
|
||||
|
||||
options = {
|
||||
'isSilent': isSilent,
|
||||
'isTemplate': isTemplate,
|
||||
'outputPath': outputPath
|
||||
};
|
||||
|
||||
source = fs.readFileSync(filePath, 'utf8');
|
||||
options = {
|
||||
'silent': isSilent,
|
||||
'workingName': workingName,
|
||||
'onComplete': function(source) {
|
||||
fs.writeFileSync(outputPath, source, 'utf8');
|
||||
}
|
||||
};
|
||||
}
|
||||
new Minify(source, options);
|
||||
}
|
||||
@@ -72,35 +76,28 @@
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {String} source The source to minify.
|
||||
* @param {Object} options The options object containing `onComplete`,
|
||||
* `silent`, and `workingName`.
|
||||
* @param {Object} options The options object.
|
||||
*/
|
||||
function Minify(source, options) {
|
||||
source || (source = '');
|
||||
options || (options = {});
|
||||
|
||||
if (typeof source != 'string') {
|
||||
// juggle arguments
|
||||
if (typeof source == 'object' && source) {
|
||||
options = source || options;
|
||||
source = options.source || '';
|
||||
}
|
||||
// create the destination directory if it doesn't exist
|
||||
if (!fs.existsSync(distPath)) {
|
||||
// avoid errors when called as a npm executable
|
||||
try {
|
||||
fs.mkdirSync(distPath);
|
||||
} catch(e) { }
|
||||
}
|
||||
|
||||
this.compiled = {};
|
||||
this.hybrid = {};
|
||||
this.uglified = {};
|
||||
this.isSilent = !!options.silent;
|
||||
this.onComplete = options.onComplete || function() {};
|
||||
this.workingName = options.workingName || 'temp';
|
||||
this.isSilent = !!options.isSilent;
|
||||
this.isTemplate = !!options.isTemplate;
|
||||
this.outputPath = options.outputPath;
|
||||
|
||||
source = preprocess(source);
|
||||
source = preprocess(source, options);
|
||||
this.source = source;
|
||||
|
||||
this.onComplete = options.onComplete || function(source) {
|
||||
fs.writeFileSync(this.outputPath, source, 'utf8');
|
||||
};
|
||||
|
||||
// begin the minification process
|
||||
closureCompile.call(this, source, onClosureCompile.bind(this));
|
||||
}
|
||||
@@ -117,10 +114,19 @@
|
||||
* @param {Function} callback The function to call once the process completes.
|
||||
*/
|
||||
function closureCompile(source, message, callback) {
|
||||
var options = closureOptions.slice();
|
||||
|
||||
// use simple optimizations when minifying template files
|
||||
if (this.isTemplate) {
|
||||
options = options.map(function(value) {
|
||||
return value.replace(/^(compilation_level)=.+$/, '$1=SIMPLE_OPTIMIZATIONS');
|
||||
});
|
||||
}
|
||||
|
||||
// the standard error stream, standard output stream, and Closure Compiler process
|
||||
var error = '',
|
||||
output = '',
|
||||
compiler = spawn('java', ['-jar', closurePath].concat(closureOptions));
|
||||
compiler = spawn('java', ['-jar', closurePath].concat(options));
|
||||
|
||||
// juggle arguments
|
||||
if (typeof message == 'function') {
|
||||
@@ -130,7 +136,7 @@
|
||||
|
||||
if (!this.isSilent) {
|
||||
console.log(message == null
|
||||
? 'Compressing ' + this.workingName + ' using the Closure Compiler...'
|
||||
? 'Compressing ' + path.basename(this.outputPath, '.js') + ' using the Closure Compiler...'
|
||||
: message
|
||||
);
|
||||
}
|
||||
@@ -183,7 +189,7 @@
|
||||
|
||||
if (!this.isSilent) {
|
||||
console.log(message == null
|
||||
? 'Compressing ' + this.workingName + ' using UglifyJS...'
|
||||
? 'Compressing ' + path.basename(this.outputPath, '.js') + ' using UglifyJS...'
|
||||
: message
|
||||
);
|
||||
}
|
||||
@@ -278,7 +284,7 @@
|
||||
if (!this.isSilent) {
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
}
|
||||
var message = 'Compressing ' + this.workingName + ' using hybrid minification...';
|
||||
var message = 'Compressing ' + path.basename(this.outputPath, '.js') + ' using hybrid minification...';
|
||||
|
||||
// store the gzipped result and report the size
|
||||
this.uglified.gzip = result;
|
||||
@@ -332,24 +338,8 @@
|
||||
function onComplete() {
|
||||
var compiled = this.compiled,
|
||||
hybrid = this.hybrid,
|
||||
name = this.workingName,
|
||||
uglified = this.uglified;
|
||||
|
||||
// avoid errors when called as a npm executable
|
||||
try {
|
||||
// save the Closure Compiled version to disk
|
||||
fs.writeFileSync(path.join(distPath, name + '.compiler.js'), compiled.source);
|
||||
fs.writeFileSync(path.join(distPath, name + '.compiler.js.gz'), compiled.gzip);
|
||||
|
||||
// save the Uglified version to disk
|
||||
fs.writeFileSync(path.join(distPath, name + '.uglify.js'), uglified.source);
|
||||
fs.writeFileSync(path.join(distPath, name + '.uglify.js.gz'), uglified.gzip);
|
||||
|
||||
// save the hybrid minified version to disk
|
||||
fs.writeFileSync(path.join(distPath, name + '.hybrid.js'), hybrid.source);
|
||||
fs.writeFileSync(path.join(distPath, name + '.hybrid.js.gz'), hybrid.gzip);
|
||||
} catch(e) { }
|
||||
|
||||
// select the smallest gzipped file and use its minified counterpart as the
|
||||
// official minified release (ties go to Closure Compiler)
|
||||
var min = Math.min(compiled.gzip.length, hybrid.gzip.length, uglified.gzip.length);
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
'lodash':
|
||||
'/*!\n' +
|
||||
' Lo-Dash @VERSION lodash.com/license\n' +
|
||||
' Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE\n' +
|
||||
' Underscore.js 1.4.1 underscorejs.org/LICENSE\n' +
|
||||
'*/',
|
||||
'underscore':
|
||||
'/*! Underscore.js @VERSION github.com/documentcloud/underscore/blob/master/LICENSE */'
|
||||
'/*! Underscore.js @VERSION underscorejs.org/LICENSE */'
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -27,7 +27,7 @@
|
||||
*/
|
||||
function postprocess(source) {
|
||||
// move vars exposed by Closure Compiler into the IIFE
|
||||
source = source.replace(/^([^(\n]+)\s*(\(function[^)]+\){)/, '$2$1');
|
||||
source = source.replace(/^((?:(['"])use strict\2;)?(?:var (?:[a-z]+=(?:!0|!1|null)[,;])+)?)([\s\S]*?function[^)]+\){)/, '$3$1');
|
||||
|
||||
// unescape properties (i.e. foo["bar"] => foo.bar)
|
||||
source = source.replace(/(\w)\["([^."]+)"\]/g, function(match, left, right) {
|
||||
@@ -56,13 +56,20 @@
|
||||
// expose `postprocess`
|
||||
if (module != require.main) {
|
||||
module.exports = postprocess;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// read the Lo-Dash source file from the first argument if the script
|
||||
// was invoked directly (e.g. `node post-compile.js source.js`) and write to
|
||||
// the same file
|
||||
(function() {
|
||||
var source = fs.readFileSync(process.argv[2], 'utf8');
|
||||
fs.writeFileSync(process.argv[2], postprocess(source), 'utf8');
|
||||
var options = process.argv;
|
||||
if (options.length < 3) {
|
||||
return;
|
||||
}
|
||||
var filePath = options[options.length - 1],
|
||||
source = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
fs.writeFileSync(filePath, postprocess(source), 'utf8');
|
||||
}());
|
||||
}
|
||||
}());
|
||||
|
||||
@@ -12,12 +12,11 @@
|
||||
'callback',
|
||||
'collection',
|
||||
'concat',
|
||||
'createCallback',
|
||||
'ctor',
|
||||
'hasOwnProperty',
|
||||
'identity',
|
||||
'index',
|
||||
'iteratee',
|
||||
'iteratorBind',
|
||||
'length',
|
||||
'nativeKeys',
|
||||
'object',
|
||||
@@ -33,6 +32,7 @@
|
||||
'stringClass',
|
||||
'thisArg',
|
||||
'toString',
|
||||
'undefined',
|
||||
'value',
|
||||
|
||||
// lesser used variables
|
||||
@@ -44,7 +44,6 @@
|
||||
'callee',
|
||||
'className',
|
||||
'compareAscending',
|
||||
'data',
|
||||
'forIn',
|
||||
'found',
|
||||
'funcs',
|
||||
@@ -58,19 +57,18 @@
|
||||
'isPlainObject',
|
||||
'methodName',
|
||||
'noaccum',
|
||||
'noop',
|
||||
'objectClass',
|
||||
'objectTypes',
|
||||
'pass',
|
||||
'properties',
|
||||
'property',
|
||||
'propsLength',
|
||||
'recursive',
|
||||
'source',
|
||||
'sources',
|
||||
'stackA',
|
||||
'stackB',
|
||||
'stackLength',
|
||||
'target',
|
||||
'valueProp',
|
||||
'values'
|
||||
'target'
|
||||
];
|
||||
|
||||
/** Used to minify `compileIterator` option properties */
|
||||
@@ -80,7 +78,6 @@
|
||||
'arrayBranch',
|
||||
'beforeLoop',
|
||||
'bottom',
|
||||
'exit',
|
||||
'firstArg',
|
||||
'hasDontEnumBug',
|
||||
'inLoop',
|
||||
@@ -106,7 +103,6 @@
|
||||
var propWhitelist = [
|
||||
'_',
|
||||
'__chain__',
|
||||
'__proto__',
|
||||
'__wrapped__',
|
||||
'after',
|
||||
'all',
|
||||
@@ -118,7 +114,6 @@
|
||||
'chain',
|
||||
'clearTimeout',
|
||||
'clone',
|
||||
'clones',
|
||||
'collect',
|
||||
'compact',
|
||||
'compose',
|
||||
@@ -177,12 +172,14 @@
|
||||
'isNull',
|
||||
'isNumber',
|
||||
'isObject',
|
||||
'isPlainObject',
|
||||
'isRegExp',
|
||||
'isString',
|
||||
'isUndefined',
|
||||
'keys',
|
||||
'last',
|
||||
'lastIndexOf',
|
||||
'lateBind',
|
||||
'map',
|
||||
'max',
|
||||
'memoize',
|
||||
@@ -214,13 +211,11 @@
|
||||
'sortBy',
|
||||
'sortedIndex',
|
||||
'source',
|
||||
'sources',
|
||||
'stackA',
|
||||
'stackB',
|
||||
'tail',
|
||||
'take',
|
||||
'tap',
|
||||
'template',
|
||||
'templates',
|
||||
'templateSettings',
|
||||
'throttle',
|
||||
'times',
|
||||
@@ -249,16 +244,24 @@
|
||||
/**
|
||||
* Pre-process a given Lo-Dash `source`, preparing it for minification.
|
||||
*
|
||||
* @param {String} source The source to process.
|
||||
* @param {String} [source=''] The source to process.
|
||||
* @param {Object} [options={}] The options object.
|
||||
* @returns {String} Returns the processed source.
|
||||
*/
|
||||
function preprocess(source) {
|
||||
// remove copyright to add later in post-compile.js
|
||||
source = source.replace(/\/\*![\s\S]+?\*\//, '');
|
||||
function preprocess(source, options) {
|
||||
source || (source = '');
|
||||
options || (options = {});
|
||||
|
||||
// remove unrecognized JSDoc tags so Closure Compiler won't complain
|
||||
source = source.replace(/@(?:alias|category)\b.*/g, '');
|
||||
|
||||
if (options.isTemplate) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// remove copyright to add later in post-compile.js
|
||||
source = source.replace(/\/\*![\s\S]+?\*\//, '');
|
||||
|
||||
// add brackets to whitelisted properties so Closure Compiler won't mung them
|
||||
// http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
|
||||
source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']");
|
||||
@@ -278,7 +281,7 @@
|
||||
// remove whitespace from string literals
|
||||
source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) {
|
||||
// avoids removing the '\n' of the `stringEscapes` object
|
||||
return string.replace(/\[object |delete |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) {
|
||||
return string.replace(/\[object |delete |else |function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) {
|
||||
return match == false || match == '\\n' ? '' : match;
|
||||
});
|
||||
});
|
||||
@@ -287,7 +290,7 @@
|
||||
source = source.replace(/\+"__p\+='"/g, '+"\\n__p+=\'"');
|
||||
|
||||
// remove whitespace from `_.template` related regexes
|
||||
source = source.replace(/(?:reDelimiterCode\w+|reEmptyString\w+|reInsertVariable) *=.+/g, function(match) {
|
||||
source = source.replace(/(?:reEmptyString\w+|reInsertVariable) *=.+/g, function(match) {
|
||||
return match.replace(/ |\\n/g, '');
|
||||
});
|
||||
|
||||
@@ -303,12 +306,12 @@
|
||||
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *try *\{(?:\s*\/\/.*)*\n *var useSourceURL[\s\S]+?catch[^}]+}\n/, '');
|
||||
|
||||
// remove debug sourceURL use in `_.template`
|
||||
source = source.replace(/(?:\s*\/\/.*\n)* *if *\(useSourceURL[^}]+}/, '');
|
||||
source = source.replace(/(?:\s*\/\/.*\n)* *var sourceURL[^;]+;|\+ *sourceURL/g, '');
|
||||
|
||||
// minify internal properties used by 'compareAscending', `_.clone`, `_.isEqual`, `_.merge`, and `_.sortBy`
|
||||
// minify internal properties used by 'compareAscending', `_.merge`, and `_.sortBy`
|
||||
(function() {
|
||||
var properties = ['clones', 'criteria', 'index', 'sources', 'thorough', 'value', 'values'],
|
||||
snippets = source.match(/( +)(?:function (?:clone|compareAscending|isEqual)|var merge|var sortBy)\b[\s\S]+?\n\1}/g);
|
||||
var properties = ['criteria', 'index', 'value'],
|
||||
snippets = source.match(/( +)(?:function compareAscending|var merge|var sortBy)\b[\s\S]+?\n\1}/g);
|
||||
|
||||
if (!snippets) {
|
||||
return;
|
||||
@@ -443,8 +446,17 @@
|
||||
// was invoked directly (e.g. `node pre-compile.js source.js`) and write to
|
||||
// the same file
|
||||
(function() {
|
||||
var source = fs.readFileSync(process.argv[2], 'utf8');
|
||||
fs.writeFileSync(process.argv[2], preprocess(source), 'utf8');
|
||||
var options = process.argv;
|
||||
if (options.length < 3) {
|
||||
return;
|
||||
}
|
||||
var filePath = options[options.length - 1],
|
||||
isTemplate = options.indexOf('-t') > -1 || options.indexOf('--template') > -1,
|
||||
source = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
fs.writeFileSync(filePath, preprocess(source, {
|
||||
'isTemplate': isTemplate
|
||||
}), 'utf8');
|
||||
}());
|
||||
}
|
||||
}());
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "lodash",
|
||||
"version": "0.7.0",
|
||||
"description": "A drop-in replacement for Underscore.js delivering performance, bug fixes, and additional features.",
|
||||
"homepage": "http://lodash.com",
|
||||
"main": [
|
||||
"./lodash.js",
|
||||
"./lodash.min.js"
|
||||
],
|
||||
"keywords": [
|
||||
"browser",
|
||||
"client",
|
||||
"functional",
|
||||
"performance",
|
||||
"server",
|
||||
"speed",
|
||||
"util"
|
||||
],
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "http://lodash.com/license"
|
||||
}
|
||||
],
|
||||
"author": {
|
||||
"name": "John-David Dalton",
|
||||
"email": "john.david.dalton@gmail.com",
|
||||
"web": "http://allyoucanleet.com/"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bestiejs/lodash.git"
|
||||
}
|
||||
}
|
||||
548
doc/README.md
548
doc/README.md
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@
|
||||
// generate Markdown
|
||||
$markdown = docdown(array(
|
||||
'path' => '../' . $file,
|
||||
'title' => 'Lo-Dash <sup>v0.7.0</sup>',
|
||||
'title' => 'Lo-Dash <sup>v0.8.1</sup>',
|
||||
'url' => 'https://github.com/bestiejs/lodash/blob/master/lodash.js'
|
||||
));
|
||||
|
||||
|
||||
77
lodash.min.js
vendored
77
lodash.min.js
vendored
@@ -1,42 +1,39 @@
|
||||
/*!
|
||||
Lo-Dash 0.7.0 lodash.com/license
|
||||
Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE
|
||||
Lo-Dash 0.8.1 lodash.com/license
|
||||
Underscore.js 1.4.1 underscorejs.org/LICENSE
|
||||
*/
|
||||
;(function(e,t){function s(e){return new o(e)}function o(e){if(e&&e.__wrapped__)return e;this.__wrapped__=e}function u(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||V),s=i?{}:e;if(i)for(var o=t-1;++o<r;)n=e[o]+"",(lt.call(s,n)?s[n]:s[n]=[]).push(e[o]);return function(e){if(i){var n=e+"";return lt.call(s,n)&&-1<k(s[n],e)}return-1<k(s,e,t)}}function a(){for(var e,t,n,s=-1,o=arguments.length,u={e:"",f:"",j:"",q:"",c:{d:""},m:{d:""}};++s<o;)for(t in e=arguments[s],e)n=(n=e[t])==r?"":n,/d|i/.test(t)?("string"==typeof
|
||||
n&&(n={b:n,l:n}),u.c[t]=n.b||"",u.m[t]=n.l||""):u[t]=n;e=u.a,t=/^[^,]+/.exec(e)[0],n=u.s,u.g=t,u.h=Dt,u.k=zt,u.n=Bt,u.p=st,u.r=u.r!==i,u.s=n==r?Wt:n,u.o==r&&(u.o=It),u.f||(u.f="if(!"+t+")return u");if("d"!=t||!u.c.i)u.c=r;t="",u.s&&(t+="'use strict';"),t+="var i,A,j="+u.g+",u",u.j&&(t+="="+u.j),t+=";"+u.f+";"+u.q+";",u.c&&(t+="var l=j.length;i=-1;",u.m&&(t+="if(l>-1&&l===l>>>0){"),u.o&&(t+="if(z.call(j)==x){j=j.split('')}"),t+=u.c.d+";while(++i<l){A=j[i];"+u.c.i+"}",u.m&&(t+="}"));if(u.m){u.c?t+="else{"
|
||||
:u.n&&(t+="var l=j.length;i=-1;if(l&&P(j)){while(++i<l){A=j[i+=''];"+u.m.i+"}}else{"),u.h||(t+="var v=typeof j=='function'&&r.call(j,'prototype');");if(u.k&&u.r)t+="var o=-1,p=Y[typeof j]?m(j):[],l=p.length;"+u.m.d+";while(++o<l){i=p[o];",u.h||(t+="if(!(v&&i=='prototype')){"),t+="A=j[i];"+u.m.i+"",u.h||(t+="}");else{t+=u.m.d+";for(i in j){";if(!u.h||u.r)t+="if(",u.h||(t+="!(v&&i=='prototype')"),!u.h&&u.r&&(t+="&&"),u.r&&(t+="g.call(j,i)"),t+="){";t+="A=j[i];"+u.m.i+";";if(!u.h||u.r)t+="}"}t+="}";
|
||||
if(u.h){t+="var f=j.constructor;";for(n=0;7>n;n++)t+="i='"+u.p[n]+"';if(","constructor"==u.p[n]&&(t+="!(f&&f.prototype===j)&&"),t+="g.call(j,i)){A=j[i];"+u.m.i+"}"}if(u.c||u.n)t+="}"}return t+=u.e+";return u",Function("D,E,F,I,e,K,g,h,N,P,R,T,U,k,X,Y,m,r,w,x,z","var G=function("+e+"){"+t+"};return G")(Xt,q,_,f,ft,hn,lt,D,k,b,un,w,an,p,Lt,Kt,bt,ht,pt,Ot,dt)}function f(e,n){var r=e.c,i=n.c,e=e.b,n=n.b;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<i?-1:1}function l(e,t){return at[
|
||||
t]}function c(e){return"\\"+Qt[e]}function h(e){return $t[e]}function p(e,t){return function(n,r,i){return e.call(t,n,r,i)}}function d(){}function v(e,t){if(e&&J.test(t))return"<e%-"+t+"%>";var n=at.length;return at[n]="'+__e("+t+")+'",ot+n+ut}function m(e,t,n,i){return i?(e=at.length,at[e]="';"+i+";__p+='",ot+e+ut):t?v(r,t):g(r,n)}function g(e,t){if(e&&J.test(t))return"<e%="+t+"%>";var n=at.length;return at[n]="'+((__t=("+t+"))==null?'':__t)+'",ot+n+ut}function y(e){return Jt[e]}function b(e){return dt
|
||||
.call(e)==xt}function w(e){return"function"==typeof e}function E(e,t){var n=i;if(!e||"object"!=typeof e||!t&&b(e))return n;var r=e.constructor;return(!qt||"function"==typeof e.toString||"string"!=typeof (e+""))&&(!w(r)||r instanceof r)?Ht?(hn(e,function(e,t,r){return n=!lt.call(r,t),i}),n===i):(hn(e,function(e,t){n=t}),n===i||lt.call(e,n)):n}function S(e,t,s,o){if(e==r)return e;s&&(t=i),o||(o={e:r}),o.t==r&&(o.t=!(!R.clone&&!z.clone&&!W.clone));if(((s=Kt[typeof e])||o.t)&&e.clone&&w(e.clone))return o
|
||||
.t=r,e.clone(t);if(s){var u=dt.call(e);if(!Vt[u]||jt&&b(e))return e;var a=u==Tt,s=a||(u==Lt?an(e,n):s)}if(!s||!t)return s?a?pt.call(e):cn({},e):e;s=e.constructor;switch(u){case Nt:return new s(e==n);case Ct:return new s(+e);case kt:case Ot:return new s(e);case At:return s(e.source,Z.exec(e))}for(var f=o.a||(o.a=[]),l=o.d||(o.d=[]),u=f.length;u--;)if(l[u]==e)return f[u];var c=a?s(u=e.length):{};f.push(c),l.push(e);if(a)for(a=-1;++a<u;)c[a]=S(e[a],t,r,o);else pn(e,function(e,n){c[n]=S(e,t,r,o)});return c
|
||||
}function x(e,t,s){if(e==r||t==r)return e===t;s||(s={e:r}),s.t==r&&(s.t=!(!R.isEqual&&!z.isEqual&&!W.isEqual));if(Kt[typeof e]||Kt[typeof t]||s.t){e=e.__wrapped__||e,t=t.__wrapped__||t;if(e.isEqual&&w(e.isEqual))return s.t=r,e.isEqual(t);if(t.isEqual&&w(t.isEqual))return s.t=r,t.isEqual(e)}if(e===t)return 0!==e||1/e==1/t;var o=dt.call(e);if(o!=dt.call(t))return i;switch(o){case Nt:case Ct:return+e==+t;case kt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case At:case Ot:return e==t+""}var u=Xt[o];if(jt&&!
|
||||
u&&(u=b(e))&&!b(t)||!u&&(o!=Lt||qt&&("function"!=typeof e.toString&&"string"==typeof (e+"")||"function"!=typeof t.toString&&"string"==typeof (t+""))))return i;for(var a=s.stackA||(s.stackA=[]),f=s.stackB||(s.stackB=[]),o=a.length;o--;)if(a[o]==e)return f[o]==t;var o=-1,l=n,c=0;a.push(e),f.push(t);if(u){c=e.length;if(l=c==t.length)for(;c--&&(l=x(e[c],t[c],s)););return l}u=e.constructor,a=t.constructor;if(u!=a&&(!w(u)||!(u instanceof u&&w(a)&&a instanceof a)))return i;for(var h in e)if(lt.call(e,h)&&
|
||||
(c++,!lt.call(t,h)||!x(e[h],t[h],s)))return i;for(h in t)if(lt.call(t,h)&&!(c--))return i;if(Dt)for(;7>++o;)if(h=st[o],lt.call(e,h)&&(!lt.call(t,h)||!x(e[h],t[h],s)))return i;return n}function T(e,t,n,r){if(!e)return n;var i=e.length,s=3>arguments.length;r&&(t=p(t,r));if(-1<i&&i===i>>>0){var o=It&&dt.call(e)==Ot?e.split(""):e;for(i&&s&&(n=o[--i]);i--;)n=t(n,o[i],i,e);return n}o=gn(e);for((i=o.length)&&s&&(n=e[o[--i]]);i--;)s=o[i],n=t(n,e[s],s,e);return n}function N(e,t,n){if(e)return t==r||n?e[0]
|
||||
:pt.call(e,0,t)}function C(e,t){var n=[];if(!e)return n;for(var r,i=-1,s=e.length;++i<s;)r=e[i],un(r)?ct.apply(n,t?r:C(r)):n.push(r);return n}function k(e,t,n){if(!e)return-1;var r=-1,i=e.length;if(n){if("number"!=typeof n)return r=O(e,t),e[r]===t?r:-1;r=(0>n?wt(0,i+n):n)-1}for(;++r<i;)if(e[r]===t)return r;return-1}function L(e,t,n){var r=-Infinity,i=r;if(!e)return i;var s=-1,o=e.length;if(!t){for(;++s<o;)e[s]>i&&(i=e[s]);return i}for(n&&(t=p(t,n));++s<o;)n=t(e[s],s,e),n>r&&(r=n,i=e[s]);return i}
|
||||
function A(e,t,n){return e?pt.call(e,t==r||n?1:t):[]}function O(e,t,n,r){if(!e)return 0;var i=0,s=e.length;if(n){r&&(n=_(n,r));for(t=n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r}else for(;i<s;)r=i+s>>>1,e[r]<t?i=r+1:s=r;return i}function M(e,t,n,r){var s=[];if(!e)return s;var o=-1,u=e.length,a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n?r&&(n=p(n,r)):n=D;++o<u;)if(r=n(e[o],o,e),t?!o||a[a.length-1]!==r:0>k(a,r))a.push(r),s.push(e[o]);return s}function _(e,t){function n(){var o=arguments,u=t;return i||
|
||||
(e=t[r]),s.length&&(o=o.length?s.concat(pt.call(o)):s),this instanceof n?(d.prototype=e.prototype,u=new d,(o=e.apply(u,o))&&Kt[typeof o]?o:u):e.apply(u,o)}var r,i=w(e);if(i){if(Ut||vt&&2<arguments.length)return vt.call.apply(vt,arguments)}else r=t,t=e;var s=pt.call(arguments,2);return n}function D(e){return e}function P(e){Ln(dn(e),function(t){var r=s[t]=e[t];o.prototype[t]=function(){var e=[this.__wrapped__];return arguments.length&&ct.apply(e,arguments),e=r.apply(s,e),this.__chain__&&(e=new o(e
|
||||
),e.__chain__=n),e}})}var n=!0,r=null,i=!1,H,B,j,F,I="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),q=Array.prototype,R=Boolean.prototype,U=Object.prototype,z=Number.prototype,W=String.prototype,X=0,V=30,$=e._,J=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,K=/&(?:amp|lt|gt|quot|#x27);/g,Q=/\b__p\+='';/g,G=/\b(__p\+=)''\+/g,Y=/(__e\(.*?\)|\b__t\))\+'';/g,Z=/\w*$/,et=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,tt=
|
||||
RegExp("^"+(U.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),nt=/__token(\d+)__/g,rt=/[&<>"']/g,it=/['\n\r\t\u2028\u2029\\]/g,st="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),ot="__token",ut="__",at=[],ft=q.concat,lt=U.hasOwnProperty,ct=q.push,ht=U.propertyIsEnumerable,pt=q.slice,dt=U.toString,vt=tt.test(vt=pt.bind)&&vt,mt=Math.floor,gt=tt.test(gt=Array.isArray)&>,yt=e.isFinite,bt=tt.test
|
||||
(bt=Object.keys)&&bt,wt=Math.max,Et=Math.min,St=Math.random,xt="[object Arguments]",Tt="[object Array]",Nt="[object Boolean]",Ct="[object Date]",kt="[object Number]",Lt="[object Object]",At="[object RegExp]",Ot="[object String]",Mt=e.clearTimeout,_t=e.setTimeout,Dt,Pt,Ht,Bt=n;(function(){function e(){this.x=1}var t={0:1,length:1},n=[];e.prototype={valueOf:1,y:1};for(var r in new e)n.push(r);for(r in arguments)Bt=!r;Dt=4>(n+"").length,Ht="x"!=n[0],Pt=(n.splice.call(t,0,1),t[0])})(1);var jt=!b(arguments
|
||||
),Ft="x"!=pt.call("x")[0],It="xx"!="x"[0]+Object("x")[0];try{var qt=("[object Object]",dt.call(e.document||0)==Lt)}catch(Rt){}var Ut=vt&&/\n|Opera/.test(vt+dt.call(e.opera)),zt=bt&&/^.+$|true/.test(bt+!!e.attachEvent),Wt=!Ut,Xt={};Xt[Nt]=Xt[Ct]=Xt["[object Function]"]=Xt[kt]=Xt[Lt]=Xt[At]=i,Xt[xt]=Xt[Tt]=Xt[Ot]=n;var Vt={};Vt[xt]=Vt["[object Function]"]=i,Vt[Tt]=Vt[Nt]=Vt[Ct]=Vt[kt]=Vt[Lt]=Vt[At]=Vt[Ot]=n;var $t={"&":"&","<":"<",">":">",'"':""","'":"'"},Jt={"&":"&","<":"<"
|
||||
,">":">",""":'"',"'":"'"},Kt={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},Qt={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};s.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""};var Gt={a:"d,c,y",j:"d",q:"if(!c)c=h;else if(y)c=k(c,y)",i:"if(c(A,i,d)===false)return u"},Yt={j:"{}",q:"var q;if(typeof c!='function'){var ii=c;c=function(A){return A[ii]}}else if(y)c=k(c,y)"
|
||||
,i:"q=c(A,i,d);(g.call(u,q)?u[q]++:u[q]=1)"},Zt={j:"true",i:"if(!c(A,i,d))return!u"},en={r:i,s:i,a:"n",j:"n",q:"for(var a=1,b=arguments.length;a<b;a++){if(j=arguments[a]){",i:"u[i]=A",e:"}}"},tn={j:"[]",i:"c(A,i,d)&&u.push(A)"},nn={q:"if(y)c=k(c,y)"},rn={i:{l:Gt.i}},sn={j:"",f:"if(!d)return[]",d:{b:"u=Array(l)",l:"u="+(zt?"Array(l)":"[]")},i:{b:"u[i]=c(A,i,d)",l:"u"+(zt?"[o]=":".push")+"(c(A,i,d))"}},on={r:i,a:"n,c,y",j:"{}",q:"var S=typeof c=='function';if(!S){var t=e.apply(E,arguments)}else if(y)c=k(c,y)"
|
||||
,i:"if(S?!c(A,i,n):N(t,i)<0)u[i]=A"};jt&&(b=function(e){return!!e&&!!lt.call(e,"callee")});var un=gt||function(e){return dt.call(e)==Tt};w(/x/)&&(w=function(e){return"[object Function]"==dt.call(e)});var an=Kt.__proto__!=U?E:function(e,t){if(!e)return i;var n=e.valueOf,r="function"==typeof n&&(r=n.__proto__)&&r.__proto__;return r?e==r||e.__proto__==r&&(t||!b(e)):E(e)},fn=a({a:"n",j:"[]",i:"u.push(i)"}),ln=a(en,{i:"if(u[i]==null)"+en.i}),cn=a(en),hn=a(Gt,nn,rn,{r:i}),pn=a(Gt,nn,rn),dn=a({r:i,a:"n"
|
||||
,j:"[]",i:"if(T(A))u.push(i)",e:"u.sort()"}),vn=a({a:"n",j:"{}",i:"u[A]=i"}),mn=a({a:"A",j:"true",q:"var H=z.call(A),l=A.length;if(D[H]"+(jt?"||P(A)":"")+"||(H==X&&l>-1&&l===l>>>0&&T(A.splice)))return!l",i:{l:"return false"}}),gn=bt?function(e){var t=typeof e;return"function"==t&&ht.call(e,"prototype")?fn(e):e&&Kt[t]?bt(e):[]}:fn,yn=a(en,{a:"n,ee,O",q:"var Q,dd=O==U,J=dd?arguments[3]:{g:[],d:[]};for(var a=1,b=dd?2:arguments.length;a<b;a++){if(j=arguments[a]){",i:"if((ee=A)&&((Q=R(ee))||U(ee))){var L=false,jj=J.g,ff=J.d,gg=ff.length;while(gg--)if(L=ff[gg]==ee)break;if(L){u[i]=jj[gg]}else{jj.push(A=(A=u[i])&&Q?(R(A)?A:[]):(U(A)?A:{}));ff.push(ee);u[i]=G(A,ee,U,J)}}else if(ee!=null)u[i]=ee"
|
||||
}),bn=a(on),wn=a({a:"n",j:"[]",i:"u"+(zt?"[o]=":".push")+"([i,A])"}),En=a(on,{q:"if(typeof c!='function'){var q,t=e.apply(E,arguments),l=t.length;for(i=1;i<l;i++){q=t[i];if(q in n)u[q]=n[q]}}else{if(y)c=k(c,y)",i:"if(c(A,i,n))u[i]=A",e:"}"}),Sn=a({a:"n",j:"[]",i:"u.push(A)"}),xn=a({a:"d,hh",j:"false",o:i,d:{b:"if(z.call(d)==x)return d.indexOf(hh)>-1"},i:"if(A===hh)return true"}),Tn=a(Gt,Yt),Nn=a(Gt,Zt),Cn=a(Gt,tn),kn=a(Gt,nn,{j:"",i:"if(c(A,i,d))return A"}),Ln=a(Gt,nn),An=a(Gt,Yt,{i:"q=c(A,i,d);(g.call(u,q)?u[q]:u[q]=[]).push(A)"
|
||||
}),On=a(sn,{a:"d,V",q:"var C=w.call(arguments,2),S=typeof V=='function'",i:{b:"u[i]=(S?V:A[V]).apply(A,C)",l:"u"+(zt?"[o]=":".push")+"((S?V:A[V]).apply(A,C))"}}),Mn=a(Gt,sn),_n=a(sn,{a:"d,bb",i:{b:"u[i]=A[bb]",l:"u"+(zt?"[o]=":".push")+"(A[bb])"}}),Dn=a({a:"d,c,B,y",j:"B",q:"var W=arguments.length<3;if(y)c=k(c,y)",d:{b:"if(W)u=j[++i]"},i:{b:"u=c(u,A,i,d)",l:"u=W?(W=false,A):c(u,A,i,d)"}}),Pn=a(Gt,tn,{i:"!"+tn.i}),Hn=a(Gt,Zt,{j:"false",i:Zt.i.replace("!","")}),Bn=a(Gt,Yt,sn,{i:{b:"u[i]={b:c(A,i,d),c:i,f:A}"
|
||||
,l:"u"+(zt?"[o]=":".push")+"({b:c(A,i,d),c:i,f:A})"},e:"u.sort(I);l=u.length;while(l--)u[l]=u[l].f"}),jn=a(tn,{a:"d,aa",q:"var t=[];K(aa,function(A,q){t.push(q)});var cc=t.length",i:"for(var q,Z=true,s=0;s<cc;s++){q=t[s];if(!(Z=A[q]===aa[q]))break}Z&&u.push(A)"}),Fn=a({r:i,s:i,a:"n",j:"n",q:"var M=arguments,l=M.length;if(l>1){for(var i=1;i<l;i++)u[M[i]]=F(u[M[i]],u);return u}",i:"if(T(u[i]))u[i]=F(u[i],u)"});s.VERSION="0.7.0",s.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply
|
||||
(this,arguments)}},s.bind=_,s.bindAll=Fn,s.chain=function(e){return e=new o(e),e.__chain__=n,e},s.clone=S,s.compact=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length;++n<r;)e[n]&&t.push(e[n]);return t},s.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},s.contains=xn,s.countBy=Tn,s.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,Mt
|
||||
(a),a=_t(i,t),r&&(o=e.apply(u,s)),o}},s.defaults=ln,s.defer=function(e){var n=pt.call(arguments,1);return _t(function(){return e.apply(t,n)},1)},s.delay=function(e,n){var r=pt.call(arguments,2);return _t(function(){return e.apply(t,r)},n)},s.difference=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length,i=ft.apply(t,arguments),i=u(i,r);++n<r;)i(e[n])||t.push(e[n]);return t},s.escape=function(e){return e==r?"":(e+"").replace(rt,h)},s.every=Nn,s.extend=cn,s.filter=Cn,s.find=kn,s.first=N,s.flatten=
|
||||
C,s.forEach=Ln,s.forIn=hn,s.forOwn=pn,s.functions=dn,s.groupBy=An,s.has=function(e,t){return e?lt.call(e,t):i},s.identity=D,s.indexOf=k,s.initial=function(e,t,n){return e?pt.call(e,0,-(t==r||n?1:t)):[]},s.intersection=function(e){var t=[];if(!e)return t;var n,r=arguments.length,i=[],s=-1,o=e.length;e:for(;++s<o;)if(n=e[s],0>k(t,n)){for(var a=1;a<r;a++)if(!(i[a]||(i[a]=u(arguments[a])))(n))continue e;t.push(n)}return t},s.invert=vn,s.invoke=On,s.isArguments=b,s.isArray=un,s.isBoolean=function(e){return e===
|
||||
n||e===i||dt.call(e)==Nt},s.isElement=function(e){return e?1===e.nodeType:i},s.isEmpty=mn,s.isEqual=x,s.isFinite=function(e){return yt(e)&&dt.call(e)==kt},s.isFunction=w,s.isNaN=function(e){return dt.call(e)==kt&&e!=+e},s.isNull=function(e){return e===r},s.isObject=function(e){return e?Kt[typeof e]:i},s.isUndefined=function(e){return e===t},s.keys=gn,s.last=function(e,t,n){if(e){var i=e.length;return t==r||n?e[i-1]:pt.call(e,-t||i)}},s.lastIndexOf=function(e,t,n){if(!e)return-1;var r=e.length;for(
|
||||
n&&"number"==typeof n&&(r=(0>n?wt(0,r+n):Et(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},s.map=Mn,s.max=L,s.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return lt.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},s.merge=yn,s.min=function(e,t,n){var r=Infinity,i=r;if(!e)return i;var s=-1,o=e.length;if(!t){for(;++s<o;)e[s]<i&&(i=e[s]);return i}for(n&&(t=p(t,n));++s<o;)n=t(e[s],s,e),n<r&&(r=n,i=e[s]);return i},s.mixin=P,s.noConflict=function(){return e
|
||||
._=$,this},s.object=function(e,t){if(!e)return{};for(var n=-1,r=e.length,i={};++n<r;)t?i[e[n]]=t[n]:i[e[n][0]]=e[n][1];return i},s.omit=bn,s.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},s.pairs=wn,s.partial=function(e){var t=pt.call(arguments,1),n=t.length;return function(){var r;return r=arguments,r.length&&(t.length=n,ct.apply(t,r)),r=1==t.length?e.call(this,t[0]):e.apply(this,t),t.length=n,r}},s.pick=En,s.pluck=_n,s.random=function(e,t){return e==
|
||||
r&&t==r?St():(e=+e||0,t==r&&(t=e,e=0),e+mt(St()*((+t||0)-e+1)))},s.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=wt(0,Math.ceil((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},s.reduce=Dn,s.reduceRight=T,s.reject=Pn,s.rest=A,s.result=function(e,t){if(!e)return r;var n=e[t];return w(n)?e[t]():n},s.shuffle=function(e){if(!e)return[];for(var t,n=-1,r=e.length,i=Array(r);++n<r;)t=mt(St()*(n+1)),i[n]=i[t],i[t]=e[n];return i},s.size=function(e){if(!e)return 0;var t=e.length;return-1<
|
||||
t&&t===t>>>0?t:gn(e).length},s.some=Hn,s.sortBy=Bn,s.sortedIndex=O,s.tap=function(e,t){return t(e),e},s.template=function(e,t,n){n||(n={});var e=e+"",o,u;o=n.escape;var a=n.evaluate,f=n.interpolate,h=s.templateSettings,p=n=n.variable||h.variable;o==r&&(o=h.escape),a==r&&(a=h.evaluate||i),f==r&&(f=h.interpolate),o&&(e=e.replace(o,v)),f&&(e=e.replace(f,g)),a!=H&&(H=a,F=RegExp("<e%-([\\s\\S]+?)%>|<e%=([\\s\\S]+?)%>"+(a?"|"+a.source:""),"g")),o=at.length,e=e.replace(F,m),o=o!=at.length,e="__p += '"+e
|
||||
.replace(it,c).replace(nt,l)+"';",at.length=0,p||(n=B||"obj",o?e="with("+n+"){"+e+"}":(n!=B&&(B=n,j=RegExp("(\\(\\s*)"+n+"\\."+n+"\\b","g")),e=e.replace(et,"$&"+n+".").replace(j,"$1__d"))),e=(o?e.replace(Q,""):e).replace(G,"$1").replace(Y,"$1;"),e="function("+n+"){"+(p?"":n+"||("+n+"={});")+"var __t,__p='',__e=_.escape"+(o?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(p?"":",__d="+n+"."+n+"||"+n)+";")+e+"return __p}";try{u=Function("_","return "+e)(s)}catch(d){throw d
|
||||
.source=e,d}return t?u(t):(u.source=e,u)},s.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function(){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(a=r,s=e.apply(o,i)):u||(u=_t(n,f)),s}},s.times=function(e,t,n){var r=-1;if(n)for(;++r<e;)t.call(n,r);else for(;++r<e;)t(r)},s.toArray=function(e){if(!e)return[];if(e.toArray&&w(e.toArray))return e.toArray();var t=e.length;return-1<t&&t===t>>>0?(Ft?dt.call(e)==Ot:"string"==typeof e)?e.split(""):pt.call
|
||||
(e):Sn(e)},s.unescape=function(e){return e==r?"":(e+"").replace(K,y)},s.union=function(){for(var e=-1,t=[],n=ft.apply(t,arguments),r=n.length;++e<r;)0>k(t,n[e])&&t.push(n[e]);return t},s.uniq=M,s.uniqueId=function(e){var t=X++;return e?e+t:t},s.values=Sn,s.where=jn,s.without=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length,i=u(arguments,1,20);++n<r;)i(e[n])||t.push(e[n]);return t},s.wrap=function(e,t){return function(){var n=[e];return arguments.length&&ct.apply(n,arguments),t.apply(this
|
||||
,n)}},s.zip=function(e){if(!e)return[];for(var t=-1,n=L(_n(arguments,"length")),r=Array(n);++t<n;)r[t]=_n(arguments,t);return r},s.all=Nn,s.any=Hn,s.collect=Mn,s.detect=kn,s.drop=A,s.each=Ln,s.foldl=Dn,s.foldr=T,s.head=N,s.include=xn,s.inject=Dn,s.methods=dn,s.select=Cn,s.tail=A,s.take=N,s.unique=M,Ln({Date:Ct,Number:kt,RegExp:At,String:Ot},function(e,t){s["is"+t]=function(t){return dt.call(t)==e}}),o.prototype=s.prototype,P(s),o.prototype.chain=function(){return this.__chain__=n,this},o.prototype
|
||||
.value=function(){return this.__wrapped__},Ln("pop push reverse shift sort splice unshift".split(" "),function(e){var t=q[e];o.prototype[e]=function(){var e=this.__wrapped__;return t.apply(e,arguments),Pt&&e.length===0&&delete e[0],this.__chain__&&(e=new o(e),e.__chain__=n),e}}),Ln(["concat","join","slice"],function(e){var t=q[e];o.prototype[e]=function(){var e=t.apply(this.__wrapped__,arguments);return this.__chain__&&(e=new o(e),e.__chain__=n),e}}),typeof define=="function"&&typeof define.amd=="object"&&
|
||||
define.amd?(e._=s,define(function(){return s})):I?"object"==typeof module&&module&&module.exports==I?(module.exports=s)._=s:I._=s:e._=s})(this);
|
||||
;(function(e,t){function s(e){if(e&&e.__wrapped__)return e;if(!(this instanceof s))return new s(e);this.__wrapped__=e}function o(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||H),s=i?{}:e;if(i)for(var o=t-1;++o<r;)n=e[o]+"",(Q.call(s,n)?s[n]:s[n]=[]).push(e[o]);return function(e){if(i){var n=e+"";return Q.call(s,n)&&-1<x(s[n],e)}return-1<x(s,e,t)}}function u(e,n){var r=e.b,i=n.b,e=e.a,n=n.a;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<i?-1:1}function a(e,t,n){function r(){var u=arguments
|
||||
,a=s?this:t;return i||(e=t[o]),n.length&&(u=u.length?n.concat(Z.call(u)):n),this instanceof r?(p.prototype=e.prototype,a=new p,(u=e.apply(a,u))&&Pt[typeof u]?u:a):e.apply(a,u)}var i=m(e),s=!n,o=e;return s&&(n=t),r}function f(e,n){return e?"function"!=typeof e?function(t){return t[e]}:n!==t?function(t,r,i){return e.call(n,t,r,i)}:e:A}function l(){for(var e=-1,t=arguments.length,i={e:"",g:wt,j:Ot,m:xt,n:Ct,o:J,p:"",q:n,r:Mt,c:{},l:{}};++e<t;){var s=arguments[e],o;for(o in s){var a=s[o];/d|h/.test(o
|
||||
)?("string"==typeof a&&(a={b:a,k:a}),i.c[o]=a.b,i.l[o]=a.k):i[o]=a}}e=i.a,t=/^[^,]+/.exec(e)[0],s=i.i,i.f=t,i.i=s==r?t:s;if("d"!=t||!i.c.h)i.c=r;t="",i.r&&(t+="'use strict';"),t+="var i,A,j="+i.f+",t",i.i&&(t+="="+i.i),t+=";if(!"+i.f+")return t;"+i.p+";",i.c&&(t+="var k=j.length;i=-1;",i.l&&(t+="if(k===+k){"),i.n&&(t+="if(y.call(j)==w){j=j.split('')}"),t+=i.c.d+";while(++i<k){A=j[i];"+i.c.h+"}",i.l&&(t+="}"));if(i.l){i.c?t+="else {":i.m&&(t+="var k=j.length;i=-1;if(k&&O(j)){while(++i<k){A=j[i+=''];"+
|
||||
i.l.h+"}}else {"),i.g||(t+="var u=typeof j=='function'&&q.call(j,'prototype');");if(i.j&&i.q)t+="var n=-1,o=Y[typeof j]?l(j):[],k=o.length;"+i.l.d+";while(++n<k){i=o[n];",i.g||(t+="if(!(u&&i=='prototype')){"),t+="A=j[i];"+i.l.h+"",i.g||(t+="}");else{t+=i.l.d+";for(i in j){";if(!i.g||i.q)t+="if(",i.g||(t+="!(u&&i=='prototype')"),!i.g&&i.q&&(t+="&&"),i.q&&(t+="h.call(j,i)"),t+="){";t+="A=j[i];"+i.l.h+";";if(!i.g||i.q)t+="}"}t+="}";if(i.g){t+="var g=j.constructor;";for(s=0;7>s;s++)t+="i='"+i.o[s]+"';if("
|
||||
,"constructor"==i.o[s]&&(t+="!(g&&g.prototype===j)&&"),t+="h.call(j,i)){A=j[i];"+i.l.h+"}"}if(i.c||i.m)t+="}"}return t+=i.e+";return t",Function("D,E,F,I,e,f,J,h,M,O,Q,S,T,X,Y,l,q,v,w,y,z","var G=function("+e+"){"+t+"};return G")(_t,_,L,u,K,f,Zt,Q,x,v,Vt,m,$t,vt,Pt,ot,Y,Z,gt,et)}function c(e){return"\\"+Ht[e]}function h(e){return Kt[e]}function p(){}function d(e){return Qt[e]}function v(e){return et.call(e)==lt}function m(e){return"function"==typeof e}function g(e){var t=i;if(!e||"object"!=typeof
|
||||
e||v(e))return t;var n=e.constructor;return(!kt||"function"==typeof e.toString||"string"!=typeof (e+""))&&(!m(n)||n instanceof n)?St?(Zt(e,function(e,n,r){return t=!Q.call(r,n),i}),t===i):(Zt(e,function(e,n){t=n}),t===i||Q.call(e,t)):t}function y(e,t,s,o,u){if(e==r)return e;s&&(t=i);if(s=Pt[typeof e]){var a=et.call(e);if(!Dt[a]||Tt&&v(e))return e;var f=a==ct,s=f||(a==vt?$t(e):s)}if(!s||!t)return s?f?Z.call(e):Yt({},e):e;s=e.constructor;switch(a){case ht:return new s(e==n);case pt:return new s(+e)
|
||||
;case dt:case gt:return new s(e);case mt:return s(e.source,U.exec(e))}o||(o=[]),u||(u=[]);for(a=o.length;a--;)if(o[a]==e)return u[a];var l=f?s(a=e.length):{};o.push(e),u.push(l);if(f)for(f=-1;++f<a;)l[f]=y(e[f],t,r,o,u);else en(e,function(e,n){l[n]=y(e,t,r,o,u)});return l}function b(e,t,s,o){if(e==r||t==r)return e===t;if(e===t)return 0!==e||1/e==1/t;if(Pt[typeof e]||Pt[typeof t])e=e.__wrapped__||e,t=t.__wrapped__||t;var u=et.call(e);if(u!=et.call(t))return i;switch(u){case ht:case pt:return+e==+t
|
||||
;case dt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case mt:case gt:return e==t+""}var a=_t[u];if(Tt&&!a&&(a=v(e))&&!v(t)||!a&&(u!=vt||kt&&("function"!=typeof e.toString&&"string"==typeof (e+"")||"function"!=typeof t.toString&&"string"==typeof (t+""))))return i;s||(s=[]),o||(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var u=-1,f=n,l=0;s.push(e),o.push(t);if(a){l=e.length;if(f=l==t.length)for(;l--&&(f=b(e[l],t[l],s,o)););return f}a=e.constructor,f=t.constructor;if(a!=f&&(!m(a)||!(a instanceof
|
||||
a&&m(f)&&f instanceof f)))return i;for(var c in e)if(Q.call(e,c)&&(l++,!Q.call(t,c)||!b(e[c],t[c],s,o)))return i;for(c in t)if(Q.call(t,c)&&!(l--))return i;if(wt)for(;7>++u;)if(c=J[u],Q.call(e,c)&&(!Q.call(t,c)||!b(e[c],t[c],s,o)))return i;return n}function w(e,t,n,r){var s=e,o=e?e.length:0,u=3>arguments.length;if(o!==+o)var a=rn(e),o=a.length;else Ct&&et.call(e)==gt&&(s=e.split(""));return vn(e,function(e,f,l){f=a?a[--o]:--o,n=u?(u=i,s[f]):t.call(r,n,s[f],f,l)}),n}function E(e,t,n){if(e)return t==
|
||||
r||n?e[0]:Z.call(e,0,t)}function S(e,t){for(var n,r=-1,i=e?e.length:0,s=[];++r<i;)n=e[r],Vt(n)?G.apply(s,t?n:S(n)):s.push(n);return s}function x(e,t,n){var r=-1,i=e?e.length:0;if("number"==typeof n)r=(0>n?ut(0,i+n):n||0)-1;else if(n)return r=C(e,t),e[r]===t?r:-1;for(;++r<i;)if(e[r]===t)return r;return-1}function T(e,t,n){for(var r=-Infinity,i=-1,s=e?e.length:0,o=r,t=f(t,n);++i<s;)n=t(e[i],i,e),n>r&&(r=n,o=e[i]);return o}function N(e,t,n){return e?Z.call(e,t==r||n?1:t):[]}function C(e,t,n,r){for(var i=0
|
||||
,s=e?e.length:i,n=f(n,r),t=n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r;return i}function k(e,t,n,r){var s=-1,o=e?e.length:0,u=[],a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n=f(n,r);++s<o;)if(r=n(e[s],s,e),t?!s||a[a.length-1]!==r:0>x(a,r))a.push(r),u.push(e[s]);return u}function L(e,t){return At||tt&&2<arguments.length?tt.call.apply(tt,arguments):a(e,t,Z.call(arguments,2))}function A(e){return e}function O(e){vn(tn(e),function(t){var r=s[t]=e[t];s.prototype[t]=function(){var e=[this.__wrapped__];return arguments
|
||||
.length&&G.apply(e,arguments),e=r.apply(s,e),this.__chain__&&(e=new s(e),e.__chain__=n),e}})}var n=!0,r=null,i=!1,M="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),_=Array.prototype,D=Object.prototype,P=0,H=30,B=e._,j=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,F=/&(?:amp|lt|gt|quot|#x27);/g,I=/\b__p\+='';/g,q=/\b(__p\+=)''\+/g,R=/(__e\(.*?\)|\b__t\))\+'';/g,U=/\w*$/,z=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g
|
||||
,W=RegExp("^"+(D.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),X=/($^)/,V=/[&<>"']/g,$=/['\n\r\t\u2028\u2029\\]/g,J="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),K=_.concat,Q=D.hasOwnProperty,G=_.push,Y=D.propertyIsEnumerable,Z=_.slice,et=D.toString,tt=W.test(tt=Z.bind)&&tt,nt=Math.floor,rt=W.test(rt=Object.getPrototypeOf)&&rt,it=W.test(it=Array.isArray)&&it,st=e.isFinite,ot=W.test(ot=Object
|
||||
.keys)&&ot,ut=Math.max,at=Math.min,ft=Math.random,lt="[object Arguments]",ct="[object Array]",ht="[object Boolean]",pt="[object Date]",dt="[object Number]",vt="[object Object]",mt="[object RegExp]",gt="[object String]",yt=e.clearTimeout,bt=e.setTimeout,wt,Et,St,xt=n;(function(){function e(){this.x=1}var t={0:1,length:1},n=[];e.prototype={valueOf:1,y:1};for(var r in new e)n.push(r);for(r in arguments)xt=!r;wt=4>(n+"").length,St="x"!=n[0],Et=(n.splice.call(t,0,1),t[0])})(1);var Tt=!v(arguments),Nt="x"!=
|
||||
Z.call("x")[0],Ct="xx"!="x"[0]+Object("x")[0];try{var kt=("[object Object]",et.call(e.document||0)==vt)}catch(Lt){}var At=tt&&/\n|Opera/.test(tt+et.call(e.opera)),Ot=ot&&/^.+$|true/.test(ot+!!e.attachEvent),Mt=!At,_t={};_t[ht]=_t[pt]=_t["[object Function]"]=_t[dt]=_t[vt]=_t[mt]=i,_t[lt]=_t[ct]=_t[gt]=n;var Dt={};Dt[lt]=Dt["[object Function]"]=i,Dt[ct]=Dt[ht]=Dt[pt]=Dt[dt]=Dt[vt]=Dt[mt]=Dt[gt]=n;var Pt={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},Ht={"\\":"\\","'":"'"
|
||||
,"\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};s.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""};var Bt={a:"d,c,x",i:"d",p:"c=f(c,x)",h:"if(c(A,i,d)===false)return t"},jt={i:"{}",p:"c=f(c,x)",h:"var p=c(A,i,d);(h.call(t,p)?t[p]++:t[p]=1)"},Ft={i:"true",h:"if(!c(A,i,d))return!t"},It={q:i,r:i,a:"m",i:"m",p:"for(var a=1,b=arguments.length;a<b;a++){if(j=arguments[a]){",h:"t[i]=A",e:"}}"},qt={i:"[]",h:"c(A,i,d)&&t.push(A)"
|
||||
},Rt={p:"c=f(c,x)"},Ut={h:{k:Bt.h}},zt={i:i,d:{b:"t=Array(k)",k:"t="+(Ot?"Array(k)":"[]")},h:{b:"t[i]=c(A,i,d)",k:"t"+(Ot?"[n]=":".push")+"(c(A,i,d))"}},Wt={q:i,a:"m,c,x",i:"{}",p:"var R=typeof c=='function';if(R)c=f(c,x);else var s=e.apply(E,arguments)",h:"if(R?!c(A,i,m):M(s,i)<0)t[i]=A"},Xt=l({a:"m",i:"{}",h:"t[A]=i"});Tt&&(v=function(e){return e?Q.call(e,"callee"):i});var Vt=it||function(e){return et.call(e)==ct};m(/x/)&&(m=function(e){return"[object Function]"==et.call(e)});var $t=rt?function(
|
||||
e){if(!e||"object"!=typeof e)return i;var t=e.valueOf,n="function"==typeof t&&(n=rt(t))&&rt(n);return n?e==n||rt(e)==n&&!v(e):g(e)}:g,Jt=l({a:"m",i:"[]",h:"t.push(i)"}),Kt={"&":"&","<":"<",">":">",'"':""","'":"'"},Qt=Xt(Kt),Gt=l(It,{h:"if(t[i]==null)"+It.h}),Yt=l(It),Zt=l(Bt,Rt,Ut,{q:i}),en=l(Bt,Rt,Ut),tn=l({q:i,a:"m",i:"[]",h:"if(S(A))t.push(i)",e:"t.sort()"}),nn=l({a:"A",i:"true",p:"var H=y.call(A),k=A.length;if(D[H]"+(Tt?"||O(A)":"")+"||(H==X&&k===+k&&S(A.splice)))return!k"
|
||||
,h:{k:"return false"}}),rn=ot?function(e){var t=typeof e;return"function"==t&&Y.call(e,"prototype")?Jt(e):e&&Pt[t]?ot(e):[]}:Jt,sn=l(It,{a:"m,dd,N",p:"var P,C=arguments,a=0;if(N==I){var b=2,ee=C[3],ff=C[4]}else var b=C.length,ee=[],ff=[];while(++a<b){if(j=C[a]){",h:"if((dd=A)&&((P=Q(dd))||T(dd))){var K=false,gg=ee.length;while(gg--)if(K=ee[gg]==dd)break;if(K){t[i]=ff[gg]}else {ee.push(dd);ff.push(A=(A=t[i])&&P?(Q(A)?A:[]):(T(A)?A:{}));t[i]=G(A,dd,I,ee,ff)}}else if(dd!=null)t[i]=dd"}),on=l(Wt),un=
|
||||
l({a:"m",i:"[]",h:"t"+(Ot?"[n]=":".push")+"([i,A])"}),an=l(Wt,{p:"if(typeof c!='function'){var p,s=e.apply(E,arguments),k=s.length;for(i=1;i<k;i++){p=s[i];if(p in m)t[p]=m[p]}}else {c=f(c,x)",h:"if(c(A,i,m))t[i]=A",e:"}"}),fn=l({a:"m",i:"[]",h:"t.push(A)"}),ln=l({a:"d,hh",i:"false",n:i,d:{b:"if(y.call(d)==w)return d.indexOf(hh)>-1"},h:"if(A===hh)return true"}),cn=l(Bt,jt),hn=l(Bt,Ft),pn=l(Bt,qt),dn=l(Bt,Rt,{i:i,h:"if(c(A,i,d))return A"}),vn=l(Bt,Rt),mn=l(Bt,jt,{h:"var p=c(A,i,d);(h.call(t,p)?t[p]:t[p]=[]).push(A)"
|
||||
}),gn=l(zt,{a:"d,U",p:"var C=v.call(arguments,2),R=typeof U=='function'",h:{b:"t[i]=(R?U:A[U]).apply(A,C)",k:"t"+(Ot?"[n]=":".push")+"((R?U:A[U]).apply(A,C))"}}),yn=l(Bt,zt),bn=l(zt,{a:"d,bb",h:{b:"t[i]=A[bb]",k:"t"+(Ot?"[n]=":".push")+"(A[bb])"}}),wn=l({a:"d,c,B,x",i:"B",p:"var V=arguments.length<3;c=f(c,x)",d:{b:"if(V)t=j[++i]"},h:{b:"t=c(t,A,i,d)",k:"t=V?(V=false,A):c(t,A,i,d)"}}),En=l(Bt,qt,{h:"!"+qt.h}),Sn=l(Bt,Ft,{i:"false",h:Ft.h.replace("!","")}),xn=l(Bt,jt,zt,{h:{b:"t[i]={a:c(A,i,d),b:i,c:A}"
|
||||
,k:"t"+(Ot?"[n]=":".push")+"({a:c(A,i,d),b:i,c:A})"},e:"t.sort(I);k=t.length;while(k--)t[k]=t[k].c"}),Tn=l(qt,{a:"d,aa",p:"var s=[];J(aa,function(A,p){s.push(p)});var cc=s.length",h:"for(var p,Z=true,r=0;r<cc;r++){p=s[r];if(!(Z=A[p]===aa[p]))break}Z&&t.push(A)"}),Nn=l({q:i,r:i,a:"m",p:"var L=arguments,k=L.length;if(k>1){for(var i=1;i<k;i++)t[L[i]]=F(t[L[i]],t);return t}",h:"if(S(A))t[i]=F(A,t)"});s.VERSION="0.8.1",s.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this,arguments
|
||||
)}},s.bind=L,s.bindAll=Nn,s.chain=function(e){return e=new s(e),e.__chain__=n,e},s.clone=y,s.compact=function(e){for(var t=-1,n=e?e.length:0,r=[];++t<n;)e[t]&&r.push(e[t]);return r},s.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},s.contains=ln,s.countBy=cn,s.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,yt(a),a=bt(i,t),r&&(o=e.apply(u,
|
||||
s)),o}},s.defaults=Gt,s.defer=function(e){var n=Z.call(arguments,1);return bt(function(){return e.apply(t,n)},1)},s.delay=function(e,n){var r=Z.call(arguments,2);return bt(function(){return e.apply(t,r)},n)},s.difference=function(e){var t=[];if(!e)return t;for(var n=-1,r=e.length,i=K.apply(_,arguments),i=o(i,r);++n<r;){var s=e[n];i(s)||t.push(s)}return t},s.escape=function(e){return e==r?"":(e+"").replace(V,h)},s.every=hn,s.extend=Yt,s.filter=pn,s.find=dn,s.first=E,s.flatten=S,s.forEach=vn,s.forIn=
|
||||
Zt,s.forOwn=en,s.functions=tn,s.groupBy=mn,s.has=function(e,t){return e?Q.call(e,t):i},s.identity=A,s.indexOf=x,s.initial=function(e,t,n){return e?Z.call(e,0,-(t==r||n?1:t)):[]},s.intersection=function(e){var t=arguments.length,n=[],r=-1,i=e?e.length:0,s=[];e:for(;++r<i;){var u=e[r];if(0>x(s,u)){for(var a=1;a<t;a++)if(!(n[a]||(n[a]=o(arguments[a])))(u))continue e;s.push(u)}}return s},s.invert=Xt,s.invoke=gn,s.isArguments=v,s.isArray=Vt,s.isBoolean=function(e){return e===n||e===i||et.call(e)==ht},
|
||||
s.isDate=function(e){return et.call(e)==pt},s.isElement=function(e){return e?1===e.nodeType:i},s.isEmpty=nn,s.isEqual=b,s.isFinite=function(e){return st(e)&&et.call(e)==dt},s.isFunction=m,s.isNaN=function(e){return et.call(e)==dt&&e!=+e},s.isNull=function(e){return e===r},s.isNumber=function(e){return et.call(e)==dt},s.isObject=function(e){return e?Pt[typeof e]:i},s.isPlainObject=$t,s.isRegExp=function(e){return et.call(e)==mt},s.isString=function(e){return et.call(e)==gt},s.isUndefined=function(
|
||||
e){return e===t},s.keys=rn,s.last=function(e,t,n){if(e){var i=e.length;return t==r||n?e[i-1]:Z.call(e,-t||i)}},s.lastIndexOf=function(e,t,n){var r=e?e.length:0;for("number"==typeof n&&(r=(0>n?ut(0,r+n):at(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},s.lateBind=function(e,t){return a(t,e,Z.call(arguments,2))},s.map=yn,s.max=T,s.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return Q.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},s.merge=sn,s.min=function(
|
||||
e,t,n){for(var r=Infinity,i=-1,s=e?e.length:0,o=r,t=f(t,n);++i<s;)n=t(e[i],i,e),n<r&&(r=n,o=e[i]);return o},s.mixin=O,s.noConflict=function(){return e._=B,this},s.object=function(e,t){for(var n=-1,r=e?e.length:0,i={};++n<r;)t?i[e[n]]=t[n]:i[e[n][0]]=e[n][1];return i},s.omit=on,s.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},s.pairs=un,s.partial=function(e){return a(e,Z.call(arguments,1))},s.pick=an,s.pluck=bn,s.random=function(e,t){return e==r&&t==
|
||||
r&&(t=1),e=+e||0,t==r&&(t=e,e=0),e+nt(ft()*((+t||0)-e+1))},s.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=ut(0,Math.ceil((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},s.reduce=wn,s.reduceRight=w,s.reject=En,s.rest=N,s.result=function(e,t){var n=e?e[t]:r;return m(n)?e[t]():n},s.shuffle=function(e){for(var t=-1,n=e?e.length:0,r=Array(n);++t<n;){var i=nt(ft()*(t+1));r[t]=r[i],r[i]=e[t]}return r},s.size=function(e){var t=e?e.length:0;return t===+t?t:rn(e).length},s.some=Sn
|
||||
,s.sortBy=xn,s.sortedIndex=C,s.tap=function(e,t){return t(e),e},s.template=function(e,t,n){e+="",n||(n={});var r,i,o=0,u=s.templateSettings,a="__p += '",f=n.variable||u.variable,l=f;e.replace(RegExp((n.escape||u.escape||X).source+"|"+(n.interpolate||u.interpolate||X).source+"|"+(n.evaluate||u.evaluate||X).source+"|$","g"),function(t,n,i,s,u){a+=e.slice(o,u).replace($,c),a+=n?"'+__e("+n+")+'":s?"';"+s+";__p+='":i?"'+((__t=("+i+"))==null?'':__t)+'":"",r||(r=s||j.test(n||i)),o=u+t.length}),a+="';",l||
|
||||
(f="obj",r?a="with("+f+"){"+a+"}":(n=RegExp("(\\(\\s*)"+f+"\\."+f+"\\b","g"),a=a.replace(z,"$&"+f+".").replace(n,"$1__d"))),a=(r?a.replace(I,""):a).replace(q,"$1").replace(R,"$1;"),a="function("+f+"){"+(l?"":f+"||("+f+"={});")+"var __t,__p='',__e=_.escape"+(r?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(l?"":",__d="+f+"."+f+"||"+f)+";")+a+"return __p}";try{i=Function("_","return "+a)(s)}catch(h){throw h.source=a,h}return t?i(t):(i.source=a,i)},s.throttle=function(e,t
|
||||
){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function(){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(a=r,s=e.apply(o,i)):u||(u=bt(n,f)),s}},s.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r<e;)i[r]=t.call(n,r);return i},s.toArray=function(e){if(!e)return[];var t=e.length;return t===+t?(Nt?et.call(e)==gt:"string"==typeof e)?e.split(""):Z.call(e):fn(e)},s.unescape=function(e){return e==r?"":(e+"").replace(F,d)},s.union=function(){for(var e=-1,t=K.apply(_
|
||||
,arguments),n=t.length,r=[];++e<n;)0>x(r,t[e])&&r.push(t[e]);return r},s.uniq=k,s.uniqueId=function(e){var t=P++;return e?e+t:t},s.values=fn,s.where=Tn,s.without=function(e){for(var t=-1,n=e?e.length:0,r=o(arguments,1,20),i=[];++t<n;){var s=e[t];r(s)||i.push(s)}return i},s.wrap=function(e,t){return function(){var n=[e];return arguments.length&&G.apply(n,arguments),t.apply(this,n)}},s.zip=function(e){for(var t=-1,n=e?T(bn(arguments,"length")):0,r=Array(n);++t<n;)r[t]=bn(arguments,t);return r},s.all=
|
||||
hn,s.any=Sn,s.collect=yn,s.detect=dn,s.drop=N,s.each=vn,s.foldl=wn,s.foldr=w,s.head=E,s.include=ln,s.inject=wn,s.methods=tn,s.select=pn,s.tail=N,s.take=E,s.unique=k,O(s),s.prototype.chain=function(){return this.__chain__=n,this},s.prototype.value=function(){return this.__wrapped__},vn("pop push reverse shift sort splice unshift".split(" "),function(e){var t=_[e];s.prototype[e]=function(){var e=this.__wrapped__;return t.apply(e,arguments),Et&&e.length===0&&delete e[0],this.__chain__&&(e=new s(e),e
|
||||
.__chain__=n),e}}),vn(["concat","join","slice"],function(e){var t=_[e];s.prototype[e]=function(){var e=t.apply(this.__wrapped__,arguments);return this.__chain__&&(e=new s(e),e.__chain__=n),e}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(e._=s,define(function(){return s})):M?"object"==typeof module&&module&&module.exports==M?(module.exports=s)._=s:M._=s:e._=s})(this);
|
||||
36
lodash.underscore.min.js
vendored
Normal file
36
lodash.underscore.min.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*!
|
||||
Lo-Dash 0.8.1 lodash.com/license
|
||||
Underscore.js 1.4.1 underscorejs.org/LICENSE
|
||||
*/
|
||||
;(function(e,t){function s(e,t,r){var s;if(!e)return i;var t=x(t,r),o=e.length,r=-1;if(o===+o){for(;++r<o;)if(s=e[r],t(s,r,e))return n}else for(r in e)if(it.call(e,r)&&(s=e[r],t(s,r,e)))return n;return i}function o(e,t,n,r){var s,o,u=n;if(!e)return u;var a=3>arguments.length,t=x(t,r),f=e.length;s=-1;if(f===+f)for(a&&(u=e[++s]);++s<f;)o=e[s],u=t(u,o,s,e);else for(s in e)it.call(e,s)&&(o=e[s],u=a?(a=i,o):t(u,o,s,e));return u}function u(e,t){var n,r,i;if(!e)return i;var s=e.length;n=-1;if(s===+s)for(
|
||||
i=Array(s);++n<s;)r=e[n],i[n]=r[t];else for(n in i=[],e)it.call(e,n)&&(r=e[n],i.push(r[t]));return i}function a(e,t,n){var r,i;if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(i=Array(s);++n<s;)r=e[n],i[n]=t(r,n,e);else for(n in i=[],e)it.call(e,n)&&(r=e[n],i.push(t(r,n,e)));return i}function f(e,t,n){var r;if(!e)return e;var t=x(t,n),i=e.length,n=-1;if(i===+i)for(;++n<i;)r=e[n],t(r,n,e);else for(n in e)it.call(e,n)&&(r=e[n],t(r,n,e));return e}function l(e,t,n){var r;if(e){var t=x(t,n),i=
|
||||
e.length,n=-1;if(i===+i){for(;++n<i;)if(r=e[n],t(r,n,e))return r}else for(n in e)if(it.call(e,n)&&(r=e[n],t(r,n,e)))return r}}function c(e,t,n){var r,i=[];if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],t(r,n,e)&&i.push(r);else for(n in e)it.call(e,n)&&(r=e[n],t(r,n,e)&&i.push(r));return i}function h(e,t,r){var s;if(!e)return n;var t=x(t,r),o=e.length,r=-1;if(o===+o){for(;++r<o;)if(s=e[r],!t(s,r,e))return i}else for(r in e)if(it.call(e,r)&&(s=e[r],!t(s,r,e)))return i;return n
|
||||
}function p(e,t){var r,s;if(!e)return i;var o=e.length;r=-1;if(o===+o){if(ut.call(e)==St)return-1<e.indexOf(t);for(;++r<o;)if(s=e[r],s===t)return n}else for(r in e)if(it.call(e,r)&&(s=e[r],s===t))return n;return i}function d(e){var t,n,r=[];if(!e)return r;for(t in e)it.call(e,t)&&(n=e[t],r.push(n));return r}function v(e){var t,n,r=[];if(!e)return r;for(t in e)n=e[t],L(n)&&r.push(t);return r.sort(),r}function m(e,t,n){var r;if(!e)return e;t=x(t,n);for(r in e)n=e[r],t(n,r,e);return e}function g(e){
|
||||
var t,n,r=e;if(!e)return e;for(var i=1,s=arguments.length;i<s;i++)if(r=arguments[i])for(t in r)n=r[t],e[t]=n;return e}function y(e){var t,n=[];if(!e)return n;for(t in e)it.call(e,t)&&n.push(t);return n}function b(e){var t,n,r={};if(!e)return r;for(t in e)it.call(e,t)&&(n=e[t],r[n]=t);return r}function w(e){if(e&&e.__wrapped__)return e;if(!(this instanceof w))return new w(e);this.__wrapped__=e}function E(e,n){var r=e.b,i=n.b,e=e.a,n=n.a;if(e!==n){if(e>n||e===t)return 1;if(e<n||n===t)return-1}return r<
|
||||
i?-1:1}function S(e,t,n){function r(){var i=arguments,s=t;return n.length&&(i=i.length?n.concat(ot.call(i)):n),this instanceof r?(C.prototype=e.prototype,s=new C,(i=e.apply(s,i))&&Ct[typeof i]?i:s):e.apply(s,i)}return r}function x(e,n){return e?"function"!=typeof e?function(t){return t[e]}:n!==t?function(t,r,i){return e.call(n,t,r,i)}:e:q}function T(e){return"\\"+kt[e]}function N(e){return At[e]}function C(){}function k(e){return Ot[e]}function L(e){return"function"==typeof e}function A(e){var t=
|
||||
i;if(!e||"object"!=typeof e||isArguments(e))return t;var n=e.constructor;return!L(n)||n instanceof n?(m(e,function(e,n){t=n}),t===i||it.call(e,t)):t}function O(e,t,s,o){if(e==r||t==r)return e===t;if(e===t)return 0!==e||1/e==1/t;if(Ct[typeof e]||Ct[typeof t])e=e.__wrapped__||e,t=t.__wrapped__||t;var u=ut.call(e);if(u!=ut.call(t))return i;switch(u){case gt:case yt:return+e==+t;case bt:return e!=+e?t!=+t:0==e?1/e==1/t:e==+t;case Et:case St:return e==t+""}var a=Lt(e);if(!a&&u!=wt)return i;s||(s=[]),o||
|
||||
(o=[]);for(u=s.length;u--;)if(s[u]==e)return o[u]==t;var f=n,u=0;s.push(e),o.push(t);if(a){u=e.length;if(f=u==t.length)for(;u--&&(f=O(e[u],t[u],s,o)););return f}a=e.constructor,f=t.constructor;if(a!=f&&(!L(a)||!(a instanceof a&&L(f)&&f instanceof f)))return i;for(var l in e)if(it.call(e,l)&&(u++,!it.call(t,l)||!O(e[l],t[l],s,o)))return i;for(l in t)if(it.call(t,l)&&!(u--))return i;return n}function M(e,t,n,r){var s=e?e.length:0,o=3>arguments.length;if(s!==+s)var u=Mt(e),s=u.length;return f(e,function(
|
||||
a,f,l){f=u?u[--s]:--s,n=o?(o=i,e[f]):t.call(r,n,e[f],f,l)}),n}function _(e,t,n){if(e)return t==r||n?e[0]:ot.call(e,0,t)}function D(e,t){for(var n,r=-1,i=e?e.length:0,s=[];++r<i;)n=e[r],Lt(n)?st.apply(s,t?n:D(n)):s.push(n);return s}function P(e,t,n){var r=-1,i=e?e.length:0;if("number"==typeof n)r=(0>n?dt(0,i+n):n||0)-1;else if(n)return r=j(e,t),e[r]===t?r:-1;for(;++r<i;)if(e[r]===t)return r;return-1}function H(e,t,n){for(var r=-Infinity,i=-1,s=e?e.length:0,o=r,t=x(t,n);++i<s;)n=t(e[i],i,e),n>r&&(r=
|
||||
n,o=e[i]);return o}function B(e,t,n){return e?ot.call(e,t==r||n?1:t):[]}function j(e,t,n,r){for(var i=0,s=e?e.length:i,n=x(n,r),t=n(t);i<s;)r=i+s>>>1,n(e[r])<t?i=r+1:s=r;return i}function F(e,t,n,r){var s=-1,o=e?e.length:0,u=[],a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n=x(n,r);++s<o;)if(r=n(e[s],s,e),t?!s||a[a.length-1]!==r:0>P(a,r))a.push(r),u.push(e[s]);return u}function I(e,t){return Nt||at&&2<arguments.length?at.call.apply(at,arguments):S(e,t,ot.call(arguments,2))}function q(e){return e}function R
|
||||
(e){f(v(e),function(t){var r=w[t]=e[t];w.prototype[t]=function(){var e=[this.__wrapped__];return arguments.length&&st.apply(e,arguments),e=r.apply(w,e),this.__chain__&&(e=new w(e),e.__chain__=n),e}})}var n=!0,r=null,i=!1,U="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),z=Array.prototype,W=Object.prototype,X=0,V=e._,$=/[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,J=/&(?:amp|lt|gt|quot|#x27);/g,K=/\b__p\+='';/g
|
||||
,Q=/\b(__p\+=)''\+/g,G=/(__e\(.*?\)|\b__t\))\+'';/g,Y=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g,Z=RegExp("^"+(W.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),et=/($^)/,tt=/[&<>"']/g,nt=/['\n\r\t\u2028\u2029\\]/g,rt=z.concat,it=W.hasOwnProperty,st=z.push,ot=z.slice,ut=W.toString,at=Z.test(at=ot.bind)&&at,ft=Math.floor,lt=Z.test(lt=Object.getPrototypeOf)&<,ct=Z.test(ct=Array.isArray)&&ct,ht=e.isFinite,pt=Z.test(pt=Object.keys)&&pt,dt=Math.max,vt=Math
|
||||
.min,mt=Math.random,gt="[object Boolean]",yt="[object Date]",bt="[object Number]",wt="[object Object]",Et="[object RegExp]",St="[object String]",xt=e.clearTimeout,Tt=e.setTimeout,Nt=at&&/\n|Opera/.test(at+ut.call(e.opera)),Ct={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i,unknown:n},kt={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};w.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""
|
||||
},w.isArguments=function(e){return"[object Arguments]"==ut.call(e)},w.isArguments(arguments)||(w.isArguments=function(e){return e?it.call(e,"callee"):i});var Lt=ct||function(e){return"[object Array]"==ut.call(e)};L(/x/)&&(L=function(e){return"[object Function]"==ut.call(e)});var W=lt?function(e){if(!e||"object"!=typeof e)return i;var t=e.valueOf,n="function"==typeof t&&(n=lt(t))&<(n);return n?e==n||lt(e)==n&&!isArguments(e):A(e)}:A,At={"&":"&","<":"<",">":">",'"':""","'":"'"
|
||||
},Ot=b(At),Mt=pt?function(e){return e&&Ct[typeof e]?pt(e):[]}:y;w.VERSION="0.8.1",w.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this,arguments)}},w.bind=I,w.bindAll=function(e){var t,n,r=e,i=e;if(!e)return i;n=arguments;var s=n.length;if(1<s){for(t=1;t<s;t++)i[n[t]]=I(i[n[t]],i);return i}for(t in r)n=r[t],L(n)&&(i[t]=I(n,i));return i},w.chain=function(e){return e=new w(e),e.__chain__=n,e},w.clone=function(e){return e&&Ct[typeof e]?Lt(e)?ot.call(e):g({},e):e},w.compact=function(
|
||||
e){for(var t=-1,n=e?e.length:0,r=[];++t<n;)e[t]&&r.push(e[t]);return r},w.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},w.contains=p,w.countBy=function(e,t,n){var r,i={};if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],r=t(r,n,e),it.call(i,r)?i[r]++:i[r]=1;else for(n in e)it.call(e,n)&&(r=e[n],r=t(r,n,e),it.call(i,r)?i[r]++:i[r]=1);return i},w.debounce=function(e,t,n){function i(){a=r,n||(o=e.apply
|
||||
(u,s))}var s,o,u,a;return function(){var r=n&&!a;return s=arguments,u=this,xt(a),a=Tt(i,t),r&&(o=e.apply(u,s)),o}},w.defaults=function(e){var t,n,i=e;if(!e)return e;for(var s=1,o=arguments.length;s<o;s++)if(i=arguments[s])for(t in i)n=i[t],e[t]==r&&(e[t]=n);return e},w.defer=function(e){var n=ot.call(arguments,1);return Tt(function(){return e.apply(t,n)},1)},w.delay=function(e,n){var r=ot.call(arguments,2);return Tt(function(){return e.apply(t,r)},n)},w.difference=function(e){for(var t=-1,n=e.length
|
||||
,r=rt.apply(z,arguments),i=[];++t<n;){var s=e[t];0>P(r,s,n)&&i.push(s)}return i},w.escape=function(e){return e==r?"":(e+"").replace(tt,N)},w.every=h,w.extend=g,w.filter=c,w.find=l,w.first=_,w.flatten=D,w.forEach=f,w.forIn=m,w.forOwn=function(e,t,n){var r;if(!e)return e;t=x(t,n);for(r in e)it.call(e,r)&&(n=e[r],t(n,r,e));return e},w.functions=v,w.groupBy=function(e,t,n){var r,i={};if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;){r=e[n];var o=t(r,n,e);(it.call(i,o)?i[o]:i[o]=[]).push
|
||||
(r)}else for(n in e)it.call(e,n)&&(r=e[n],o=t(r,n,e),(it.call(i,o)?i[o]:i[o]=[]).push(r));return i},w.has=function(e,t){return e?it.call(e,t):i},w.identity=q,w.indexOf=P,w.initial=function(e,t,n){return e?ot.call(e,0,-(t==r||n?1:t)):[]},w.intersection=function(e){var t=arguments.length,n=-1,r=e.length,i=[];e:for(;++n<r;){var s=e[n];if(0>P(i,s)){for(var o=1;o<t;o++)if(0>P(arguments[o],s))continue e;i.push(s)}}return i},w.invert=b,w.invoke=function(e,t){var n,r,i=e,s;if(!e)return s;var o=ot.call(arguments
|
||||
,2),u="function"==typeof t,a=i.length;n=-1;if(a===+a)for(s=Array(a);++n<a;)r=i[n],s[n]=(u?t:r[t]).apply(r,o);else for(n in s=[],i)it.call(i,n)&&(r=i[n],s.push((u?t:r[t]).apply(r,o)));return s},w.isArray=Lt,w.isBoolean=function(e){return e===n||e===i||ut.call(e)==gt},w.isDate=function(e){return ut.call(e)==yt},w.isElement=function(e){return e?1===e.nodeType:i},w.isEmpty=function(e){var t;if(!e)return n;var r=ut.call(e),s=e.length;if(Lt(e)||r==St||r==wt&&s===+s&&L(e.splice))return!s;for(t in e)if(it
|
||||
.call(e,t))return i;return n},w.isEqual=O,w.isFinite=function(e){return ht(e)&&ut.call(e)==bt},w.isFunction=L,w.isNaN=function(e){return ut.call(e)==bt&&e!=+e},w.isNull=function(e){return e===r},w.isNumber=function(e){return ut.call(e)==bt},w.isObject=function(e){return e?Ct[typeof e]:i},w.isPlainObject=W,w.isRegExp=function(e){return ut.call(e)==Et},w.isString=function(e){return ut.call(e)==St},w.isUndefined=function(e){return e===t},w.keys=Mt,w.last=function(e,t,n){if(e){var i=e.length;return t==
|
||||
r||n?e[i-1]:ot.call(e,-t||i)}},w.lastIndexOf=function(e,t,n){var r=e?e.length:0;for("number"==typeof n&&(r=(0>n?dt(0,r+n):vt(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},w.map=a,w.max=H,w.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return it.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},w.min=function(e,t,n){for(var r=Infinity,i=-1,s=e?e.length:0,o=r,t=x(t,n);++i<s;)n=t(e[i],i,e),n<r&&(r=n,o=e[i]);return o},w.mixin=R,w.noConflict=function(){return e
|
||||
._=V,this},w.object=function(e,t){for(var n=-1,r=e?e.length:0,i={};++n<r;)t?i[e[n]]=t[n]:i[e[n][0]]=e[n][1];return i},w.omit=function(e,t,n){var r,i,s=e,o={};if(!e)return o;var u="function"==typeof t;if(u)t=x(t,n);else var a=rt.apply(z,arguments);for(r in s)if(i=s[r],u?!t(i,r,e):0>P(a,r))o[r]=i;return o},w.once=function(e){var t,s=i;return function(){return s?t:(s=n,t=e.apply(this,arguments),e=r,t)}},w.pairs=function(e){var t,n,r=[];if(!e)return r;for(t in e)it.call(e,t)&&(n=e[t],r.push([t,n]));return r
|
||||
},w.pick=function(e,t,n){var r,i,s=e,o={};if(!e)return o;if("function"!=typeof t){var s=rt.apply(z,arguments),u=s.length;for(r=1;r<u;r++)i=s[r],i in e&&(o[i]=e[i])}else for(r in t=x(t,n),s)i=s[r],t(i,r,e)&&(o[r]=i);return o},w.pluck=u,w.random=function(e,t){return e==r&&t==r&&(t=1),e=+e||0,t==r&&(t=e,e=0),e+ft(mt()*((+t||0)-e+1))},w.range=function(e,t,n){e=+e||0,n=+n||1,t==r&&(t=e,e=0);for(var i=-1,t=dt(0,Math.ceil((t-e)/n)),s=Array(t);++i<t;)s[i]=e,e+=n;return s},w.reduce=o,w.reduceRight=M,w.reject=
|
||||
function(e,t,n){var r,i=[];if(!e)return i;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(;++n<s;)r=e[n],!t(r,n,e)&&i.push(r);else for(n in e)it.call(e,n)&&(r=e[n],!t(r,n,e)&&i.push(r));return i},w.rest=B,w.result=function(e,t){var n=e?e[t]:r;return L(n)?e[t]():n},w.shuffle=function(e){for(var t=-1,n=e?e.length:0,r=Array(n);++t<n;){var i=ft(mt()*(t+1));r[t]=r[i],r[i]=e[t]}return r},w.size=function(e){var t=e?e.length:0;return t===+t?t:Mt(e).length},w.some=s,w.sortBy=function(e,t,n){var r,i;if(!e)return i
|
||||
;var t=x(t,n),s=e.length,n=-1;if(s===+s)for(i=Array(s);++n<s;)r=e[n],i[n]={a:t(r,n,e),b:n,c:r};else for(n in i=[],e)it.call(e,n)&&(r=e[n],i.push({a:t(r,n,e),b:n,c:r}));i.sort(E);for(s=i.length;s--;)i[s]=i[s].c;return i},w.sortedIndex=j,w.tap=function(e,t){return t(e),e},w.template=function(e,t,n){e+="",n||(n={});var r,i,s=0,o=w.templateSettings,u="__p += '",a=n.variable||o.variable,f=a;e.replace(RegExp((n.escape||o.escape||et).source+"|"+(n.interpolate||o.interpolate||et).source+"|"+(n.evaluate||
|
||||
o.evaluate||et).source+"|$","g"),function(t,n,i,o,a){u+=e.slice(s,a).replace(nt,T),u+=n?"'+__e("+n+")+'":o?"';"+o+";__p+='":i?"'+((__t=("+i+"))==null?'':__t)+'":"",r||(r=o||$.test(n||i)),s=a+t.length}),u+="';",f||(a="obj",r?u="with("+a+"){"+u+"}":(n=RegExp("(\\(\\s*)"+a+"\\."+a+"\\b","g"),u=u.replace(Y,"$&"+a+".").replace(n,"$1__d"))),u=(r?u.replace(K,""):u).replace(Q,"$1").replace(G,"$1;"),u="function("+a+"){"+(f?"":a+"||("+a+"={});")+"var __t,__p='',__e=_.escape"+(r?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"
|
||||
:(f?"":",__d="+a+"."+a+"||"+a)+";")+u+"return __p}";try{i=Function("_","return "+u)(w)}catch(l){throw l.source=u,l}return t?i(t):(i.source=u,i)},w.throttle=function(e,t){function n(){a=new Date,u=r,s=e.apply(o,i)}var i,s,o,u,a=0;return function(){var r=new Date,f=t-(r-a);return i=arguments,o=this,0>=f?(a=r,s=e.apply(o,i)):u||(u=Tt(n,f)),s}},w.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r<e;)i[r]=t.call(n,r);return i},w.toArray=function(e){if(!e)return[];var t=e.length;return t===+t?"string"==typeof
|
||||
e?e.split(""):ot.call(e):d(e)},w.unescape=function(e){return e==r?"":(e+"").replace(J,k)},w.union=function(){for(var e=-1,t=rt.apply(z,arguments),n=t.length,r=[];++e<n;)0>P(r,t[e])&&r.push(t[e]);return r},w.uniq=F,w.uniqueId=function(e){var t=X++;return e?e+t:t},w.values=d,w.where=function(e,t){var r,i,s=[];if(!e)return s;var o=[];m(t,function(e,t){o.push(t)});var u=o.length,a=e.length;r=-1;if(a===+a)for(;++r<a;){i=e[r];var f;f=n;for(var l=0;l<u&&(f=o[l],f=i[f]===t[f]);l++);f&&s.push(i)}else for(
|
||||
r in e)if(it.call(e,r)){i=e[r],f=n;for(l=0;l<u&&(f=o[l],f=i[f]===t[f]);l++);f&&s.push(i)}return s},w.without=function(e){for(var t=-1,n=e.length,r=[];++t<n;){var i=e[t];0>P(arguments,i,1)&&r.push(i)}return r},w.wrap=function(e,t){return function(){var n=[e];return arguments.length&&st.apply(n,arguments),t.apply(this,n)}},w.zip=function(e){for(var t=-1,n=e?H(u(arguments,"length")):0,r=Array(n);++t<n;)r[t]=u(arguments,t);return r},w.all=h,w.any=s,w.collect=a,w.detect=l,w.drop=B,w.each=f,w.foldl=o,w
|
||||
.foldr=M,w.head=_,w.include=p,w.inject=o,w.methods=v,w.select=c,w.tail=B,w.take=_,w.unique=F,R(w),w.prototype.chain=function(){return this.__chain__=n,this},w.prototype.value=function(){return this.__wrapped__},f("pop push reverse shift sort splice unshift".split(" "),function(e){var t=z[e];w.prototype[e]=function(){var e=this.__wrapped__;return t.apply(e,arguments),this.__chain__&&(e=new w(e),e.__chain__=n),e}}),f(["concat","join","slice"],function(e){var t=z[e];w.prototype[e]=function(){var e=t
|
||||
.apply(this.__wrapped__,arguments);return this.__chain__&&(e=new w(e),e.__chain__=n),e}}),U?"object"==typeof module&&module&&module.exports==U?(module.exports=w)._=w:U._=w:e._=w})(this);
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "lodash",
|
||||
"version": "0.7.0",
|
||||
"version": "0.8.1",
|
||||
"description": "A drop-in replacement for Underscore.js delivering performance, bug fixes, and additional features.",
|
||||
"homepage": "http://lodash.com",
|
||||
"main": "lodash",
|
||||
"main": "./lodash",
|
||||
"keywords": [
|
||||
"browser",
|
||||
"client",
|
||||
@@ -43,10 +43,10 @@
|
||||
"rhino"
|
||||
],
|
||||
"jam": {
|
||||
"main": "./lodash.min.js"
|
||||
"main": "./lodash.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build",
|
||||
"test": "node test/test"
|
||||
"test": "node test/test && node test/test-build"
|
||||
}
|
||||
}
|
||||
|
||||
102
perf/perf.js
102
perf/perf.js
@@ -276,7 +276,6 @@
|
||||
var twentyFiveValues = Array(25),\
|
||||
twentyFiveValues2 = Array(25),\
|
||||
fiftyValues = Array(50),\
|
||||
fiftyValues2 = Array(50),\
|
||||
seventyFiveValues = Array(75),\
|
||||
seventyFiveValues2 = Array(75),\
|
||||
lowerChars = "abcdefghijklmnopqrstuvwxyz".split(""),\
|
||||
@@ -294,14 +293,11 @@
|
||||
}\
|
||||
fiftyValues[index] =\
|
||||
seventyFiveValues[index] = lowerChars[index];\
|
||||
\
|
||||
fiftyValues2[index] =\
|
||||
seventyFiveValues2[index] = upperChars[index];\
|
||||
}\
|
||||
else {\
|
||||
if (index < 50) {\
|
||||
fiftyValues[index] = index;\
|
||||
fiftyValues2[index] = index + (index < 40 ? 75 : 0);\
|
||||
}\
|
||||
seventyFiveValues[index] = index;\
|
||||
seventyFiveValues2[index] = index + (index < 60 ? 75 : 0);\
|
||||
@@ -575,13 +571,13 @@
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.difference` iterating 50 elements')
|
||||
Benchmark.Suite('`_.difference` iterating 50 and 75 elements')
|
||||
.add('Lo-Dash', {
|
||||
'fn': 'lodash.difference(fiftyValues, fiftyValues2)',
|
||||
'fn': 'lodash.difference(fiftyValues, seventyFiveValues2)',
|
||||
'teardown': 'function multiArrays(){}'
|
||||
})
|
||||
.add('Underscore', {
|
||||
'fn': '_.difference(fiftyValues, fiftyValues2)',
|
||||
'fn': '_.difference(fiftyValues, seventyFiveValues2)',
|
||||
'teardown': 'function multiArrays(){}'
|
||||
})
|
||||
);
|
||||
@@ -839,13 +835,13 @@
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.intersection` iterating 50 elements')
|
||||
Benchmark.Suite('`_.intersection` iterating 50 and 75 elements')
|
||||
.add('Lo-Dash', {
|
||||
'fn': 'lodash.intersection(fiftyValues, fiftyValues2)',
|
||||
'fn': 'lodash.intersection(fiftyValues, seventyFiveValues2)',
|
||||
'teardown': 'function multiArrays(){}'
|
||||
})
|
||||
.add('Underscore', {
|
||||
'fn': '_.intersection(fiftyValues, fiftyValues2)',
|
||||
'fn': '_.intersection(fiftyValues, seventyFiveValues2)',
|
||||
'teardown': 'function multiArrays(){}'
|
||||
})
|
||||
);
|
||||
@@ -1152,6 +1148,74 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.reduce` iterating an array')
|
||||
.add('Lo-Dash', '\
|
||||
lodash.reduce(numbers, function(result, value, index) {\
|
||||
result[index] = value;\
|
||||
return result;\
|
||||
}, {});'
|
||||
)
|
||||
.add('Underscore', '\
|
||||
_.reduce(numbers, function(result, value, index) {\
|
||||
result[index] = value;\
|
||||
return result;\
|
||||
}, {});'
|
||||
)
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.reduce` iterating an object')
|
||||
.add('Lo-Dash', '\
|
||||
lodash.reduce(object, function(result, value, key) {\
|
||||
result.push([key, value]);\
|
||||
return result;\
|
||||
}, []);'
|
||||
)
|
||||
.add('Underscore', '\
|
||||
_.reduce(object, function(result, value, key) {\
|
||||
result.push([key, value]);\
|
||||
return result;\
|
||||
}, []);'
|
||||
)
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.reduceRight` iterating an array')
|
||||
.add('Lo-Dash', '\
|
||||
lodash.reduceRight(numbers, function(result, value, index) {\
|
||||
result[index] = value;\
|
||||
return result;\
|
||||
}, {});'
|
||||
)
|
||||
.add('Underscore', '\
|
||||
_.reduceRight(numbers, function(result, value, index) {\
|
||||
result[index] = value;\
|
||||
return result;\
|
||||
}, {});'
|
||||
)
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.reduceRight` iterating an object')
|
||||
.add('Lo-Dash', '\
|
||||
lodash.reduceRight(object, function(result, value, key) {\
|
||||
result.push([key, value]);\
|
||||
return result;\
|
||||
}, []);'
|
||||
)
|
||||
.add('Underscore', '\
|
||||
_.reduceRight(object, function(result, value, key) {\
|
||||
result.push([key, value]);\
|
||||
return result;\
|
||||
}, []);'
|
||||
)
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.shuffle`')
|
||||
.add('Lo-Dash', '\
|
||||
@@ -1412,6 +1476,18 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.where`')
|
||||
.add('Lo-Dash', '\
|
||||
lodash.where(objects, { "num": 9 });'
|
||||
)
|
||||
.add('Underscore', '\
|
||||
_.where(objects, { "num": 9 });'
|
||||
)
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.without`')
|
||||
.add('Lo-Dash', '\
|
||||
@@ -1435,13 +1511,13 @@
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('`_.without` iterating an array of 50 elements')
|
||||
Benchmark.Suite('`_.without` iterating an array of 75 and 50 elements')
|
||||
.add('Lo-Dash', {
|
||||
'fn': 'lodash.without.apply(lodash, [fiftyValues].concat(fiftyValues2));',
|
||||
'fn': 'lodash.without.apply(lodash, [seventyFiveValues2].concat(fiftyValues));',
|
||||
'teardown': 'function multiArrays(){}'
|
||||
})
|
||||
.add('Underscore', {
|
||||
'fn': '_.without.apply(_, [fiftyValues].concat(fiftyValues2));',
|
||||
'fn': '_.without.apply(_, [seventyFiveValues2].concat(fiftyValues));',
|
||||
'teardown': 'function multiArrays(){}'
|
||||
})
|
||||
);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
<script>
|
||||
// load Lo-Dash as a module
|
||||
var lodashModule,
|
||||
shimmedModule,
|
||||
underscoreModule;
|
||||
|
||||
window.require && require({
|
||||
@@ -51,15 +52,25 @@
|
||||
'urlArgs': 't=' + (+new Date),
|
||||
'paths': {
|
||||
'lodash': '../../' + QUnit.config.lodashFilename,
|
||||
'underscore': './../../' + QUnit.config.lodashFilename
|
||||
'shimmed': './../../' + QUnit.config.lodashFilename,
|
||||
'underscore': '../underscore/../../' + QUnit.config.lodashFilename
|
||||
},
|
||||
'shim': {
|
||||
'shimmed': {
|
||||
'exports': '_'
|
||||
}
|
||||
}
|
||||
},
|
||||
['lodash', 'underscore'], function(lodash, underscore) {
|
||||
if (lodash.noConflict) {
|
||||
['lodash', 'shimmed', 'underscore'], function(lodash, shimmed, underscore) {
|
||||
if (lodash && lodash.noConflict) {
|
||||
lodashModule = lodash.noConflict();
|
||||
lodashModule.moduleName = 'lodash';
|
||||
}
|
||||
if (underscore.noConflict) {
|
||||
if (shimmed.noConflict) {
|
||||
shimmedModule = shimmed.noConflict();
|
||||
shimmedModule.moduleName = 'shimmed';
|
||||
}
|
||||
if (underscore && underscore.noConflict) {
|
||||
underscoreModule = underscore.noConflict();
|
||||
underscoreModule.moduleName = 'underscore';
|
||||
}
|
||||
|
||||
3
test/template/a.jst
Normal file
3
test/template/a.jst
Normal file
@@ -0,0 +1,3 @@
|
||||
<ul>
|
||||
<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>
|
||||
</ul>
|
||||
1
test/template/b.jst
Normal file
1
test/template/b.jst
Normal file
@@ -0,0 +1 @@
|
||||
<% print("Hello " + epithet); %>.
|
||||
1
test/template/c.tpl
Normal file
1
test/template/c.tpl
Normal file
@@ -0,0 +1 @@
|
||||
Hello {{ name }}!
|
||||
@@ -134,6 +134,7 @@
|
||||
'debounce',
|
||||
'defer',
|
||||
'delay',
|
||||
'lateBind',
|
||||
'memoize',
|
||||
'once',
|
||||
'partial',
|
||||
@@ -164,6 +165,7 @@
|
||||
'isNull',
|
||||
'isNumber',
|
||||
'isObject',
|
||||
'isPlainObject',
|
||||
'isRegExp',
|
||||
'isString',
|
||||
'isUndefined',
|
||||
@@ -237,18 +239,12 @@
|
||||
|
||||
/** List of methods used by Underscore */
|
||||
var underscoreMethods = _.without.apply(_, [allMethods].concat([
|
||||
'countBy',
|
||||
'forIn',
|
||||
'forOwn',
|
||||
'invert',
|
||||
'isPlainObject',
|
||||
'lateBind',
|
||||
'merge',
|
||||
'object',
|
||||
'omit',
|
||||
'pairs',
|
||||
'partial',
|
||||
'random',
|
||||
'unescape',
|
||||
'where'
|
||||
'partial'
|
||||
]));
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -292,6 +288,31 @@
|
||||
return realToAliasMap[funcName] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of methods belonging to the given `category`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} category The category to filter by.
|
||||
* @returns {Array} Returns a new array of method names belonging to the given category.
|
||||
*/
|
||||
function getMethodsByCategory(category) {
|
||||
switch (category) {
|
||||
case 'Arrays':
|
||||
return arraysMethods.slice();
|
||||
case 'Chaining':
|
||||
return chainingMethods.slice();
|
||||
case 'Collections':
|
||||
return collectionsMethods.slice();
|
||||
case 'Functions':
|
||||
return functionsMethods.slice();
|
||||
case 'Objects':
|
||||
return objectsMethods.slice();
|
||||
case 'Utilities':
|
||||
return utilityMethods.slice();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the real name, not alias, of a given function name.
|
||||
*
|
||||
@@ -370,14 +391,16 @@
|
||||
else if (functionsMethods.indexOf(methodName) > -1) {
|
||||
if (methodName == 'after') {
|
||||
func(1, noop);
|
||||
} else if (methodName == 'bindAll') {
|
||||
func({ 'noop': noop });
|
||||
} else if (methodName == 'lateBind') {
|
||||
func(lodash, 'identity', array, string);
|
||||
} else if (/^(?:bind|partial)$/.test(methodName)) {
|
||||
func(noop, object, array, string);
|
||||
} else if (/^(?:compose|memoize|wrap)$/.test(methodName)) {
|
||||
func(noop, noop);
|
||||
} else if (/^(?:debounce|throttle)$/.test(methodName)) {
|
||||
func(noop, 100);
|
||||
} else if (methodName == 'bindAll') {
|
||||
func({ 'noop': noop });
|
||||
} else {
|
||||
func(noop);
|
||||
}
|
||||
@@ -413,102 +436,112 @@
|
||||
console.log(e);
|
||||
pass = false;
|
||||
}
|
||||
equal(pass, true, methodName + ': ' + message);
|
||||
equal(pass, true, '_.' + methodName + ': ' + message);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash build');
|
||||
QUnit.module('minified AMD snippet');
|
||||
|
||||
(function() {
|
||||
var commands = [
|
||||
'backbone',
|
||||
'csp',
|
||||
'legacy',
|
||||
'mobile',
|
||||
'strict',
|
||||
'underscore',
|
||||
'category=arrays',
|
||||
'category=chaining',
|
||||
'category=collections',
|
||||
'category=functions',
|
||||
'category=objects',
|
||||
'category=utilities',
|
||||
'exclude=union,uniq,zip',
|
||||
'include=each,filter,map',
|
||||
'category=collections,functions',
|
||||
'underscore backbone',
|
||||
'backbone legacy category=utilities exclude=first,last',
|
||||
'underscore mobile strict category=functions exports=amd,global include=pick,uniq',
|
||||
]
|
||||
.concat(
|
||||
allMethods.map(function(methodName) {
|
||||
return 'include=' + methodName;
|
||||
})
|
||||
);
|
||||
var start = _.once(QUnit.start);
|
||||
|
||||
commands.forEach(function(command) {
|
||||
asyncTest('`lodash`', function() {
|
||||
build(['-s'], function(source, filePath) {
|
||||
// used by r.js build optimizer
|
||||
var defineHasRegExp = /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g,
|
||||
basename = path.basename(filePath, '.js');
|
||||
|
||||
ok(!!defineHasRegExp.exec(source), basename);
|
||||
start();
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('template builds');
|
||||
|
||||
(function() {
|
||||
var templatePath = __dirname + '/template';
|
||||
|
||||
asyncTest('`lodash template=*.jst`', function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
asyncTest('`lodash ' + command +'`', function() {
|
||||
build(['--silent'].concat(command.split(' ')), function(source, filepath) {
|
||||
var basename = path.basename(filepath, '.js'),
|
||||
context = createContext(),
|
||||
methodNames = [];
|
||||
build(['-s', 'template=' + templatePath + '/*.jst'], function(source, filePath) {
|
||||
var basename = path.basename(filePath, '.js'),
|
||||
context = createContext();
|
||||
|
||||
try {
|
||||
vm.runInContext(source, context);
|
||||
} catch(e) { }
|
||||
var data = {
|
||||
'a': { 'people': ['moe', 'larry', 'curly'] },
|
||||
'b': { 'epithet': 'stooge' }
|
||||
};
|
||||
|
||||
if (/underscore/.test(command)) {
|
||||
methodNames = underscoreMethods;
|
||||
}
|
||||
if (/backbone/.test(command)) {
|
||||
methodNames = backboneDependencies;
|
||||
}
|
||||
if (/include/.test(command)) {
|
||||
methodNames = methodNames.concat(command.match(/include=(\S*)/)[1].split(/, */));
|
||||
}
|
||||
if (/category/.test(command)) {
|
||||
methodNames = command.match(/category=(\S*)/)[1].split(/, */).reduce(function(result, category) {
|
||||
switch (category) {
|
||||
case 'arrays':
|
||||
return result.concat(arraysMethods);
|
||||
case 'chaining':
|
||||
return result.concat(chainingMethods);
|
||||
case 'collections':
|
||||
return result.concat(collectionsMethods);
|
||||
case 'functions':
|
||||
return result.concat(functionsMethods);
|
||||
case 'objects':
|
||||
return result.concat(objectsMethods);
|
||||
case 'utilities':
|
||||
return result.concat(utilityMethods);
|
||||
}
|
||||
return result;
|
||||
}, methodNames);
|
||||
}
|
||||
if (!methodNames.length) {
|
||||
methodNames = allMethods;
|
||||
}
|
||||
context._ = _;
|
||||
vm.runInContext(source, context);
|
||||
var templates = context._.templates;
|
||||
|
||||
if (/exclude/.test(command)) {
|
||||
methodNames = _.without.apply(_, [methodNames].concat(
|
||||
expandMethodNames(command.match(/exclude=(\S*)/)[1].split(/, */))
|
||||
));
|
||||
} else {
|
||||
methodNames = expandMethodNames(methodNames);
|
||||
}
|
||||
equal(templates.a(data.a).replace(/[\r\n]+/g, ''), '<ul><li>moe</li><li>larry</li><li>curly</li></ul>', basename);
|
||||
equal(templates.b(data.b), 'Hello stooge.', basename);
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
var lodash = context._ || {};
|
||||
methodNames = _.unique(methodNames);
|
||||
asyncTest('`lodash settings=...`', function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
methodNames.forEach(function(methodName) {
|
||||
testMethod(lodash, methodName, basename);
|
||||
});
|
||||
build(['-s', 'template=' + templatePath + '/*.tpl', 'settings={interpolate:/\\{\\{([\\s\\S]+?)\\}\\}/}'], function(source, filePath) {
|
||||
var basename = path.basename(filePath, '.js'),
|
||||
context = createContext();
|
||||
|
||||
start();
|
||||
});
|
||||
var data = {
|
||||
'c': { 'name': 'Mustache' }
|
||||
};
|
||||
|
||||
context._ = _;
|
||||
vm.runInContext(source, context);
|
||||
var templates = context._.templates;
|
||||
|
||||
equal(templates.c(data.c), 'Hello Mustache!', basename);
|
||||
start();
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('independent builds');
|
||||
|
||||
(function() {
|
||||
asyncTest('debug only', function() {
|
||||
var start = _.once(QUnit.start);
|
||||
build(['-d', '-s'], function(source, filePath) {
|
||||
equal(path.basename(filePath, '.js'), 'lodash');
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest('debug custom', function () {
|
||||
var start = _.once(QUnit.start);
|
||||
build(['-d', '-s', 'backbone'], function(source, filePath) {
|
||||
equal(path.basename(filePath, '.js'), 'lodash.custom');
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest('minified only', function() {
|
||||
var start = _.once(QUnit.start);
|
||||
build(['-m', '-s'], function(source, filePath) {
|
||||
equal(path.basename(filePath, '.js'), 'lodash.min');
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest('minified custom', function () {
|
||||
var start = _.once(QUnit.start);
|
||||
build(['-m', '-s', 'backbone'], function(source, filePath) {
|
||||
equal(path.basename(filePath, '.js'), 'lodash.custom.min');
|
||||
start();
|
||||
});
|
||||
});
|
||||
}());
|
||||
@@ -524,16 +557,15 @@
|
||||
});
|
||||
|
||||
['non-strict', 'strict'].forEach(function(strictMode, index) {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
asyncTest(strictMode + ' should ' + (index ? 'error': 'silently fail') + ' attempting to overwrite read-only properties', function() {
|
||||
var commands = ['-s', 'include=bindAll,defaults,extend'];
|
||||
var commands = ['-s', 'include=bindAll,defaults,extend'],
|
||||
start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
if (index) {
|
||||
commands.push('strict');
|
||||
}
|
||||
|
||||
build(commands, function(source, filepath) {
|
||||
var basename = path.basename(filepath, '.js'),
|
||||
build(commands, function(source, filePath) {
|
||||
var basename = path.basename(filePath, '.js'),
|
||||
context = createContext(),
|
||||
pass = !index;
|
||||
|
||||
@@ -559,18 +591,63 @@
|
||||
QUnit.module('underscore modifier');
|
||||
|
||||
(function() {
|
||||
var start = _.once(QUnit.start);
|
||||
asyncTest('modified methods should work correctly', function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
asyncTest('should not have deep clone', function() {
|
||||
build(['-s', 'underscore'], function(source, filepath) {
|
||||
var array = [{ 'a': 1 }],
|
||||
basename = path.basename(filepath, '.js'),
|
||||
build(['-s', 'underscore'], function(source, filePath) {
|
||||
var last,
|
||||
array = [{ 'value': 1 }, { 'value': 2 }],
|
||||
basename = path.basename(filePath, '.js'),
|
||||
context = createContext();
|
||||
|
||||
vm.runInContext(source, context);
|
||||
var lodash = context._;
|
||||
|
||||
ok(lodash.clone(array, true)[0] === array[0], basename);
|
||||
lodash.each(array, function(value) {
|
||||
last = value;
|
||||
return false;
|
||||
});
|
||||
|
||||
equal(last.value, 2, '_.each: ' + basename);
|
||||
equal(lodash.isEmpty('moe'), false, '_.isEmpty: ' + basename);
|
||||
|
||||
var object = { 'fn': lodash.bind(function(x) { return this.x + x; }, { 'x': 1 }, 1) };
|
||||
equal(object.fn(), 2, '_.bind: ' + basename);
|
||||
|
||||
ok(lodash.clone(array, true)[0] === array[0], '_.clone: ' + basename);
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest('`lodash underscore include=partial`', function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
build(['-s', 'underscore', 'include=partial'], function(source, filePath) {
|
||||
var basename = path.basename(filePath, '.js'),
|
||||
context = createContext();
|
||||
|
||||
vm.runInContext(source, context);
|
||||
var lodash = context._;
|
||||
|
||||
equal(lodash.partial(_.identity, 2)(), 2, '_.partial: ' + basename);
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest('`lodash underscore plus=clone`', function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
build(['-s', 'underscore', 'plus=clone'], function(source, filePath) {
|
||||
var array = [{ 'value': 1 }],
|
||||
basename = path.basename(filePath, '.js'),
|
||||
context = createContext();
|
||||
|
||||
vm.runInContext(source, context);
|
||||
var lodash = context._,
|
||||
clone = lodash.clone(array, true);
|
||||
|
||||
deepEqual(array, clone, basename);
|
||||
notEqual(array, clone, basename);
|
||||
start();
|
||||
});
|
||||
});
|
||||
@@ -590,11 +667,11 @@
|
||||
];
|
||||
|
||||
commands.forEach(function(command, index) {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
asyncTest('`lodash ' + command +'`', function() {
|
||||
build(['-s', command], function(source, filepath) {
|
||||
var basename = path.basename(filepath, '.js'),
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
build(['-s', command], function(source, filePath) {
|
||||
var basename = path.basename(filePath, '.js'),
|
||||
context = createContext(),
|
||||
pass = false;
|
||||
|
||||
@@ -644,21 +721,33 @@
|
||||
QUnit.module('iife command');
|
||||
|
||||
(function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
var commands = [
|
||||
'iife=this["lodash"]=(function(window,undefined){%output%;return lodash}(this))',
|
||||
'iife=define(function(window,undefined){return function(){%output%;return lodash}}(this));'
|
||||
];
|
||||
|
||||
asyncTest('`lodash iife=...`', function() {
|
||||
build(['-s', 'iife=!function(window,undefined){%output%}(this)'], function(source, filepath) {
|
||||
var basename = path.basename(filepath, '.js'),
|
||||
context = createContext();
|
||||
commands.forEach(function(command) {
|
||||
asyncTest('`lodash ' + command +'`', function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
try {
|
||||
vm.runInContext(source, context);
|
||||
} catch(e) { }
|
||||
build(['-s', 'exports=none', command], function(source, filePath) {
|
||||
var basename = path.basename(filePath, '.js'),
|
||||
context = createContext();
|
||||
|
||||
var lodash = context._ || {};
|
||||
ok(_.isString(lodash.VERSION), basename);
|
||||
ok(/!function/.test(source), basename);
|
||||
start();
|
||||
context.define = function(func) {
|
||||
context.lodash = func();
|
||||
};
|
||||
|
||||
try {
|
||||
vm.runInContext(source, context);
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
var lodash = context.lodash || {};
|
||||
ok(_.isString(lodash.VERSION), basename);
|
||||
start();
|
||||
});
|
||||
});
|
||||
});
|
||||
}());
|
||||
@@ -669,11 +758,11 @@
|
||||
|
||||
(function() {
|
||||
['-o a.js', '--output a.js'].forEach(function(command, index) {
|
||||
var start = _.once(QUnit.start);
|
||||
|
||||
asyncTest('`lodash ' + command +'`', function() {
|
||||
build(['-s'].concat(command.split(' ')), function(source, filepath) {
|
||||
equal(filepath, 'a.js', command);
|
||||
var start = _.once(QUnit.start);
|
||||
|
||||
build(['-s'].concat(command.split(' ')), function(source, filePath) {
|
||||
equal(path.basename(filePath, '.js'), 'a', command);
|
||||
start();
|
||||
});
|
||||
});
|
||||
@@ -686,12 +775,18 @@
|
||||
|
||||
(function() {
|
||||
['-c', '--stdout'].forEach(function(command, index) {
|
||||
var descriptor = Object.getOwnPropertyDescriptor(global, 'console'),
|
||||
start = _.once(QUnit.start);
|
||||
|
||||
asyncTest('`lodash ' + command +'`', function() {
|
||||
build([command, 'exports=', 'include='], function(source, filepath) {
|
||||
equal(source, '');
|
||||
var written,
|
||||
start = _.once(QUnit.start),
|
||||
write = process.stdout.write;
|
||||
|
||||
process.stdout.write = function(string) {
|
||||
written = string;
|
||||
};
|
||||
|
||||
build([command, 'exports=', 'include='], function(source) {
|
||||
process.stdout.write = write;
|
||||
equal(written, source);
|
||||
equal(arguments.length, 1);
|
||||
start();
|
||||
});
|
||||
@@ -704,10 +799,10 @@
|
||||
QUnit.module('minify underscore');
|
||||
|
||||
(function() {
|
||||
var start = _.once(QUnit.start);
|
||||
|
||||
asyncTest('`node minify underscore.js`', function() {
|
||||
var source = fs.readFileSync(path.join(__dirname, '..', 'vendor', 'underscore', 'underscore.js'), 'utf8');
|
||||
var source = fs.readFileSync(path.join(__dirname, '..', 'vendor', 'underscore', 'underscore.js'), 'utf8'),
|
||||
start = _.once(QUnit.start);
|
||||
|
||||
minify(source, {
|
||||
'silent': true,
|
||||
'workingName': 'underscore.min',
|
||||
@@ -716,15 +811,158 @@
|
||||
|
||||
try {
|
||||
vm.runInContext(result, context);
|
||||
} catch(e) { }
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
var underscore = context._ || {};
|
||||
ok(_.isString(underscore.VERSION));
|
||||
ok(result.match(/\n/g).length < source.match(/\n/g).length);
|
||||
ok(!/Lo-Dash/.test(result) && result.match(/\n/g).length < source.match(/\n/g).length);
|
||||
start();
|
||||
}
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('mobile build');
|
||||
|
||||
(function() {
|
||||
asyncTest('`lodash mobile`', function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
build(['-s', 'mobile'], function(source, filePath) {
|
||||
var basename = path.basename(filePath, '.js'),
|
||||
context = createContext();
|
||||
|
||||
try {
|
||||
vm.runInContext(source, context);
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
var array = [1, 2, 3],
|
||||
object1 = [{ 'a': 1 }],
|
||||
object2 = [{ 'b': 2 }],
|
||||
object3 = [{ 'a': 1, 'b': 2 }],
|
||||
circular1 = { 'a': 1 },
|
||||
circular2 = { 'a': 1 },
|
||||
lodash = context._;
|
||||
|
||||
circular1.b = circular1;
|
||||
circular2.b = circular2;
|
||||
|
||||
deepEqual(lodash.merge(object1, object2), object3, basename);
|
||||
deepEqual(lodash.sortBy([3, 2, 1], _.identity), array, basename);
|
||||
equal(lodash.isEqual(circular1, circular2), true, basename);
|
||||
|
||||
var actual = lodash.clone(circular1, true);
|
||||
ok(actual != circular1 && actual.b == actual, basename);
|
||||
start();
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash build');
|
||||
|
||||
(function() {
|
||||
var commands = [
|
||||
'backbone',
|
||||
'csp',
|
||||
'legacy',
|
||||
'mobile',
|
||||
'strict',
|
||||
'underscore',
|
||||
'category=arrays',
|
||||
'category=chaining',
|
||||
'category=collections',
|
||||
'category=functions',
|
||||
'category=objects',
|
||||
'category=utilities',
|
||||
'exclude=union,uniq,zip',
|
||||
'include=each,filter,map',
|
||||
'include=once plus=bind,Chaining',
|
||||
'category=collections,functions',
|
||||
'underscore backbone',
|
||||
'backbone legacy category=utilities minus=first,last',
|
||||
'underscore include=debounce,throttle plus=after minus=throttle',
|
||||
'underscore mobile strict category=functions exports=amd,global plus=pick,uniq',
|
||||
]
|
||||
.concat(
|
||||
allMethods.map(function(methodName) {
|
||||
return 'include=' + methodName;
|
||||
})
|
||||
);
|
||||
|
||||
commands.forEach(function(command) {
|
||||
asyncTest('`lodash ' + command +'`', function() {
|
||||
var start = _.after(2, _.once(QUnit.start));
|
||||
|
||||
build(['--silent'].concat(command.split(' ')), function(source, filePath) {
|
||||
var methodNames,
|
||||
basename = path.basename(filePath, '.js'),
|
||||
context = createContext();
|
||||
|
||||
try {
|
||||
vm.runInContext(source, context);
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
// add method names explicitly
|
||||
if (/include/.test(command)) {
|
||||
methodNames = command.match(/include=(\S*)/)[1].split(/, */);
|
||||
}
|
||||
// add method names required by Backbone and Underscore builds
|
||||
if (/backbone/.test(command) && !methodNames) {
|
||||
methodNames = backboneDependencies.slice();
|
||||
}
|
||||
if (/underscore/.test(command) && !methodNames) {
|
||||
methodNames = underscoreMethods.slice();
|
||||
}
|
||||
// add method names explicitly by category
|
||||
if (/category/.test(command)) {
|
||||
// resolve method names belonging to each category (case-insensitive)
|
||||
methodNames = command.match(/category=(\S*)/)[1].split(/, */).reduce(function(result, category) {
|
||||
var capitalized = category[0].toUpperCase() + category.toLowerCase().slice(1);
|
||||
return result.concat(getMethodsByCategory(capitalized));
|
||||
}, methodNames || []);
|
||||
}
|
||||
// init `methodNames` if it hasn't been inited
|
||||
if (!methodNames) {
|
||||
methodNames = allMethods.slice();
|
||||
}
|
||||
if (/plus/.test(command)) {
|
||||
methodNames = methodNames.concat(command.match(/plus=(\S*)/)[1].split(/, */));
|
||||
}
|
||||
if (/minus/.test(command)) {
|
||||
methodNames = _.without.apply(_, [methodNames]
|
||||
.concat(expandMethodNames(command.match(/minus=(\S*)/)[1].split(/, */))));
|
||||
}
|
||||
if (/exclude/.test(command)) {
|
||||
methodNames = _.without.apply(_, [methodNames]
|
||||
.concat(expandMethodNames(command.match(/exclude=(\S*)/)[1].split(/, */))));
|
||||
}
|
||||
|
||||
// expand aliases and categories to real method names
|
||||
methodNames = expandMethodNames(methodNames).reduce(function(result, methodName) {
|
||||
return result.concat(methodName, getMethodsByCategory(methodName));
|
||||
}, []);
|
||||
|
||||
// remove nonexistent and duplicate method names
|
||||
methodNames = _.uniq(_.intersection(allMethods, expandMethodNames(methodNames)));
|
||||
|
||||
var lodash = context._ || {};
|
||||
methodNames.forEach(function(methodName) {
|
||||
testMethod(lodash, methodName, basename);
|
||||
});
|
||||
|
||||
start();
|
||||
});
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
}());
|
||||
|
||||
268
test/test.js
268
test/test.js
@@ -106,7 +106,7 @@
|
||||
|
||||
(function() {
|
||||
// ensure this test is executed before any other template tests to avoid false positives
|
||||
test('should initialize `reEvaluateDelimiter` correctly (test with production build)', function() {
|
||||
test('should initialize `reEvaluateDelimiter` (test with production build)', function() {
|
||||
var data = { 'a': [1, 2] },
|
||||
settings = _.templateSettings;
|
||||
|
||||
@@ -123,6 +123,14 @@
|
||||
}
|
||||
});
|
||||
|
||||
test('supports loading lodash.js with the Require.js "shim" configuration option', function() {
|
||||
if (window.document && window.require) {
|
||||
equal((shimmedModule || {}).moduleName, 'shimmed');
|
||||
} else {
|
||||
skipTest();
|
||||
}
|
||||
});
|
||||
|
||||
test('supports loading lodash.js as the "underscore" module', function() {
|
||||
if (window.document && window.require) {
|
||||
equal((underscoreModule || {}).moduleName, 'underscore');
|
||||
@@ -160,30 +168,13 @@
|
||||
QUnit.module('lodash.bind');
|
||||
|
||||
(function() {
|
||||
test('should correctly append array arguments to partially applied arguments (test in IE < 9)', function() {
|
||||
test('should append array arguments to partially applied arguments (test in IE < 9)', function() {
|
||||
var args,
|
||||
bound = _.bind(function() { args = slice.call(arguments); }, {}, 'a');
|
||||
|
||||
bound(['b'], 'c');
|
||||
deepEqual(args, ['a', ['b'], 'c']);
|
||||
});
|
||||
|
||||
test('supports lazy bind', function() {
|
||||
var object = {
|
||||
'name': 'moe',
|
||||
'greet': function(greeting) {
|
||||
return greeting + ': ' + this.name;
|
||||
}
|
||||
};
|
||||
|
||||
var func = _.bind(object, 'greet', 'hi');
|
||||
equal(func(), 'hi: moe');
|
||||
|
||||
object.greet = function(greeting) {
|
||||
return greeting + ' ' + this.name + '!';
|
||||
};
|
||||
equal(func(), 'hi moe!');
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -221,7 +212,7 @@
|
||||
objects['an array'].length = 5;
|
||||
|
||||
_.forOwn(objects, function(object, key) {
|
||||
test('should deep clone ' + key + ' correctly', function() {
|
||||
test('should deep clone ' + key, function() {
|
||||
var clone = _.clone(object, true);
|
||||
ok(_.isEqual(object, clone));
|
||||
|
||||
@@ -260,19 +251,6 @@
|
||||
ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c && clone !== object);
|
||||
});
|
||||
|
||||
test('should clone using Klass#clone', function() {
|
||||
var object = new Klass;
|
||||
Klass.prototype.clone = function() { return new Klass; };
|
||||
|
||||
var clone = _.clone(object);
|
||||
ok(clone !== object && clone instanceof Klass);
|
||||
|
||||
clone = _.clone(object, true);
|
||||
ok(clone !== object && clone instanceof Klass);
|
||||
|
||||
delete Klass.prototype.clone;
|
||||
});
|
||||
|
||||
test('should clone problem JScript properties (test in IE < 9)', function() {
|
||||
deepEqual(_.clone(shadowed), shadowed);
|
||||
ok(_.clone(shadowed) != shadowed);
|
||||
@@ -341,7 +319,7 @@
|
||||
QUnit.module('lodash.difference');
|
||||
|
||||
(function() {
|
||||
test('should work correctly when using `cachedContains`', function() {
|
||||
test('should work when using `cachedContains`', function() {
|
||||
var array1 = _.range(27),
|
||||
array2 = array1.slice(),
|
||||
a = {},
|
||||
@@ -400,11 +378,12 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('strict mode checks');
|
||||
|
||||
_.each(['bindAll', 'defaults', 'extend'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
QUnit.module('lodash.' + methodName + ' strict mode checks');
|
||||
|
||||
test('should not throw strict mode errors', function() {
|
||||
test('lodash.' + methodName + ' should not throw strict mode errors', function() {
|
||||
var object = { 'a': null, 'b': function(){} },
|
||||
pass = true;
|
||||
|
||||
@@ -488,18 +467,6 @@
|
||||
equal(_.forEach(collection, Boolean), collection);
|
||||
});
|
||||
|
||||
test('should treat array-like object with invalid `length` as a regular object', function() {
|
||||
var keys = [],
|
||||
object = { 'length': -1 };
|
||||
|
||||
_.forEach(object, function(value, key) { keys.push(key); });
|
||||
deepEqual(keys, ['length']);
|
||||
|
||||
keys = []; object.length = Math.pow(2, 32);
|
||||
_.forEach(object, function(value, key) { keys.push(key); });
|
||||
deepEqual(keys, ['length']);
|
||||
});
|
||||
|
||||
_.each({
|
||||
'literal': 'abc',
|
||||
'object': Object('abc')
|
||||
@@ -551,17 +518,18 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('object iteration bugs');
|
||||
|
||||
_.each(['forEach', 'forIn', 'forOwn'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
QUnit.module('lodash.' + methodName + ' iteration bugs');
|
||||
|
||||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
|
||||
test('lodash.' + methodName + ' fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
|
||||
var keys = [];
|
||||
func(shadowed, function(value, key) { keys.push(key); });
|
||||
deepEqual(keys.sort(), shadowedKeys);
|
||||
});
|
||||
|
||||
test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() {
|
||||
test('lodash.' + methodName + ' skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() {
|
||||
function Foo() {}
|
||||
Foo.prototype.a = 1;
|
||||
|
||||
@@ -578,11 +546,14 @@
|
||||
});
|
||||
});
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('exit early');
|
||||
|
||||
_.each(['forEach', 'forIn', 'forOwn'], function(methodName) {
|
||||
var func = _[methodName];
|
||||
QUnit.module('lodash.' + methodName + ' can exit early');
|
||||
|
||||
test('can exit early when iterating arrays', function() {
|
||||
test('lodash.' + methodName + ' can exit early when iterating arrays', function() {
|
||||
var array = [1, 2, 3],
|
||||
values = [];
|
||||
|
||||
@@ -590,7 +561,7 @@
|
||||
deepEqual(values, [1]);
|
||||
});
|
||||
|
||||
test('can exit early when iterating objects', function() {
|
||||
test('lodash.' + methodName + ' can exit early when iterating objects', function() {
|
||||
var object = { 'a': 1, 'b': 2, 'c': 3 },
|
||||
values = [];
|
||||
|
||||
@@ -675,6 +646,15 @@
|
||||
var array = [1, 2, 3];
|
||||
deepEqual(_.initial(array, 0), []);
|
||||
});
|
||||
|
||||
test('should allow a falsey `array` argument', function() {
|
||||
_.each(falsey, function(index, value) {
|
||||
try {
|
||||
var actual = index ? _.initial(value) : _.initial();
|
||||
} catch(e) { }
|
||||
deepEqual(actual, []);
|
||||
})
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -755,17 +735,6 @@
|
||||
equal(_.isEqual(args1, args3), false);
|
||||
});
|
||||
|
||||
test('should respect custom `isEqual` result despite objects strict equaling each other', function() {
|
||||
var object = { 'isEqual': function() { return false; } };
|
||||
equal(_.isEqual(object, object), false);
|
||||
});
|
||||
|
||||
test('should use custom `isEqual` methods on primitives', function() {
|
||||
Boolean.prototype.isEqual = function() { return true; };
|
||||
equal(_.isEqual(true, false), true);
|
||||
delete Boolean.prototype.isEqual;
|
||||
});
|
||||
|
||||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
|
||||
equal(_.isEqual(shadowed, {}), false);
|
||||
});
|
||||
@@ -827,6 +796,24 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.isPlainObject');
|
||||
|
||||
(function() {
|
||||
test('should detect plain objects', function() {
|
||||
function Foo(a) {
|
||||
this.a = 1;
|
||||
}
|
||||
|
||||
equal(_.isPlainObject(new Foo(1)), false);
|
||||
equal(_.isPlainObject([1, 2, 3]), false);
|
||||
equal(_.isPlainObject({ 'a': 1 }), true);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('isType checks');
|
||||
|
||||
_.each([
|
||||
'isArguments',
|
||||
'isArray',
|
||||
@@ -846,9 +833,8 @@
|
||||
'isUndefined'
|
||||
], function(methodName) {
|
||||
var func = _[methodName];
|
||||
QUnit.module('lodash.' + methodName + ' result');
|
||||
|
||||
test('should return a boolean', function() {
|
||||
test('lodash.' + methodName + ' should return a boolean', function() {
|
||||
var expected = 'boolean';
|
||||
|
||||
equal(typeof func(arguments), expected);
|
||||
@@ -938,6 +924,29 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.lateBind');
|
||||
|
||||
(function() {
|
||||
test('should work when the target function is overwritten', function() {
|
||||
var object = {
|
||||
'name': 'moe',
|
||||
'greet': function(greeting) {
|
||||
return greeting + ': ' + this.name;
|
||||
}
|
||||
};
|
||||
|
||||
var func = _.lateBind(object, 'greet', 'hi');
|
||||
equal(func(), 'hi: moe');
|
||||
|
||||
object.greet = function(greeting) {
|
||||
return greeting + ' ' + this.name + '!';
|
||||
};
|
||||
equal(func(), 'hi moe!');
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.merge');
|
||||
|
||||
(function() {
|
||||
@@ -1185,9 +1194,9 @@
|
||||
QUnit.module('lodash.random');
|
||||
|
||||
(function() {
|
||||
test('should work like `Math.random` if no arguments are passed', function() {
|
||||
test('should return `0` or `1` when no arguments are passed', function() {
|
||||
var actual = _.random();
|
||||
ok(actual >= 0 && actual < 1);
|
||||
ok(actual === 0 || actual === 1);
|
||||
});
|
||||
|
||||
test('supports not passing a `max` argument', function() {
|
||||
@@ -1270,22 +1279,6 @@
|
||||
deepEqual(args, expected);
|
||||
});
|
||||
|
||||
test('should treat array-like object with invalid `length` as a regular object', function() {
|
||||
var args,
|
||||
object = { 'a': 1, 'length': -1 },
|
||||
lastKey = _.keys(object).pop();
|
||||
|
||||
var expected = lastKey == 'length'
|
||||
? [-1, 1, 'a', object]
|
||||
: [1, -1, 'length', object];
|
||||
|
||||
_.reduceRight(object, function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
deepEqual(args, expected);
|
||||
});
|
||||
|
||||
_.each({
|
||||
'literal': 'abc',
|
||||
'object': Object('abc')
|
||||
@@ -1307,6 +1300,21 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.rest');
|
||||
|
||||
(function() {
|
||||
test('should allow a falsey `array` argument', function() {
|
||||
_.each(falsey, function(index, value) {
|
||||
try {
|
||||
var actual = index ? _.rest(value) : _.rest();
|
||||
} catch(e) { }
|
||||
deepEqual(actual, []);
|
||||
})
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.size');
|
||||
|
||||
(function() {
|
||||
@@ -1508,7 +1516,7 @@
|
||||
ok(pass);
|
||||
});
|
||||
|
||||
test('should tokenize delimiters correctly', function() {
|
||||
test('should tokenize delimiters', function() {
|
||||
var compiled = _.template('<span class="icon-<%= type %>2"></span>');
|
||||
equal(compiled({ 'type': 1 }), '<span class="icon-12"></span>');
|
||||
});
|
||||
@@ -1517,6 +1525,13 @@
|
||||
var compiled = _.template('<%= value ? value : "b" %>');
|
||||
equal(compiled({ 'value': 'a' }), 'a');
|
||||
});
|
||||
|
||||
test('should parse delimiters with newlines', function() {
|
||||
var expected = '<<\nprint("<p>" + (value ? "yes" : "no") + "</p>")\n>>',
|
||||
compiled = _.template(expected, null, { 'evaluate': /<<(.+?)>>/g });
|
||||
|
||||
equal(compiled({ 'value': true }), expected);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -1568,27 +1583,12 @@
|
||||
(function() {
|
||||
var args = arguments;
|
||||
|
||||
_.each({
|
||||
'an array': ['a', 'b', 'c'],
|
||||
'a string': Object('abc')
|
||||
}, function(collection, key) {
|
||||
test('should call custom `toArray` method of ' + key, function() {
|
||||
collection.toArray = function() { return [3, 2, 1]; };
|
||||
deepEqual(_.toArray(collection), [3, 2, 1]);
|
||||
});
|
||||
});
|
||||
|
||||
test('should treat array-like objects like arrays', function() {
|
||||
var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 };
|
||||
deepEqual(_.toArray(object), ['a', 'b', 'c']);
|
||||
deepEqual(_.toArray(args), [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('should treat array-like object with invalid `length` as a regular object', function() {
|
||||
var object = { 'length': -1 };
|
||||
deepEqual(_.toArray(object), [-1]);
|
||||
});
|
||||
|
||||
test('should work with a string for `collection` (test in Opera < 10.52)', function() {
|
||||
deepEqual(_.toArray('abc'), ['a', 'b', 'c']);
|
||||
deepEqual(_.toArray(Object('abc')), ['a', 'b', 'c']);
|
||||
@@ -1597,6 +1597,16 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.times');
|
||||
|
||||
(function() {
|
||||
test('should return an array of the results of each `callback` execution', function() {
|
||||
deepEqual(_.times(3, function(n) { return n * 2; }), [0, 2, 4]);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.unescape');
|
||||
|
||||
(function() {
|
||||
@@ -1749,7 +1759,61 @@
|
||||
}
|
||||
});
|
||||
|
||||
ok(pass, methodName + ' allows falsey arguments');
|
||||
ok(pass, '_.' + methodName + ' allows falsey arguments');
|
||||
});
|
||||
});
|
||||
|
||||
test('should handle `null` `thisArg` arguments', function() {
|
||||
var thisArg,
|
||||
array = ['a'],
|
||||
callback = function() { thisArg = this; },
|
||||
expected = (function() { return this; }).call(null);
|
||||
|
||||
var funcs = [
|
||||
'countBy',
|
||||
'every',
|
||||
'filter',
|
||||
'find',
|
||||
'forEach',
|
||||
'forIn',
|
||||
'forOwn',
|
||||
'groupBy',
|
||||
'map',
|
||||
'max',
|
||||
'min',
|
||||
'omit',
|
||||
'pick',
|
||||
'reduce',
|
||||
'reduceRight',
|
||||
'reject',
|
||||
'some',
|
||||
'sortBy',
|
||||
'sortedIndex',
|
||||
'times',
|
||||
'uniq'
|
||||
];
|
||||
|
||||
_.each(funcs, function(methodName) {
|
||||
var func = _[methodName],
|
||||
message = '_.' + methodName + ' handles `null` `thisArg` arguments';
|
||||
|
||||
thisArg = undefined;
|
||||
|
||||
if (/^reduce/.test(methodName)) {
|
||||
func(array, callback, 0, null);
|
||||
} else if (methodName == 'sortedIndex') {
|
||||
func(array, 'a', callback, null);
|
||||
} else if (methodName == 'times') {
|
||||
func(1, callback, null);
|
||||
} else {
|
||||
func(array, callback, null);
|
||||
}
|
||||
|
||||
if (expected === null) {
|
||||
deepEqual(thisArg, null, message);
|
||||
} else {
|
||||
equal(thisArg, expected, message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}());
|
||||
|
||||
256
vendor/backbone/backbone.js
vendored
256
vendor/backbone/backbone.js
vendored
@@ -20,6 +20,7 @@
|
||||
|
||||
// Create a local reference to array methods.
|
||||
var ArrayProto = Array.prototype;
|
||||
var push = ArrayProto.push;
|
||||
var slice = ArrayProto.slice;
|
||||
var splice = ArrayProto.splice;
|
||||
|
||||
@@ -182,22 +183,22 @@
|
||||
// is automatically generated and assigned for you.
|
||||
var Model = Backbone.Model = function(attributes, options) {
|
||||
var defaults;
|
||||
attributes || (attributes = {});
|
||||
var attrs = attributes || {};
|
||||
if (options && options.collection) this.collection = options.collection;
|
||||
if (options && options.parse) attributes = this.parse(attributes);
|
||||
if (defaults = _.result(this, 'defaults')) {
|
||||
attributes = _.extend({}, defaults, attributes);
|
||||
attrs = _.extend({}, defaults, attrs);
|
||||
}
|
||||
this.attributes = {};
|
||||
this._escapedAttributes = {};
|
||||
this.cid = _.uniqueId('c');
|
||||
this.changed = {};
|
||||
this._silent = {};
|
||||
this._changes = {};
|
||||
this._pending = {};
|
||||
this.set(attributes, {silent: true});
|
||||
this.set(attrs, {silent: true});
|
||||
// Reset change tracking.
|
||||
this.changed = {};
|
||||
this._silent = {};
|
||||
this._changes = {};
|
||||
this._pending = {};
|
||||
this._previousAttributes = _.clone(this.attributes);
|
||||
this.initialize.apply(this, arguments);
|
||||
@@ -209,14 +210,18 @@
|
||||
// A hash of attributes whose current and previous value differ.
|
||||
changed: null,
|
||||
|
||||
// A hash of attributes that have silently changed since the last time
|
||||
// `change` was called. Will become pending attributes on the next call.
|
||||
_silent: null,
|
||||
// A hash of attributes that have changed since the last time `change`
|
||||
// was called.
|
||||
_changes: null,
|
||||
|
||||
// A hash of attributes that have changed since the last `'change'` event
|
||||
// A hash of attributes that have changed since the last `change` event
|
||||
// began.
|
||||
_pending: null,
|
||||
|
||||
// A hash of attributes with the current model state to determine if
|
||||
// a `change` should be recorded within a nested `change` block.
|
||||
_changing : null,
|
||||
|
||||
// The default name for the JSON `id` attribute is `"id"`. MongoDB and
|
||||
// CouchDB users may want to set this to `"_id"`.
|
||||
idAttribute: 'id',
|
||||
@@ -256,23 +261,22 @@
|
||||
|
||||
// Set a hash of model attributes on the object, firing `"change"` unless
|
||||
// you choose to silence it.
|
||||
set: function(key, value, options) {
|
||||
var attrs, attr, val;
|
||||
set: function(attrs, options) {
|
||||
var attr, key, val;
|
||||
if (attrs == null) return this;
|
||||
|
||||
// Handle both `"key", value` and `{key: value}` -style arguments.
|
||||
if (_.isObject(key) || key == null) {
|
||||
attrs = key;
|
||||
options = value;
|
||||
} else {
|
||||
attrs = {};
|
||||
attrs[key] = value;
|
||||
if (!_.isObject(attrs)) {
|
||||
key = attrs;
|
||||
(attrs = {})[key] = options;
|
||||
options = arguments[2];
|
||||
}
|
||||
|
||||
// Extract attributes and options.
|
||||
options || (options = {});
|
||||
if (!attrs) return this;
|
||||
var silent = options && options.silent;
|
||||
var unset = options && options.unset;
|
||||
if (attrs instanceof Model) attrs = attrs.attributes;
|
||||
if (options.unset) for (attr in attrs) attrs[attr] = void 0;
|
||||
if (unset) for (attr in attrs) attrs[attr] = void 0;
|
||||
|
||||
// Run validation.
|
||||
if (!this._validate(attrs, options)) return false;
|
||||
@@ -280,7 +284,7 @@
|
||||
// Check for changes of `id`.
|
||||
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
|
||||
|
||||
var changes = options.changes = {};
|
||||
var changing = this._changing;
|
||||
var now = this.attributes;
|
||||
var escaped = this._escapedAttributes;
|
||||
var prev = this._previousAttributes || {};
|
||||
@@ -290,27 +294,30 @@
|
||||
val = attrs[attr];
|
||||
|
||||
// If the new and current value differ, record the change.
|
||||
if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
|
||||
if (!_.isEqual(now[attr], val) || (unset && _.has(now, attr))) {
|
||||
delete escaped[attr];
|
||||
(options.silent ? this._silent : changes)[attr] = true;
|
||||
this._changes[attr] = true;
|
||||
}
|
||||
|
||||
// Update or delete the current value.
|
||||
options.unset ? delete now[attr] : now[attr] = val;
|
||||
unset ? delete now[attr] : now[attr] = val;
|
||||
|
||||
// If the new and previous value differ, record the change. If not,
|
||||
// then remove changes for this attribute.
|
||||
if (!_.isEqual(prev[attr], val) || (_.has(now, attr) !== _.has(prev, attr))) {
|
||||
this.changed[attr] = val;
|
||||
if (!options.silent) this._pending[attr] = true;
|
||||
if (!silent) this._pending[attr] = true;
|
||||
} else {
|
||||
delete this.changed[attr];
|
||||
delete this._pending[attr];
|
||||
if (!changing) delete this._changes[attr];
|
||||
}
|
||||
|
||||
if (changing && _.isEqual(now[attr], changing[attr])) delete this._changes[attr];
|
||||
}
|
||||
|
||||
// Fire the `"change"` events.
|
||||
if (!options.silent) this.change(options);
|
||||
if (!silent) this.change(options);
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -345,16 +352,14 @@
|
||||
// Set a hash of model attributes, and sync the model to the server.
|
||||
// If the server returns an attributes hash that differs, the model's
|
||||
// state will be `set` again.
|
||||
save: function(key, value, options) {
|
||||
var attrs, current, done;
|
||||
save: function(attrs, options) {
|
||||
var key, current, done;
|
||||
|
||||
// Handle both `("key", value)` and `({key: value})` -style calls.
|
||||
if (_.isObject(key) || key == null) {
|
||||
attrs = key;
|
||||
options = value;
|
||||
} else {
|
||||
attrs = {};
|
||||
attrs[key] = value;
|
||||
// Handle both `"key", value` and `{key: value}` -style arguments.
|
||||
if (attrs != null && !_.isObject(attrs)) {
|
||||
key = attrs;
|
||||
(attrs = {})[key] = options;
|
||||
options = arguments[2];
|
||||
}
|
||||
options = options ? _.clone(options) : {};
|
||||
|
||||
@@ -371,7 +376,7 @@
|
||||
}
|
||||
|
||||
// Do not persist invalid models.
|
||||
if (!attrs && !this.isValid()) return false;
|
||||
if (!attrs && !this._validate(null, options)) return false;
|
||||
|
||||
// After a successful server-side save, the client is (optionally)
|
||||
// updated with the server-side state.
|
||||
@@ -454,18 +459,25 @@
|
||||
// a `"change:attribute"` event for each changed attribute.
|
||||
// Calling this will cause all objects observing the model to update.
|
||||
change: function(options) {
|
||||
options || (options = {});
|
||||
var changing = this._changing;
|
||||
this._changing = true;
|
||||
var current = this._changing = {};
|
||||
|
||||
// Silent changes become pending changes.
|
||||
for (var attr in this._silent) this._pending[attr] = true;
|
||||
for (var attr in this._changes) this._pending[attr] = true;
|
||||
|
||||
// Silent changes are triggered.
|
||||
var changes = _.extend({}, options.changes, this._silent);
|
||||
this._silent = {};
|
||||
// Trigger 'change:attr' for any new or silent changes.
|
||||
var changes = this._changes;
|
||||
this._changes = {};
|
||||
|
||||
// Set the correct state for this._changing values
|
||||
var triggers = [];
|
||||
for (var attr in changes) {
|
||||
this.trigger('change:' + attr, this, this.get(attr), options);
|
||||
current[attr] = this.get(attr);
|
||||
triggers.push(attr);
|
||||
}
|
||||
|
||||
for (var i=0, l=triggers.length; i < l; i++) {
|
||||
this.trigger('change:' + triggers[i], this, current[triggers[i]], options);
|
||||
}
|
||||
if (changing) return this;
|
||||
|
||||
@@ -475,13 +487,13 @@
|
||||
this.trigger('change', this, options);
|
||||
// Pending and silent changes still remain.
|
||||
for (var attr in this.changed) {
|
||||
if (this._pending[attr] || this._silent[attr]) continue;
|
||||
if (this._pending[attr] || this._changes[attr]) continue;
|
||||
delete this.changed[attr];
|
||||
}
|
||||
this._previousAttributes = _.clone(this.attributes);
|
||||
}
|
||||
|
||||
this._changing = false;
|
||||
this._changing = null;
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -531,7 +543,7 @@
|
||||
// returning `true` if all is well. If a specific `error` callback has
|
||||
// been passed, call that instead of firing the general `"error"` event.
|
||||
_validate: function(attrs, options) {
|
||||
if (options.silent || !this.validate) return true;
|
||||
if (options && options.silent || !this.validate) return true;
|
||||
attrs = _.extend({}, this.attributes, attrs);
|
||||
var error = this.validate(attrs, options);
|
||||
if (!error) return true;
|
||||
@@ -585,59 +597,51 @@
|
||||
// Add a model, or list of models to the set. Pass **silent** to avoid
|
||||
// firing the `add` event for every new model.
|
||||
add: function(models, options) {
|
||||
var i, index, length, model, cid, id, cids = {}, ids = {}, dups = [];
|
||||
options || (options = {});
|
||||
var i, args, length, model, existing;
|
||||
var at = options && options.at;
|
||||
models = _.isArray(models) ? models.slice() : [models];
|
||||
|
||||
// Begin by turning bare objects into model references, and preventing
|
||||
// invalid models or duplicate models from being added.
|
||||
// invalid models from being added.
|
||||
for (i = 0, length = models.length; i < length; i++) {
|
||||
if (!(model = models[i] = this._prepareModel(models[i], options))) {
|
||||
throw new Error("Can't add an invalid model to a collection");
|
||||
}
|
||||
cid = model.cid;
|
||||
id = model.id;
|
||||
if (cids[cid] || this._byCid[cid] || ((id != null) && (ids[id] || this._byId[id]))) {
|
||||
dups.push(i);
|
||||
if (models[i] = this._prepareModel(models[i], options)) continue;
|
||||
throw new Error("Can't add an invalid model to a collection");
|
||||
}
|
||||
|
||||
for (i = models.length - 1; i >= 0; i--) {
|
||||
model = models[i];
|
||||
existing = model.id != null && this._byId[model.id];
|
||||
|
||||
// If a duplicate is found, splice it out and optionally merge it into
|
||||
// the existing model.
|
||||
if (existing || this._byCid[model.cid]) {
|
||||
if (options && options.merge && existing) {
|
||||
existing.set(model, options);
|
||||
}
|
||||
models.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
cids[cid] = ids[id] = model;
|
||||
}
|
||||
|
||||
// Remove duplicates.
|
||||
i = dups.length;
|
||||
while (i--) {
|
||||
dups[i] = models.splice(dups[i], 1)[0];
|
||||
}
|
||||
|
||||
// Listen to added models' events, and index models for lookup by
|
||||
// `id` and by `cid`.
|
||||
for (i = 0, length = models.length; i < length; i++) {
|
||||
(model = models[i]).on('all', this._onModelEvent, this);
|
||||
// Listen to added models' events, and index models for lookup by
|
||||
// `id` and by `cid`.
|
||||
model.on('all', this._onModelEvent, this);
|
||||
this._byCid[model.cid] = model;
|
||||
if (model.id != null) this._byId[model.id] = model;
|
||||
}
|
||||
|
||||
// Insert models into the collection, re-sorting if needed, and triggering
|
||||
// `add` events unless silenced.
|
||||
this.length += length;
|
||||
index = options.at != null ? options.at : this.models.length;
|
||||
splice.apply(this.models, [index, 0].concat(models));
|
||||
|
||||
// Merge in duplicate models.
|
||||
if (options.merge) {
|
||||
for (i = 0, length = dups.length; i < length; i++) {
|
||||
if (model = this._byId[dups[i].id]) model.set(dups[i], options);
|
||||
}
|
||||
}
|
||||
// Update `length` and splice in new models.
|
||||
this.length += models.length;
|
||||
args = [at != null ? at : this.models.length, 0];
|
||||
push.apply(args, models);
|
||||
splice.apply(this.models, args);
|
||||
|
||||
// Sort the collection if appropriate.
|
||||
if (this.comparator && options.at == null) this.sort({silent: true});
|
||||
if (this.comparator && at == null) this.sort({silent: true});
|
||||
|
||||
if (options.silent) return this;
|
||||
for (i = 0, length = this.models.length; i < length; i++) {
|
||||
if (!cids[(model = this.models[i]).cid]) continue;
|
||||
options.index = i;
|
||||
if (options && options.silent) return this;
|
||||
|
||||
// Trigger `add` events.
|
||||
while (model = models.shift()) {
|
||||
model.trigger('add', model, this, options);
|
||||
}
|
||||
|
||||
@@ -731,35 +735,35 @@
|
||||
// normal circumstances, as the set will maintain sort order as each item
|
||||
// is added.
|
||||
sort: function(options) {
|
||||
options || (options = {});
|
||||
if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
|
||||
var boundComparator = _.bind(this.comparator, this);
|
||||
if (this.comparator.length === 1) {
|
||||
this.models = this.sortBy(boundComparator);
|
||||
} else {
|
||||
this.models.sort(boundComparator);
|
||||
if (!this.comparator) {
|
||||
throw new Error('Cannot sort a set without a comparator');
|
||||
}
|
||||
if (!options.silent) this.trigger('reset', this, options);
|
||||
|
||||
if (_.isString(this.comparator) || this.comparator.length === 1) {
|
||||
this.models = this.sortBy(this.comparator, this);
|
||||
} else {
|
||||
this.models.sort(_.bind(this.comparator, this));
|
||||
}
|
||||
|
||||
if (!options || !options.silent) this.trigger('reset', this, options);
|
||||
return this;
|
||||
},
|
||||
|
||||
// Pluck an attribute from each model in the collection.
|
||||
pluck: function(attr) {
|
||||
return _.map(this.models, function(model){ return model.get(attr); });
|
||||
return _.invoke(this.models, 'get', attr);
|
||||
},
|
||||
|
||||
// When you have more items than you want to add or remove individually,
|
||||
// you can reset the entire set with a new list of models, without firing
|
||||
// any `add` or `remove` events. Fires `reset` when finished.
|
||||
reset: function(models, options) {
|
||||
models || (models = []);
|
||||
options || (options = {});
|
||||
for (var i = 0, l = this.models.length; i < l; i++) {
|
||||
this._removeReference(this.models[i]);
|
||||
}
|
||||
this._reset();
|
||||
this.add(models, _.extend({silent: true}, options));
|
||||
if (!options.silent) this.trigger('reset', this, options);
|
||||
if (models) this.add(models, _.extend({silent: true}, options));
|
||||
if (!options || !options.silent) this.trigger('reset', this, options);
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -861,9 +865,9 @@
|
||||
var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
|
||||
'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
|
||||
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
|
||||
'max', 'min', 'sortBy', 'sortedIndex', 'toArray', 'size', 'first', 'head',
|
||||
'take', 'initial', 'rest', 'tail', 'last', 'without', 'indexOf', 'shuffle',
|
||||
'lastIndexOf', 'isEmpty', 'groupBy'];
|
||||
'max', 'min', 'sortedIndex', 'toArray', 'size', 'first', 'head', 'take',
|
||||
'initial', 'rest', 'tail', 'last', 'without', 'indexOf', 'shuffle',
|
||||
'lastIndexOf', 'isEmpty'];
|
||||
|
||||
// Mix in each Underscore method as a proxy to `Collection#models`.
|
||||
_.each(methods, function(method) {
|
||||
@@ -874,6 +878,19 @@
|
||||
};
|
||||
});
|
||||
|
||||
// Underscore methods that take a property name as an argument.
|
||||
var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
|
||||
|
||||
// Use attributes instead of properties.
|
||||
_.each(attributeMethods, function(method) {
|
||||
Collection.prototype[method] = function(value, context) {
|
||||
var iterator = _.isFunction(value) ? value : function(model) {
|
||||
return model.get(value);
|
||||
};
|
||||
return _[method](this.models, iterator, context);
|
||||
};
|
||||
});
|
||||
|
||||
// Backbone.Router
|
||||
// -------------------
|
||||
|
||||
@@ -888,9 +905,10 @@
|
||||
|
||||
// Cached regular expressions for matching named param parts and splatted
|
||||
// parts of route strings.
|
||||
var optionalParam = /\((.*?)\)/g;
|
||||
var namedParam = /:\w+/g;
|
||||
var splatParam = /\*\w+/g;
|
||||
var escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g;
|
||||
var escapeRegExp = /[-{}[\]+?.,\\^$|#\s]/g;
|
||||
|
||||
// Set up all inheritable **Backbone.Router** properties and methods.
|
||||
_.extend(Router.prototype, Events, {
|
||||
@@ -920,6 +938,7 @@
|
||||
// Simple proxy to `Backbone.history` to save a fragment into the history.
|
||||
navigate: function(fragment, options) {
|
||||
Backbone.history.navigate(fragment, options);
|
||||
return this;
|
||||
},
|
||||
|
||||
// Bind all defined routes to `Backbone.history`. We have to reverse the
|
||||
@@ -940,6 +959,7 @@
|
||||
// against the current location hash.
|
||||
_routeToRegExp: function(route) {
|
||||
route = route.replace(escapeRegExp, '\\$&')
|
||||
.replace(optionalParam, '(?:$1)?')
|
||||
.replace(namedParam, '([^\/]+)')
|
||||
.replace(splatParam, '(.*?)');
|
||||
return new RegExp('^' + route + '$');
|
||||
@@ -958,11 +978,15 @@
|
||||
|
||||
// Handles cross-browser history management, based on URL fragments. If the
|
||||
// browser does not support `onhashchange`, falls back to polling.
|
||||
var History = Backbone.History = function(options) {
|
||||
var History = Backbone.History = function() {
|
||||
this.handlers = [];
|
||||
_.bindAll(this, 'checkUrl');
|
||||
this.location = options && options.location || root.location;
|
||||
this.history = options && options.history || root.history;
|
||||
|
||||
// #1653 - Ensure that `History` can be used outside of the browser.
|
||||
if (typeof window !== 'undefined') {
|
||||
this.location = window.location;
|
||||
this.history = window.history;
|
||||
}
|
||||
};
|
||||
|
||||
// Cached regex for cleaning leading hashes and slashes.
|
||||
@@ -1048,7 +1072,7 @@
|
||||
// opened by a non-pushState browser.
|
||||
this.fragment = fragment;
|
||||
var loc = this.location;
|
||||
var atRoot = (loc.pathname.replace(/[^/]$/, '$&/') === this.root) && !loc.search;
|
||||
var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
|
||||
|
||||
// If we've started off with a route from a `pushState`-enabled browser,
|
||||
// but we're currently in a browser that doesn't support it...
|
||||
@@ -1062,7 +1086,7 @@
|
||||
// in a browser where it could be `pushState`-based instead...
|
||||
} else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
|
||||
this.fragment = this.getHash().replace(routeStripper, '');
|
||||
this.history.replaceState({}, document.title, this.root + this.fragment);
|
||||
this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
|
||||
}
|
||||
|
||||
if (!this.options.silent) return this.loadUrl();
|
||||
@@ -1121,7 +1145,7 @@
|
||||
fragment = this.getFragment(fragment || '');
|
||||
if (this.fragment === fragment) return;
|
||||
this.fragment = fragment;
|
||||
var url = (fragment.indexOf(this.root) !== 0 ? this.root : '') + fragment;
|
||||
var url = this.root + fragment;
|
||||
|
||||
// If pushState is available, we use it to set the fragment as a real URL.
|
||||
if (this._hasPushState) {
|
||||
@@ -1151,9 +1175,11 @@
|
||||
// a new one to the browser history.
|
||||
_updateHash: function(location, fragment, replace) {
|
||||
if (replace) {
|
||||
location.replace(location.href.replace(/(javascript:|#).*$/, '') + '#' + fragment);
|
||||
var href = location.href.replace(/(javascript:|#).*$/, '');
|
||||
location.replace(href + '#' + fragment);
|
||||
} else {
|
||||
location.hash = fragment;
|
||||
// #1649 - Some browsers require that `hash` contains a leading #.
|
||||
location.hash = '#' + fragment;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,7 +1333,7 @@
|
||||
if (this.className) attrs['class'] = _.result(this, 'className');
|
||||
this.setElement(this.make(_.result(this, 'tagName'), attrs), false);
|
||||
} else {
|
||||
this.setElement(this.el, false);
|
||||
this.setElement(_.result(this, 'el'), false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1422,9 +1448,12 @@
|
||||
child = function(){ parent.apply(this, arguments); };
|
||||
}
|
||||
|
||||
// Add static properties to the constructor function, if supplied.
|
||||
_.extend(child, parent, staticProps);
|
||||
|
||||
// Set the prototype chain to inherit from `parent`, without calling
|
||||
// `parent`'s constructor function.
|
||||
function Surrogate(){ this.constructor = child; };
|
||||
var Surrogate = function(){ this.constructor = child; };
|
||||
Surrogate.prototype = parent.prototype;
|
||||
child.prototype = new Surrogate;
|
||||
|
||||
@@ -1432,9 +1461,6 @@
|
||||
// if supplied.
|
||||
if (protoProps) _.extend(child.prototype, protoProps);
|
||||
|
||||
// Add static properties to the constructor function, if supplied.
|
||||
_.extend(child, parent, staticProps);
|
||||
|
||||
// Set a convenience property in case the parent's prototype is needed
|
||||
// later.
|
||||
child.__super__ = parent.prototype;
|
||||
|
||||
79
vendor/backbone/test/collection.js
vendored
79
vendor/backbone/test/collection.js
vendored
@@ -34,6 +34,15 @@ $(document).ready(function() {
|
||||
equal(col.length, 4);
|
||||
});
|
||||
|
||||
test("String comparator.", 1, function() {
|
||||
var collection = new Backbone.Collection([
|
||||
{id: 3},
|
||||
{id: 1},
|
||||
{id: 2}
|
||||
], {comparator: 'id'});
|
||||
deepEqual(collection.pluck('id'), [1, 2, 3]);
|
||||
});
|
||||
|
||||
test("new and parse", 3, function() {
|
||||
var Collection = Backbone.Collection.extend({
|
||||
parse : function(data) {
|
||||
@@ -88,7 +97,7 @@ $(document).ready(function() {
|
||||
equal(col.pluck('label').join(' '), 'a b c d');
|
||||
});
|
||||
|
||||
test("add", 11, function() {
|
||||
test("add", 10, function() {
|
||||
var added, opts, secondAdded;
|
||||
added = opts = secondAdded = null;
|
||||
e = new Backbone.Model({id: 10, label : 'e'});
|
||||
@@ -98,7 +107,6 @@ $(document).ready(function() {
|
||||
});
|
||||
col.on('add', function(model, collection, options){
|
||||
added = model.get('label');
|
||||
equal(options.index, 4);
|
||||
opts = options;
|
||||
});
|
||||
col.add(e, {amazing: true});
|
||||
@@ -222,7 +230,7 @@ $(document).ready(function() {
|
||||
equal(col.indexOf(tom), 2);
|
||||
});
|
||||
|
||||
test("comparator that depends on `this`", 1, function() {
|
||||
test("comparator that depends on `this`", 2, function() {
|
||||
var col = new Backbone.Collection;
|
||||
col.negative = function(num) {
|
||||
return -num;
|
||||
@@ -231,7 +239,12 @@ $(document).ready(function() {
|
||||
return this.negative(a.id);
|
||||
};
|
||||
col.add([{id: 1}, {id: 2}, {id: 3}]);
|
||||
equal(col.pluck('id').join(' '), '3 2 1');
|
||||
deepEqual(col.pluck('id'), [3, 2, 1]);
|
||||
col.comparator = function(a, b) {
|
||||
return this.negative(b.id) - this.negative(a.id);
|
||||
};
|
||||
col.sort();
|
||||
deepEqual(col.pluck('id'), [1, 2, 3]);
|
||||
});
|
||||
|
||||
test("remove", 5, function() {
|
||||
@@ -549,23 +562,6 @@ $(document).ready(function() {
|
||||
});
|
||||
});
|
||||
|
||||
test("index with comparator", 4, function() {
|
||||
var counter = 0;
|
||||
var col = new Backbone.Collection([{id: 2}, {id: 4}], {
|
||||
comparator: function(model){ return model.id; }
|
||||
}).on('add', function(model, colleciton, options){
|
||||
if (model.id == 1) {
|
||||
equal(options.index, 0);
|
||||
equal(counter++, 0);
|
||||
}
|
||||
if (model.id == 3) {
|
||||
equal(options.index, 2);
|
||||
equal(counter++, 1);
|
||||
}
|
||||
});
|
||||
col.add([{id: 3}, {id: 1}]);
|
||||
});
|
||||
|
||||
test("throwing during add leaves consistent state", 4, function() {
|
||||
var col = new Backbone.Collection();
|
||||
col.on('test', function() { ok(false); });
|
||||
@@ -651,7 +647,7 @@ $(document).ready(function() {
|
||||
collection.create({id: 1});
|
||||
});
|
||||
|
||||
test("#1447 - create with wait adds model.", function() {
|
||||
test("#1447 - create with wait adds model.", 1, function() {
|
||||
var collection = new Backbone.Collection;
|
||||
var model = new Backbone.Model;
|
||||
model.sync = function(method, model, options){ options.success(); };
|
||||
@@ -659,7 +655,7 @@ $(document).ready(function() {
|
||||
collection.create(model, {wait: true});
|
||||
});
|
||||
|
||||
test("#1448 - add sorts collection after merge.", function() {
|
||||
test("#1448 - add sorts collection after merge.", 1, function() {
|
||||
var collection = new Backbone.Collection([
|
||||
{id: 1, x: 1},
|
||||
{id: 2, x: 2}
|
||||
@@ -668,4 +664,41 @@ $(document).ready(function() {
|
||||
collection.add({id: 1, x: 3}, {merge: true});
|
||||
deepEqual(collection.pluck('id'), [2, 1]);
|
||||
});
|
||||
|
||||
test("#1655 - groupBy can be used with a string argument.", 3, function() {
|
||||
var collection = new Backbone.Collection([{x: 1}, {x: 2}]);
|
||||
var grouped = collection.groupBy('x');
|
||||
strictEqual(_.keys(grouped).length, 2);
|
||||
strictEqual(grouped[1][0].get('x'), 1);
|
||||
strictEqual(grouped[2][0].get('x'), 2);
|
||||
});
|
||||
|
||||
test("#1655 - sortBy can be used with a string argument.", 1, function() {
|
||||
var collection = new Backbone.Collection([{x: 3}, {x: 1}, {x: 2}]);
|
||||
var values = _.map(collection.sortBy('x'), function(model) {
|
||||
return model.get('x');
|
||||
});
|
||||
deepEqual(values, [1, 2, 3]);
|
||||
});
|
||||
|
||||
test("#1604 - Removal during iteration.", 0, function() {
|
||||
var collection = new Backbone.Collection([{}, {}]);
|
||||
collection.on('add', function() {
|
||||
collection.at(0).destroy();
|
||||
});
|
||||
collection.add({}, {at: 0});
|
||||
});
|
||||
|
||||
test("#1638 - `sort` during `add` triggers correctly.", function() {
|
||||
var collection = new Backbone.Collection;
|
||||
collection.comparator = function(model) { return model.get('x'); };
|
||||
var added = [];
|
||||
collection.on('add', function(model) {
|
||||
model.set({x: 3});
|
||||
collection.sort();
|
||||
added.push(model.id);
|
||||
});
|
||||
collection.add([{id: 1, x: 1}, {id: 2, x: 2}]);
|
||||
deepEqual(added, [1, 2]);
|
||||
});
|
||||
});
|
||||
|
||||
66
vendor/backbone/test/model.js
vendored
66
vendor/backbone/test/model.js
vendored
@@ -740,9 +740,9 @@ $(document).ready(function() {
|
||||
model.set({b: 2}, {silent: true});
|
||||
});
|
||||
model.set({b: 0});
|
||||
deepEqual(changes, [0, 1, 1]);
|
||||
deepEqual(changes, [0, 1]);
|
||||
model.change();
|
||||
deepEqual(changes, [0, 1, 1, 2, 1]);
|
||||
deepEqual(changes, [0, 1, 2, 1]);
|
||||
});
|
||||
|
||||
test("nested set multiple times", 1, function() {
|
||||
@@ -816,4 +816,66 @@ $(document).ready(function() {
|
||||
strictEqual(model.save(), false);
|
||||
});
|
||||
|
||||
test("#1377 - Save without attrs triggers 'error'.", 1, function() {
|
||||
var Model = Backbone.Model.extend({
|
||||
url: '/test/',
|
||||
sync: function(method, model, options){ options.success(); },
|
||||
validate: function(){ return 'invalid'; }
|
||||
});
|
||||
var model = new Model({id: 1});
|
||||
model.on('error', function(){ ok(true); });
|
||||
model.save();
|
||||
});
|
||||
|
||||
test("#1545 - `undefined` can be passed to a model constructor without coersion", function() {
|
||||
var Model = Backbone.Model.extend({
|
||||
defaults: { one: 1 },
|
||||
initialize : function(attrs, opts) {
|
||||
equal(attrs, undefined);
|
||||
}
|
||||
});
|
||||
var emptyattrs = new Model();
|
||||
var undefinedattrs = new Model(undefined);
|
||||
});
|
||||
|
||||
asyncTest("#1478 - Model `save` does not trigger change on unchanged attributes", 0, function() {
|
||||
var Model = Backbone.Model.extend({
|
||||
sync: function(method, model, options) {
|
||||
setTimeout(function(){
|
||||
options.success();
|
||||
start();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
new Model({x: true})
|
||||
.on('change:x', function(){ ok(false); })
|
||||
.save(null, {wait: true});
|
||||
});
|
||||
|
||||
test("#1664 - Changing from one value, silently to another, back to original does not trigger change.", 0, function() {
|
||||
var model = new Backbone.Model({x:1});
|
||||
model.on('change:x', function() { ok(false); });
|
||||
model.set({x:2},{silent:true});
|
||||
model.set({x:3},{silent:true});
|
||||
model.set({x:1});
|
||||
});
|
||||
|
||||
test("#1664 - multiple silent changes nested inside a change event", 2, function() {
|
||||
var changes = [];
|
||||
var model = new Backbone.Model();
|
||||
model.on('change', function() {
|
||||
model.set({a:'c'}, {silent:true});
|
||||
model.set({b:2}, {silent:true});
|
||||
model.unset('c', {silent:true});
|
||||
model.set({a:'a'}, {silent:true});
|
||||
model.set({b:1}, {silent:true});
|
||||
model.set({c:'item'}, {silent:true});
|
||||
});
|
||||
model.on('change:a change:b change:c', function(model, val) { changes.push(val); });
|
||||
model.set({a:'a', b:1, c:'item'});
|
||||
deepEqual(changes, ['a',1,'item']);
|
||||
model.change();
|
||||
deepEqual(changes, ['a',1,'item']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
62
vendor/backbone/test/router.js
vendored
62
vendor/backbone/test/router.js
vendored
@@ -41,7 +41,7 @@ $(document).ready(function() {
|
||||
|
||||
setup: function() {
|
||||
location = new Location('http://example.com');
|
||||
Backbone.history = new Backbone.History({location: location});
|
||||
Backbone.history = _.extend(new Backbone.History, {location: location});
|
||||
router = new Router({testing: 101});
|
||||
Backbone.history.interval = 9;
|
||||
Backbone.history.start({pushState: false});
|
||||
@@ -69,6 +69,7 @@ $(document).ready(function() {
|
||||
"contacts": "contacts",
|
||||
"contacts/new": "newContact",
|
||||
"contacts/:id": "loadContact",
|
||||
"optional(/:item)": "optionalItem",
|
||||
"splat/*args/end": "splat",
|
||||
"*first/complex-:part/*rest": "complex",
|
||||
":entity?*args": "query",
|
||||
@@ -105,6 +106,10 @@ $(document).ready(function() {
|
||||
this.contact = 'load';
|
||||
},
|
||||
|
||||
optionalItem: function(arg){
|
||||
this.arg = arg !== undefined ? arg : null;
|
||||
},
|
||||
|
||||
splat : function(args) {
|
||||
this.args = args;
|
||||
},
|
||||
@@ -199,6 +204,15 @@ $(document).ready(function() {
|
||||
equal(router.args, 'long-list/of/splatted_99args');
|
||||
});
|
||||
|
||||
test("routes (optional)", 2, function() {
|
||||
location.replace('http://example.com#optional');
|
||||
Backbone.history.checkUrl();
|
||||
equal(router.arg, null);
|
||||
location.replace('http://example.com#optional/thing');
|
||||
Backbone.history.checkUrl();
|
||||
equal(router.arg, 'thing');
|
||||
});
|
||||
|
||||
test("routes (complex)", 3, function() {
|
||||
location.replace('http://example.com#one/two/three/complex-part/four/five/six/seven');
|
||||
Backbone.history.checkUrl();
|
||||
@@ -233,12 +247,12 @@ $(document).ready(function() {
|
||||
location.replace('http://example.com/root/foo');
|
||||
|
||||
Backbone.history.stop();
|
||||
Backbone.history = new Backbone.History({location: location});
|
||||
Backbone.history = _.extend(new Backbone.History, {location: location});
|
||||
Backbone.history.start({root: '/root', hashChange: false, silent: true});
|
||||
strictEqual(Backbone.history.getFragment(), 'foo');
|
||||
|
||||
Backbone.history.stop();
|
||||
Backbone.history = new Backbone.History({location: location});
|
||||
Backbone.history = _.extend(new Backbone.History, {location: location});
|
||||
Backbone.history.start({root: '/root/', hashChange: false, silent: true});
|
||||
strictEqual(Backbone.history.getFragment(), 'foo');
|
||||
});
|
||||
@@ -272,7 +286,7 @@ $(document).ready(function() {
|
||||
test("#1185 - Use pathname when hashChange is not wanted.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/path/name#hash');
|
||||
Backbone.history = new Backbone.History({location: location});
|
||||
Backbone.history = _.extend(new Backbone.History, {location: location});
|
||||
Backbone.history.start({hashChange: false});
|
||||
var fragment = Backbone.history.getFragment();
|
||||
strictEqual(fragment, location.pathname.replace(/^\//, ''));
|
||||
@@ -281,7 +295,7 @@ $(document).ready(function() {
|
||||
test("#1206 - Strip leading slash before location.assign.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root/');
|
||||
Backbone.history = new Backbone.History({location: location});
|
||||
Backbone.history = _.extend(new Backbone.History, {location: location});
|
||||
Backbone.history.start({hashChange: false, root: '/root/'});
|
||||
location.assign = function(pathname) {
|
||||
strictEqual(pathname, '/root/fragment');
|
||||
@@ -292,7 +306,7 @@ $(document).ready(function() {
|
||||
test("#1387 - Root fragment without trailing slash.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root');
|
||||
Backbone.history = new Backbone.History({location: location});
|
||||
Backbone.history = _.extend(new Backbone.History, {location: location});
|
||||
Backbone.history.start({hashChange: false, root: '/root/', silent: true});
|
||||
strictEqual(Backbone.history.getFragment(), '');
|
||||
});
|
||||
@@ -300,7 +314,7 @@ $(document).ready(function() {
|
||||
test("#1366 - History does not prepend root to fragment.", 2, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root/');
|
||||
Backbone.history = new Backbone.History({
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(state, title, url) {
|
||||
@@ -320,7 +334,7 @@ $(document).ready(function() {
|
||||
test("Normalize root.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root');
|
||||
Backbone.history = new Backbone.History({
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(state, title, url) {
|
||||
@@ -339,7 +353,7 @@ $(document).ready(function() {
|
||||
test("Normalize root.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root#fragment');
|
||||
Backbone.history = new Backbone.History({
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(state, title, url) {},
|
||||
@@ -357,7 +371,7 @@ $(document).ready(function() {
|
||||
test("Normalize root.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root');
|
||||
Backbone.history = new Backbone.History({location: location});
|
||||
Backbone.history = _.extend(new Backbone.History, {location: location});
|
||||
Backbone.history.loadUrl = function() { ok(true); };
|
||||
Backbone.history.start({
|
||||
pushState: true,
|
||||
@@ -368,7 +382,7 @@ $(document).ready(function() {
|
||||
test("Normalize root - leading slash.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root');
|
||||
Backbone.history = new Backbone.History({
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(){},
|
||||
@@ -382,7 +396,7 @@ $(document).ready(function() {
|
||||
test("Transition from hashChange to pushState.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root#x/y');
|
||||
Backbone.history = new Backbone.History({
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(){},
|
||||
@@ -400,7 +414,7 @@ $(document).ready(function() {
|
||||
test("#1619: Router: Normalize empty root", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/');
|
||||
Backbone.history = new Backbone.History({
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(){},
|
||||
@@ -414,7 +428,7 @@ $(document).ready(function() {
|
||||
test("#1619: Router: nagivate with empty root", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/');
|
||||
Backbone.history = new Backbone.History({
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(state, title, url) {
|
||||
@@ -436,7 +450,7 @@ $(document).ready(function() {
|
||||
location.replace = function(url) {
|
||||
strictEqual(url, '/root/?a=b#x/y');
|
||||
};
|
||||
Backbone.history = new Backbone.History({
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: null,
|
||||
@@ -449,4 +463,22 @@ $(document).ready(function() {
|
||||
});
|
||||
});
|
||||
|
||||
test("#1695 - hashChange to pushState with search.", 1, function() {
|
||||
Backbone.history.stop();
|
||||
location.replace('http://example.com/root?a=b#x/y');
|
||||
Backbone.history = _.extend(new Backbone.History, {
|
||||
location: location,
|
||||
history: {
|
||||
pushState: function(){},
|
||||
replaceState: function(state, title, url){
|
||||
strictEqual(url, '/root/x/y?a=b');
|
||||
}
|
||||
}
|
||||
});
|
||||
Backbone.history.start({
|
||||
root: 'root',
|
||||
pushState: true
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
11
vendor/backbone/test/view.js
vendored
11
vendor/backbone/test/view.js
vendored
@@ -312,4 +312,15 @@ $(document).ready(function() {
|
||||
view.remove();
|
||||
});
|
||||
|
||||
test("Provide function for el.", 1, function() {
|
||||
var View = Backbone.View.extend({
|
||||
el: function() {
|
||||
return "<p><a></a></p>";
|
||||
}
|
||||
});
|
||||
|
||||
var view = new View;
|
||||
ok(view.$el.is('p:has(a)'));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
1
vendor/benchmark.js/README.md
vendored
1
vendor/benchmark.js/README.md
vendored
@@ -1,4 +1,5 @@
|
||||
# Benchmark.js <sup>v1.0.0</sup>
|
||||
[](http://travis-ci.org/bestiejs/benchmark.js)
|
||||
|
||||
A [robust](http://calendar.perfplanet.com/2010/bulletproof-javascript-benchmarks/ "Bulletproof JavaScript benchmarks") benchmarking library that works on nearly all JavaScript platforms<sup><a name="fnref1" href="#fn1">1</a></sup>, supports high-resolution timers, and returns statistically significant results. As seen on [jsPerf](http://jsperf.com/).
|
||||
|
||||
|
||||
4
vendor/platform.js/platform.js
vendored
4
vendor/platform.js/platform.js
vendored
@@ -830,10 +830,10 @@
|
||||
};
|
||||
}
|
||||
// add browser/OS architecture
|
||||
if ((data = / (?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) {
|
||||
if ((data = /\b(?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) {
|
||||
if (os) {
|
||||
os.architecture = 64;
|
||||
os.family = os.family.replace(data, '');
|
||||
os.family = os.family.replace(RegExp(' *' + data), '');
|
||||
}
|
||||
if (name && (/WOW64/i.test(ua) ||
|
||||
(useFeatures && /\w(?:86|32)$/.test(nav.cpuClass || nav.platform)))) {
|
||||
|
||||
7
vendor/qunit-clib/qunit-clib.js
vendored
7
vendor/qunit-clib/qunit-clib.js
vendored
@@ -171,7 +171,12 @@
|
||||
|
||||
// exit out of Node.js
|
||||
try {
|
||||
process.exit();
|
||||
if (details.failed) {
|
||||
console.error('Error: ' + details.failed + ' of ' + details.total + ' tests failed.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
} catch(e) { }
|
||||
}
|
||||
|
||||
|
||||
15
vendor/underscore/test/arrays.js
vendored
15
vendor/underscore/test/arrays.js
vendored
@@ -144,7 +144,6 @@ $(document).ready(function() {
|
||||
equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
|
||||
var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
|
||||
equal(result, 1, 'works on an arguments object');
|
||||
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
|
||||
|
||||
var numbers = [10, 20, 30, 40, 50], num = 35;
|
||||
var index = _.indexOf(numbers, num, true);
|
||||
@@ -157,16 +156,26 @@ $(document).ready(function() {
|
||||
numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40;
|
||||
index = _.indexOf(numbers, num, true);
|
||||
equal(index, 1, '40 is in the list');
|
||||
|
||||
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
|
||||
index = _.indexOf(numbers, 2, 5);
|
||||
equal(index, 7, 'supports the fromIndex argument');
|
||||
});
|
||||
|
||||
test("lastIndexOf", function() {
|
||||
var numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0];
|
||||
var numbers = [1, 0, 1];
|
||||
equal(_.lastIndexOf(numbers, 1), 2);
|
||||
|
||||
numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0];
|
||||
numbers.lastIndexOf = null;
|
||||
equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function');
|
||||
equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
|
||||
var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0);
|
||||
equal(result, 5, 'works on an arguments object');
|
||||
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
|
||||
|
||||
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
|
||||
index = _.lastIndexOf(numbers, 2, 2);
|
||||
equal(index, 1, 'supports the fromIndex argument');
|
||||
});
|
||||
|
||||
test("range", function() {
|
||||
|
||||
141
vendor/underscore/test/collections.js
vendored
141
vendor/underscore/test/collections.js
vendored
@@ -25,10 +25,6 @@ $(document).ready(function() {
|
||||
answer = null;
|
||||
_.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; });
|
||||
ok(answer, 'can reference the original collection from inside the iterator');
|
||||
|
||||
answers = 0;
|
||||
_.each(null, function(){ ++answers; });
|
||||
equal(answers, 0, 'handles a null properly');
|
||||
});
|
||||
|
||||
test('map', function() {
|
||||
@@ -44,14 +40,16 @@ $(document).ready(function() {
|
||||
var doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
|
||||
equal(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers');
|
||||
|
||||
if (document.querySelectorAll) {
|
||||
var ids = _.map(document.querySelectorAll('#map-test *'), function(n){ return n.id; });
|
||||
deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on NodeLists.');
|
||||
}
|
||||
|
||||
var ids = _.map($('#map-test').children(), function(n){ return n.id; });
|
||||
deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on NodeLists.');
|
||||
deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on jQuery Array-likes.');
|
||||
|
||||
var ids = _.map(document.images, function(n){ return n.id; });
|
||||
ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections');
|
||||
|
||||
var ifnull = _.map(null, function(){});
|
||||
ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly');
|
||||
});
|
||||
|
||||
test('reduce', function() {
|
||||
@@ -71,15 +69,6 @@ $(document).ready(function() {
|
||||
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
|
||||
equal(sum, 6, 'default initial value');
|
||||
|
||||
var ifnull;
|
||||
try {
|
||||
_.reduce(null, function(){});
|
||||
} catch (ex) {
|
||||
ifnull = ex;
|
||||
}
|
||||
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
|
||||
|
||||
ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
|
||||
equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
|
||||
raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
|
||||
});
|
||||
@@ -94,18 +83,44 @@ $(document).ready(function() {
|
||||
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; });
|
||||
equal(list, 'bazbarfoo', 'default initial value');
|
||||
|
||||
var ifnull;
|
||||
try {
|
||||
_.reduceRight(null, function(){});
|
||||
} catch (ex) {
|
||||
ifnull = ex;
|
||||
}
|
||||
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
|
||||
|
||||
ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
|
||||
var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; });
|
||||
equal(sum, 6, 'default initial value on object');
|
||||
|
||||
equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
|
||||
raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
|
||||
|
||||
// Assert that the correct arguments are being passed.
|
||||
|
||||
var args,
|
||||
memo = {},
|
||||
object = {a: 1, b: 2},
|
||||
lastKey = _.keys(object).pop();
|
||||
|
||||
var expected = lastKey == 'a'
|
||||
? [memo, 1, 'a', object]
|
||||
: [memo, 2, 'b', object];
|
||||
|
||||
_.reduceRight(object, function() {
|
||||
args || (args = _.toArray(arguments));
|
||||
}, memo);
|
||||
|
||||
deepEqual(args, expected);
|
||||
|
||||
// And again, with numeric keys.
|
||||
|
||||
object = {'2': 'a', '1': 'b'};
|
||||
lastKey = _.keys(object).pop();
|
||||
args = null;
|
||||
|
||||
expected = lastKey == '2'
|
||||
? [memo, 'a', '2', object]
|
||||
: [memo, 'b', '1', object];
|
||||
|
||||
_.reduceRight(object, function() {
|
||||
args || (args = _.toArray(arguments));
|
||||
}, memo);
|
||||
|
||||
deepEqual(args, expected);
|
||||
});
|
||||
|
||||
test('find', function() {
|
||||
@@ -201,6 +216,16 @@ $(document).ready(function() {
|
||||
equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'pulls names out of objects');
|
||||
});
|
||||
|
||||
test('where', function() {
|
||||
var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
|
||||
var result = _.where(list, {a: 1});
|
||||
equal(result.length, 3);
|
||||
equal(result[result.length - 1].b, 4);
|
||||
result = _.where(list, {b: 2});
|
||||
equal(result.length, 2);
|
||||
equal(result[0].a, 1);
|
||||
});
|
||||
|
||||
test('max', function() {
|
||||
equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max');
|
||||
|
||||
@@ -240,6 +265,29 @@ $(document).ready(function() {
|
||||
var list = ["one", "two", "three", "four", "five"];
|
||||
var sorted = _.sortBy(list, 'length');
|
||||
equal(sorted.join(' '), 'one two four five three', 'sorted by length');
|
||||
|
||||
function Pair(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
var collection = [
|
||||
new Pair(1, 1), new Pair(1, 2),
|
||||
new Pair(1, 3), new Pair(1, 4),
|
||||
new Pair(1, 5), new Pair(1, 6),
|
||||
new Pair(2, 1), new Pair(2, 2),
|
||||
new Pair(2, 3), new Pair(2, 4),
|
||||
new Pair(2, 5), new Pair(2, 6),
|
||||
new Pair(undefined, 1), new Pair(undefined, 2),
|
||||
new Pair(undefined, 3), new Pair(undefined, 4),
|
||||
new Pair(undefined, 5), new Pair(undefined, 6)
|
||||
];
|
||||
|
||||
var actual = _.sortBy(collection, function(pair) {
|
||||
return pair.x;
|
||||
});
|
||||
|
||||
deepEqual(actual, collection, 'sortBy should be stable');
|
||||
});
|
||||
|
||||
test('groupBy', function() {
|
||||
@@ -252,6 +300,18 @@ $(document).ready(function() {
|
||||
equal(grouped['3'].join(' '), 'one two six ten');
|
||||
equal(grouped['4'].join(' '), 'four five nine');
|
||||
equal(grouped['5'].join(' '), 'three seven eight');
|
||||
|
||||
var context = {};
|
||||
_.groupBy([{}], function(){ ok(this === context); }, context);
|
||||
|
||||
grouped = _.groupBy([4.2, 6.1, 6.4], function(num) {
|
||||
return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
|
||||
});
|
||||
equal(grouped.constructor.length, 1);
|
||||
equal(grouped.hasOwnProperty.length, 2);
|
||||
|
||||
var array = [{}];
|
||||
_.groupBy(array, function(value, index, obj){ ok(obj === array); });
|
||||
});
|
||||
|
||||
test('countBy', function() {
|
||||
@@ -264,6 +324,18 @@ $(document).ready(function() {
|
||||
equal(grouped['3'], 4);
|
||||
equal(grouped['4'], 3);
|
||||
equal(grouped['5'], 3);
|
||||
|
||||
var context = {};
|
||||
_.countBy([{}], function(){ ok(this === context); }, context);
|
||||
|
||||
grouped = _.countBy([4.2, 6.1, 6.4], function(num) {
|
||||
return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
|
||||
});
|
||||
equal(grouped.constructor, 1);
|
||||
equal(grouped.hasOwnProperty, 2);
|
||||
|
||||
var array = [{}];
|
||||
_.countBy(array, function(value, index, obj){ ok(obj === array); });
|
||||
});
|
||||
|
||||
test('sortedIndex', function() {
|
||||
@@ -273,6 +345,15 @@ $(document).ready(function() {
|
||||
|
||||
var indexFor30 = _.sortedIndex(numbers, 30);
|
||||
equal(indexFor30, 2, '30 should be inserted at index 2');
|
||||
|
||||
var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}];
|
||||
var iterator = function(obj){ return obj.x; };
|
||||
strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2);
|
||||
strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3);
|
||||
|
||||
var context = {1: 2, 2: 3, 3: 4};
|
||||
iterator = function(obj){ return this[obj]; };
|
||||
strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1);
|
||||
});
|
||||
|
||||
test('shuffle', function() {
|
||||
@@ -291,14 +372,6 @@ $(document).ready(function() {
|
||||
|
||||
var numbers = _.toArray({one : 1, two : 2, three : 3});
|
||||
equal(numbers.join(', '), '1, 2, 3', 'object flattened into array');
|
||||
|
||||
var objectWithToArrayFunction = {toArray: function() {
|
||||
return [1, 2, 3];
|
||||
}};
|
||||
equal(_.toArray(objectWithToArrayFunction).join(', '), '1, 2, 3', 'toArray method used if present');
|
||||
|
||||
var objectWithToArrayValue = {toArray: 1};
|
||||
equal(_.toArray(objectWithToArrayValue).join(', '), '1', 'toArray property ignored if not a function');
|
||||
});
|
||||
|
||||
test('size', function() {
|
||||
|
||||
16
vendor/underscore/test/functions.js
vendored
16
vendor/underscore/test/functions.js
vendored
@@ -141,7 +141,7 @@ $(document).ready(function() {
|
||||
var incr = function(){ return ++counter; };
|
||||
var throttledIncr = _.throttle(incr, 100);
|
||||
var results = [];
|
||||
var saveResult = function() { results.push(throttledIncr()); }
|
||||
var saveResult = function() { results.push(throttledIncr()); };
|
||||
saveResult(); saveResult(); saveResult();
|
||||
setTimeout(saveResult, 70);
|
||||
setTimeout(saveResult, 120);
|
||||
@@ -159,7 +159,7 @@ $(document).ready(function() {
|
||||
equal(results[6], 2, "incr was throttled");
|
||||
equal(results[7], 3, "incr was called thrice");
|
||||
equal(results[8], 3, "incr was throttled");
|
||||
start();
|
||||
start();
|
||||
}, 400);
|
||||
});
|
||||
|
||||
@@ -176,11 +176,17 @@ $(document).ready(function() {
|
||||
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 220);
|
||||
});
|
||||
|
||||
asyncTest("debounce asap", 2, function() {
|
||||
asyncTest("debounce asap", 5, function() {
|
||||
var a, b, c;
|
||||
var counter = 0;
|
||||
var incr = function(){ counter++; };
|
||||
var incr = function(){ return ++counter; };
|
||||
var debouncedIncr = _.debounce(incr, 50, true);
|
||||
debouncedIncr(); debouncedIncr(); debouncedIncr();
|
||||
a = debouncedIncr();
|
||||
b = debouncedIncr();
|
||||
c = debouncedIncr();
|
||||
equal(a, 1);
|
||||
equal(b, 1);
|
||||
equal(c, 1);
|
||||
equal(counter, 1, 'incr was called immediately');
|
||||
setTimeout(debouncedIncr, 30);
|
||||
setTimeout(debouncedIncr, 60);
|
||||
|
||||
70
vendor/underscore/test/objects.js
vendored
70
vendor/underscore/test/objects.js
vendored
@@ -15,17 +15,22 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
test("values", function() {
|
||||
equal(_.values({one : 1, two : 2}).join(', '), '1, 2', 'can extract the values from an object');
|
||||
equal(_.values({one: 1, two: 2}).join(', '), '1, 2', 'can extract the values from an object');
|
||||
equal(_.values({one: 1, two: 2, length: 3}).join(', '), '1, 2, 3', '... even when one of them is "length"');
|
||||
});
|
||||
|
||||
test("pairs", function() {
|
||||
deepEqual(_.pairs({one: 1, two: 2}), [['one', 1], ['two', 2]], 'can convert an object into pairs');
|
||||
deepEqual(_.pairs({one: 1, two: 2, length: 3}), [['one', 1], ['two', 2], ['length', 3]], '... even when one of them is "length"');
|
||||
});
|
||||
|
||||
test("invert", function() {
|
||||
var obj = {first: 'Moe', second: 'Larry', third: 'Curly'};
|
||||
equal(_.keys(_.invert(obj)).join(' '), 'Moe Larry Curly', 'can invert an object');
|
||||
ok(_.isEqual(_.invert(_.invert(obj)), obj), 'two inverts gets you back where you started');
|
||||
|
||||
var obj = {length: 3};
|
||||
ok(_.invert(obj)['3'] == 'length', 'can invert an object with "length"')
|
||||
});
|
||||
|
||||
test("functions", function() {
|
||||
@@ -228,14 +233,6 @@ $(document).ready(function() {
|
||||
ok(_.isEqual(Array(3), Array(3)), "Sparse arrays of identical lengths are equal");
|
||||
ok(!_.isEqual(Array(3), Array(6)), "Sparse arrays of different lengths are not equal when both are empty");
|
||||
|
||||
// According to the Microsoft deviations spec, section 2.1.26, JScript 5.x treats `undefined`
|
||||
// elements in arrays as elisions. Thus, sparse arrays and dense arrays containing `undefined`
|
||||
// values are equivalent.
|
||||
if (0 in [undefined]) {
|
||||
ok(!_.isEqual(Array(3), [undefined, undefined, undefined]), "Sparse and dense arrays are not equal");
|
||||
ok(!_.isEqual([undefined, undefined, undefined], Array(3)), "Commutative equality is implemented for sparse and dense arrays");
|
||||
}
|
||||
|
||||
// Simple objects.
|
||||
ok(_.isEqual({a: "Curly", b: 1, c: true}, {a: "Curly", b: 1, c: true}), "Objects containing identical primitives are equal");
|
||||
ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), "Objects containing equivalent members are equal");
|
||||
@@ -351,57 +348,8 @@ $(document).ready(function() {
|
||||
ok(!_.isEqual(isEqualObj, {}), 'Objects that do not implement equivalent `isEqual` methods are not equal');
|
||||
ok(!_.isEqual({}, isEqualObj), 'Commutative equality is implemented for objects with different `isEqual` methods');
|
||||
|
||||
// Custom `isEqual` methods - comparing different types
|
||||
LocalizedString = (function() {
|
||||
function LocalizedString(id) { this.id = id; this.string = (this.id===10)? 'Bonjour': ''; }
|
||||
LocalizedString.prototype.isEqual = function(that) {
|
||||
if (_.isString(that)) return this.string == that;
|
||||
else if (that instanceof LocalizedString) return this.id == that.id;
|
||||
return false;
|
||||
};
|
||||
return LocalizedString;
|
||||
})();
|
||||
var localized_string1 = new LocalizedString(10), localized_string2 = new LocalizedString(10), localized_string3 = new LocalizedString(11);
|
||||
ok(_.isEqual(localized_string1, localized_string2), 'comparing same typed instances with same ids');
|
||||
ok(!_.isEqual(localized_string1, localized_string3), 'comparing same typed instances with different ids');
|
||||
ok(_.isEqual(localized_string1, 'Bonjour'), 'comparing different typed instances with same values');
|
||||
ok(_.isEqual('Bonjour', localized_string1), 'comparing different typed instances with same values');
|
||||
ok(!_.isEqual('Bonjour', localized_string3), 'comparing two localized strings with different ids');
|
||||
ok(!_.isEqual(localized_string1, 'Au revoir'), 'comparing different typed instances with different values');
|
||||
ok(!_.isEqual('Au revoir', localized_string1), 'comparing different typed instances with different values');
|
||||
|
||||
// Custom `isEqual` methods - comparing with serialized data
|
||||
Date.prototype.toJSON = function() {
|
||||
return {
|
||||
_type:'Date',
|
||||
year:this.getUTCFullYear(),
|
||||
month:this.getUTCMonth(),
|
||||
day:this.getUTCDate(),
|
||||
hours:this.getUTCHours(),
|
||||
minutes:this.getUTCMinutes(),
|
||||
seconds:this.getUTCSeconds()
|
||||
};
|
||||
};
|
||||
Date.prototype.isEqual = function(that) {
|
||||
var this_date_components = this.toJSON();
|
||||
var that_date_components = (that instanceof Date) ? that.toJSON() : that;
|
||||
delete this_date_components['_type']; delete that_date_components['_type'];
|
||||
return _.isEqual(this_date_components, that_date_components);
|
||||
};
|
||||
|
||||
var date = new Date();
|
||||
var date_json = {
|
||||
_type:'Date',
|
||||
year:date.getUTCFullYear(),
|
||||
month:date.getUTCMonth(),
|
||||
day:date.getUTCDate(),
|
||||
hours:date.getUTCHours(),
|
||||
minutes:date.getUTCMinutes(),
|
||||
seconds:date.getUTCSeconds()
|
||||
};
|
||||
|
||||
ok(_.isEqual(date_json, date), 'serialized date matches date');
|
||||
ok(_.isEqual(date, date_json), 'date matches serialized date');
|
||||
// Objects from another frame.
|
||||
ok(_.isEqual({}, iObject));
|
||||
});
|
||||
|
||||
test("isEmpty", function() {
|
||||
@@ -438,6 +386,7 @@ $(document).ready(function() {
|
||||
parent.iNull = null;\
|
||||
parent.iBoolean = new Boolean(false);\
|
||||
parent.iUndefined = undefined;\
|
||||
parent.iObject = {};\
|
||||
</script>"
|
||||
);
|
||||
iDoc.close();
|
||||
@@ -550,6 +499,7 @@ $(document).ready(function() {
|
||||
ok(!_.isNaN(0), '0 is not NaN');
|
||||
ok(_.isNaN(NaN), 'but NaN is');
|
||||
ok(_.isNaN(iNaN), 'even from another frame');
|
||||
ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN');
|
||||
});
|
||||
|
||||
test("isNull", function() {
|
||||
|
||||
5
vendor/underscore/test/utility.js
vendored
5
vendor/underscore/test/utility.js
vendored
@@ -241,4 +241,9 @@ $(document).ready(function() {
|
||||
deepEqual(settings, {});
|
||||
});
|
||||
|
||||
test('#779 - delimeters are applied to unescaped text.', 1, function() {
|
||||
var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g});
|
||||
strictEqual(template(), '<<\nx\n>>');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
38
vendor/underscore/underscore-min.js
vendored
38
vendor/underscore/underscore-min.js
vendored
File diff suppressed because one or more lines are too long
296
vendor/underscore/underscore.js
vendored
296
vendor/underscore/underscore.js
vendored
@@ -1,10 +1,7 @@
|
||||
// Underscore.js 1.3.3
|
||||
// Underscore.js 1.4.1
|
||||
// http://underscorejs.org
|
||||
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||
// Underscore may be freely distributed under the MIT license.
|
||||
// Portions of Underscore are inspired or borrowed from Prototype,
|
||||
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
||||
// For all details and documentation:
|
||||
// http://documentcloud.github.com/underscore
|
||||
|
||||
(function() {
|
||||
|
||||
@@ -26,6 +23,7 @@
|
||||
// Create quick reference variables for speed access to core prototypes.
|
||||
var push = ArrayProto.push,
|
||||
slice = ArrayProto.slice,
|
||||
concat = ArrayProto.concat,
|
||||
unshift = ArrayProto.unshift,
|
||||
toString = ObjProto.toString,
|
||||
hasOwnProperty = ObjProto.hasOwnProperty;
|
||||
@@ -67,7 +65,7 @@
|
||||
}
|
||||
|
||||
// Current version.
|
||||
_.VERSION = '1.3.3';
|
||||
_.VERSION = '1.4.1';
|
||||
|
||||
// Collection Functions
|
||||
// --------------------
|
||||
@@ -76,7 +74,6 @@
|
||||
// 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) {
|
||||
@@ -96,7 +93,6 @@
|
||||
// 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[results.length] = iterator.call(context, value, index, list);
|
||||
@@ -108,7 +104,6 @@
|
||||
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
|
||||
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
|
||||
var initial = arguments.length > 2;
|
||||
if (obj == null) obj = [];
|
||||
if (nativeReduce && obj.reduce === nativeReduce) {
|
||||
if (context) iterator = _.bind(iterator, context);
|
||||
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
|
||||
@@ -129,14 +124,26 @@
|
||||
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
|
||||
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
||||
var initial = arguments.length > 2;
|
||||
if (obj == null) obj = [];
|
||||
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
||||
if (context) iterator = _.bind(iterator, context);
|
||||
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
||||
return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
||||
}
|
||||
var reversed = _.toArray(obj).reverse();
|
||||
if (context && !initial) iterator = _.bind(iterator, context);
|
||||
return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
|
||||
var length = obj.length;
|
||||
if (length !== +length) {
|
||||
var keys = _.keys(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('Reduce of empty array with no initial value');
|
||||
return memo;
|
||||
};
|
||||
|
||||
// Return the first value which passes a truth test. Aliased as `detect`.
|
||||
@@ -156,7 +163,6 @@
|
||||
// Aliased as `select`.
|
||||
_.filter = _.select = function(obj, iterator, 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[results.length] = value;
|
||||
@@ -167,7 +173,6 @@
|
||||
// Return all the elements for which a truth test fails.
|
||||
_.reject = function(obj, iterator, context) {
|
||||
var results = [];
|
||||
if (obj == null) return results;
|
||||
each(obj, function(value, index, list) {
|
||||
if (!iterator.call(context, value, index, list)) results[results.length] = value;
|
||||
});
|
||||
@@ -180,7 +185,6 @@
|
||||
_.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;
|
||||
@@ -194,7 +198,6 @@
|
||||
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;
|
||||
@@ -202,11 +205,10 @@
|
||||
return !!result;
|
||||
};
|
||||
|
||||
// Determine if a given value is included in the array or object using `===`.
|
||||
// Aliased as `contains`.
|
||||
_.include = _.contains = function(obj, target) {
|
||||
// Determine if the array or object contains a given value (using `===`).
|
||||
// Aliased as `include`.
|
||||
_.contains = _.include = function(obj, target) {
|
||||
var found = false;
|
||||
if (obj == null) return found;
|
||||
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
||||
found = any(obj, function(value) {
|
||||
return value === target;
|
||||
@@ -227,6 +229,18 @@
|
||||
return _.map(obj, function(value){ return value[key]; });
|
||||
};
|
||||
|
||||
// Convenience version of a common use case of `filter`: selecting only objects
|
||||
// with specific `key:value` pairs.
|
||||
_.where = function(obj, attrs) {
|
||||
if (_.isEmpty(attrs)) return [];
|
||||
return _.filter(obj, function(value) {
|
||||
for (var key in attrs) {
|
||||
if (attrs[key] !== value[key]) return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
// 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
|
||||
@@ -263,40 +277,44 @@
|
||||
var index = 0;
|
||||
var shuffled = [];
|
||||
each(obj, function(value) {
|
||||
rand = Math.floor(Math.random() * ++index);
|
||||
rand = _.random(index++);
|
||||
shuffled[index - 1] = shuffled[rand];
|
||||
shuffled[rand] = value;
|
||||
});
|
||||
return shuffled;
|
||||
};
|
||||
|
||||
// An internal function to generate lookup iterators.
|
||||
var lookupIterator = function(value) {
|
||||
return _.isFunction(value) ? value : function(obj){ return obj[value]; };
|
||||
};
|
||||
|
||||
// Sort the object's values by a criterion produced by an iterator.
|
||||
_.sortBy = function(obj, val, context) {
|
||||
var iterator = lookupIterator(obj, val);
|
||||
_.sortBy = function(obj, value, context) {
|
||||
var iterator = lookupIterator(value);
|
||||
return _.pluck(_.map(obj, function(value, index, list) {
|
||||
return {
|
||||
value : value,
|
||||
index : index,
|
||||
criteria : iterator.call(context, value, index, list)
|
||||
};
|
||||
}).sort(function(left, right) {
|
||||
var a = left.criteria, b = right.criteria;
|
||||
if (a === void 0) return 1;
|
||||
if (b === void 0) return -1;
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
var a = left.criteria;
|
||||
var b = right.criteria;
|
||||
if (a !== b) {
|
||||
if (a > b || a === void 0) return 1;
|
||||
if (a < b || b === void 0) return -1;
|
||||
}
|
||||
return left.index < right.index ? -1 : 1;
|
||||
}), 'value');
|
||||
};
|
||||
|
||||
// An internal function to generate lookup iterators.
|
||||
var lookupIterator = function(obj, val) {
|
||||
return _.isFunction(val) ? val : function(obj) { return obj[val]; };
|
||||
};
|
||||
|
||||
// An internal function used for aggregate "group by" operations.
|
||||
var group = function(obj, val, behavior) {
|
||||
var group = function(obj, value, context, behavior) {
|
||||
var result = {};
|
||||
var iterator = lookupIterator(obj, val);
|
||||
var iterator = lookupIterator(value);
|
||||
each(obj, function(value, index) {
|
||||
var key = iterator(value, index);
|
||||
var key = iterator.call(context, value, index, obj);
|
||||
behavior(result, key, value);
|
||||
});
|
||||
return result;
|
||||
@@ -304,40 +322,39 @@
|
||||
|
||||
// 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, val) {
|
||||
return group(obj, val, function(result, key, value) {
|
||||
(result[key] || (result[key] = [])).push(value);
|
||||
_.groupBy = function(obj, value, context) {
|
||||
return group(obj, value, context, function(result, key, value) {
|
||||
(_.has(result, key) ? result[key] : (result[key] = [])).push(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, val) {
|
||||
return group(obj, val, function(result, key, value) {
|
||||
result[key] || (result[key] = 0);
|
||||
_.countBy = function(obj, value, context) {
|
||||
return group(obj, value, context, function(result, key, value) {
|
||||
if (!_.has(result, key)) result[key] = 0;
|
||||
result[key]++;
|
||||
});
|
||||
};
|
||||
|
||||
// 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) {
|
||||
iterator || (iterator = _.identity);
|
||||
var value = iterator(obj);
|
||||
_.sortedIndex = function(array, obj, iterator, context) {
|
||||
iterator = iterator == null ? _.identity : lookupIterator(iterator);
|
||||
var value = iterator.call(context, obj);
|
||||
var low = 0, high = array.length;
|
||||
while (low < high) {
|
||||
var mid = (low + high) >> 1;
|
||||
iterator(array[mid]) < value ? low = mid + 1 : high = mid;
|
||||
var mid = (low + high) >>> 1;
|
||||
iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
|
||||
}
|
||||
return low;
|
||||
};
|
||||
|
||||
// Safely convert anything iterable into a real, live array.
|
||||
_.toArray = function(obj) {
|
||||
if (!obj) return [];
|
||||
if (_.isArray(obj) || _.isArguments(obj)) return slice.call(obj);
|
||||
if (_.isFunction(obj.toArray)) return obj.toArray();
|
||||
if (!obj) return [];
|
||||
if (obj.length === +obj.length) return slice.call(obj);
|
||||
return _.values(obj);
|
||||
};
|
||||
|
||||
@@ -412,23 +429,23 @@
|
||||
// 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) {
|
||||
var initial = iterator ? _.map(array, iterator) : array;
|
||||
_.uniq = _.unique = function(array, isSorted, iterator, context) {
|
||||
var initial = iterator ? _.map(array, iterator, context) : array;
|
||||
var results = [];
|
||||
_.reduce(initial, function(memo, value, index) {
|
||||
if (isSorted ? (_.last(memo) !== value || !memo.length) : !_.include(memo, value)) {
|
||||
memo.push(value);
|
||||
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]);
|
||||
}
|
||||
return memo;
|
||||
}, []);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
// Produce an array that contains the union: each distinct element from all of
|
||||
// the passed-in arrays.
|
||||
_.union = function() {
|
||||
return _.uniq(flatten(arguments, true, []));
|
||||
return _.uniq(concat.apply(ArrayProto, arguments));
|
||||
};
|
||||
|
||||
// Produce an array that contains every item shared between all the
|
||||
@@ -445,8 +462,8 @@
|
||||
// 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 = flatten(slice.call(arguments, 1), true, []);
|
||||
return _.filter(array, function(value){ return !_.include(rest, value); });
|
||||
var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
|
||||
return _.filter(array, function(value){ return !_.contains(rest, value); });
|
||||
};
|
||||
|
||||
// Zip together multiple lists into a single array -- elements that share
|
||||
@@ -483,22 +500,27 @@
|
||||
// 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, l;
|
||||
var i = 0, l = array.length;
|
||||
if (isSorted) {
|
||||
i = _.sortedIndex(array, item);
|
||||
return array[i] === item ? i : -1;
|
||||
if (typeof isSorted == 'number') {
|
||||
i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
|
||||
} else {
|
||||
i = _.sortedIndex(array, item);
|
||||
return array[i] === item ? i : -1;
|
||||
}
|
||||
}
|
||||
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
|
||||
for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
|
||||
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
|
||||
for (; i < l; i++) if (array[i] === item) return i;
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
||||
_.lastIndexOf = function(array, item) {
|
||||
if (array == null) return -1;
|
||||
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
|
||||
var i = array.length;
|
||||
_.lastIndexOf = function(array, item, from) {
|
||||
var hasIndex = from != null;
|
||||
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
|
||||
return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
|
||||
}
|
||||
var i = (hasIndex ? from : array.length);
|
||||
while (i--) if (array[i] === item) return i;
|
||||
return -1;
|
||||
};
|
||||
@@ -613,17 +635,18 @@
|
||||
// N milliseconds. If `immediate` is passed, trigger the function on the
|
||||
// leading edge, instead of the trailing.
|
||||
_.debounce = function(func, wait, immediate) {
|
||||
var timeout;
|
||||
var timeout, result;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
var later = function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
if (!immediate) result = func.apply(context, args);
|
||||
};
|
||||
var callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
if (callNow) result = func.apply(context, args);
|
||||
return result;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -645,7 +668,8 @@
|
||||
// conditionally execute the original function.
|
||||
_.wrap = function(func, wrapper) {
|
||||
return function() {
|
||||
var args = [func].concat(slice.call(arguments, 0));
|
||||
var args = [func];
|
||||
push.apply(args, arguments);
|
||||
return wrapper.apply(this, args);
|
||||
};
|
||||
};
|
||||
@@ -687,22 +711,23 @@
|
||||
|
||||
// Retrieve the values of an object's properties.
|
||||
_.values = function(obj) {
|
||||
return _.map(obj, _.identity);
|
||||
var values = [];
|
||||
for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
|
||||
return values;
|
||||
};
|
||||
|
||||
// Convert an object into a list of `[key, value]` pairs.
|
||||
_.pairs = function(obj) {
|
||||
return _.map(obj, function(value, key) {
|
||||
return [key, value];
|
||||
});
|
||||
var pairs = [];
|
||||
for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
|
||||
return pairs;
|
||||
};
|
||||
|
||||
// Invert the keys and values of an object. The values must be serializable.
|
||||
_.invert = function(obj) {
|
||||
return _.reduce(obj, function(memo, value, key) {
|
||||
memo[value] = key;
|
||||
return memo;
|
||||
}, {});
|
||||
var result = {};
|
||||
for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
|
||||
return result;
|
||||
};
|
||||
|
||||
// Return a sorted list of the function names available on the object.
|
||||
@@ -728,7 +753,7 @@
|
||||
// Return a copy of the object only containing the whitelisted properties.
|
||||
_.pick = function(obj) {
|
||||
var copy = {};
|
||||
var keys = _.flatten(slice.call(arguments, 1));
|
||||
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
|
||||
each(keys, function(key) {
|
||||
if (key in obj) copy[key] = obj[key];
|
||||
});
|
||||
@@ -738,9 +763,9 @@
|
||||
// Return a copy of the object without the blacklisted properties.
|
||||
_.omit = function(obj) {
|
||||
var copy = {};
|
||||
var keys = _.flatten(slice.call(arguments, 1));
|
||||
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
|
||||
for (var key in obj) {
|
||||
if (!_.include(keys, key)) copy[key] = obj[key];
|
||||
if (!_.contains(keys, key)) copy[key] = obj[key];
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
@@ -779,9 +804,6 @@
|
||||
// Unwrap any wrapped objects.
|
||||
if (a instanceof _) a = a._wrapped;
|
||||
if (b instanceof _) b = b._wrapped;
|
||||
// Invoke a custom `isEqual` method if one is provided.
|
||||
if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
|
||||
if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
|
||||
// Compare `[[Class]]` names.
|
||||
var className = toString.call(a);
|
||||
if (className != toString.call(b)) return false;
|
||||
@@ -829,13 +851,17 @@
|
||||
if (result) {
|
||||
// Deep compare the contents, ignoring non-numeric properties.
|
||||
while (size--) {
|
||||
// Ensure commutative equality for sparse arrays.
|
||||
if (!(result = size in a == size in b && eq(a[size], b[size], aStack, bStack))) break;
|
||||
if (!(result = eq(a[size], b[size], aStack, bStack))) break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Objects with different constructors are not equivalent.
|
||||
if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
|
||||
// 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)) {
|
||||
@@ -875,7 +901,7 @@
|
||||
|
||||
// Is a given value a DOM element?
|
||||
_.isElement = function(obj) {
|
||||
return !!(obj && obj.nodeType == 1);
|
||||
return !!(obj && obj.nodeType === 1);
|
||||
};
|
||||
|
||||
// Is a given value an array?
|
||||
@@ -904,15 +930,21 @@
|
||||
};
|
||||
}
|
||||
|
||||
// Optimize `isFunction` if appropriate.
|
||||
if (typeof (/./) !== 'function') {
|
||||
_.isFunction = function(obj) {
|
||||
return typeof obj === 'function';
|
||||
};
|
||||
}
|
||||
|
||||
// Is a given object a finite number?
|
||||
_.isFinite = function(obj) {
|
||||
return _.isNumber(obj) && isFinite(obj);
|
||||
};
|
||||
|
||||
// Is the given value `NaN`?
|
||||
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
|
||||
_.isNaN = function(obj) {
|
||||
// `NaN` is the only value for which `===` is not reflexive.
|
||||
return obj !== obj;
|
||||
return _.isNumber(obj) && obj != +obj;
|
||||
};
|
||||
|
||||
// Is a given value a boolean?
|
||||
@@ -958,6 +990,10 @@
|
||||
|
||||
// Return a random integer between min and max (inclusive).
|
||||
_.random = function(min, max) {
|
||||
if (max == null) {
|
||||
max = min;
|
||||
min = 0;
|
||||
}
|
||||
return min + (0 | Math.random() * (max - min + 1));
|
||||
};
|
||||
|
||||
@@ -1003,8 +1039,8 @@
|
||||
each(_.functions(obj), function(name){
|
||||
var func = _[name] = obj[name];
|
||||
_.prototype[name] = function() {
|
||||
var args = slice.call(arguments);
|
||||
args.unshift(this._wrapped);
|
||||
var args = [this._wrapped];
|
||||
push.apply(args, arguments);
|
||||
return result.call(this, func.apply(_, args));
|
||||
};
|
||||
});
|
||||
@@ -1029,31 +1065,21 @@
|
||||
// When customizing `templateSettings`, if you don't want to define an
|
||||
// interpolation, evaluation or escaping regex, we need one that is
|
||||
// guaranteed not to match.
|
||||
var noMatch = /.^/;
|
||||
var noMatch = /(.)^/;
|
||||
|
||||
// Certain characters need to be escaped so that they can be put into a
|
||||
// string literal.
|
||||
var escapes = {
|
||||
'\\': '\\',
|
||||
"'": "'",
|
||||
r: '\r',
|
||||
n: '\n',
|
||||
t: '\t',
|
||||
u2028: '\u2028',
|
||||
u2029: '\u2029'
|
||||
"'": "'",
|
||||
'\\': '\\',
|
||||
'\r': 'r',
|
||||
'\n': 'n',
|
||||
'\t': 't',
|
||||
'\u2028': 'u2028',
|
||||
'\u2029': 'u2029'
|
||||
};
|
||||
|
||||
for (var key in escapes) escapes[escapes[key]] = key;
|
||||
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
|
||||
var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
|
||||
|
||||
// Within an interpolation, evaluation, or escaping, remove HTML escaping
|
||||
// that had been previously added.
|
||||
var unescape = function(code) {
|
||||
return code.replace(unescaper, function(match, escape) {
|
||||
return escapes[escape];
|
||||
});
|
||||
};
|
||||
|
||||
// JavaScript micro-templating, similar to John Resig's implementation.
|
||||
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
||||
@@ -1061,22 +1087,26 @@
|
||||
_.template = function(text, data, settings) {
|
||||
settings = _.defaults({}, settings, _.templateSettings);
|
||||
|
||||
// Compile the template source, taking care to escape characters that
|
||||
// cannot be included in a string literal and then unescape them in code
|
||||
// blocks.
|
||||
var source = "__p+='" + text
|
||||
.replace(escaper, function(match) {
|
||||
return '\\' + escapes[match];
|
||||
})
|
||||
.replace(settings.escape || noMatch, function(match, code) {
|
||||
return "'+\n((__t=(" + unescape(code) + "))==null?'':_.escape(__t))+\n'";
|
||||
})
|
||||
.replace(settings.interpolate || noMatch, function(match, code) {
|
||||
return "'+\n((__t=(" + unescape(code) + "))==null?'':__t)+\n'";
|
||||
})
|
||||
.replace(settings.evaluate || noMatch, function(match, code) {
|
||||
return "';\n" + unescape(code) + "\n__p+='";
|
||||
}) + "';\n";
|
||||
// Combine delimiters into one regular expression via alternation.
|
||||
var matcher = new RegExp([
|
||||
(settings.escape || noMatch).source,
|
||||
(settings.interpolate || noMatch).source,
|
||||
(settings.evaluate || noMatch).source
|
||||
].join('|') + '|$', 'g');
|
||||
|
||||
// Compile the template source, escaping string literals appropriately.
|
||||
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 +=
|
||||
escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" :
|
||||
interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" :
|
||||
evaluate ? "';\n" + evaluate + "\n__p+='" : '';
|
||||
index = offset + match.length;
|
||||
});
|
||||
source += "';\n";
|
||||
|
||||
// If a variable is not specified, place data values in local scope.
|
||||
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
|
||||
|
||||
Reference in New Issue
Block a user