Compare commits
204 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51a459fe48 | ||
|
|
03c07abbc3 | ||
|
|
5eabe1a172 | ||
|
|
5b6ea7afb2 | ||
|
|
7c1c5e70ca | ||
|
|
d475f8f965 | ||
|
|
fd239076dd | ||
|
|
5f786bbe47 | ||
|
|
f66dc6bed8 | ||
|
|
52c36ac445 | ||
|
|
8f6a78cba5 | ||
|
|
7053e9113f | ||
|
|
89f9ab9940 | ||
|
|
240bc40b39 | ||
|
|
74649b5f28 | ||
|
|
b484d4b2dc | ||
|
|
da1124dd37 | ||
|
|
210485d0be | ||
|
|
d9aee5ae60 | ||
|
|
9ac64623fc | ||
|
|
6ea4226680 | ||
|
|
c1416bba39 | ||
|
|
ddb3ab3238 | ||
|
|
5e7c9698c7 | ||
|
|
4c66b95516 | ||
|
|
2d03060a0d | ||
|
|
3313b0aa42 | ||
|
|
5d2928d2b3 | ||
|
|
f6e2ae41d6 | ||
|
|
7ccb038b6d | ||
|
|
7d62bbf74f | ||
|
|
3d8cc32302 | ||
|
|
861eea5148 | ||
|
|
b432721fe5 | ||
|
|
f13a0cc7e0 | ||
|
|
1f7e37a1a3 | ||
|
|
548e9cac26 | ||
|
|
0d2a1641c9 | ||
|
|
a67281f8e7 | ||
|
|
281475e6ef | ||
|
|
a5712fc873 | ||
|
|
205ded45e2 | ||
|
|
8ef039b9db | ||
|
|
3d2428b278 | ||
|
|
35d5704e3f | ||
|
|
c1860d30d6 | ||
|
|
e0fba5cb51 | ||
|
|
570ba189ed | ||
|
|
e335e0fd72 | ||
|
|
74a2d8dcb1 | ||
|
|
43ea0c9072 | ||
|
|
dde3eb2e36 | ||
|
|
2008bf90af | ||
|
|
06ffa93bd0 | ||
|
|
5da03cac79 | ||
|
|
8a5eb89aa8 | ||
|
|
f81ede2fd6 | ||
|
|
6f7df67ded | ||
|
|
bb9ad69219 | ||
|
|
8f7667a524 | ||
|
|
86e125a6f3 | ||
|
|
8b3ba13ff0 | ||
|
|
82f062caf2 | ||
|
|
67303eb9fb | ||
|
|
af3ded68c4 | ||
|
|
b94eb44e18 | ||
|
|
c62b24b024 | ||
|
|
baa37450cc | ||
|
|
231fd46cd2 | ||
|
|
b2728d9902 | ||
|
|
451a33f526 | ||
|
|
3670bce918 | ||
|
|
afb041b23c | ||
|
|
5315058e2d | ||
|
|
26d9cc972e | ||
|
|
52ae87812e | ||
|
|
f8af24b383 | ||
|
|
b38947146e | ||
|
|
5c48abff4b | ||
|
|
3994c7fc2b | ||
|
|
859f2b2f3b | ||
|
|
f5040a7bec | ||
|
|
a604494aa9 | ||
|
|
eaaef83ace | ||
|
|
9cf1424d8f | ||
|
|
cb74e45b89 | ||
|
|
1da0498f74 | ||
|
|
754b1de597 | ||
|
|
7e39941ad3 | ||
|
|
79a27b18ce | ||
|
|
194551fdbf | ||
|
|
5a82c8f89b | ||
|
|
2e540368eb | ||
|
|
d5966ae5db | ||
|
|
97f4dfc089 | ||
|
|
b03c2b3b8f | ||
|
|
9a81df6d77 | ||
|
|
a9d55121bb | ||
|
|
88327aeba2 | ||
|
|
8e2d972281 | ||
|
|
7b44ef1664 | ||
|
|
5204fac055 | ||
|
|
c2a1f50dc0 | ||
|
|
c8f3b128cb | ||
|
|
b32ed95597 | ||
|
|
57da1d3062 | ||
|
|
6dfe18fe18 | ||
|
|
1dd9ee2397 | ||
|
|
d31471c6a1 | ||
|
|
930f04951f | ||
|
|
8846835ab8 | ||
|
|
b080cc4d23 | ||
|
|
c910a95ee4 | ||
|
|
4601129fc7 | ||
|
|
9c79259e9c | ||
|
|
bdca0cf668 | ||
|
|
628ad0fcb2 | ||
|
|
793332beb8 | ||
|
|
4e9688cc18 | ||
|
|
ef9a6a0027 | ||
|
|
9e9222c65d | ||
|
|
9ef0d9084f | ||
|
|
36df8f7828 | ||
|
|
8ee1cc8d27 | ||
|
|
e4e2658a3b | ||
|
|
ae8e7ae992 | ||
|
|
e0c936ba03 | ||
|
|
0297e31893 | ||
|
|
5b975adc8e | ||
|
|
12fc6b3a67 | ||
|
|
cb4cc61c5b | ||
|
|
9f4404628b | ||
|
|
5441f6b55b | ||
|
|
258fc518a6 | ||
|
|
6a06bf5efa | ||
|
|
ff93f7cbb5 | ||
|
|
2e291396bd | ||
|
|
b779f8b029 | ||
|
|
04a05b4c02 | ||
|
|
90989a816d | ||
|
|
9b26b96836 | ||
|
|
972a716600 | ||
|
|
b5c4a9241b | ||
|
|
45f9d80a81 | ||
|
|
98435d2d92 | ||
|
|
ccbf965bd9 | ||
|
|
5c82104d7b | ||
|
|
4c29fbb36d | ||
|
|
88e754850d | ||
|
|
21b86980a7 | ||
|
|
98942c5e1a | ||
|
|
9c54df2de5 | ||
|
|
f31c2d24f9 | ||
|
|
52cf17b24a | ||
|
|
d26fc7154c | ||
|
|
14c8863657 | ||
|
|
6d3d5f77bc | ||
|
|
293fc695a4 | ||
|
|
a317d2471f | ||
|
|
afe7ff6d2c | ||
|
|
2f908870e7 | ||
|
|
312f0310dc | ||
|
|
1a1bd5322c | ||
|
|
04ca0ae309 | ||
|
|
221f70e609 | ||
|
|
a426109c1c | ||
|
|
d5e2489cad | ||
|
|
367f0bd6a9 | ||
|
|
8396ed3167 | ||
|
|
6cc360d613 | ||
|
|
e86eef5905 | ||
|
|
24d5fbb595 | ||
|
|
6fb7681a2d | ||
|
|
0b404d4bb1 | ||
|
|
464826e81d | ||
|
|
e871ffeff0 | ||
|
|
2847b1f08e | ||
|
|
d702e00446 | ||
|
|
142ee20bca | ||
|
|
e3f03fa2ce | ||
|
|
8dc3fb86db | ||
|
|
358ec3fb39 | ||
|
|
f4a38a25c8 | ||
|
|
dcb62a3df5 | ||
|
|
59c26957bb | ||
|
|
09d8561b3c | ||
|
|
6246e71c87 | ||
|
|
adcc2dd8d2 | ||
|
|
947fc9ce97 | ||
|
|
5caca9175d | ||
|
|
520d09e81e | ||
|
|
7fa4304097 | ||
|
|
ceed641730 | ||
|
|
1d4ce28b62 | ||
|
|
a551992c3f | ||
|
|
23b8d083a4 | ||
|
|
b3d249f2ef | ||
|
|
647633a1a0 | ||
|
|
313ffb8821 | ||
|
|
774f159e67 | ||
|
|
f9358531ad | ||
|
|
bb09d77eb5 | ||
|
|
ba8cc970d0 | ||
|
|
89c986d50f |
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
*.custom.*
|
||||
.DS_Store
|
||||
dist/
|
||||
node_modules/
|
||||
6
.gitmodules
vendored
@@ -16,3 +16,9 @@
|
||||
[submodule "vendor/uglifyjs"]
|
||||
path = vendor/uglifyjs
|
||||
url = git://github.com/mishoo/UglifyJS.git
|
||||
[submodule "vendor/underscore"]
|
||||
path = vendor/underscore
|
||||
url = git://github.com/documentcloud/underscore.git
|
||||
[submodule "vendor/backbone"]
|
||||
path = vendor/backbone
|
||||
url = git://github.com/documentcloud/backbone.git
|
||||
|
||||
18
.npmignore
@@ -1,5 +1,19 @@
|
||||
*.custom.*
|
||||
*.min.*
|
||||
.*
|
||||
dist/*
|
||||
build.*
|
||||
build/
|
||||
dist/
|
||||
doc/*.php
|
||||
node_modules/
|
||||
perf/*.html
|
||||
perf/*.sh
|
||||
test/*.html
|
||||
vendor/
|
||||
test/*.sh
|
||||
vendor/backbone/
|
||||
vendor/closure-compiler/
|
||||
vendor/docdown/
|
||||
vendor/firebug-lite/
|
||||
vendor/requirejs/
|
||||
vendor/uglifyjs/
|
||||
vendor/underscore/
|
||||
224
README.md
@@ -1,40 +1,92 @@
|
||||
# Lo-Dash <sup>v0.1.0</sup>
|
||||
# Lo-Dash <sup>v0.3.0</sup>
|
||||
|
||||
A drop-in replacement for [Underscore.js](https://github.com/documentcloud/underscore/) that delivers up to [8x performance improvements](http://jsperf.com/lodash-underscore#chart=bar), [bug fixes](https://github.com/bestiejs/lodash/blob/master/test/test.js#L71), and additional features.
|
||||
A drop-in replacement for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), that delivers [performance improvements](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#closed-underscorejs-issues), and [additional features](https://github.com/bestiejs/lodash#features).
|
||||
|
||||
## BestieJS
|
||||
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.
|
||||
|
||||
Lo-Dash is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation.
|
||||
## Download
|
||||
|
||||
## Documentation
|
||||
* [Development source](https://raw.github.com/bestiejs/lodash/v0.3.0/lodash.js)
|
||||
* [Production source](https://raw.github.com/bestiejs/lodash/v0.3.0/lodash.min.js)
|
||||
* For optimal performance, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need
|
||||
|
||||
The documentation for Lo-Dash can be viewed here: [/doc/README.md](https://github.com/bestiejs/lodash/blob/master/doc/README.md#readme)
|
||||
## Dive in
|
||||
|
||||
Underscore's [documentation](http://documentcloud.github.com/underscore/) may also be used.
|
||||
We’ve got [API docs](http://lodash.com/docs), [benchmarks](http://lodash.com/benchmarks), and [unit tests](http://lodash.com/tests).
|
||||
|
||||
For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/lodash/wiki/Roadmap).
|
||||
|
||||
## So What's The Secret?
|
||||
## Screencasts
|
||||
|
||||
Lo-Dash's performance is gained by avoiding 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.
|
||||
For more information check out these screencasts over Lo-Dash:
|
||||
|
||||
## What else?
|
||||
* [Introducing Lo-Dash](http://dl.dropbox.com/u/513327/allyoucanleet/post/20/file/screencast.mp4)
|
||||
* [Optimizations and custom builds](http://dl.dropbox.com/u/513327/allyoucanleet/post/21/file/screencast.mp4)
|
||||
|
||||
Lo-Dash comes with AMD loader support baked in, chainable `_.each`, and will [soon address](https://github.com/bestiejs/lodash/wiki/Roadmap) cross-browser object iteration issues.
|
||||
## Features
|
||||
|
||||
## Screencast
|
||||
* AMD loader support (RequireJS, curl.js, etc.)
|
||||
* [_.bind](http://lodash.com/docs#bind) supports *"lazy"* binding
|
||||
* [_.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
|
||||
* [_.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
|
||||
* [_.groupBy](http://lodash.com/docs#groupBy), [_.sortedIndex](http://lodash.com/docs#sortedIndex), and [_.uniq](http://lodash.com/docs#uniq) accept a `thisArg` argument
|
||||
* [_.indexOf](http://lodash.com/docs#indexOf) and [_.lastIndexOf](http://lodash.com/docs#lastIndexOf) accept a `fromIndex` argument
|
||||
* [_.partial](http://lodash.com/docs#partial) for more functional fun
|
||||
* [_.size](http://lodash.com/docs#size) supports returning the `length` of string values
|
||||
* [_.template](http://lodash.com/docs#template) utilizes [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier debugging
|
||||
|
||||
For more information check out [this screencast](http://dl.dropbox.com/u/513327/allyoucanleet/post/20/file/screencast.mp4) over Lo-Dash.
|
||||
## Support
|
||||
|
||||
Lo-Dash has been tested in at least Chrome 5-19, Firefox 1.5-13, IE 6-9, Opera 9.25-11.64, Safari 3.0.4-5.1.3, Node.js 0.4.8-0.6.18, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC3.
|
||||
|
||||
## Custom builds
|
||||
|
||||
Custom builds make it easy to create lightweight versions of Lo-Dash containing only the methods you need.
|
||||
We handle all the method dependency and alias mapping for you.
|
||||
|
||||
Mobile builds, with IE bug fixes and method compilation removed, may be created by using the `mobile` argument.
|
||||
|
||||
~~~ bash
|
||||
node build mobile
|
||||
~~~
|
||||
|
||||
Custom builds may be created in three ways:
|
||||
|
||||
1. Use the `category` argument to pass the categories of methods to include in the build.<br>
|
||||
Valid categories are *"arrays"*, *"chaining"*, *"collections"*, *"functions"*, *"objects"*, and *"utilities"*.
|
||||
~~~ bash
|
||||
node build category=collections,functions
|
||||
node build category="collections, functions"
|
||||
node build mobile category=collections,functions
|
||||
~~~
|
||||
|
||||
2. Use the `include` argument to pass the names of the methods to include in the build.
|
||||
~~~ bash
|
||||
node build include=each,filter,map
|
||||
node build include="each, filter, map"
|
||||
node build mobile include=each,filter,map
|
||||
~~~
|
||||
|
||||
3. Use the `exclude` argument to pass the names of the methods to exclude from the build.
|
||||
~~~ bash
|
||||
node build exclude=union,uniq,zip
|
||||
node build exclude="union, uniq, zip"
|
||||
node build mobile exclude=union,uniq,zip
|
||||
~~~
|
||||
|
||||
Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`.
|
||||
|
||||
## Installation and usage
|
||||
|
||||
In a browser:
|
||||
In browsers:
|
||||
|
||||
~~~ html
|
||||
<script src="lodash.js"></script>
|
||||
~~~
|
||||
|
||||
Via [npm](http://npmjs.org/):
|
||||
Using [npm](http://npmjs.org/):
|
||||
|
||||
~~~ bash
|
||||
npm install lodash
|
||||
@@ -61,15 +113,12 @@ load('lodash.js');
|
||||
In an AMD loader like [RequireJS](http://requirejs.org/):
|
||||
|
||||
~~~ js
|
||||
// opt-in
|
||||
define.amd.lodash = true;
|
||||
|
||||
require({
|
||||
'paths': {
|
||||
'lodash': 'path/to/lodash'
|
||||
'underscore': 'path/to/lodash'
|
||||
}
|
||||
},
|
||||
['lodash'], function(_) {
|
||||
['underscore'], function(_) {
|
||||
console.log(_.VERSION);
|
||||
});
|
||||
~~~
|
||||
@@ -91,7 +140,138 @@ cd lodash
|
||||
git submodule update --init
|
||||
~~~
|
||||
|
||||
Feel free to fork and send pull requests if you see improvements!
|
||||
## Closed 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), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L266-272)]
|
||||
* Ensure array-like objects with invalid `length` properties are treated like regular objects [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L237-243), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L533-542), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L661-664)]
|
||||
* Ensure `_(...)` returns passed wrapper instances [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L106-109)]
|
||||
* Ensure `_.groupBy` adds values to own, not inherited, properties [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L317-324)]
|
||||
* Ensure `_.sortedIndex` supports arrays with high `length` values [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L586-595)]
|
||||
* Ensure `_.throttle` works when called in tight loops [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L629-639)]
|
||||
* Fix Firefox, IE, Opera, and Safari object iteration bugs [[#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L175-187), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L277-302), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L379-390), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L398-400), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L418-438), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L554-556)]
|
||||
* Handle arrays with `undefined` values correctly in IE < 9 [[#601](https://github.com/documentcloud/underscore/issues/601)]
|
||||
* Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L88-94)]
|
||||
* Register as AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L72-86)]
|
||||
* `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L232-235)]
|
||||
* `_isNaN(new Number(NaN))` should return `true` [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L408-410)]
|
||||
* `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L521-531)]
|
||||
* `_.size` should return the `length` of string values [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L550-552)]
|
||||
|
||||
## Optimized methods <sup>(50+)</sup>
|
||||
|
||||
* `_.bind`
|
||||
* `_.bindAll`
|
||||
* `_.clone`
|
||||
* `_.compact`
|
||||
* `_.contains`, `_.include`
|
||||
* `_.defaults`
|
||||
* `_.defer`
|
||||
* `_.difference`
|
||||
* `_.each`
|
||||
* `_.escape`
|
||||
* `_.every`, `_.all`
|
||||
* `_.extend`
|
||||
* `_.filter`, `_.select`
|
||||
* `_.find`, `_.detect`
|
||||
* `_.flatten`
|
||||
* `_.forEach`, `_.each`
|
||||
* `_.functions`, `_.methods`
|
||||
* `_.groupBy`
|
||||
* `_.indexOf`
|
||||
* `_.intersection`
|
||||
* `_.invoke`
|
||||
* `_.isEmpty`
|
||||
* `_.isEqual`
|
||||
* `_.isFinite`
|
||||
* `_.isObject`
|
||||
* `_.isString`
|
||||
* `_.keys`
|
||||
* `_.lastIndexOf`
|
||||
* `_.map`, `_.collect`
|
||||
* `_.max`
|
||||
* `_.memoize`
|
||||
* `_.min`
|
||||
* `_.mixin`
|
||||
* `_.pick`
|
||||
* `_.pluck`
|
||||
* `_.reduce`, `_.foldl`, `_.inject`
|
||||
* `_.reject`
|
||||
* `_.result`
|
||||
* `_.shuffle`
|
||||
* `_.some`, `_.any`
|
||||
* `_.sortBy`
|
||||
* `_.sortedIndex`
|
||||
* `_.template`
|
||||
* `_.throttle`
|
||||
* `_.times`
|
||||
* `_.toArray`
|
||||
* `_.union`
|
||||
* `_.uniq`, `_.unique`
|
||||
* `_.values`
|
||||
* `_.without`
|
||||
* `_.wrap`
|
||||
* `_.zip`
|
||||
* plus all `_(...)` method wrappers
|
||||
|
||||
## Changelog
|
||||
|
||||
### <sup>v0.3.0</sup>
|
||||
|
||||
* Added `category` build option
|
||||
* Added `fromIndex` argument to `_.indexOf` and `_.lastIndexOf`
|
||||
* Added `//@ sourceURL` support to `_.template`
|
||||
* Added `thisArg` argument to `_.sortedIndex` and `_.uniq`
|
||||
* Added `_.forIn` and `_.forOwn` methods
|
||||
* Ensured array-like objects with invalid `length` properties are treated like regular objects
|
||||
* Ensured `_.sortedIndex` supports arrays with high `length` values
|
||||
* Fixed `prototype` property iteration bug in `_.keys` for Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
|
||||
* Optimized `_.times` and `this` bindings in iterator methods
|
||||
|
||||
### <sup>v0.2.2</sup>
|
||||
|
||||
* Added `mobile` build option
|
||||
* Ensured `_.find` returns `undefined` for unmatched values
|
||||
* Ensured `_.templateSettings.variable` is compatible with Underscore.js
|
||||
* Optimized `_.escape`
|
||||
* Reduced dependencies in `_.find`
|
||||
|
||||
### <sup>v0.2.1</sup>
|
||||
|
||||
* Adjusted the Lo-Dash export order for r.js
|
||||
* Ensured `_.groupBy` values are added to own, not inherited, properties
|
||||
* Made `_.bind` follow ES5 spec to support a popular Backbone.js pattern
|
||||
* Removed the alias `intersect`
|
||||
* Simplified `_.bind`, `_.flatten`, `_.groupBy`, `_.max`, and `_.min`
|
||||
|
||||
### <sup>v0.2.0</sup>
|
||||
|
||||
* Added custom build options
|
||||
* Added default `_.templateSettings.variable` value
|
||||
* Added *"lazy bind"* support to `_.bind`
|
||||
* Added native method overwrite detection to avoid bad native shims
|
||||
* Added support for more AMD build optimizers and aliasing as the *"underscore"* module
|
||||
* Added `thisArg` argument to `_.groupBy`
|
||||
* Added whitespace to compiled strings
|
||||
* Added `_.partial` method
|
||||
* Commented the `iterationFactory` options object
|
||||
* Ensured `_(...)` returns passed wrapper instances
|
||||
* Ensured `_.max` and `_.min` support extremely large arrays
|
||||
* Ensured `_.throttle` works in tight loops
|
||||
* Fixed IE < 9 `[DontEnum]` bug and Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1’s `prototype` property iteration bug
|
||||
* Inlined `_.isFunction` calls.
|
||||
* Made `_.debounce`’ed functions match `_.throttle`’ed functions’ return value behavior
|
||||
* Made `_.escape` no longer translate the *">"* character
|
||||
* Fixed `clearTimeout` typo
|
||||
* Simplified all methods in the *"Arrays"* category
|
||||
* Optimized `_.debounce`, `_.escape`, `_.flatten`, `_.forEach`, `_.groupBy`, `_.intersection`, `_.invoke`, `_.isObject`, `_.max`, `_.min`, `_.pick`, `_.shuffle`, `_.sortedIndex`, `_.template`, `_.throttle`, `_.union`, `_.uniq`
|
||||
|
||||
### <sup>v0.1.0</sup>
|
||||
|
||||
* Initial release
|
||||
|
||||
## BestieJS
|
||||
|
||||
Lo-Dash is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation.
|
||||
|
||||
## Author
|
||||
|
||||
@@ -102,3 +282,5 @@ Feel free to fork and send pull requests if you see improvements!
|
||||
|
||||
* [Kit Cambridge](http://kitcambridge.github.com/)
|
||||
[](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter")
|
||||
* [Mathias Bynens](http://mathiasbynens.be/)
|
||||
[](https://twitter.com/mathias "Follow @mathias on Twitter")
|
||||
|
||||
722
build.js
@@ -2,253 +2,525 @@
|
||||
;(function() {
|
||||
'use strict';
|
||||
|
||||
/** The Node filesystem, path, and child process modules */
|
||||
/** The Node filesystem and path modules */
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
spawn = require('child_process').spawn;
|
||||
|
||||
/** The build directory containing the build scripts */
|
||||
var buildPath = path.join(__dirname, 'build');
|
||||
|
||||
/** The directory where the Closure Compiler is located */
|
||||
var closurePath = path.join(__dirname, 'vendor', 'closure-compiler', 'compiler.jar');
|
||||
|
||||
/** The distribution directory */
|
||||
var distPath = path.join(__dirname, 'dist');
|
||||
path = require('path');
|
||||
|
||||
/** Load other modules */
|
||||
var preprocess = require(path.join(buildPath, 'pre-compile')),
|
||||
postprocess = require(path.join(buildPath, 'post-compile')),
|
||||
uglifyJS = require(path.join(__dirname, 'vendor', 'uglifyjs', 'uglify-js'));
|
||||
var lodash = require(path.join(__dirname, 'lodash')),
|
||||
minify = require(path.join(__dirname, 'build', 'minify'));
|
||||
|
||||
/** Used to shares values between multiple callbacks */
|
||||
var accumulator = {
|
||||
'compiled': {},
|
||||
'uglified': {}
|
||||
/** Flag used to specify a mobile build */
|
||||
var isMobile = process.argv.indexOf('mobile') > -1;
|
||||
|
||||
/** Shortcut used to convert array-like objects to arrays */
|
||||
var slice = [].slice;
|
||||
|
||||
/** The lodash.js source */
|
||||
var source = fs.readFileSync(path.join(__dirname, 'lodash.js'), 'utf8');
|
||||
|
||||
/** Used to associate aliases with their real names */
|
||||
var aliasToRealMap = {
|
||||
'all': 'every',
|
||||
'any': 'some',
|
||||
'collect': 'map',
|
||||
'detect': 'find',
|
||||
'each': 'forEach',
|
||||
'foldl': 'reduce',
|
||||
'foldr': 'reduceRight',
|
||||
'head': 'first',
|
||||
'include': 'contains',
|
||||
'inject': 'reduce',
|
||||
'methods': 'functions',
|
||||
'select': 'filter',
|
||||
'tail': 'rest',
|
||||
'take': 'first',
|
||||
'unique': 'uniq'
|
||||
};
|
||||
|
||||
/** Closure Compiler command-line options */
|
||||
var closureOptions = [
|
||||
'--compilation_level=ADVANCED_OPTIMIZATIONS',
|
||||
'--language_in=ECMASCRIPT5_STRICT',
|
||||
'--warning_level=QUIET'
|
||||
];
|
||||
/** Used to associate real names with their aliases */
|
||||
var realToAliasMap = {
|
||||
'contains': ['include'],
|
||||
'every': ['all'],
|
||||
'filter': ['select'],
|
||||
'find': ['detect'],
|
||||
'first': ['head', 'take'],
|
||||
'forEach': ['each'],
|
||||
'functions': ['methods'],
|
||||
'map': ['collect'],
|
||||
'reduce': ['foldl', 'inject'],
|
||||
'reduceRight': ['foldr'],
|
||||
'rest': ['tail'],
|
||||
'some': ['any'],
|
||||
'uniq': ['unique']
|
||||
};
|
||||
|
||||
/** Gzip command-line options */
|
||||
var gzipOptions = ['-9f', '-c'];
|
||||
/** Used to track function dependencies */
|
||||
var dependencyMap = {
|
||||
'after': [],
|
||||
'bind': [],
|
||||
'bindAll': ['bind'],
|
||||
'chain': ['mixin'],
|
||||
'clone': ['extend', 'isArray'],
|
||||
'compact': [],
|
||||
'compose': [],
|
||||
'contains': ['createIterator'],
|
||||
'createIterator': [],
|
||||
'debounce': [],
|
||||
'defaults': ['createIterator'],
|
||||
'defer': [],
|
||||
'delay': [],
|
||||
'difference': ['indexOf'],
|
||||
'escape': [],
|
||||
'every': ['createIterator', 'identity'],
|
||||
'extend': ['createIterator'],
|
||||
'filter': ['createIterator', 'identity'],
|
||||
'find': ['createIterator'],
|
||||
'first': [],
|
||||
'flatten': ['isArray'],
|
||||
'forEach': ['createIterator'],
|
||||
'forIn': ['createIterator'],
|
||||
'forOwn': ['createIterator'],
|
||||
'functions': ['createIterator'],
|
||||
'groupBy': ['createIterator'],
|
||||
'has': [],
|
||||
'identity': [],
|
||||
'indexOf': ['sortedIndex'],
|
||||
'initial': [],
|
||||
'intersection': ['every', 'indexOf'],
|
||||
'invoke': [],
|
||||
'isArguments': [],
|
||||
'isArray': [],
|
||||
'isBoolean': [],
|
||||
'isDate': [],
|
||||
'isElement': [],
|
||||
'isEmpty': ['createIterator'],
|
||||
'isEqual': [],
|
||||
'isFinite': [],
|
||||
'isFunction': [],
|
||||
'isNaN': [],
|
||||
'isNull': [],
|
||||
'isNumber': [],
|
||||
'isObject': [],
|
||||
'isRegExp': [],
|
||||
'isString': [],
|
||||
'isUndefined': [],
|
||||
'keys': ['createIterator'],
|
||||
'last': [],
|
||||
'lastIndexOf': [],
|
||||
'map': ['createIterator', 'identity'],
|
||||
'max': [],
|
||||
'memoize': [],
|
||||
'min': [],
|
||||
'mixin': ['forEach'],
|
||||
'noConflict': [],
|
||||
'once': [],
|
||||
'partial': [],
|
||||
'pick': [],
|
||||
'pluck': ['createIterator'],
|
||||
'range': [],
|
||||
'reduce': ['createIterator'],
|
||||
'reduceRight': ['keys'],
|
||||
'reject': ['createIterator', 'identity'],
|
||||
'rest': [],
|
||||
'result': [],
|
||||
'shuffle': [],
|
||||
'size': ['keys'],
|
||||
'some': ['createIterator', 'identity'],
|
||||
'sortBy': ['map', 'pluck'],
|
||||
'sortedIndex': ['identity'],
|
||||
'tap': [],
|
||||
'template': ['escape'],
|
||||
'throttle': [],
|
||||
'times': [],
|
||||
'toArray': ['values'],
|
||||
'union': ['indexOf'],
|
||||
'uniq': ['identity', 'indexOf'],
|
||||
'uniqueId': [],
|
||||
'values': ['createIterator'],
|
||||
'without': ['indexOf'],
|
||||
'wrap': [],
|
||||
'zip': ['max', 'pluck']
|
||||
};
|
||||
|
||||
/** The pre-processed Lo-Dash source */
|
||||
var source = preprocess(fs.readFileSync(path.join(__dirname, 'lodash.js'), 'utf8'));
|
||||
/** Names of all methods */
|
||||
var allMethods = Object.keys(dependencyMap);
|
||||
|
||||
/** Names of methods to filter for the build */
|
||||
var filterMethods = allMethods;
|
||||
|
||||
/** Used to specify whether `filterMethods` is used for exclusion or inclusion */
|
||||
var filterType = process.argv.reduce(function(result, value) {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
var pair = value.match(/^(category|exclude|include)=(.*)$/);
|
||||
if (!pair) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = pair[1];
|
||||
filterMethods = pair[2].split(/, */).map(getRealName);
|
||||
|
||||
if (result == 'category') {
|
||||
// resolve method names belonging to each category
|
||||
filterMethods = filterMethods.reduce(function(result, category) {
|
||||
return result.concat(allMethods.filter(function(funcName) {
|
||||
return RegExp('@category ' + category + '\\b', 'i').test(matchFunction(source, funcName));
|
||||
}));
|
||||
}, []);
|
||||
}
|
||||
else {
|
||||
// remove nonexistent method names
|
||||
filterMethods = lodash.intersection(allMethods, filterMethods);
|
||||
}
|
||||
return result;
|
||||
}, '');
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Invokes a process with the given `name`, `parameters`, and `source` (used as
|
||||
* the standard input). Yields the result to a `callback` function. The optional
|
||||
* `encoding` argument specifies the output stream encoding.
|
||||
* Gets the aliases associated with a given `funcName`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} name The name of the process.
|
||||
* @param {Array} parameters An array of arguments to proxy to the process.
|
||||
* @param {String} source The standard input to proxy to the process.
|
||||
* @param {String} [encoding] The expected encoding of the output stream.
|
||||
* @param {Function} callback The function to call once the process completes.
|
||||
* @param {String} funcName The name of the function to get aliases for.
|
||||
* @returns {Array} Returns an array of aliases.
|
||||
*/
|
||||
function invoke(name, parameters, source, encoding, callback) {
|
||||
// the standard error stream, standard output stream, and process instance
|
||||
var error = '',
|
||||
output = '',
|
||||
process = spawn(name, parameters);
|
||||
function getAliases(funcName) {
|
||||
return realToAliasMap[funcName] || [];
|
||||
}
|
||||
|
||||
// juggle arguments
|
||||
if (typeof encoding == 'string' && callback != null) {
|
||||
// explicitly set the encoding of the output stream if one is specified
|
||||
process.stdout.setEncoding(encoding);
|
||||
} else {
|
||||
callback = encoding;
|
||||
encoding = null;
|
||||
}
|
||||
|
||||
process.stdout.on('data', function(data) {
|
||||
// append the data to the output stream
|
||||
output += data;
|
||||
});
|
||||
|
||||
process.stderr.on('data', function(data) {
|
||||
// append the error message to the error stream
|
||||
error += data;
|
||||
});
|
||||
|
||||
process.on('exit', function(status) {
|
||||
var exception = null;
|
||||
// `status` contains the process exit code
|
||||
if (status) {
|
||||
exception = new Error(error);
|
||||
exception.status = status;
|
||||
/**
|
||||
* Gets an array of depenants for a function by the given `funcName`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} funcName The name of the function to query.
|
||||
* @returns {Array} Returns an array of function dependants.
|
||||
*/
|
||||
function getDependants(funcName) {
|
||||
// iterate over `dependencyMap`, adding the names of functions that
|
||||
// have `funcName` as a dependency
|
||||
return lodash.reduce(dependencyMap, function(result, dependencies, otherName) {
|
||||
if (dependencies.indexOf(funcName) > -1) {
|
||||
result.push(otherName);
|
||||
}
|
||||
callback(exception, output);
|
||||
return result;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of dependencies for a function of the given `funcName`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} funcName The name of the function to query.
|
||||
* @returns {Array} Returns an array of function dependencies.
|
||||
*/
|
||||
function getDependencies(funcName) {
|
||||
var dependencies = dependencyMap[funcName],
|
||||
result = [];
|
||||
|
||||
if (!dependencies) {
|
||||
return result;
|
||||
}
|
||||
// recursively accumulate the dependencies of the `funcName` function, and
|
||||
// the dependencies of its dependencies, and so on.
|
||||
return dependencies.reduce(function(result, otherName) {
|
||||
result.push.apply(result, getDependencies(otherName).concat(otherName));
|
||||
return result;
|
||||
}, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the real name, not alias, of a given `funcName`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} funcName The name of the function to resolve.
|
||||
* @returns {String} Returns the real name.
|
||||
*/
|
||||
function getRealName(funcName) {
|
||||
return aliasToRealMap[funcName] || funcName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if all functions of the given names have been removed from the `source`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to inspect.
|
||||
* @param {String} [funcName1, funcName2, ...] The names of functions to check.
|
||||
* @returns {Boolean} Returns `true` if all functions have been removed, else `false`.
|
||||
*/
|
||||
function isRemoved(source) {
|
||||
return slice.call(arguments, 1).every(function(funcName) {
|
||||
return !matchFunction(source, funcName);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the `source` for a `funcName` function declaration, expression, or
|
||||
* assignment and returns the matched snippet.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to inspect.
|
||||
* @param {String} funcName The name of the function to match.
|
||||
* @returns {String} Returns the matched function snippet.
|
||||
*/
|
||||
function matchFunction(source, funcName) {
|
||||
var result = source.match(RegExp(
|
||||
// match multi-line comment block (could be on a single line)
|
||||
'\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/\\n' +
|
||||
// begin non-capturing group
|
||||
'(?:' +
|
||||
// match a function declaration
|
||||
'( +)function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' +
|
||||
// match a variable declaration with `createIterator`
|
||||
' +var ' + funcName + ' *=.*?createIterator\\((?:{|[a-zA-Z])[\\s\\S]+?\\);|' +
|
||||
// match a variable declaration with function expression
|
||||
'( +)var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\2};' +
|
||||
// end non-capturing group
|
||||
')\\n'
|
||||
));
|
||||
|
||||
return result ? result[0] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the all references to `refName` from the `createIterator` source.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @param {String} refName The name of the reference to remove.
|
||||
* @returns {String} Returns the modified source.
|
||||
*/
|
||||
function removeFromCreateIterator(source, refName) {
|
||||
var snippet = matchFunction(source, 'createIterator'),
|
||||
modified = snippet.replace(RegExp('\\b' + refName + '\\b,? *', 'g'), '');
|
||||
|
||||
return source.replace(snippet, modified);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the `funcName` function declaration, expression, or assignment and
|
||||
* associated code from the `source`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @param {String} funcName The name of the function to remove.
|
||||
* @returns {String} Returns the source with the function removed.
|
||||
*/
|
||||
function removeFunction(source, funcName) {
|
||||
var modified,
|
||||
snippet = matchFunction(source, funcName);
|
||||
|
||||
// exit early if function is not found
|
||||
if (!snippet) {
|
||||
return source;
|
||||
}
|
||||
// remove function
|
||||
source = source.replace(matchFunction(source, funcName), '');
|
||||
|
||||
// grab the method assignments snippet
|
||||
snippet = source.match(/lodash\.VERSION *= *[\s\S]+?\/\*-+\*\/\n/)[0];
|
||||
|
||||
// remove assignment and aliases
|
||||
modified = getAliases(funcName).concat(funcName).reduce(function(result, otherName) {
|
||||
return result.replace(RegExp('(?:\\n *//.*\\s*)* *lodash\\.' + otherName + ' *= *.+\\n'), '');
|
||||
}, snippet);
|
||||
|
||||
// replace with the modified snippet
|
||||
source = source.replace(snippet, modified);
|
||||
|
||||
return removeFromCreateIterator(source, funcName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a given variable from the `source`.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @param {String} varName The name of the variable to remove.
|
||||
* @returns {String} Returns the source with the variable removed.
|
||||
*/
|
||||
function removeVar(source, varName) {
|
||||
source = source.replace(RegExp(
|
||||
// begin non-capturing group
|
||||
'(?:' +
|
||||
// match multi-line comment block
|
||||
'(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' +
|
||||
// match a variable declaration that's not part of a declaration list
|
||||
'( +)var ' + varName + ' *= *(?:.*?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\1.+?;)\\n|' +
|
||||
// match a variable in a declaration list
|
||||
'\\n +' + varName + ' *=.*?,' +
|
||||
// end non-capturing group
|
||||
')'
|
||||
), '');
|
||||
|
||||
// remove a varaible at the start of a variable declaration list
|
||||
source = source.replace(RegExp('(var +)' + varName + ' *=.+?,\\s+'), '$1');
|
||||
|
||||
// remove a variable at the end of a variable declaration list
|
||||
source = source.replace(RegExp(',\\s*' + varName + ' *=.*?;'), ';');
|
||||
|
||||
return removeFromCreateIterator(source, varName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes non-syntax critical whitespace from a string.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @returns {String} Returns the source with whitespace removed.
|
||||
*/
|
||||
function removeWhitespace(source) {
|
||||
return source.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |var |@ |\\\\n|\\n|\s+/g, function(match) {
|
||||
return match == false || match == '\\n' ? '' : match;
|
||||
});
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// custom build
|
||||
(function() {
|
||||
// exit early if "category", "exclude", or "include" options aren't specified
|
||||
if (!filterType) {
|
||||
return;
|
||||
}
|
||||
if (filterType == 'exclude') {
|
||||
// remove methods that are named in `filterMethods` and their dependants
|
||||
filterMethods.forEach(function(funcName) {
|
||||
getDependants(funcName).concat(funcName).forEach(function(otherName) {
|
||||
source = removeFunction(source, otherName);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
// add dependencies to `filterMethods`
|
||||
filterMethods = lodash.uniq(filterMethods.reduce(function(result, funcName) {
|
||||
result.push.apply(result, getDependencies(funcName).concat(funcName));
|
||||
return result;
|
||||
}, []));
|
||||
|
||||
// remove methods that aren't named in `filterMethods`
|
||||
lodash.each(dependencyMap, function(dependencies, otherName) {
|
||||
if (filterMethods.indexOf(otherName) < 0) {
|
||||
source = removeFunction(source, otherName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// remove associated functions, variables and code snippets
|
||||
if (isRemoved(source, 'isArguments')) {
|
||||
// remove `isArguments` if-statement
|
||||
source = source.replace(/(?:\s*\/\/.*)*\s*if *\(!isArguments[^)]+\)[\s\S]+?};?\s*}\n/, '');
|
||||
}
|
||||
if (isRemoved(source, 'mixin')) {
|
||||
// remove `LoDash` constructor
|
||||
source = removeFunction(source, 'LoDash');
|
||||
// remove `LoDash` calls
|
||||
source = source.replace(/(?:new +LoDash(?!\()|(?:new +)?LoDash\([^)]*\));?/g, '');
|
||||
// remove `LoDash.prototype` additions
|
||||
source = source.replace(/(?:\s*\/\/.*)*\s*LoDash.prototype *=[\s\S]+?\/\*-+\*\//, '');
|
||||
}
|
||||
if (isRemoved(source, 'template')) {
|
||||
// remove `templateSettings` assignment
|
||||
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *lodash\.templateSettings[\s\S]+?};\n/, '');
|
||||
}
|
||||
if (isRemoved(source, 'isArray', 'isEmpty', 'isEqual', 'size')) {
|
||||
source = removeVar(source, 'arrayClass');
|
||||
}
|
||||
if (isRemoved(source, 'bind', 'functions', 'groupBy', 'invoke', 'isEqual', 'isFunction', 'result', 'sortBy', 'toArray')) {
|
||||
source = removeVar(source, 'funcClass');
|
||||
}
|
||||
if (isRemoved(source, 'bind')) {
|
||||
source = removeVar(source, 'nativeBind');
|
||||
}
|
||||
if (isRemoved(source, 'isArray')) {
|
||||
source = removeVar(source, 'nativeIsArray');
|
||||
}
|
||||
if (isRemoved(source, 'keys')) {
|
||||
source = removeVar(source, 'nativeKeys');
|
||||
}
|
||||
if (isRemoved(source, 'clone', 'isObject', 'keys')) {
|
||||
source = removeVar(source, 'objectTypes');
|
||||
source = removeFromCreateIterator(source, 'objectTypes');
|
||||
}
|
||||
if (isRemoved(source, 'bind', 'isArray', 'keys')) {
|
||||
source = removeVar(source, 'reNative');
|
||||
}
|
||||
if (isRemoved(source, 'isEmpty', 'isEqual', 'isString', 'size')) {
|
||||
source = removeVar(source, 'stringClass');
|
||||
}
|
||||
|
||||
// consolidate consecutive horizontal rule comment separators
|
||||
source = source.replace(/(?:\s*\/\*-+\*\/\s*){2,}/g, function(separators) {
|
||||
return separators.match(/^\s*/)[0] + separators.slice(separators.lastIndexOf('/*'));
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
if (isMobile) {
|
||||
// inline functions defined with `createIterator`
|
||||
lodash.functions(lodash).forEach(function(funcName) {
|
||||
// match `funcName` with pseudo private `_` prefixes removed to allow matching `shimKeys`
|
||||
var reFunc = RegExp('(\\bvar ' + funcName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n');
|
||||
|
||||
// skip if not defined with `createIterator`
|
||||
if (!reFunc.test(source)) {
|
||||
return;
|
||||
}
|
||||
// extract and format the function's code
|
||||
var code = (lodash[funcName] + '').replace(/\n(?:.*)/g, function(match) {
|
||||
match = match.slice(1);
|
||||
return (match == '}' ? '\n ' : '\n ') + match;
|
||||
});
|
||||
|
||||
source = source.replace(reFunc, '$1' + code + ';\n');
|
||||
});
|
||||
|
||||
// proxy the standard input to the process
|
||||
process.stdin.end(source);
|
||||
// remove `iteratorTemplate`
|
||||
source = removeVar(source, 'iteratorTemplate');
|
||||
|
||||
// remove JScript [[DontEnum]] fix from `isEqual`
|
||||
source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(result *&& *hasDontEnumBug[\s\S]+?\n\1}\n/, '\n');
|
||||
|
||||
// remove IE `shift` and `splice` fix
|
||||
source = source.replace(/(?:\s*\/\/.*\n)*( +)if *\(value.length *=== *0[\s\S]+?\n\1}\n/, '\n');
|
||||
}
|
||||
else {
|
||||
// inline `iteratorTemplate` template
|
||||
source = source.replace(/(( +)var iteratorTemplate *= *)([\s\S]+?\n\2.+?);\n/, (function() {
|
||||
// extract `iteratorTemplate` code
|
||||
var code = /^function[^{]+{([\s\S]+?)}$/.exec(lodash._iteratorTemplate)[1];
|
||||
|
||||
code = removeWhitespace(code)
|
||||
// remove unnecessary code
|
||||
.replace(/\|\|\{\}|,__t,__j=Array.prototype.join|function print[^}]+}|\+''/g, '')
|
||||
.replace(/(\{);|;(\})/g, '$1$2')
|
||||
.replace(/\(\(__t=\(([^)]+)\)\)==null\?'':__t\)/g, '$1')
|
||||
// ensure escaped characters are interpreted correctly in the string literal
|
||||
.replace(/\\/g, '\\\\');
|
||||
|
||||
// add `code` to `Function()` as a string literal to avoid strict mode
|
||||
// errors caused by the required with-statement
|
||||
return '$1Function(\'obj\',\n$2 "' + code + '"\n$2);\n';
|
||||
}()));
|
||||
}
|
||||
|
||||
// remove pseudo private properties
|
||||
source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n');
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Compresses a `source` string using the Closure Compiler. Yields the
|
||||
* minified result, and any exceptions encountered, to a `callback` function.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The JavaScript source to minify.
|
||||
* @param {Function} callback The function to call once the process completes.
|
||||
*/
|
||||
function closureCompile(source, callback) {
|
||||
console.log('Compressing lodash.js using the Closure Compiler...');
|
||||
invoke('java', ['-jar', closurePath].concat(closureOptions), source, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses a `source` string using UglifyJS. Yields the result to a
|
||||
* `callback` function. This function is synchronous; the `callback` is used
|
||||
* for symmetry.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The JavaScript source to minify.
|
||||
* @param {Function} callback The function to call once the process completes.
|
||||
*/
|
||||
function uglify(source, callback) {
|
||||
var exception,
|
||||
result,
|
||||
ugly = uglifyJS.uglify;
|
||||
|
||||
console.log('Compressing lodash.js using UglifyJS...');
|
||||
|
||||
try {
|
||||
result = ugly.gen_code(
|
||||
// enable unsafe transformations
|
||||
ugly.ast_squeeze_more(
|
||||
ugly.ast_squeeze(
|
||||
// munge variable and function names, excluding the special `define`
|
||||
// function exposed by AMD loaders
|
||||
ugly.ast_mangle(uglifyJS.parser.parse(source), {
|
||||
'except': ['define']
|
||||
}
|
||||
))), {
|
||||
'ascii_only': true
|
||||
});
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
// lines are restricted to 500 characters for consistency with the Closure Compiler
|
||||
callback(exception, result && ugly.split_lines(result, 500));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The `closureCompile()` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {String} result The resulting minified source.
|
||||
*/
|
||||
function onClosureCompile(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the post-processed Closure Compiler result and gzip it
|
||||
accumulator.compiled.source = result = postprocess(result);
|
||||
invoke('gzip', gzipOptions, result, 'binary', onClosureGzip);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Closure Compiler `gzip` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {String} result The resulting gzipped source.
|
||||
*/
|
||||
function onClosureGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the gzipped result and report the size
|
||||
accumulator.compiled.gzip = result;
|
||||
console.log('Done. Size: %d KB.', result.length);
|
||||
|
||||
// next, minify using UglifyJS
|
||||
uglify(source, onUglify);
|
||||
}
|
||||
|
||||
/**
|
||||
* The `uglify()` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {String} result The resulting minified source.
|
||||
*/
|
||||
function onUglify(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the post-processed Uglified result and gzip it
|
||||
accumulator.uglified.source = postprocess(result);
|
||||
invoke('gzip', gzipOptions, result, 'binary', onUglifyGzip);
|
||||
}
|
||||
|
||||
/**
|
||||
* The UglifyJS `gzip` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {String} result The resulting gzipped source.
|
||||
*/
|
||||
function onUglifyGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the gzipped result and report the size
|
||||
accumulator.uglified.gzip = result;
|
||||
console.log('Done. Size: %d KB.', result.length);
|
||||
|
||||
// finish by choosing the smallest compressed file
|
||||
onComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback executed after JavaScript source is minified and gzipped.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function onComplete() {
|
||||
var compiled = accumulator.compiled,
|
||||
uglified = accumulator.uglified;
|
||||
|
||||
// save the Closure Compiled version to disk
|
||||
fs.writeFileSync(path.join(distPath, 'lodash.compiler.js'), compiled.source);
|
||||
// explicit 'binary' is necessary to ensure the stream is written correctly
|
||||
fs.writeFileSync(path.join(distPath, 'lodash.compiler.js.gz'), compiled.gzip, 'binary');
|
||||
|
||||
// save the Uglified version to disk
|
||||
fs.writeFileSync(path.join(distPath, 'lodash.uglify.js'), uglified.source);
|
||||
fs.writeFileSync(path.join(distPath, 'lodash.uglify.js.gz'), uglified.gzip, 'binary');
|
||||
|
||||
// select the smallest gzipped file and use its minified form as the
|
||||
// official minified release (ties go to Closure Compiler)
|
||||
fs.writeFileSync(path.join(__dirname, 'lodash.min.js'),
|
||||
uglified.gzip.length < compiled.gzip.length
|
||||
? uglified.source
|
||||
: compiled.source
|
||||
);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// create the destination directory if it doesn't exist
|
||||
if (!path.existsSync(distPath)) {
|
||||
fs.mkdirSync(distPath);
|
||||
}
|
||||
// begin the minification process
|
||||
closureCompile(source, onClosureCompile);
|
||||
if (filterType || isMobile) {
|
||||
fs.writeFileSync(path.join(__dirname, 'lodash.custom.js'), source);
|
||||
minify(source, 'lodash.custom.min', function(result) {
|
||||
fs.writeFileSync(path.join(__dirname, 'lodash.custom.min.js'), result);
|
||||
});
|
||||
}
|
||||
else {
|
||||
minify(source, 'lodash.min', function(result) {
|
||||
fs.writeFileSync(path.join(__dirname, 'lodash.min.js'), result);
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
||||
341
build/minify.js
Executable file
@@ -0,0 +1,341 @@
|
||||
#!/usr/bin/env node
|
||||
;(function() {
|
||||
'use strict';
|
||||
|
||||
/** The Node filesystem, path, `zlib`, and child process modules */
|
||||
var fs = require('fs'),
|
||||
gzip = require('zlib').gzip,
|
||||
path = require('path'),
|
||||
spawn = require('child_process').spawn;
|
||||
|
||||
/** The directory that is the base of the repository */
|
||||
var basePath = 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'));
|
||||
|
||||
/** Closure Compiler command-line options */
|
||||
var closureOptions = [
|
||||
'--compilation_level=ADVANCED_OPTIMIZATIONS',
|
||||
'--language_in=ECMASCRIPT5_STRICT',
|
||||
'--warning_level=QUIET'
|
||||
];
|
||||
|
||||
/** Reassign `existsSync` for older versions of Node */
|
||||
fs.existsSync || (fs.existsSync = path.existsSync);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The exposed `minify` function minifies a given `source` and invokes the
|
||||
* `onComplete` callback when finished.
|
||||
*
|
||||
* @param {String} source The source to minify.
|
||||
* @param {String} workingName The name to give temporary files creates during the minification process.
|
||||
* @param {Function} onComplete A function called when minification has completed.
|
||||
*/
|
||||
function minify(source, workingName, onComplete) {
|
||||
new Minify(source, workingName, onComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Minify constructor used to keep state of each `minify` invocation.
|
||||
*
|
||||
* @private
|
||||
* @constructor
|
||||
* @param {String} source The source to minify.
|
||||
* @param {String} workingName The name to give temporary files creates during the minification process.
|
||||
* @param {Function} onComplete A function called when minification has completed.
|
||||
*/
|
||||
function Minify(source, workingName, onComplete) {
|
||||
// create the destination directory if it doesn't exist
|
||||
if (!fs.existsSync(distPath)) {
|
||||
fs.mkdirSync(distPath);
|
||||
}
|
||||
|
||||
this.compiled = {};
|
||||
this.hybrid = {};
|
||||
this.uglified = {};
|
||||
this.onComplete = onComplete;
|
||||
this.source = source = preprocess(source);
|
||||
this.workingName = workingName;
|
||||
|
||||
// begin the minification process
|
||||
closureCompile.call(this, source, onClosureCompile.bind(this));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Compresses a `source` string using the Closure Compiler. Yields the
|
||||
* minified result, and any exceptions encountered, to a `callback` function.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The JavaScript source to minify.
|
||||
* @param {String} [message] The message to log.
|
||||
* @param {Function} callback The function to call once the process completes.
|
||||
*/
|
||||
function closureCompile(source, message, callback) {
|
||||
// the standard error stream, standard output stream, and Closure Compiler process
|
||||
var error = '',
|
||||
output = '',
|
||||
compiler = spawn('java', ['-jar', closurePath].concat(closureOptions));
|
||||
|
||||
// juggle arguments
|
||||
if (typeof message == 'function') {
|
||||
callback = message;
|
||||
message = null;
|
||||
}
|
||||
|
||||
console.log(message == null
|
||||
? 'Compressing ' + this.workingName + ' using the Closure Compiler...'
|
||||
: message
|
||||
);
|
||||
|
||||
compiler.stdout.on('data', function(data) {
|
||||
// append the data to the output stream
|
||||
output += data;
|
||||
});
|
||||
|
||||
compiler.stderr.on('data', function(data) {
|
||||
// append the error message to the error stream
|
||||
error += data;
|
||||
});
|
||||
|
||||
compiler.on('exit', function(status) {
|
||||
var exception = null;
|
||||
|
||||
// `status` contains the process exit code
|
||||
if (status) {
|
||||
exception = new Error(error);
|
||||
exception.status = status;
|
||||
}
|
||||
callback(exception, output);
|
||||
});
|
||||
|
||||
// proxy the standard input to the Closure Compiler
|
||||
compiler.stdin.end(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses a `source` string using UglifyJS. Yields the result to a
|
||||
* `callback` function. This function is synchronous; the `callback` is used
|
||||
* for symmetry.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The JavaScript source to minify.
|
||||
* @param {String} [message] The message to log.
|
||||
* @param {Function} callback The function to call once the process completes.
|
||||
*/
|
||||
function uglify(source, message, callback) {
|
||||
var exception,
|
||||
result,
|
||||
ugly = uglifyJS.uglify;
|
||||
|
||||
// juggle arguments
|
||||
if (typeof message == 'function') {
|
||||
callback = message;
|
||||
message = null;
|
||||
}
|
||||
|
||||
console.log(message == null
|
||||
? 'Compressing ' + this.workingName + ' using UglifyJS...'
|
||||
: message
|
||||
);
|
||||
|
||||
try {
|
||||
result = ugly.gen_code(
|
||||
// enable unsafe transformations
|
||||
ugly.ast_squeeze_more(
|
||||
ugly.ast_squeeze(
|
||||
// munge variable and function names, excluding the special `define`
|
||||
// function exposed by AMD loaders
|
||||
ugly.ast_mangle(uglifyJS.parser.parse(source), {
|
||||
'except': ['define']
|
||||
}
|
||||
))), {
|
||||
'ascii_only': true
|
||||
});
|
||||
} catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
// lines are restricted to 500 characters for consistency with the Closure Compiler
|
||||
callback(exception, result && ugly.split_lines(result, 500));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The `closureCompile()` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {String} result The resulting minified source.
|
||||
*/
|
||||
function onClosureCompile(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the post-processed Closure Compiler result and gzip it
|
||||
this.compiled.source = result = postprocess(result);
|
||||
gzip(result, onClosureGzip.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The Closure Compiler `gzip` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {Buffer} result The resulting gzipped source.
|
||||
*/
|
||||
function onClosureGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the gzipped result and report the size
|
||||
this.compiled.gzip = result;
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
|
||||
// next, minify the source using only UglifyJS
|
||||
uglify.call(this, this.source, onUglify.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The `uglify()` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {String} result The resulting minified source.
|
||||
*/
|
||||
function onUglify(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the post-processed Uglified result and gzip it
|
||||
this.uglified.source = result = postprocess(result);
|
||||
gzip(result, onUglifyGzip.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The UglifyJS `gzip` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {Buffer} result The resulting gzipped source.
|
||||
*/
|
||||
function onUglifyGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
var message = 'Compressing ' + this.workingName + ' using hybrid minification...';
|
||||
|
||||
// store the gzipped result and report the size
|
||||
this.uglified.gzip = result;
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
|
||||
// next, minify the Closure Compiler minified source using UglifyJS
|
||||
uglify.call(this, this.compiled.source, message, onHybrid.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The hybrid `uglify()` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {String} result The resulting minified source.
|
||||
*/
|
||||
function onHybrid(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the post-processed Uglified result and gzip it
|
||||
this.hybrid.source = result = postprocess(result);
|
||||
gzip(result, onHybridGzip.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* The hybrid `gzip` callback.
|
||||
*
|
||||
* @private
|
||||
* @param {Object|Undefined} exception The error object.
|
||||
* @param {Buffer} result The resulting gzipped source.
|
||||
*/
|
||||
function onHybridGzip(exception, result) {
|
||||
if (exception) {
|
||||
throw exception;
|
||||
}
|
||||
// store the gzipped result and report the size
|
||||
this.hybrid.gzip = result;
|
||||
console.log('Done. Size: %d bytes.', result.length);
|
||||
|
||||
// finish by choosing the smallest compressed file
|
||||
onComplete.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback executed after JavaScript source is minified and gzipped.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function onComplete() {
|
||||
var compiled = this.compiled,
|
||||
hybrid = this.hybrid,
|
||||
name = this.workingName,
|
||||
uglified = this.uglified;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// pass the minified source to the minify instances "onComplete" callback
|
||||
this.onComplete(
|
||||
compiled.gzip.length == min
|
||||
? compiled.source
|
||||
: uglified.gzip.length == min
|
||||
? uglified.source
|
||||
: hybrid.source
|
||||
);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// expose `minify`
|
||||
if (module != require.main) {
|
||||
module.exports = minify;
|
||||
}
|
||||
else {
|
||||
// read the JavaScript source file from the first argument if the script
|
||||
// was invoked directly (e.g. `node minify.js source.js`) and write to
|
||||
// the same file
|
||||
(function() {
|
||||
var filePath = process.argv[2],
|
||||
dirPath = path.dirname(filePath),
|
||||
source = fs.readFileSync(filePath, 'utf8'),
|
||||
workingName = path.basename(filePath, '.js') + '.min';
|
||||
|
||||
minify(source, workingName, function(result) {
|
||||
fs.writeFileSync(path.join(dirPath, workingName + '.js'), result);
|
||||
});
|
||||
}());
|
||||
}
|
||||
}());
|
||||
@@ -8,7 +8,7 @@
|
||||
/** The minimal license/copyright template */
|
||||
var licenseTemplate =
|
||||
'/*!\n' +
|
||||
' Lo-Dash @VERSION github.com/bestiejs/lodash/blob/master/LICENSE.txt\n' +
|
||||
' Lo-Dash @VERSION lodash.com/license\n' +
|
||||
' Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE\n' +
|
||||
'*/';
|
||||
|
||||
@@ -18,19 +18,36 @@
|
||||
* Post-process a given minified JavaScript `source`, preparing it for
|
||||
* deployment.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @returns {String} Returns the processed source.
|
||||
*/
|
||||
function postprocess(source) {
|
||||
// exit early if snippet isn't found
|
||||
var snippet = /VERSION\s*[=:]\s*([\'"])(.*?)\1/.exec(source);
|
||||
if (!snippet) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// set the version
|
||||
var license = licenseTemplate.replace('@VERSION', (/VERSION:([\'"])(.*?)\1/).exec(source).pop());
|
||||
var license = licenseTemplate.replace('@VERSION', snippet[2]);
|
||||
|
||||
// move vars exposed by Closure Compiler into the IIFE
|
||||
source = source.replace(/^([^(\n]+)\s*(\(function[^)]+\){)/, '$2$1');
|
||||
|
||||
// use double quotes consistently
|
||||
source = source.replace(/'use strict'/, '"use strict"');
|
||||
|
||||
// unescape properties (i.e. foo["bar"] => foo.bar)
|
||||
source = source.replace(/(\w)\["([^."]+)"\]/g, '$1.$2');
|
||||
|
||||
// correct AMD module definition for AMD build optimizers
|
||||
source = source.replace(/("function")==(typeof define)&&\(?("object")==(typeof define\.amd)(&&define\.amd)\)?/, '$2==$1&&$4==$3$5');
|
||||
|
||||
// add license
|
||||
return license + '\n;' + source;
|
||||
source = license + '\n;' + source;
|
||||
|
||||
// add trailing semicolon
|
||||
return source.replace(/[\s;]*$/, ';');
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
@@ -5,65 +5,56 @@
|
||||
/** The Node filesystem module */
|
||||
var fs = require('fs');
|
||||
|
||||
/** Used to minify string values embedded in compiled strings */
|
||||
var compiledValues = [
|
||||
'arrays',
|
||||
'objects'
|
||||
];
|
||||
|
||||
/** Used to minify variables embedded in compiled strings */
|
||||
var compiledVars = [
|
||||
'accumulator',
|
||||
'array',
|
||||
'arrayClass',
|
||||
'bind',
|
||||
'callback',
|
||||
'className',
|
||||
'collection',
|
||||
'computed',
|
||||
'concat',
|
||||
'current',
|
||||
'ctor',
|
||||
'false',
|
||||
'funcClass',
|
||||
'hasOwnProperty',
|
||||
'identity',
|
||||
'index',
|
||||
'indexOf',
|
||||
'Infinity',
|
||||
'initial',
|
||||
'isArray',
|
||||
'isEmpty',
|
||||
'iteratorBind',
|
||||
'length',
|
||||
'object',
|
||||
'Math',
|
||||
'objectTypes',
|
||||
'noaccum',
|
||||
'property',
|
||||
'result',
|
||||
'slice',
|
||||
'skipProto',
|
||||
'source',
|
||||
'sourceIndex',
|
||||
'stringClass',
|
||||
'target',
|
||||
'thisArg',
|
||||
'toString',
|
||||
'true',
|
||||
'undefined',
|
||||
'value',
|
||||
'values'
|
||||
'value'
|
||||
];
|
||||
|
||||
/** Used to minify `iterationFactory` option properties */
|
||||
var iterationFactoryOptions = [
|
||||
'afterLoop',
|
||||
/** Used to minify `compileIterator` option properties */
|
||||
var iteratorOptions = [
|
||||
'args',
|
||||
'array',
|
||||
'arrayBranch',
|
||||
'beforeLoop',
|
||||
'bottom',
|
||||
'exits',
|
||||
'exit',
|
||||
'firstArg',
|
||||
'hasExp',
|
||||
'hasDontEnumBug',
|
||||
'inLoop',
|
||||
'init',
|
||||
'iterate',
|
||||
'iteratedObject',
|
||||
'loopExp',
|
||||
'object',
|
||||
'returns',
|
||||
'objectBranch',
|
||||
'shadowed',
|
||||
'top',
|
||||
'useHas'
|
||||
];
|
||||
@@ -71,24 +62,125 @@
|
||||
/** Used to minify variables and string values to a single character */
|
||||
var minNames = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
||||
|
||||
/** Used protect the specified properties from getting minified */
|
||||
/** Used to protect the specified properties from getting minified */
|
||||
var propWhitelist = [
|
||||
'_',
|
||||
'_chain',
|
||||
'_wrapped',
|
||||
'after',
|
||||
'all',
|
||||
'amd',
|
||||
'any',
|
||||
'bind',
|
||||
'bindAll',
|
||||
'chain',
|
||||
'clearTimeout',
|
||||
'clone',
|
||||
'collect',
|
||||
'compact',
|
||||
'compose',
|
||||
'contains',
|
||||
'criteria',
|
||||
'debounce',
|
||||
'defaults',
|
||||
'defer',
|
||||
'delay',
|
||||
'detect',
|
||||
'difference',
|
||||
'each',
|
||||
'environment',
|
||||
'escape',
|
||||
'escape',
|
||||
'evaluate',
|
||||
'every',
|
||||
'extend',
|
||||
'filter',
|
||||
'find',
|
||||
'first',
|
||||
'flatten',
|
||||
'foldl',
|
||||
'foldr',
|
||||
'forEach',
|
||||
'forIn',
|
||||
'forOwn',
|
||||
'functions',
|
||||
'groupBy',
|
||||
'has',
|
||||
'head',
|
||||
'identity',
|
||||
'include',
|
||||
'indexOf',
|
||||
'initial',
|
||||
'inject',
|
||||
'interpolate',
|
||||
'intersection',
|
||||
'invoke',
|
||||
'isArguments',
|
||||
'isArray',
|
||||
'isBoolean',
|
||||
'isDate',
|
||||
'isElement',
|
||||
'isEmpty',
|
||||
'isEqual',
|
||||
'isEqual',
|
||||
'isFinite',
|
||||
'lodash',
|
||||
'isFinite',
|
||||
'isFunction',
|
||||
'isNaN',
|
||||
'isNull',
|
||||
'isNumber',
|
||||
'isObject',
|
||||
'isRegExp',
|
||||
'isString',
|
||||
'isUndefined',
|
||||
'keys',
|
||||
'last',
|
||||
'lastIndexOf',
|
||||
'map',
|
||||
'max',
|
||||
'memoize',
|
||||
'methods',
|
||||
'min',
|
||||
'mixin',
|
||||
'noConflict',
|
||||
'once',
|
||||
'opera',
|
||||
'partial',
|
||||
'pick',
|
||||
'pluck',
|
||||
'range',
|
||||
'reduce',
|
||||
'reduceRight',
|
||||
'reject',
|
||||
'rest',
|
||||
'result',
|
||||
'select',
|
||||
'setTimeout',
|
||||
'shuffle',
|
||||
'size',
|
||||
'some',
|
||||
'sortBy',
|
||||
'sortedIndex',
|
||||
'source',
|
||||
'tail',
|
||||
'take',
|
||||
'tap',
|
||||
'template',
|
||||
'templateSettings',
|
||||
'throttle',
|
||||
'times',
|
||||
'toArray',
|
||||
'union',
|
||||
'uniq',
|
||||
'unique',
|
||||
'uniqueId',
|
||||
'value',
|
||||
'variable'
|
||||
'values',
|
||||
'variable',
|
||||
'VERSION',
|
||||
'without',
|
||||
'wrap',
|
||||
'zip'
|
||||
];
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -96,7 +188,6 @@
|
||||
/**
|
||||
* Pre-process a given JavaScript `source`, preparing it for minification.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @returns {String} Returns the processed source.
|
||||
*/
|
||||
@@ -104,88 +195,125 @@
|
||||
// remove copyright to add later in post-compile.js
|
||||
source = source.replace(/\/\*![\s\S]+?\*\//, '');
|
||||
|
||||
// correct JSDoc tags for Closure Compiler
|
||||
source = source.replace(/@(?:alias|category)[^\n]*/g, '');
|
||||
// remove unrecognized JSDoc tags so Closure Compiler won't complain
|
||||
source = source.replace(/@(?:alias|category)\b.*/g, '');
|
||||
|
||||
// add brackets to whitelisted properties so Closure Compiler won't mung them.
|
||||
// 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('\\.(' + iterationFactoryOptions.concat(propWhitelist).join('|') + ')\\b', 'g'), "['$1']");
|
||||
source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']");
|
||||
|
||||
// minify `sortBy` and `template` methods
|
||||
['sortBy', 'template'].forEach(function(methodName) {
|
||||
var properties = ['criteria', 'value'],
|
||||
snippet = source.match(RegExp('(\\n\\s*)function ' + methodName + '[\\s\\S]+?\\1}'))[0],
|
||||
result = snippet;
|
||||
// remove brackets from `_.escape(__t)` in `tokenizeEscape`
|
||||
source = source.replace("_['escape'](__t)", '_.escape(__t)');
|
||||
|
||||
// minify property strings
|
||||
properties.forEach(function(property, index) {
|
||||
result = result.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'");
|
||||
// remove whitespace from string literals
|
||||
source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) {
|
||||
// avoids removing the '\n' of the `stringEscapes` object
|
||||
return string.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) {
|
||||
return match == false || match == '\\n' ? '' : match;
|
||||
});
|
||||
|
||||
// remove escaped newlines in strings
|
||||
result = result.replace(/\\n/g, '');
|
||||
|
||||
// replace with modified snippet
|
||||
source = source.replace(snippet, result);
|
||||
});
|
||||
|
||||
// minify all `iterationFactory` related snippets
|
||||
source.match(
|
||||
RegExp([
|
||||
// match variables storing `iterationFactory` options
|
||||
'var [a-zA-Z]+FactoryOptions\\s*=\\s*\\{[\\s\\S]+?};\\n',
|
||||
// match the the `iterationFactory` function
|
||||
'(\\n\\s*)function iterationFactory[\\s\\S]+?\\1}',
|
||||
// match methods created by `iterationFactor` calls
|
||||
'iterationFactory\\((?:[\'{]|[a-zA-Z]+,)[\\s\\S]+?\\);\\n'
|
||||
].join('|'), 'g')
|
||||
)
|
||||
.forEach(function(snippet, index) {
|
||||
var result = snippet;
|
||||
// remove newline from double-quoted string in `_.template`
|
||||
source = source.replace('"\';\\n"', '"\';"');
|
||||
|
||||
// add `true` and `false` arguments to be minified
|
||||
if (/function iterationFactory/.test(snippet)) {
|
||||
result = result
|
||||
.replace(/(Function\('[\s\S]+?)undefined/, '$1true,false,undefined')
|
||||
.replace(/\)\([^)]+/, '$&,true,false');
|
||||
// remove debug sourceURL in `_.template`
|
||||
source = source.replace(/\+(?:\s*\/\/.*)*\s*'\/\/@ sourceURL=[^;]+/, '');
|
||||
|
||||
// replace with modified snippet early and clip snippet
|
||||
// minify `_.sortBy` internal properties
|
||||
(function() {
|
||||
var properties = ['criteria', 'value'],
|
||||
snippet = (source.match(/( +)function sortBy\b[\s\S]+?\n\1}/) || 0)[0],
|
||||
result = snippet;
|
||||
|
||||
if (snippet) {
|
||||
// minify property strings
|
||||
properties.forEach(function(property, index) {
|
||||
result = result.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'");
|
||||
});
|
||||
// replace with modified snippet
|
||||
source = source.replace(snippet, result);
|
||||
snippet = result = result.replace(/\)\([\s\S]+$/, '');
|
||||
}
|
||||
}());
|
||||
|
||||
// minify all compilable snippets
|
||||
var snippets = source.match(
|
||||
RegExp([
|
||||
// match the `iteratorTemplate`
|
||||
'var iteratorTemplate\\b[\\s\\S]+?\\);\\n',
|
||||
// match methods created by `createIterator` calls
|
||||
'createIterator\\((?:{|[a-zA-Z]+)[\\s\\S]+?\\);\\n',
|
||||
// match variables storing `createIterator` options
|
||||
'( +)var [a-zA-Z]+IteratorOptions\\b[\\s\\S]+?\\n\\1}',
|
||||
// match the the `createIterator` function
|
||||
'( +)function createIterator\\b[\\s\\S]+?\\n\\2}'
|
||||
].join('|'), 'g')
|
||||
);
|
||||
|
||||
// exit early if no compilable snippets
|
||||
if (!snippets) {
|
||||
return source;
|
||||
}
|
||||
|
||||
snippets.forEach(function(snippet, index) {
|
||||
var isCreateIterator = /function createIterator\b/.test(snippet),
|
||||
isIteratorTemplate = /var iteratorTemplate\b/.test(snippet),
|
||||
result = snippet;
|
||||
|
||||
|
||||
// add brackets to whitelisted properties so Closure Compiler won't mung them
|
||||
result = result.replace(RegExp('\\.(' + iteratorOptions.join('|') + ')\\b', 'g'), "['$1']");
|
||||
|
||||
if (isCreateIterator) {
|
||||
// add `true` and `false` arguments to be minified
|
||||
result = result
|
||||
.replace(/(Function\(\s*'[\s\S]+?)undefined/, '$1true,false,undefined')
|
||||
.replace(/factory\([^)]+/, '$&,true,false');
|
||||
|
||||
// replace with modified snippet early and clip snippet so other arguments
|
||||
// aren't minified
|
||||
source = source.replace(snippet, result);
|
||||
snippet = result = result.replace(/factory\([\s\S]+$/, '');
|
||||
}
|
||||
|
||||
// minify snippet variables/arguments
|
||||
// minify snippet variables / arguments
|
||||
compiledVars.forEach(function(variable, index) {
|
||||
result = result.replace(RegExp('([^.]\\b|\\\\n)' + variable + '\\b(?!\'\\s*[\\]:])', 'g'), '$1' + minNames[index]);
|
||||
// ensure properties in compiled strings aren't minified
|
||||
result = result.replace(RegExp('([^.]\\b)' + variable + '\\b(?!\' *[\\]:])', 'g'), '$1' + minNames[index]);
|
||||
|
||||
// correct `typeof x == 'object'`
|
||||
if (variable == 'object') {
|
||||
result = result.replace(RegExp("(typeof [^']+')" + minNames[index] + "'", 'g'), "$1object'");
|
||||
}
|
||||
// correct boolean literals
|
||||
if (variable == 'true' || variable == 'false') {
|
||||
// correct external boolean literals
|
||||
else if (variable == 'true' || variable == 'false') {
|
||||
result = result
|
||||
.replace(RegExp(':\\s*' + minNames[index] + '\\s*,', 'g'), ':' + variable + ',')
|
||||
.replace(RegExp('\\s*' + minNames[index] + '\\s*;', 'g'), variable + ';');
|
||||
.replace(RegExp(': *' + minNames[index] + '([,\\n])', 'g'), ':' + variable + '$1')
|
||||
.replace(RegExp('\\b' + minNames[index] + ';', 'g'), variable + ';');
|
||||
}
|
||||
});
|
||||
|
||||
// minify snippet values
|
||||
compiledValues.forEach(function(value, index) {
|
||||
result = result.replace(RegExp("'" + value + "'", 'g'), "'" + minNames[index] + "'");
|
||||
});
|
||||
|
||||
// minify iterationFactory option property strings
|
||||
iterationFactoryOptions.forEach(function(property, index) {
|
||||
if (property == 'array' || property == 'object') {
|
||||
result = result.replace(RegExp("'" + property + "'(\\s*[\\]:])", 'g'), "'" + minNames[index] + "'$1");
|
||||
} else {
|
||||
result = result.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'");
|
||||
// minify `createIterator` option property names
|
||||
iteratorOptions.forEach(function(property, index) {
|
||||
if (isIteratorTemplate) {
|
||||
// minify property names as interpolated template variables
|
||||
result = result.replace(RegExp('\\b' + property + '\\b', 'g'), minNames[index]);
|
||||
}
|
||||
else {
|
||||
if (property == 'array' || property == 'object') {
|
||||
// minify "array" and "object" sub property names
|
||||
result = result.replace(RegExp("'" + property + "'( *[\\]:])", 'g'), "'" + minNames[index] + "'$1");
|
||||
}
|
||||
else {
|
||||
// minify property name strings
|
||||
result = result.replace(RegExp("'" + property + "'", 'g'), "'" + minNames[index] + "'");
|
||||
// minify property names in regexps and accessors
|
||||
if (isCreateIterator) {
|
||||
result = result.replace(RegExp('([\\.|/])' + property + '\\b' , 'g'), '$1' + minNames[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// remove escaped newlines in strings
|
||||
result = result.replace(/\\n/g, '');
|
||||
|
||||
// replace with modified snippet
|
||||
source = source.replace(snippet, result);
|
||||
});
|
||||
@@ -198,7 +326,8 @@
|
||||
// expose `preprocess`
|
||||
if (module != require.main) {
|
||||
module.exports = preprocess;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// read the JavaScript source file from the first argument if the script
|
||||
// was invoked directly (e.g. `node pre-compile.js source.js`) and write to
|
||||
// the same file
|
||||
|
||||
1247
doc/README.md
@@ -21,8 +21,8 @@
|
||||
// generate Markdown
|
||||
$markdown = docdown(array(
|
||||
'path' => '../' . $file,
|
||||
'title' => 'Lo-Dash <sup>v0.1.0</sup>',
|
||||
'url' => 'https://github.com/bestiejs/lodash/blob/master/lodash.js'
|
||||
'title' => 'Lo-Dash <sup>v0.3.0</sup>',
|
||||
'url' => 'https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js'
|
||||
));
|
||||
|
||||
// save to a .md file
|
||||
|
||||
52
lodash.min.js
vendored
@@ -1,26 +1,32 @@
|
||||
/*!
|
||||
Lo-Dash 0.1.0 github.com/bestiejs/lodash/blob/master/LICENSE.txt
|
||||
Lo-Dash 0.3.0 lodash.com/license
|
||||
Underscore.js 1.3.3 github.com/documentcloud/underscore/blob/master/LICENSE
|
||||
*/
|
||||
;(function(r,h){"use strict";var n=!0,o=!1;function Q(a){return"[object Arguments]"==k.call(a)}function i(a){return new p(a)}function p(a){this.o=a}function g(){for(var a,b=-1,c={},d={},f={},e=["d","j","g","a"];++b<arguments.length;)for(a in arguments[b])f[a]=arguments[b][a];for(;a=e.pop();)"object"==typeof f[a]?(c[a]=f[a].c,d[a]=f[a].k):c[a]=d[a]=f[a]||"";a=f.b;var b=/^[^,]+/.exec(a)[0],e=f.h,j=f.i,g=!("v"==a||"b"==j),j=!("b"==a||"a"==j),h=f.n!==o;return Function("c,d,i,l,m,n,p,q,s,t,w,z,B,E,F,k,G",'"use strict";return function('+
|
||||
a+"){"+(f.m||"")+";"+("var o, y"+(e?"="+e:""))+";if("+b+"==G)return "+(f.f||"y")+";"+(g?"var u="+b+".length;o=-1;"+((j?"if(u===+u){":"")+(c.d||"")+";while("+(c.j||"++o<u")+"){"+c.g+"}"+(c.a||"")+";"+(j?"}":"")):"")+(j?(g?"else{":"")+(d.d||"")+";for("+(d.j||"o in "+b)+"){"+(h?"if(m.call("+/\S+$/.exec(d.j||b)[0]+",o)){":"")+d.g+(h?"}":"")+"}"+(d.a||"")+";"+(g?"}":""):"")+(f.e||"")+";return "+(f.l||"y")+"}")(D,u,ba,ca,s,R,E,Infinity,F,da,Math,l,G,k,n,o)}function S(a){return a.replace(ua,function(a,c){return y[c]})}
|
||||
function ea(a,b,c,d){var f=2<arguments.length;if(a==h)return c;d&&(b=u(b,d));var e=a.length;if(e===+e){for(e&&!f&&(c=a[--e]);e--;)c=b(c,a[e],e,a);return c}var j=T(a);for((e=j.length)&&!f&&(c=a[j[--e]]);e--;)f=j[e],c=b(c,a[f],f,a);return c}function fa(a,b,c){var d=0,f=a.length;for(c||(c=R);d<f;){var e=d+f>>1;c(a[e])<c(b)?d=e+1:f=e}return d}function U(a,b,c){return b==h||c?a[0]:l.call(a,0,b)}function H(a,b){return b?ba.apply([],a):z(a,function(a,b){if(F(b))return V.apply(a,H(b)),a;a.push(b);return a},
|
||||
[])}function E(a,b,c){var d;if(a==h)return-1;if(c)return c=fa(a,b),a[c]===b?c:-1;c=0;for(d=a.length;c<d;c++)if(a[c]===b)return c;return-1}function ga(a){var b=l.call(arguments,1);return W(I(a),function(a){return X(b,function(b){return 0<=E(b,a)})})}function ha(a,b,c){var d=a.length;return b==h||c?a[d-1]:l.call(a,-b||d)}function ia(a,b,c){return l.call(a,b==h||c?1:b)}function I(a,b,c){var c=c?A(a,c):a,d=[];3>a.length&&(b=n);z(c,function(c,e,j){if(b?ha(c)!==e||!c.length:0>E(c,e))c.push(e),d.push(a[j]);
|
||||
return c},[]);return d}function u(a,b){var c=l.call(arguments,2),d=c.length;return function(){c.length=d;V.apply(c,arguments);return a.apply(b,c)}}function ja(a,b,c){var d;return function(){var f=arguments,e=this;c&&!d&&a.apply(e,f);va(d);d=J(function(){d=h;c||a.apply(e,f)},b)}}function Y(a,b,c){c||(c=[]);if(a===b)return 0!==a||1/a==1/b;if(a==h||b==h)return a===b;a.p&&(a=a.o);b.p&&(b=b.o);if(a.isEqual&&q(a.isEqual))return a.isEqual(b);if(b.isEqual&&q(b.isEqual))return b.isEqual(a);var d=k.call(a);
|
||||
if(d!=k.call(b))return o;switch(d){case G:return a==""+b;case K:return a!=+a?b!=+b:0==a?1/a==1/b:a==+b;case ka:case la:return+a==+b;case ma:return a.source==b.source&&a.global==b.global&&a.multiline==b.multiline&&a.ignoreCase==b.ignoreCase}if("object"!=typeof a||"object"!=typeof b)return o;for(var f=c.length;f--;)if(c[f]==a)return n;var f=n,e=0;c.push(a);if(d==D){if(e=a.length,f=e==b.length)for(;e--&&(f=e in a==e in b&&Y(a[e],b[e],c)););}else{if("constructor"in a!="constructor"in b||a.constructor!=
|
||||
b.constructor)return o;for(var j in a)if(s.call(a,j)&&(e++,!(f=s.call(b,j)&&Y(a[j],b[j],c))))break;if(f){for(j in b)if(s.call(b,j)&&!e--)break;f=!e}}c.pop();return f}function q(a){return k.call(a)==ca}function R(a){return a}function na(a){t(L(a),function(b){var c=i[b]=a[b];i.prototype[b]=function(){var a=l.call(arguments);wa.call(a,this.o);a=c.apply(i,a);return this.p?(new p(a)).chain():a}})}var y={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"};(function(){for(var a in y)y[y[a]]=
|
||||
a})();var Z="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(r=global),exports),xa=0,ya=r._,za=/\\|'|\r|\n|\t|\u2028|\u2029/g,$=/.^/,ua=/\\(\\|'|r|n|t|u2028|u2029)/g,D="[object Array]",ka="[object Boolean]",la="[object Date]",ca="[object Function]",K="[object Number]",ma="[object RegExp]",G="[object String]",v=Array.prototype,M=Object.prototype,ba=v.concat,s=M.hasOwnProperty,V=v.push,l=v.slice,k=M.toString,wa=v.unshift,Aa=r.isFinite,M=Object.keys,va=r.clearTimeout,
|
||||
J=r.setTimeout,N={b:"b",m:"var I=i.apply([],z.call(arguments,1))",h:"[]",g:"if(p(I,b[o])<0)y.push(b[o])"},w={h:"F",g:"if(!e(g[o],o,g))return !y"},aa={b:"v",h:"v",d:"for(var A,j=1,u=arguments.length;j<u;j++){A=arguments[j]",j:"o in A",g:"v[o]=A[o]",n:o,a:"}"},B={h:"[]",g:"e(g[o],o,g)&&y.push(g[o])"},m={b:"g,e,D",m:"if(!e){e=n}else if(D){e=d(e,D)}",h:"g",g:"e(g[o],o,g)"},oa={b:"v",m:"if(v!==Object(v))throw TypeError()",h:"[]",g:"y.push(o)"},C={h:"",f:"[]",d:{c:"y=Array(u)",k:"y=[]"},g:{c:"y[o]=e(g[o],o,g)",
|
||||
k:"y[y.length]=e(g[o],o,g)"}},x={m:"var j,y=-q,h=y;if(!e){if(s(g)&&g[0]===+g[0])return w.max.apply(w,g);if(t(g))return y;}else if(D)e=d(e,D)",g:"j=e?e(g[o],o,g):g[o];if(j>=h)h=j,y=g[o]"},F=Array.isArray||function(a){return k.call(a)==D},da=g({b:"H",i:"b",m:"var f=E.call(H)",h:"F",d:"if(f==c||f==B)return !H.length",g:"return k"}),pa=g({b:"g,C",h:"k",g:"if(g[o]===C)return F"}),X=g(m,w),W=g(m,B),qa=g(m,{g:"if(e(g[o],o,g))return g[o]"}),t=g(m),A=g(m,C),ra=g(m,x),x=g(m,x,{m:x.m.replace("-","").replace("max",
|
||||
"min"),g:x.g.replace(">=","<")}),O=g(C,{b:"g,x",g:{c:"y[o]=g[o][x]",k:"y[y.length]=g[o][x]"}}),z=g({b:"g,e,a,D",m:"var r=arguments.length>2;if(D)e=d(e,D)",h:"a",d:{c:"if(!r)y=g[++o]"},g:{c:"y=e(y,g[o],o,g)",k:"y=r?e(y,g[o],o,g):(r=F,g[o])"}}),B=g(m,B,{g:"!"+B.g}),w=g(m,w,{h:"k",g:w.g.replace("!","")}),sa=g(C,{b:"g",g:{c:"y[o]=g[o]",k:"y[y.length]=g[o]"}}),C=g({b:"b",h:"[]",g:"if(b[o])y.push(b[o])"}),m=g(N),N=g(N,{m:"var I=z.call(arguments,1)",h:"[]"}),ta=g(aa,{g:"if(v[o]==G)"+aa.g}),P=g(aa),L=g(oa,
|
||||
{m:"",n:o,g:"if(E.call(v[o])==l)y.push(o)",l:"y.sort()"});Q(arguments)||(Q=function(a){return!(!a||!s.call(a,"callee"))});var T=M||g(oa);P(i,{VERSION:"0.1.0",templateSettings:{escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g},after:function(a,b){return 1>a?b():function(){if(1>--a)return b.apply(this,arguments)}},bind:u,bindAll:function(a){var b=arguments,c=1;1==b.length&&(c=0,b=L(a));for(var d=b.length;c<d;c++)a[b[c]]=u(a[b[c]],a);return a},chain:function(a){return(new p(a)).chain()},
|
||||
clone:function(a){return a!==Object(a)?a:F(a)?a.slice():P({},a)},compact:C,compose:function(){var a=arguments;return function(){for(var b=arguments,c=a.length;c--;)b=[a[c].apply(this,b)];return b[0]}},contains:pa,debounce:ja,defaults:ta,defer:function(a){var b=l.call(arguments,1);return J(function(){return a.apply(h,b)},1)},delay:function(a,b){var c=l.call(arguments,2);return J(function(){return a.apply(h,c)},b)},difference:m,escape:function(a){return(a+"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,
|
||||
">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")},every:X,extend:P,filter:W,find:qa,first:U,flatten:H,forEach:t,functions:L,groupBy:function(a,b){var c={};if(!q(b))var d=b,b=function(a){return a[d]};t(a,function(a,e,d){e=b(a,e,d);(c[e]||(c[e]=[])).push(a)});return c},has:function(a,b){return s.call(a,b)},identity:R,indexOf:E,initial:function(a,b,c){return l.call(a,0,-(b==h||c?1:b))},intersection:ga,invoke:function(a,b){var c=l.call(arguments,2),d=q(b);return A(a,function(a){return(d?
|
||||
b||a:a[b]).apply(a,c)})},isArguments:Q,isArray:F,isBoolean:function(a){return a===n||a===o||k.call(a)==ka},isDate:function(a){return k.call(a)==la},isElement:function(a){return!!(a&&1==a.nodeType)},isEmpty:da,isEqual:Y,isFinite:function(a){return Aa(a)&&k.call(a)==K},isFunction:q,isNaN:function(a){return k.call(a)==K&&a!=+a},isNull:function(a){return null===a},isNumber:function(a){return k.call(a)==K},isObject:function(a){return a===Object(a)},isRegExp:function(a){return k.call(a)==ma},isString:function(a){return k.call(a)==
|
||||
G},isUndefined:function(a){return a===h},keys:T,last:ha,lastIndexOf:function(a,b){if(a==h)return-1;for(var c=a.length;c--;)if(a[c]===b)return c;return-1},map:A,max:ra,memoize:function(a,b){var c={};return function(){var d=b?b.apply(this,arguments):arguments[0];return s.call(c,d)?c[d]:c[d]=a.apply(this,arguments)}},min:x,mixin:na,noConflict:function(){r._=ya;return this},once:function(a){var b,c=o;return function(){if(c)return b;c=n;return b=a.apply(this,arguments)}},pick:function(a){for(var b,c=-1,
|
||||
d=H(l.call(arguments,1)),f=d.length,e={};++c<f;)b=d[c],b in a&&(e[b]=a[b]);return e},pluck:O,range:function(a,b,c){c||(c=1);2>arguments.length&&(b=a||0,a=0);for(var d=-1,f=Math.max(Math.ceil((b-a)/c),0),e=Array(f);++d<f;)e[d]=a,a+=c;return e},reduce:z,reduceRight:ea,reject:B,rest:ia,result:function(a,b){if(a==h)return null;var c=a[b];return q(c)?a[b]():c},shuffle:function(a){var b,c=[];t(a,function(a,f){b=Math.floor(Math.random()*(f+1));c[f]=c[b];c[b]=a});return c},size:function(a){var b=k.call(a);
|
||||
return b==D||b==G?a.length:T(a).length},some:w,sortBy:function(a,b,c){if(q(b))c&&(b=u(b,c));else var d=b,b=function(a){return a[d]};return O(A(a,function(c,e){return{a:b(c,e,a),b:c}}).sort(function(a,b){var c=a.a,d=b.a;return c===h?1:d===h?-1:c<d?-1:c>d?1:0}),"b")},sortedIndex:fa,tap:function(a,b){b(a);return a},template:function(a,b,c){function d(a){return f.call(this,a,i)}c=ta(c||{},i.templateSettings);a="__p+='"+a.replace(za,function(a){return"\\"+y[a]}).replace(c.escape||$,function(a,b){return"'+((__t=("+
|
||||
S(b)+"))==null?'':_['escape'](__t))+'"}).replace(c.interpolate||$,function(a,b){return"'+((__t=("+S(b)+"))==null?'':__t)+'"}).replace(c.evaluate||$,function(a,b){return"';"+S(b)+";__p+='"})+"';";c.variable||(a="with(object||{}){"+a+"}");var a='var __t,__j=Array.prototype.join,__p="";function print(){__p+=__j.call(arguments,"")}'+a+"return __p",f=Function(c.variable||"object","_",a);if(b)return f(b,i);d.source="function("+(c.variable||"object")+"){"+a+"}";return d},throttle:function(a,b){var c,d,f,
|
||||
e,g,i,k=ja(function(){d=g=o},b);return function(){c=arguments;e=this;i||(i=J(function(){i=h;d&&a.apply(e,c);k()},b));g?d=n:f=a.apply(e,c);k();g=n;return f}},times:function(a,b,c){c&&(b=u(b,c));for(c=0;c<a;c++)b(c)},toArray:function(a){if(!a)return[];if(q(a.toArray))return a.toArray();var b=a.length;return b===+b?l.call(a):sa(a)},union:function(){return I(H(arguments,n))},uniq:I,uniqueId:function(a){var b=xa++;return a?a+b:b},values:sa,without:N,wrap:function(a,b){return function(){var c=[a];V.apply(c,
|
||||
arguments);return b.apply(this,c)}},zip:function(){for(var a=-1,b=ra(O(arguments,"length")),c=Array(b);++a<b;)c[a]=O(arguments,a);return c},all:X,any:w,collect:A,detect:qa,each:t,foldl:z,foldr:ea,head:U,include:pa,inject:z,intersect:ga,methods:L,select:W,tail:ia,take:U,unique:I});p.prototype=i.prototype;na(i);t("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=v[a];i.prototype[a]=function(){var a=this.o;b.apply(a,arguments);a.length===0&&delete a[0];return this.p?(new p(a)).chain():
|
||||
a}});t(["concat","join","slice"],function(a){var b=v[a];p.prototype[a]=function(){var a=b.apply(this.o,arguments);return this.p?(new p(a)).chain():a}});P(p.prototype,{chain:function(){this.p=n;return this},value:function(){return this.o}});Z?"object"==typeof module&&module&&module.q==Z?(module.q=i)._=i:Z._=i:(r._=i,"function"==typeof define&&"object"==typeof define.amd&&define.amd&&define.amd.lodash&&define("lodash",function(){return i}))})(this);
|
||||
;(function(e,t){"use strict";function s(e){return"[object Arguments]"==nt.call(e)}function o(e){return new u(e)}function u(e){if(e&&e._wrapped)return e;this._wrapped=e}function a(){for(var e,t,s,o=-1,u=arguments.length,a={e:"",f:"",k:"",q:"",c:{d:"",m:"++k<m"},o:{d:""}};++o<u;)for(t in e=arguments[o],e)s=(s=e[t])==r?"":s,/d|m|j/.test(t)?("string"==typeof s&&(s={b:s,n:s}),a.c[t]=s.b,a.o[t]=s.n):a[t]=s;e=a.a,t=a.c,s=a.o;var o=/^[^,]+/.exec(e)[0],u=s.m,f=/\S+$/.exec(u||o)[0];a.g=o,a.i=O,a.h="i.call("+
|
||||
f+",k)",a.l=f,a.p=j,a.r=a.r!==i,a.f||(a.f="if(!"+o+")return r");if("n"==o||!t.j)a.c=r;return u||(s.m="k in "+f),Function("b,h,i,j,l,o,v,y,z,g,A",'"use strict";return function('+e+"){"+ft(a)+"}")(z,V,Z,k,h,R,K,nt,n,i)}function f(e,t){return I[t]}function l(e){return"\\"+U[e]}function c(e){return q[e]}function h(e,t){return function(n,r,i){return e.call(t,n,r,i)}}function p(){}function d(e,t){var n=I.length;return I[n]="'+((__t=("+t+"))==null?'':_.escape(__t))+'",F+n}function v(e,t){var n=I.length;
|
||||
return I[n]="'+((__t=("+t+"))==null?'':__t)+'",F+n}function m(e,t){var n=I.length;return I[n]="';"+t+";__p+='",F+n}function g(e,t,n,r){if(!e)return n;var i=e.length,s=3>arguments.length;r&&(t=h(t,r));if(i===i>>>0){for(i&&s&&(n=e[--i]);i--;)n=t(n,e[i],i,e);return n}var o=Lt(e);for((i=o.length)&&s&&(n=e[o[--i]]);i--;)s=o[i],n=t(n,e[s],s,e);return n}function y(e,n,r){return n==t||r?e[0]:tt.call(e,0,n)}function b(e,t){for(var n,r=-1,i=e.length,s=[];++r<i;)n=e[r],kt(n)?et.apply(s,t?n:b(n)):s.push(n);return s
|
||||
}function w(e,t,n){var r=-1,i=e.length;if(n){if("number"!=typeof n)return r=x(e,t),e[r]===t?r:-1;r=(0>n?Math.max(0,i+n):n)-1}for(;++r<i;)if(e[r]===t)return r;return-1}function E(e,t,n){var r=-Infinity,i=-1,s=e.length,o=r;if(!t){for(;++i<s;)e[i]>o&&(o=e[i]);return o}for(n&&(t=h(t,n));++i<s;)n=t(e[i],i,e),n>r&&(r=n,o=e[i]);return o}function S(e,n,r){return tt.call(e,n==t||r?1:n)}function x(e,t,n,r){var i,s=0,o=e.length;if(n)for(t=n.call(r,t);s<o;)i=s+o>>>1,n.call(r,e[i])<t?s=i+1:o=i;else for(;s<o;)
|
||||
i=s+o>>>1,e[i]<t?s=i+1:o=i;return s}function T(e,t,n,r){var s=-1,o=e.length,u=[],a=[];"function"==typeof t&&(r=n,n=t,t=i);for(n?r&&(n=h(n,r)):n=k;++s<o;)if(r=n(e[s],s,e),t?!s||a[a.length-1]!==r:0>w(a,r))a.push(r),u.push(e[s]);return u}function N(e,t){function n(){var u=arguments,a=t;return s||(e=t[i]),o.length&&(u=u.length?Y.apply(o,u):o),this instanceof n?(p.prototype=e.prototype,a=new p,u=e.apply(a,u),R[typeof u]&&u!==r?u:a):e.apply(a,u)}var i,s=nt.call(e)==V;if(s){if(rt)return rt.call.apply(rt
|
||||
,arguments)}else i=t,t=e;var o=tt.call(arguments,2);return n}function C(e,r,s){s||(s=[]);if(e===r)return 0!==e||1/e==1/r;if(e==t||r==t)return e===r;e._chain&&(e=e._wrapped),r._chain&&(r=r._wrapped);if(e.isEqual&&nt.call(e.isEqual)==V)return e.isEqual(r);if(r.isEqual&&nt.call(r.isEqual)==V)return r.isEqual(e);var o=nt.call(e);if(o!=nt.call(r))return i;switch(o){case K:return e==""+r;case $:return e!=+e?r!=+r:0==e?1/e==1/r:e==+r;case W:case X:return+e==+r;case J:return e.source==r.source&&e.global==
|
||||
r.global&&e.multiline==r.multiline&&e.ignoreCase==r.ignoreCase}if("object"!=typeof e||"object"!=typeof r)return i;for(var u=s.length;u--;)if(s[u]==e)return n;var u=-1,a=n,f=0;s.push(e);if(o==z){if(f=e.length,a=f==r.length)for(;f--&&(a=C(e[f],r[f],s)););}else{if("constructor"in e!="constructor"in r||e.constructor!=r.constructor)return i;for(var l in e)if(Z.call(e,l)&&(f++,!(a=Z.call(r,l)&&C(e[l],r[l],s))))break;if(a){for(l in r)if(Z.call(r,l)&&!(f--))break;a=!f}if(a&&O)for(;7>++u&&(l=j[u],!Z.call(
|
||||
e,l)||!!(a=Z.call(r,l)&&C(e[l],r[l],s))););}return s.pop(),a}function k(e){return e}function L(e){wt(Ct(e),function(t){var r=o[t]=e[t];u.prototype[t]=function(){var e=[this._wrapped];return arguments.length&&et.apply(e,arguments),e=1==e.length?r.call(o,e[0]):r.apply(o,e),this._chain&&(e=new u(e),e._chain=n),e}})}var n=!0,r=null,i=!1,A="object"==typeof exports&&exports&&("object"==typeof global&&global&&global==global.global&&(e=global),exports),O=!{valueOf:0}.propertyIsEnumerable("valueOf"),M=0,_=
|
||||
e._,D=RegExp("^"+({}.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),P=/__token__(\d+)/g,H=/[&<"']/g,B=/['\n\r\t\u2028\u2029\\]/g,j="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),F="__token__",I=[],q={"&":"&","<":"<",'"':""","'":"'"},R={"boolean":i,"function":n,object:n,number:i,string:i,"undefined":i},U={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029"
|
||||
:"u2029"},z="[object Array]",W="[object Boolean]",X="[object Date]",V="[object Function]",$="[object Number]",J="[object RegExp]",K="[object String]",Q=Array.prototype,G=Object.prototype,Y=Q.concat,Z=G.hasOwnProperty,et=Q.push,tt=Q.slice,nt=G.toString,rt=D.test(rt=tt.bind)&&/\n|Opera/.test(rt+nt.call(e.opera))&&rt,it=D.test(it=Array.isArray)&&it,st=e.isFinite,ot=D.test(ot=Object.keys)&&ot,ut=e.clearTimeout,at=e.setTimeout;o.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate
|
||||
:/<%=([\s\S]+?)%>/g,variable:"obj"};var ft=Function("obj","var __p;with(obj){__p='var k,r';if(k){__p+='='+k};__p+=';'+f+';'+q+';';if(c){__p+='var m='+g+'.length;k=-1;';if(o){__p+='if(m===m>>>0){'};__p+=''+c['d']+';while('+c['m']+'){'+c['j']+'}';if(o){__p+='}'}}if(o){if(c){__p+='else{'}if(!i){__p+='var s=typeof '+l+'==\\'function\\';'};__p+=''+o['d']+';for('+o['m']+'){';if(i){if(r){__p+='if('+h+'){'};__p+=''+o['j']+';';if(r){__p+='}'}}else{__p+='if(!(s&&k==\\'prototype\\')';if(r){__p+='&&'+h};__p+='){'+o['j']+'}'};__p+='}';if(i){__p+='var f='+l+'.constructor;';for(var k=0;k<7;k++){__p+='k=\\''+p[k]+'\\';if(';if(p[k]=='constructor'){__p+='!(f&&f.prototype==='+l+')&&'};__p+=''+h+'){'+o['j']+'}'}}if(c){__p+='}'}};__p+=''+e+';return r'}return __p"
|
||||
),lt={a:"e,c,x",k:"e",q:"if(!c){c=j}else if(x){c=l(c,x)}",j:"c(e[k],k,e)"},ct={k:"z",j:"if(!c(e[k],k,e))return!r"},ht={a:"n",k:"n",q:"for(var t,u=1,m=arguments.length;u<m;u++){t=arguments[u];"+(O?"if(t){":""),m:"k in t",r:i,j:"n[k]=t[k]",e:(O?"}":"")+"}"},pt={k:"[]",j:"c(e[k],k,e)&&r.push(e[k])"},dt={q:"if(x)c=l(c,x)"},vt={j:{n:lt.j}},mt={k:"",f:"if(!e)return[]",d:{b:"r=Array(m)",n:"r=[]"},j:{b:"r[k]=c(e[k],k,e)",n:"r.push(c(e[k],k,e))"}},gt=a({a:"n",f:"if(!o[typeof n]||n===null)throw TypeError()"
|
||||
,k:"[]",j:"r.push(k)"}),D=a({a:"e,w",k:"g",j:"if(e[k]===w)return z"}),yt=a(lt,ct),G=a(lt,pt),bt=a(lt,dt,{k:"",j:"if(c(e[k],k,e))return e[k]"}),wt=a(lt,dt),Et=a(lt,mt),St=a(mt,{a:"e,q",j:{b:"r[k]=e[k][q]",n:"r.push(e[k][q])"}}),xt=a({a:"e,c,a,x",k:"a",q:"var p=arguments.length<3;if(x)c=l(c,x)",d:{b:"if(p)r=e[++k]"},j:{b:"r=c(r,e[k],k,e)",n:"r=p?(p=g,e[k]):c(r,e[k],k,e)"}}),pt=a(lt,pt,{j:"!"+pt.j}),ct=a(lt,ct,{k:"g",j:ct.j.replace("!","")}),Tt=a(mt,{a:"e",j:{b:"r[k]=e[k]",n:"r.push(e[k])"}}),mt=a(ht
|
||||
,{j:"if(n[k]==A)"+ht.j}),Nt=a(ht),ht=a(lt,dt,vt,{r:i}),lt=a(lt,dt,vt),Ct=a({a:"n",k:"[]",r:i,j:"if(y.call(n[k])==h)r.push(k)",e:"r.sort()"});s(arguments)||(s=function(e){return!!e&&!!Z.call(e,"callee")});var kt=it||function(e){return nt.call(e)==z},it=a({a:"B",k:"z",q:"var d=y.call(B);if(d==b||d==v)return!B.length",j:{n:"return g"}}),Lt=ot?function(e){return"function"==typeof e?gt(e):ot(e)}:gt;o.VERSION="0.3.0",o.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this,arguments
|
||||
)}},o.bind=N,o.bindAll=function(e){var t=arguments,n=1;1==t.length&&(n=0,t=Ct(e));for(var r=t.length;n<r;n++)e[t[n]]=N(e[t[n]],e);return e},o.chain=function(e){return e=new u(e),e._chain=n,e},o.clone=function(e){return R[typeof e]&&e!==r?kt(e)?e.slice():Nt({},e):e},o.compact=function(e){for(var t=-1,n=e.length,r=[];++t<n;)e[t]&&r.push(e[t]);return r},o.compose=function(){var e=arguments;return function(){for(var t=arguments,n=e.length;n--;)t=[e[n].apply(this,t)];return t[0]}},o.contains=D,o.debounce=
|
||||
function(e,n,r){function i(){a=t,r||e.apply(u,s)}var s,o,u,a;return function(){var t=r&&!a;return s=arguments,u=this,ut(a),a=at(i,n),t&&(o=e.apply(u,s)),o}},o.defaults=mt,o.defer=function(e){var n=tt.call(arguments,1);return at(function(){return e.apply(t,n)},1)},o.delay=function(e,n){var r=tt.call(arguments,2);return at(function(){return e.apply(t,r)},n)},o.difference=function(e){for(var t=-1,n=e.length,r=[],i=Y.apply(r,tt.call(arguments,1));++t<n;)0>w(i,e[t])&&r.push(e[t]);return r},o.escape=function(
|
||||
e){return(e+"").replace(H,c)},o.every=yt,o.extend=Nt,o.filter=G,o.find=bt,o.first=y,o.flatten=b,o.forEach=wt,o.forIn=ht,o.forOwn=lt,o.functions=Ct,o.groupBy=function(e,t,n){var r,i=-1,s="function"==typeof t,o=e.length,u={};for(s&&n&&(t=h(t,n));++i<o;)r=e[i],n=s?t(r,i,e):r[t],(Z.call(u,n)?u[n]:u[n]=[]).push(r);return u},o.has=function(e,t){return Z.call(e,t)},o.identity=k,o.indexOf=w,o.initial=function(e,n,r){return tt.call(e,0,-(n==t||r?1:n))},o.intersection=function(e){for(var t,n=-1,r=e.length,
|
||||
i=tt.call(arguments,1),s=[];++n<r;)t=e[n],0>w(s,t)&&yt(i,function(e){return-1<w(e,t)})&&s.push(t);return s},o.invoke=function(e,t){for(var n=tt.call(arguments,2),r=-1,i=e.length,s="function"==typeof t,o=[];++r<i;)o[r]=(s?t:e[r][t]).apply(e[r],n);return o},o.isArguments=s,o.isArray=kt,o.isBoolean=function(e){return e===n||e===i||nt.call(e)==W},o.isDate=function(e){return nt.call(e)==X},o.isElement=function(e){return!!e&&1==e.nodeType},o.isEmpty=it,o.isEqual=C,o.isFinite=function(e){return st(e)&&nt
|
||||
.call(e)==$},o.isFunction=function(e){return nt.call(e)==V},o.isNaN=function(e){return nt.call(e)==$&&e!=+e},o.isNull=function(e){return e===r},o.isNumber=function(e){return nt.call(e)==$},o.isObject=function(e){return R[typeof e]&&e!==r},o.isRegExp=function(e){return nt.call(e)==J},o.isString=function(e){return nt.call(e)==K},o.isUndefined=function(e){return e===t},o.keys=Lt,o.last=function(e,n,r){var i=e.length;return n==t||r?e[i-1]:tt.call(e,-n||i)},o.lastIndexOf=function(e,t,n){var r=e.length
|
||||
;for(n&&"number"==typeof n&&(r=(0>n?Math.max(0,r+n):Math.min(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},o.map=Et,o.max=E,o.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return Z.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},o.min=function(e,t,n){var r=Infinity,i=-1,s=e.length,o=r;if(!t){for(;++i<s;)e[i]<o&&(o=e[i]);return o}for(n&&(t=h(t,n));++i<s;)n=t(e[i],i,e),n<r&&(r=n,o=e[i]);return o},o.mixin=L,o.noConflict=function(){return e._=_,this},o.once=
|
||||
function(e){var t,r=i;return function(){return r?t:(r=n,t=e.apply(this,arguments))}},o.partial=function(e){var t=tt.call(arguments,1),n=t.length;return function(){var r;return r=arguments,r.length&&(t.length=n,et.apply(t,r)),r=1==t.length?e.call(this,t[0]):e.apply(this,t),t.length=n,r}},o.pick=function(e){for(var t,n=0,r=Y.apply(Q,arguments),i=r.length,s={};++n<i;)t=r[n],t in e&&(s[t]=e[t]);return s},o.pluck=St,o.range=function(e,t,n){n||(n=1),2>arguments.length&&(t=e||0,e=0);for(var r=-1,i=Math.
|
||||
max(Math.ceil((t-e)/n),0),s=Array(i);++r<i;)s[r]=e,e+=n;return s},o.reduce=xt,o.reduceRight=g,o.reject=pt,o.rest=S,o.result=function(e,t){if(!e)return r;var n=e[t];return nt.call(n)==V?e[t]():n},o.shuffle=function(e){for(var t,n=-1,r=e.length,i=Array(r);++n<r;)t=Math.floor(Math.random()*(n+1)),i[n]=i[t],i[t]=e[n];return i},o.size=function(e){var t=nt.call(e);return t==z||t==K?e.length:Lt(e).length},o.some=ct,o.sortBy=function(e,n,r){if("string"==typeof n)var i=n,n=function(e){return e[i]};else r&&
|
||||
(n=h(n,r));return St(Et(e,function(t,r){return{a:n(t,r,e),b:t}}).sort(function(e,n){var r=e.a,i=n.a;return r===t?1:i===t?-1:r<i?-1:r>i?1:0}),"b")},o.sortedIndex=x,o.tap=function(e,t){return t(e),e},o.template=function(e,t,n){n||(n={});var i;i=o.templateSettings;var s=n.escape,u=n.evaluate,a=n.interpolate,n=n.variable;return s==r&&(s=i.escape),u==r&&(u=i.evaluate),a==r&&(a=i.interpolate),s&&(e=e.replace(s,d)),a&&(e=e.replace(a,v)),u&&(e=e.replace(u,m)),e="__p='"+e.replace(B,l).replace(P,f)+"';",I.
|
||||
length=0,n||(n=i.variable,e="with("+n+"||{}){"+e+"}"),e="function("+n+"){var __p,__t,__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}"+e+"return __p}",i=Function("_","return "+e)(o),t?i(t):(i.source=e,i)},o.throttle=function(e,n){function r(){a=new Date,u=t,e.apply(o,i)}var i,s,o,u,a=0;return function(){var t=new Date,f=n-(t-a);return i=arguments,o=this,0>=f?(a=t,s=e.apply(o,i)):u||(u=at(r,f)),s}},o.times=function(e,t,n){var r=-1;if(n)for(;++r<e;)t.call(n,r);else for(;++r<e;
|
||||
)t(r)},o.toArray=function(e){if(!e)return[];if(nt.call(e.toArray)==V)return e.toArray();var t=e.length;return t===t>>>0?tt.call(e):Tt(e)},o.union=function(){for(var e=-1,t=[],n=Y.apply(t,arguments),r=n.length;++e<r;)0>w(t,n[e])&&t.push(n[e]);return t},o.uniq=T,o.uniqueId=function(e){var t=M++;return e?e+t:t},o.values=Tt,o.without=function(e){for(var t=tt.call(arguments,1),n=-1,r=e.length,i=[];++n<r;)0>w(t,e[n])&&i.push(e[n]);return i},o.wrap=function(e,t){return function(){var n=[e];return arguments
|
||||
.length&&et.apply(n,arguments),t.apply(this,n)}},o.zip=function(){for(var e=-1,t=E(St(arguments,"length")),n=Array(t);++e<t;)n[e]=St(arguments,e);return n},o.all=yt,o.any=ct,o.collect=Et,o.detect=bt,o.each=wt,o.foldl=xt,o.foldr=g,o.head=y,o.include=D,o.inject=xt,o.methods=Ct,o.select=G,o.tail=S,o.take=y,o.unique=T,u.prototype=o.prototype,L(o),u.prototype.chain=function(){return this._chain=n,this},u.prototype.value=function(){return this._wrapped},wt("pop push reverse shift sort splice unshift".split
|
||||
(" "),function(e){var t=Q[e];u.prototype[e]=function(){var e=this._wrapped;return arguments.length?t.apply(e,arguments):t.call(e),e.length===0&&delete e[0],this._chain&&(e=new u(e),e._chain=n),e}}),wt(["concat","join","slice"],function(e){var t=Q[e];u.prototype[e]=function(){var e=this._wrapped,e=arguments.length?t.apply(e,arguments):t.call(e);return this._chain&&(e=new u(e),e._chain=n),e}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(e._=o,define(function(){return o})):A?"object"==typeof
|
||||
module&&module&&module.s==A?(module.s=o)._=o:A._=o:e._=o})(this);
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "lodash",
|
||||
"version": "0.1.0",
|
||||
"description": "A drop-in replacement for Underscore.js that delivers up to 8x performance improvements, bug fixes, and additional features.",
|
||||
"homepage": "https://github.com/bestiejs/lodash",
|
||||
"version": "0.3.0",
|
||||
"description": "A drop-in replacement for Underscore.js that delivers performance improvements, bug fixes, and additional features.",
|
||||
"homepage": "http://lodash.com",
|
||||
"main": "lodash",
|
||||
"keywords": [
|
||||
"browser",
|
||||
@@ -16,7 +16,7 @@
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "http://mths.be/mit"
|
||||
"url": "http://lodash.com/license"
|
||||
}
|
||||
],
|
||||
"author": {
|
||||
|
||||
48
perf/index.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Lo-Dash Performance Suite</title>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
applet {
|
||||
position: absolute;
|
||||
left: -9999em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../lodash.js"></script>
|
||||
<script>
|
||||
var lodash = _.noConflict();
|
||||
</script>
|
||||
<script src="../vendor/underscore/underscore.js"></script>
|
||||
<script src="../vendor/benchmark.js/benchmark.js"></script>
|
||||
<script src="../vendor/firebug-lite/src/firebug-lite-debug.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
if (!/[?&]nojava=true(?:&|$)/.test(location.search)) {
|
||||
// using innerHTML avoids an alert in some versions of IE6
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = '<applet code=nano archive="../vendor/benchmark.js/nano.jar">';
|
||||
document.body.insertBefore(div.lastChild, document.body.firstChild);
|
||||
}
|
||||
}());
|
||||
|
||||
window.onload = function() {
|
||||
var fbUI = document.getElementById('FirebugUI'),
|
||||
fbDoc = (fbDoc = fbUI.contentWindow || fbUI.contentDocument).document || fbDoc,
|
||||
sibling = document.getElementsByTagName('script')[0],
|
||||
script = document.createElement('script');
|
||||
|
||||
fbUI.style.height = fbDoc.body.style.height = fbDoc.documentElement.style.height = '100%';
|
||||
script.src = 'perf.js?t=' + (+new Date);
|
||||
sibling.parentNode.insertBefore(script, sibling);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
623
perf/perf.js
Normal file
@@ -0,0 +1,623 @@
|
||||
(function(window) {
|
||||
|
||||
/** Use a single load function */
|
||||
var load = typeof require == 'function' ? require : window.load;
|
||||
|
||||
/** Load Benchmark.js */
|
||||
var Benchmark =
|
||||
window.Benchmark || (
|
||||
Benchmark = load('../vendor/benchmark.js/benchmark.js') || window.Benchmark,
|
||||
Benchmark.Benchmark || Benchmark
|
||||
);
|
||||
|
||||
/** Load Lo-Dash */
|
||||
var lodash =
|
||||
window.lodash || (
|
||||
lodash = load('../lodash.js') || window._,
|
||||
lodash = lodash._ || lodash,
|
||||
lodash.noConflict()
|
||||
);
|
||||
|
||||
/** Load Underscore */
|
||||
var _ =
|
||||
window._ || (
|
||||
_ = load('../vendor/underscore/underscore.js') || window._,
|
||||
_._ || _
|
||||
);
|
||||
|
||||
/** Used to access the Firebug Lite panel */
|
||||
var fbPanel = (fbPanel = window.document && document.getElementById('FirebugUI')) &&
|
||||
(fbPanel = (fbPanel = fbPanel.contentWindow || fbPanel.contentDocument).document || fbPanel) &&
|
||||
fbPanel.getElementById('fbPanel1');
|
||||
|
||||
/** Used to score Lo-Dash and Underscore performance */
|
||||
var score = { 'lodash': 0, 'underscore': 0 };
|
||||
|
||||
/** Used to queue benchmark suites */
|
||||
var suites = [];
|
||||
|
||||
/** Add `console.log()` support for Narwhal and RingoJS */
|
||||
window.console || (window.console = { 'log': window.print });
|
||||
|
||||
/** Expose functions to the global object */
|
||||
window._ = _;
|
||||
window.Benchmark = Benchmark;
|
||||
window.lodash = lodash;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Logs text to the console.
|
||||
*
|
||||
* @private
|
||||
* @param {String} text The text to log.
|
||||
*/
|
||||
function log(text) {
|
||||
console.log(text);
|
||||
if (fbPanel) {
|
||||
// scroll the Firebug Lite panel down
|
||||
fbPanel.scrollTop = fbPanel.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
lodash.extend(Benchmark.options, {
|
||||
'async': true,
|
||||
'setup': function() {
|
||||
var window = Function('return this || global')(),
|
||||
_ = window._,
|
||||
lodash = window.lodash;
|
||||
|
||||
var length = 20,
|
||||
numbers = [],
|
||||
object = {},
|
||||
fourNumbers = [5, 25, 10, 30],
|
||||
nestedNumbers = [1, [2], [3, [[4]]]],
|
||||
twoNumbers = [12, 21];
|
||||
|
||||
var ctor = function() { },
|
||||
func = function(greeting) { return greeting + ': ' + this.name; };
|
||||
|
||||
var lodashBoundNormal = lodash.bind(func, { 'name': 'moe' }),
|
||||
lodashBoundCtor = lodash.bind(ctor, { 'name': 'moe' }),
|
||||
lodashBoundPartial = lodash.bind(func, { 'name': 'moe' }, 'hi');
|
||||
|
||||
var _boundNormal = _.bind(func, { 'name': 'moe' }),
|
||||
_boundCtor = _.bind(ctor, { 'name': 'moe' }),
|
||||
_boundPartial = _.bind(func, { 'name': 'moe' }, 'hi');
|
||||
|
||||
var wordToNumber = {
|
||||
'one': 1,
|
||||
'two': 2,
|
||||
'three': 3,
|
||||
'four': 4,
|
||||
'five': 5,
|
||||
'six': 6,
|
||||
'seven': 7,
|
||||
'eight': 8,
|
||||
'nine': 9,
|
||||
'ten': 10,
|
||||
'eleven': 11,
|
||||
'twelve': 12,
|
||||
'thirteen': 13,
|
||||
'fourteen': 14,
|
||||
'fifteen': 15,
|
||||
'sixteen': 16,
|
||||
'seventeen': 17,
|
||||
'eighteen': 18,
|
||||
'nineteen': 19,
|
||||
'twenty': 20,
|
||||
'twenty-one': 21,
|
||||
'twenty-two': 22,
|
||||
'twenty-three': 23,
|
||||
'twenty-four': 24,
|
||||
'twenty-five': 25
|
||||
};
|
||||
|
||||
var words = _.keys(wordToNumber).slice(0, length);
|
||||
|
||||
for (var index = 0; index < length; index++) {
|
||||
numbers[index] = index;
|
||||
object['key' + index] = index;
|
||||
}
|
||||
|
||||
var objects = lodash.map(numbers, function(num) {
|
||||
return { 'num': num };
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
lodash.extend(Benchmark.Suite.options, {
|
||||
'onStart': function() {
|
||||
log('\n' + this.name + ':');
|
||||
},
|
||||
'onCycle': function(event) {
|
||||
log(event.target + '');
|
||||
},
|
||||
'onComplete': function() {
|
||||
var formatNumber = Benchmark.formatNumber,
|
||||
fastest = this.filter('fastest'),
|
||||
slowest = this.filter('slowest'),
|
||||
lodashHz = 1 / (this[0].stats.mean + this[0].stats.moe),
|
||||
underscoreHz = 1 / (this[1].stats.mean + this[1].stats.moe);
|
||||
|
||||
if (fastest.length > 1) {
|
||||
log('It\'s too close to call.');
|
||||
lodashHz = underscoreHz = Math.min(lodashHz, underscoreHz);
|
||||
}
|
||||
else {
|
||||
var fastestHz = fastest[0] == this[0] ? lodashHz : underscoreHz,
|
||||
slowestHz = slowest[0] == this[0] ? lodashHz : underscoreHz,
|
||||
percent = formatNumber(Math.round(((fastestHz / slowestHz) - 1) * 100));
|
||||
|
||||
log(fastest[0].name + ' is ' + percent + '% faster.');
|
||||
}
|
||||
// add score adjusted for margin of error
|
||||
score.lodash += lodashHz;
|
||||
score.underscore += underscoreHz;
|
||||
|
||||
// remove current suite from queue
|
||||
suites.shift();
|
||||
|
||||
if (suites.length) {
|
||||
// run next suite
|
||||
suites[0].run();
|
||||
}
|
||||
else {
|
||||
var fastestTotalHz = Math.max(score.lodash, score.underscore),
|
||||
slowestTotalHz = Math.min(score.lodash, score.underscore),
|
||||
totalPercent = formatNumber(Math.round(((fastestTotalHz / slowestTotalHz) - 1) * 100)),
|
||||
totalX = fastestTotalHz / slowestTotalHz,
|
||||
message = ' is ' + totalPercent + '% ' + (totalX == 1 ? '' : '(' + formatNumber(totalX.toFixed(2)) + 'x) ') + 'faster than ';
|
||||
|
||||
// report results
|
||||
if (score.lodash >= score.underscore) {
|
||||
log('\nLo-Dash' + message + 'Underscore.');
|
||||
} else {
|
||||
log('\nUnderscore' + message + 'Lo-Dash.');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('bind call')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.bind(func, { 'name': 'moe' }, 'hi');
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.bind(func, { 'name': 'moe' }, 'hi');
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('bound')
|
||||
.add('Lo-Dash', function() {
|
||||
lodashBoundNormal();
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_boundNormal();
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('bound partial')
|
||||
.add('Lo-Dash', function() {
|
||||
lodashBoundPartial();
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_boundPartial();
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('bound constructor')
|
||||
.add('Lo-Dash', function() {
|
||||
new lodashBoundCtor();
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
new _boundCtor();
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('each array')
|
||||
.add('Lo-Dash', function() {
|
||||
var result = [];
|
||||
lodash.each(numbers, function(num) { result.push(num * 2); });
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
var result = [];
|
||||
_.each(numbers, function(num) { result.push(num * 2); });
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('each array thisArg')
|
||||
.add('Lo-Dash', function() {
|
||||
var result = [];
|
||||
lodash.each(numbers, function(num, index) {
|
||||
result.push(num + this['key' + index]);
|
||||
}, object);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
var result = [];
|
||||
_.each(numbers, function(num, index) {
|
||||
result.push(num + this['key' + index]);
|
||||
}, object);
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('each object')
|
||||
.add('Lo-Dash', function() {
|
||||
var result = [];
|
||||
lodash.each(object, function(num) {
|
||||
result.push(num * 2);
|
||||
});
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
var result = [];
|
||||
_.each(object, function(num) {
|
||||
result.push(num * 2);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('find')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.find(numbers, function(num) {
|
||||
return num === 19;
|
||||
});
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.find(numbers, function(num) {
|
||||
return num === 19;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('flatten deep')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.flatten(nestedNumbers);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.flatten(nestedNumbers);
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('flatten shallow')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.flatten(nestedNumbers, true);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.flatten(nestedNumbers, true);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('difference')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.difference(numbers, fourNumbers);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.difference(numbers, fourNumbers);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('groupBy callback')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.groupBy(numbers, function(num) { return num >> 1; });
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.groupBy(numbers, function(num) { return num >> 1; });
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('groupBy property name')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.groupBy(words, 'length');
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.groupBy(words, 'length');
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('indexOf')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.indexOf(numbers, 9);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.indexOf(numbers, 9);
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('indexOf isSorted')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.indexOf(numbers, 19, true);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.indexOf(numbers, 19, true);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('intersection')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.intersection(numbers, fourNumbers, twoNumbers);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.intersection(numbers, fourNumbers, twoNumbers);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('keys')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.keys(object);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.keys(object);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('lastIndexOf')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.lastIndexOf(numbers, 9);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.lastIndexOf(numbers, 9);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('map')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.map(objects, function(value) {
|
||||
return value.num;
|
||||
});
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.map(objects, function(value) {
|
||||
return value.num;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('map thisArg')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.map(objects, function(value, index) {
|
||||
return this['key' + index] + value.num;
|
||||
}, object);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.map(objects, function(value, index) {
|
||||
return this['key' + index] + value.num;
|
||||
}, object);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('max')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.max(numbers);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.max(numbers);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('min')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.min(numbers);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.min(numbers);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('pick')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.pick(object, 'key6', 'key13');
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.pick(object, 'key6', 'key13');
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('pluck')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.pluck(objects, 'num');
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.pluck(objects, 'num');
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('sortBy callback')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.sortBy(numbers, function(num) { return Math.sin(num); });
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.sortBy(numbers, function(num) { return Math.sin(num); });
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('sortBy callback thisArg')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.sortBy(numbers, function(num) { return this.sin(num); }, Math);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.sortBy(numbers, function(num) { return this.sin(num); }, Math);
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('sortBy property name')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.sortBy(words, 'length');
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.sortBy(words, 'length');
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('sortedIndex')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.sortedIndex(numbers, 25);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.sortedIndex(numbers, 25);
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('sortedIndex callback')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.sortedIndex(words, 'twenty-five', function(value) {
|
||||
return wordToNumber[value];
|
||||
});
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.sortedIndex(words, 'twenty-five', function(value) {
|
||||
return wordToNumber[value];
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('times')
|
||||
.add('Lo-Dash', function() {
|
||||
var result = [];
|
||||
lodash.times(length, function(n) { result.push(n); });
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
var result = [];
|
||||
_.times(length, function(n) { result.push(n); });
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('times thisArg')
|
||||
.add('Lo-Dash', function() {
|
||||
var result = [];
|
||||
lodash.times(length, function(n) { result.push(this.sin(n)); }, Math);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
var result = [];
|
||||
_.times(length, function(n) { result.push(this.sin(n)); }, Math);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('union')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.union(numbers, fourNumbers, twoNumbers);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.union(numbers, fourNumbers, twoNumbers);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('uniq')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.uniq(numbers.concat(fourNumbers, twoNumbers));
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.uniq(numbers.concat(fourNumbers, twoNumbers));
|
||||
})
|
||||
);
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('uniq callback')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.uniq(numbers.concat(fourNumbers, twoNumbers), function(num) {
|
||||
return num % 2;
|
||||
});
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.uniq(numbers.concat(fourNumbers, twoNumbers), function(num) {
|
||||
return num % 2;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
suites.push(
|
||||
Benchmark.Suite('values')
|
||||
.add('Lo-Dash', function() {
|
||||
lodash.values(objects);
|
||||
})
|
||||
.add('Underscore', function() {
|
||||
_.values(objects);
|
||||
})
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
if (Benchmark.platform + '') {
|
||||
log(Benchmark.platform + '');
|
||||
}
|
||||
// start suites
|
||||
log('\nSit back and relax, this may take a while.');
|
||||
suites[0].run();
|
||||
|
||||
}(typeof global == 'object' && global || this));
|
||||
9
perf/run-perf.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
cd "$(dirname "$0")"
|
||||
for cmd in node narwhal ringo rhino; do
|
||||
echo ""
|
||||
echo "Running performance suite in $cmd..."
|
||||
$cmd perf.js
|
||||
done
|
||||
echo ""
|
||||
echo "Running performance suite in a browser..."
|
||||
open index.html
|
||||
39
test/backbone.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Backbone Test Suite</title>
|
||||
<link rel="stylesheet" href="../vendor/backbone/test/vendor/qunit.css">
|
||||
<style>
|
||||
body > #qunit-header {
|
||||
display: none;
|
||||
}
|
||||
#jslitmus {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<h1 id="qunit-header"><a href="#">Backbone Speed Suite</a></h1>
|
||||
<div id="qunit-fixture">
|
||||
<div id='testElement'>
|
||||
<h1>Test</h1>
|
||||
</div>
|
||||
</div>
|
||||
<script src="../vendor/backbone/test/vendor/json2.js"></script>
|
||||
<script src="../vendor/backbone/test/vendor/jquery-1.7.1.js"></script>
|
||||
<script src="../vendor/backbone/test/vendor/qunit.js"></script>
|
||||
<script src="../vendor/backbone/test/vendor/jslitmus.js"></script>
|
||||
<script src="../lodash.js"></script>
|
||||
<script src="../vendor/backbone/backbone.js"></script>
|
||||
<script src="../vendor/backbone/test/noconflict.js"></script>
|
||||
<script src="../vendor/backbone/test/events.js"></script>
|
||||
<script src="../vendor/backbone/test/model.js"></script>
|
||||
<script src="../vendor/backbone/test/collection.js"></script>
|
||||
<script src="../vendor/backbone/test/router.js"></script>
|
||||
<script src="../vendor/backbone/test/view.js"></script>
|
||||
<script src="../vendor/backbone/test/sync.js"></script>
|
||||
<script src="../vendor/backbone/test/setdomlibrary.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -6,13 +6,22 @@
|
||||
<link rel="stylesheet" href="../vendor/qunit/qunit/qunit.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Lo-Dash Test Suite</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="qunit"></div>
|
||||
<script src="../vendor/qunit/qunit/qunit.js"></script>
|
||||
<script>var _2, _ = 1;</script>
|
||||
<script>
|
||||
var _2,
|
||||
_3 = Object.keys;
|
||||
|
||||
Object.keys = function() { return []; };
|
||||
</script>
|
||||
<script src="../lodash.js"></script>
|
||||
<script>
|
||||
var lodashBadKeys = _,
|
||||
_ = 1;
|
||||
|
||||
Object.keys = _3;
|
||||
_3 = void 0;
|
||||
</script>
|
||||
<script src="../lodash.js"></script>
|
||||
<script src="../vendor/requirejs/require.js"></script>
|
||||
<script>
|
||||
@@ -21,16 +30,21 @@
|
||||
document.write('<script src="test.js"><\/script>');
|
||||
}
|
||||
else {
|
||||
define.amd.lodash = true;
|
||||
require({
|
||||
'baseUrl': '../vendor/requirejs/',
|
||||
'urlArgs': 't=' + (+new Date),
|
||||
'paths': {
|
||||
'lodash': '../../lodash'
|
||||
'lodash': '../../lodash',
|
||||
'underscore': './../../lodash'
|
||||
}
|
||||
},
|
||||
['lodash'], function(_) {
|
||||
_2 = _.noConflict();
|
||||
['lodash', 'underscore'], function(lodash, lodashAsUnderscore) {
|
||||
_2 = lodash.noConflict();
|
||||
_2.moduleName = 'lodash';
|
||||
|
||||
_3 = lodashAsUnderscore.noConflict();
|
||||
_3.moduleName = 'underscore';
|
||||
|
||||
require(['test.js']);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
cd "$(dirname "$0")"
|
||||
for cmd in rhino ringo narwhal node; do
|
||||
echo ""
|
||||
echo "Testing in $cmd..."
|
||||
$cmd test.js
|
||||
done
|
||||
echo ""
|
||||
echo "Testing in a browser..."
|
||||
open index.html
|
||||
581
test/test.js
@@ -26,6 +26,28 @@
|
||||
/** Used to resolve a value's internal [[Class]] */
|
||||
var toString = {}.toString;
|
||||
|
||||
/** Used to check problem JScript properties (a.k.a. the [[DontEnum]] bug) */
|
||||
var shadowed = {
|
||||
'constructor': 1,
|
||||
'hasOwnProperty': 2,
|
||||
'isPrototypeOf': 3,
|
||||
'propertyIsEnumerable': 4,
|
||||
'toLocaleString': 5,
|
||||
'toString': 6,
|
||||
'valueOf': 7
|
||||
};
|
||||
|
||||
/** Used to check problem JScript properties too */
|
||||
var shadowedKeys = [
|
||||
'constructor',
|
||||
'hasOwnProperty',
|
||||
'isPrototypeOf',
|
||||
'propertyIsEnumerable',
|
||||
'toLocaleString',
|
||||
'toString',
|
||||
'valueOf'
|
||||
];
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
@@ -42,18 +64,34 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// must explicitly use `QUnit.module` instead of `module()`
|
||||
// explicitly call `QUnit.module()` instead of `module()`
|
||||
// in case we are in a CLI environment
|
||||
QUnit.module('lodash');
|
||||
|
||||
(function() {
|
||||
test('supports loading lodash.js as a module', function() {
|
||||
test('supports loading lodash.js as the "lodash" module', function() {
|
||||
if (window.document && window.require) {
|
||||
equal((_2 || {}).VERSION, _.VERSION);
|
||||
equal((_2 || {}).moduleName, 'lodash');
|
||||
} else {
|
||||
skipTest(1)
|
||||
}
|
||||
});
|
||||
|
||||
test('supports loading lodash.js as the "underscore" module', function() {
|
||||
if (window.document && window.require) {
|
||||
equal((_3 || {}).moduleName, 'underscore');
|
||||
} else {
|
||||
skipTest(1)
|
||||
}
|
||||
});
|
||||
|
||||
test('avoids overwritten native methods', function() {
|
||||
if (window.lodashBadKeys) {
|
||||
notDeepEqual(lodashBadKeys.keys({ 'a': 1 }), []);
|
||||
} else {
|
||||
skipTest(1);
|
||||
}
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -64,6 +102,126 @@
|
||||
test('creates a new instance when called without the `new` operator', function() {
|
||||
ok(_() instanceof _);
|
||||
});
|
||||
|
||||
test('should return passed LoDash instances', function() {
|
||||
var wrapped = _([]);
|
||||
equal(_(wrapped), wrapped);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.bind');
|
||||
|
||||
(function() {
|
||||
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!');
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.debounce');
|
||||
|
||||
(function() {
|
||||
test('subsequent "immediate" debounced calls should return the result of the first call', function() {
|
||||
var debounced = _.debounce(function(value) { return value; }, 100, true),
|
||||
result = [debounced('x'), debounced('y')];
|
||||
|
||||
deepEqual(result, ['x', 'x']);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.escape');
|
||||
|
||||
(function() {
|
||||
test('should not escape the ">" character', function() {
|
||||
equal(_.escape('>'), '>');
|
||||
});
|
||||
|
||||
test('should not escape the "/" character', function() {
|
||||
equal(_.escape('/'), '/');
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.extend');
|
||||
|
||||
(function() {
|
||||
test('should not error on `null` or `undefined` sources (test in IE < 9)', function() {
|
||||
try {
|
||||
deepEqual(_.extend({}, null, undefined, { 'a': 1 }), { 'a': 1 });
|
||||
} catch(e) {
|
||||
ok(false);
|
||||
}
|
||||
});
|
||||
|
||||
test('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.c = 3;
|
||||
|
||||
Foo.a = 1;
|
||||
Foo.b = 2;
|
||||
|
||||
var expected = { 'a': 1, 'b': 2 };
|
||||
deepEqual(_.extend({}, Foo), expected);
|
||||
|
||||
Foo.prototype = { 'c': 3 };
|
||||
deepEqual(_.extend({}, Foo), expected);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.find');
|
||||
|
||||
(function() {
|
||||
var array = [1, 2, 3];
|
||||
|
||||
test('should return found `value`', function() {
|
||||
equal(_.find(array, function(n) { return n > 2; }), 3);
|
||||
});
|
||||
|
||||
test('should return `undefined` if `value` is not found', function() {
|
||||
equal(_.find(array, function(n) { return n == 4; }), undefined);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.flatten');
|
||||
|
||||
(function() {
|
||||
test('should treat sparse arrays as dense', function() {
|
||||
var array = [[1, 2, 3], Array(3)],
|
||||
expected = [1, 2, 3],
|
||||
actual1 = _.flatten(array),
|
||||
actual2 = _.flatten(array, true);
|
||||
|
||||
expected.push(undefined, undefined, undefined);
|
||||
|
||||
deepEqual(actual1, expected);
|
||||
ok('4' in actual1);
|
||||
|
||||
deepEqual(actual2, expected);
|
||||
ok('4' in actual2);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -72,9 +230,134 @@
|
||||
|
||||
(function() {
|
||||
test('returns the collection', function() {
|
||||
var collection = [1, 2, 3, 4];
|
||||
var collection = [1, 2, 3];
|
||||
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']);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.forIn');
|
||||
|
||||
(function() {
|
||||
test('iterates over inherited properties', function() {
|
||||
function Dog(name) { this.name = name; }
|
||||
Dog.prototype.bark = function() { /* Woof, woof! */ };
|
||||
|
||||
var keys = [];
|
||||
_.forIn(new Dog('Dagny'), function(value, key) { keys.push(key); });
|
||||
deepEqual(keys.sort(), ['bark', 'name']);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.forOwn');
|
||||
|
||||
(function() {
|
||||
test('iterates over the `length` property', function() {
|
||||
var keys = [],
|
||||
object = { '0': 'zero', '1': 'one', 'length': 2 };
|
||||
|
||||
_.forOwn(object, function(value, key) { keys.push(key); });
|
||||
deepEqual(keys.sort(), ['0', '1', 'length']);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
_.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() {
|
||||
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() {
|
||||
function Foo() {}
|
||||
Foo.prototype.a = 1;
|
||||
|
||||
var keys = [];
|
||||
function callback(value, key) { keys.push(key); }
|
||||
|
||||
func(Foo, callback);
|
||||
deepEqual(keys, []);
|
||||
keys.length = 0;
|
||||
|
||||
Foo.prototype = { 'a': 1 };
|
||||
func(Foo, callback);
|
||||
deepEqual(keys, []);
|
||||
});
|
||||
});
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.groupBy');
|
||||
|
||||
(function() {
|
||||
test('supports the `thisArg` argument', function() {
|
||||
var actual = _.groupBy([1.3, 2.1, 2.4], function(num) {
|
||||
return this.floor(num);
|
||||
}, Math);
|
||||
|
||||
deepEqual(actual, { '1': [1.3], '2': [2.1, 2.4] });
|
||||
});
|
||||
|
||||
test('should only add elements to own, not inherited, properties', function() {
|
||||
var actual = _.groupBy([1.3, 2.1, 2.4], function(num) {
|
||||
return Math.floor(num) > 1 ? 'hasOwnProperty' : 'constructor';
|
||||
});
|
||||
|
||||
deepEqual(actual.constructor, [1.3]);
|
||||
deepEqual(actual.hasOwnProperty, [2.1, 2.4]);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.indexOf');
|
||||
|
||||
(function() {
|
||||
var array = [1, 2, 3, 1, 2, 3];
|
||||
|
||||
test('should work with a positive `fromIndex`', function() {
|
||||
equal(_.indexOf(array, 1, 2), 3);
|
||||
});
|
||||
|
||||
test('should work with `fromIndex` >= `array.length`', function() {
|
||||
equal(_.indexOf(array, 1, 6), -1);
|
||||
equal(_.indexOf(array, undefined, 6), -1);
|
||||
equal(_.indexOf(array, 1, 8), -1);
|
||||
equal(_.indexOf(array, undefined, 8), -1);
|
||||
});
|
||||
|
||||
test('should work with a negative `fromIndex`', function() {
|
||||
equal(_.indexOf(array, 2, -3), 4);
|
||||
});
|
||||
|
||||
test('should work with a negative `fromIndex` <= `-array.length`', function() {
|
||||
equal(_.indexOf(array, 1, -6), 0);
|
||||
equal(_.indexOf(array, 2, -8), 1);
|
||||
});
|
||||
|
||||
test('should ignore non-number `fromIndex` values', function() {
|
||||
equal(_.indexOf([1, 2, 3], 1, '1'), 0);
|
||||
});
|
||||
|
||||
test('should work with `isSorted`', function() {
|
||||
equal(_.indexOf([1, 2, 3], 1, true), 0);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -83,13 +366,42 @@
|
||||
|
||||
(function() {
|
||||
test('returns an empty collection for `n` of `0`', function() {
|
||||
var array = [1, 2, 3, 4];
|
||||
var array = [1, 2, 3];
|
||||
deepEqual(_.initial(array, 0), []);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.isEmpty');
|
||||
|
||||
(function() {
|
||||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
|
||||
equal(_.isEmpty(shadowed), false);
|
||||
});
|
||||
|
||||
test('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;
|
||||
equal(_.isEmpty(Foo), true);
|
||||
|
||||
Foo.prototype = { 'a': 1 };
|
||||
equal(_.isEmpty(Foo), true);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.isEqual');
|
||||
|
||||
(function() {
|
||||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
|
||||
equal(_.isEqual(shadowed, {}), false);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.isNaN');
|
||||
|
||||
(function() {
|
||||
@@ -100,6 +412,109 @@
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.keys');
|
||||
|
||||
(function() {
|
||||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
|
||||
function Foo() {}
|
||||
Foo.prototype.a = 1;
|
||||
|
||||
deepEqual(_.keys(Foo.prototype), ['a']);
|
||||
deepEqual(_.keys(shadowed).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() {
|
||||
function Foo() {}
|
||||
Foo.prototype.c = 3;
|
||||
|
||||
Foo.a = 1;
|
||||
Foo.b = 2;
|
||||
|
||||
var expected = ['a', 'b'];
|
||||
deepEqual(_.keys(Foo), expected);
|
||||
|
||||
Foo.prototype = { 'c': 3 };
|
||||
deepEqual(_.keys(Foo), expected);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.lastIndexOf');
|
||||
|
||||
(function() {
|
||||
var array = [1, 2, 3, 1, 2, 3];
|
||||
|
||||
test('should work with a positive `fromIndex`', function() {
|
||||
equal(_.lastIndexOf(array, 1, 2), 0);
|
||||
});
|
||||
|
||||
test('should work with `fromIndex` >= `array.length`', function() {
|
||||
equal(_.lastIndexOf(array, undefined, 6), -1);
|
||||
equal(_.lastIndexOf(array, 1, 6), 3);
|
||||
equal(_.lastIndexOf(array, undefined, 8), -1);
|
||||
equal(_.lastIndexOf(array, 1, 8), 3);
|
||||
});
|
||||
|
||||
test('should work with a negative `fromIndex`', function() {
|
||||
equal(_.lastIndexOf(array, 2, -3), 1);
|
||||
});
|
||||
|
||||
test('should work with a negative `fromIndex` <= `-array.length`', function() {
|
||||
equal(_.lastIndexOf(array, 1, -6), 0);
|
||||
equal(_.lastIndexOf(array, 2, -8), -1);
|
||||
});
|
||||
|
||||
test('should ignore non-number `fromIndex` values', function() {
|
||||
equal(_.lastIndexOf([1, 2, 3], 3, '1'), 2);
|
||||
equal(_.lastIndexOf([1, 2, 3], 3, true), 2);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.partial');
|
||||
|
||||
(function() {
|
||||
test('partially applies an argument, without additional arguments', function() {
|
||||
var arg = 'catnip',
|
||||
func = function(x) { return x; };
|
||||
|
||||
equal(_.partial(func, arg)(), arg);
|
||||
});
|
||||
|
||||
test('partially applies an argument, with additional arguments', function() {
|
||||
var arg1 = 'catnip',
|
||||
arg2 = 'cheese',
|
||||
func = function(x, y) { return [x, y]; };
|
||||
|
||||
deepEqual(_.partial(func, arg1)(arg2), [arg1, arg2]);
|
||||
});
|
||||
|
||||
test('works without partially applying arguments, without additional arguments', function() {
|
||||
var func = function() { return arguments.length; };
|
||||
|
||||
equal(_.partial(func)(), 0);
|
||||
});
|
||||
|
||||
test('works without partially applying arguments, with additional arguments', function() {
|
||||
var arg = 'catnip',
|
||||
func = function(x) { return x; };
|
||||
|
||||
equal(_.partial(func)(arg), arg);
|
||||
});
|
||||
|
||||
test('should not alter the `this` binding of either function', function() {
|
||||
var o = { 'cat': 'nip' },
|
||||
func = function() { return this.cat; };
|
||||
|
||||
equal(_.partial(_.bind(func, o))(), o.cat);
|
||||
equal(_.bind(_.partial(func), o)(), o.cat);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.reduceRight');
|
||||
|
||||
(function() {
|
||||
@@ -114,6 +529,17 @@
|
||||
|
||||
deepEqual(args, ['C', 'B', 'b', object]);
|
||||
});
|
||||
|
||||
test('should treat array-like object with invalid `length` as a regular object', function() {
|
||||
var args,
|
||||
object = { 'a': 'A', 'length': -1 };
|
||||
|
||||
_.reduceRight(object, function() {
|
||||
args || (args = slice.call(arguments));
|
||||
});
|
||||
|
||||
deepEqual(args, [-1, 'A', 'a', object]);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -124,6 +550,93 @@
|
||||
test('should detect the size of a string value', function() {
|
||||
equal(_.size('abc'), 3);
|
||||
});
|
||||
|
||||
test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() {
|
||||
equal(_.size(shadowed), 7);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.sortBy');
|
||||
|
||||
(function() {
|
||||
test('supports the `thisArg` argument', function() {
|
||||
var actual = _.sortBy([1, 2, 3], function(num) {
|
||||
return this.sin(num);
|
||||
}, Math);
|
||||
|
||||
deepEqual(actual, [3, 1, 2]);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.sortedIndex');
|
||||
|
||||
(function() {
|
||||
test('supports the `thisArg` argument', function() {
|
||||
var actual = _.sortedIndex([1, 2, 3], 4, function(num) {
|
||||
return this.sin(num);
|
||||
}, Math);
|
||||
|
||||
equal(actual, 0);
|
||||
});
|
||||
|
||||
test('supports arrays with lengths larger than `Math.pow(2, 31) - 1`', function() {
|
||||
var length = Math.pow(2, 32) - 1,
|
||||
index = length - 1,
|
||||
array = Array(length),
|
||||
steps = 0;
|
||||
|
||||
array[index] = index;
|
||||
_.sortedIndex(array, index, function() { steps++; });
|
||||
equal(steps, 33);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.template');
|
||||
|
||||
(function() {
|
||||
test('supports recursive calls', function() {
|
||||
var compiled = _.template('<%= a %><% a = _.template(c, obj) %><%= a %>'),
|
||||
data = { 'a': 'A', 'b': 'B', 'c': '<%= b %>' };
|
||||
|
||||
equal(compiled(data), 'AB');
|
||||
});
|
||||
|
||||
test('should not augment the `options` object', function() {
|
||||
var options = {};
|
||||
_.template('', null, options);
|
||||
deepEqual(options, {});
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash.throttle');
|
||||
|
||||
(function() {
|
||||
test('subsequent calls should return the result of the first call', function() {
|
||||
var throttled = _.throttle(function(value) { return value; }, 100),
|
||||
result = [throttled('x'), throttled('y')];
|
||||
|
||||
deepEqual(result, ['x', 'x']);
|
||||
});
|
||||
|
||||
test('supports calls in a loop', function() {
|
||||
var counter = 0,
|
||||
throttled = _.throttle(function() { counter++; }, 100),
|
||||
start = new Date,
|
||||
limit = 220;
|
||||
|
||||
while ((new Date - start) < limit) {
|
||||
throttled();
|
||||
}
|
||||
ok(counter > 1);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@@ -139,17 +652,63 @@
|
||||
deepEqual(_.toArray(array), [3, 2, 1]);
|
||||
});
|
||||
|
||||
test('should treat array-like-objects like arrays', function() {
|
||||
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]);
|
||||
});
|
||||
}(1, 2, 3));
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// explicitly call `QUnit.start()` in a CLI environment
|
||||
if (!window.document) {
|
||||
QUnit.start();
|
||||
}
|
||||
}(typeof global == 'object' && global || this));
|
||||
QUnit.module('lodash.uniq');
|
||||
|
||||
(function() {
|
||||
test('supports the `thisArg` argument', function() {
|
||||
var actual = _.uniq([1, 2, 1.5, 3, 2.5], function(num) {
|
||||
return this.floor(num);
|
||||
}, Math);
|
||||
|
||||
deepEqual(actual, [1, 2, 3]);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash(...).shift');
|
||||
|
||||
(function() {
|
||||
test('should remove the value at index `0` when length is `0` (test in IE 8 compatibility mode)', function() {
|
||||
var wrapped = _({ '0': 1, 'length': 1 });
|
||||
wrapped.shift();
|
||||
|
||||
deepEqual(wrapped.keys(), ['length']);
|
||||
equal(wrapped.first(), undefined);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('lodash(...).splice');
|
||||
|
||||
(function() {
|
||||
test('should remove the value at index `0` when length is `0` (test in IE < 9, and in compatibility mode for IE9)', function() {
|
||||
var wrapped = _({ '0': 1, 'length': 1 });
|
||||
wrapped.splice(0, 1);
|
||||
|
||||
deepEqual(wrapped.keys(), ['length']);
|
||||
equal(wrapped.first(), undefined);
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// explicitly call `QUnit.start()` for Narwhal, Rhino, and RingoJS
|
||||
QUnit.start();
|
||||
|
||||
}(typeof global == 'object' && global || this));
|
||||
|
||||
39
test/underscore.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Underscore Test Suite</title>
|
||||
<link rel="stylesheet" href="../vendor/underscore/test/vendor/qunit.css">
|
||||
<style>
|
||||
#jslitmus, iframe {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture">
|
||||
<div id="map-test">
|
||||
<div id="id1"></div>
|
||||
<div id="id2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="../vendor/backbone/test/vendor/json2.js"></script>
|
||||
<script src="../vendor/underscore/test/vendor/jquery.js"></script>
|
||||
<script src="../vendor/underscore/test/vendor/qunit.js"></script>
|
||||
<script src="../vendor/underscore/test/vendor/jslitmus.js"></script>
|
||||
<script src="../lodash.js"></script>
|
||||
<script src="../vendor/underscore/test/collections.js"></script>
|
||||
<script src="../vendor/underscore/test/arrays.js"></script>
|
||||
<script src="../vendor/underscore/test/functions.js"></script>
|
||||
<script src="../vendor/underscore/test/objects.js"></script>
|
||||
<script src="../vendor/underscore/test/utility.js"></script>
|
||||
<script src="../vendor/underscore/test/chaining.js"></script>
|
||||
<script type="text/html" id="template">
|
||||
<%
|
||||
// a comment
|
||||
if (data) { data += 12345; }; %>
|
||||
<li><%= data %></li>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,190 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
module("Arrays");
|
||||
|
||||
test("arrays: first", function() {
|
||||
equal(_.first([1,2,3]), 1, 'can pull out the first element of an array');
|
||||
equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"');
|
||||
equal(_.first([1,2,3], 0).join(', '), "", 'can pass an index to first');
|
||||
equal(_.first([1,2,3], 2).join(', '), '1, 2', 'can pass an index to first');
|
||||
equal(_.first([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to first');
|
||||
var result = (function(){ return _.first(arguments); })(4, 3, 2, 1);
|
||||
equal(result, 4, 'works on an arguments object.');
|
||||
result = _.map([[1,2,3],[1,2,3]], _.first);
|
||||
equal(result.join(','), '1,1', 'works well with _.map');
|
||||
result = (function() { return _.take([1,2,3], 2); })();
|
||||
equal(result.join(','), '1,2', 'aliased as take');
|
||||
});
|
||||
|
||||
test("arrays: rest", function() {
|
||||
var numbers = [1, 2, 3, 4];
|
||||
equal(_.rest(numbers).join(", "), "2, 3, 4", 'working rest()');
|
||||
equal(_.rest(numbers, 0).join(", "), "1, 2, 3, 4", 'working rest(0)');
|
||||
equal(_.rest(numbers, 2).join(', '), '3, 4', 'rest can take an index');
|
||||
var result = (function(){ return _(arguments).tail(); })(1, 2, 3, 4);
|
||||
equal(result.join(', '), '2, 3, 4', 'aliased as tail and works on arguments object');
|
||||
result = _.map([[1,2,3],[1,2,3]], _.rest);
|
||||
equal(_.flatten(result).join(','), '2,3,2,3', 'works well with _.map');
|
||||
});
|
||||
|
||||
test("arrays: initial", function() {
|
||||
equal(_.initial([1,2,3,4,5]).join(", "), "1, 2, 3, 4", 'working initial()');
|
||||
equal(_.initial([1,2,3,4],2).join(", "), "1, 2", 'initial can take an index');
|
||||
var result = (function(){ return _(arguments).initial(); })(1, 2, 3, 4);
|
||||
equal(result.join(", "), "1, 2, 3", 'initial works on arguments object');
|
||||
result = _.map([[1,2,3],[1,2,3]], _.initial);
|
||||
equal(_.flatten(result).join(','), '1,2,1,2', 'initial works with _.map');
|
||||
});
|
||||
|
||||
test("arrays: last", function() {
|
||||
equal(_.last([1,2,3]), 3, 'can pull out the last element of an array');
|
||||
equal(_.last([1,2,3], 0).join(', '), "", 'can pass an index to last');
|
||||
equal(_.last([1,2,3], 2).join(', '), '2, 3', 'can pass an index to last');
|
||||
equal(_.last([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to last');
|
||||
var result = (function(){ return _(arguments).last(); })(1, 2, 3, 4);
|
||||
equal(result, 4, 'works on an arguments object');
|
||||
result = _.map([[1,2,3],[1,2,3]], _.last);
|
||||
equal(result.join(','), '3,3', 'works well with _.map');
|
||||
});
|
||||
|
||||
test("arrays: compact", function() {
|
||||
equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values');
|
||||
var result = (function(){ return _(arguments).compact().length; })(0, 1, false, 2, false, 3);
|
||||
equal(result, 3, 'works on an arguments object');
|
||||
});
|
||||
|
||||
test("arrays: flatten", function() {
|
||||
if (window.JSON) {
|
||||
var list = [1, [2], [3, [[[4]]]]];
|
||||
equal(JSON.stringify(_.flatten(list)), '[1,2,3,4]', 'can flatten nested arrays');
|
||||
equal(JSON.stringify(_.flatten(list, true)), '[1,2,3,[[[4]]]]', 'can shallowly flatten nested arrays');
|
||||
var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]);
|
||||
equal(JSON.stringify(result), '[1,2,3,4]', 'works on an arguments object');
|
||||
}
|
||||
});
|
||||
|
||||
test("arrays: without", function() {
|
||||
var list = [1, 2, 1, 0, 3, 1, 4];
|
||||
equal(_.without(list, 0, 1).join(', '), '2, 3, 4', 'can remove all instances of an object');
|
||||
var result = (function(){ return _.without(arguments, 0, 1); })(1, 2, 1, 0, 3, 1, 4);
|
||||
equal(result.join(', '), '2, 3, 4', 'works on an arguments object');
|
||||
|
||||
var list = [{one : 1}, {two : 2}];
|
||||
ok(_.without(list, {one : 1}).length == 2, 'uses real object identity for comparisons.');
|
||||
ok(_.without(list, list[0]).length == 1, 'ditto.');
|
||||
});
|
||||
|
||||
test("arrays: uniq", function() {
|
||||
var list = [1, 2, 1, 3, 1, 4];
|
||||
equal(_.uniq(list).join(', '), '1, 2, 3, 4', 'can find the unique values of an unsorted array');
|
||||
|
||||
var list = [1, 1, 1, 2, 2, 3];
|
||||
equal(_.uniq(list, true).join(', '), '1, 2, 3', 'can find the unique values of a sorted array faster');
|
||||
|
||||
var list = [{name:'moe'}, {name:'curly'}, {name:'larry'}, {name:'curly'}];
|
||||
var iterator = function(value) { return value.name; };
|
||||
equal(_.map(_.uniq(list, false, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator');
|
||||
|
||||
var iterator = function(value) { return value +1; };
|
||||
var list = [1, 2, 2, 3, 4, 4];
|
||||
equal(_.uniq(list, true, iterator).join(', '), '1, 2, 3, 4', 'iterator works with sorted array');
|
||||
|
||||
var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4);
|
||||
equal(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
|
||||
|
||||
var list = [];
|
||||
list[2] = list[3] = null;
|
||||
list[8] = 2;
|
||||
list[10] = 2;
|
||||
list[11] = 5;
|
||||
list[14] = 5;
|
||||
list[16] = 8;
|
||||
list[19] = 8;
|
||||
list[26] = list[29] = undefined;
|
||||
list[33] = "hi";
|
||||
|
||||
var result = _.uniq(list, true);
|
||||
if (0 in [undefined]) {
|
||||
// According to the JScript ES 3 spec, section 2.1.26, JScript 5.x (IE <=
|
||||
// 8) treats `undefined` elements in arrays as elisions.
|
||||
deepEqual(result, [null, 2, 5, 8, undefined, "hi"], "Works with sorted sparse arrays");
|
||||
equal(result.length, 6, "The resulting array should not be sparse");
|
||||
} else {
|
||||
deepEqual(result, [null, 2, 5, 8, "hi"], "Works with sorted sparse arrays where `undefined` elements are elided");
|
||||
equal(result.length, 5, "The resulting array should not be sparse");
|
||||
}
|
||||
});
|
||||
|
||||
test("arrays: intersection", function() {
|
||||
var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho'];
|
||||
equal(_.intersection(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
|
||||
equal(_(stooges).intersection(leaders).join(''), 'moe', 'can perform an OO-style intersection');
|
||||
var result = (function(){ return _.intersection(arguments, leaders); })('moe', 'curly', 'larry');
|
||||
equal(result.join(''), 'moe', 'works on an arguments object');
|
||||
});
|
||||
|
||||
test("arrays: union", function() {
|
||||
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]);
|
||||
equal(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays');
|
||||
|
||||
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]);
|
||||
equal(result.join(' '), '1 2 3 30 40 1', 'takes the union of a list of nested arrays');
|
||||
});
|
||||
|
||||
test("arrays: difference", function() {
|
||||
var result = _.difference([1, 2, 3], [2, 30, 40]);
|
||||
equal(result.join(' '), '1 3', 'takes the difference of two arrays');
|
||||
|
||||
var result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]);
|
||||
equal(result.join(' '), '3 4', 'takes the difference of three arrays');
|
||||
});
|
||||
|
||||
test('arrays: zip', function() {
|
||||
var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];
|
||||
var stooges = _.zip(names, ages, leaders);
|
||||
equal(String(stooges), 'moe,30,true,larry,40,,curly,50,', 'zipped together arrays of different lengths');
|
||||
});
|
||||
|
||||
test("arrays: indexOf", function() {
|
||||
var numbers = [1, 2, 3];
|
||||
numbers.indexOf = null;
|
||||
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);
|
||||
equal(index, -1, '35 is not in the list');
|
||||
|
||||
numbers = [10, 20, 30, 40, 50]; num = 40;
|
||||
index = _.indexOf(numbers, num, true);
|
||||
equal(index, 3, '40 is in the list');
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
test("arrays: lastIndexOf", function() {
|
||||
var 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');
|
||||
});
|
||||
|
||||
test("arrays: range", function() {
|
||||
equal(_.range(0).join(''), '', 'range with 0 as a first argument generates an empty array');
|
||||
equal(_.range(4).join(' '), '0 1 2 3', 'range with a single positive argument generates an array of elements 0,1,2,...,n-1');
|
||||
equal(_.range(5, 8).join(' '), '5 6 7', 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1');
|
||||
equal(_.range(8, 5).join(''), '', 'range with two arguments a & b, b<a generates an empty array');
|
||||
equal(_.range(3, 10, 3).join(' '), '3 6 9', 'range with three arguments a & b & c, c < b-a, a < b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) < c');
|
||||
equal(_.range(3, 10, 15).join(''), '3', 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a');
|
||||
equal(_.range(12, 7, -2).join(' '), '12 10 8', 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b');
|
||||
equal(_.range(0, -10, -1).join(' '), '0 -1 -2 -3 -4 -5 -6 -7 -8 -9', 'final example in the Python docs');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,59 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
module("Chaining");
|
||||
|
||||
test("chaining: map/flatten/reduce", function() {
|
||||
var lyrics = [
|
||||
"I'm a lumberjack and I'm okay",
|
||||
"I sleep all night and I work all day",
|
||||
"He's a lumberjack and he's okay",
|
||||
"He sleeps all night and he works all day"
|
||||
];
|
||||
var counts = _(lyrics).chain()
|
||||
.map(function(line) { return line.split(''); })
|
||||
.flatten()
|
||||
.reduce(function(hash, l) {
|
||||
hash[l] = hash[l] || 0;
|
||||
hash[l]++;
|
||||
return hash;
|
||||
}, {}).value();
|
||||
ok(counts['a'] == 16 && counts['e'] == 10, 'counted all the letters in the song');
|
||||
});
|
||||
|
||||
test("chaining: select/reject/sortBy", function() {
|
||||
var numbers = [1,2,3,4,5,6,7,8,9,10];
|
||||
numbers = _(numbers).chain().select(function(n) {
|
||||
return n % 2 == 0;
|
||||
}).reject(function(n) {
|
||||
return n % 4 == 0;
|
||||
}).sortBy(function(n) {
|
||||
return -n;
|
||||
}).value();
|
||||
equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
|
||||
});
|
||||
|
||||
test("chaining: select/reject/sortBy in functional style", function() {
|
||||
var numbers = [1,2,3,4,5,6,7,8,9,10];
|
||||
numbers = _.chain(numbers).select(function(n) {
|
||||
return n % 2 == 0;
|
||||
}).reject(function(n) {
|
||||
return n % 4 == 0;
|
||||
}).sortBy(function(n) {
|
||||
return -n;
|
||||
}).value();
|
||||
equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
|
||||
});
|
||||
|
||||
test("chaining: reverse/concat/unshift/pop/map", function() {
|
||||
var numbers = [1,2,3,4,5];
|
||||
numbers = _(numbers).chain()
|
||||
.reverse()
|
||||
.concat([5, 5, 5])
|
||||
.unshift(17)
|
||||
.pop()
|
||||
.map(function(n){ return n * 2; })
|
||||
.value();
|
||||
equal(numbers.join(', '), "34, 10, 8, 6, 4, 2, 10, 10", 'can chain together array functions.');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,299 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
module("Collections");
|
||||
|
||||
test("collections: each", function() {
|
||||
_.each([1, 2, 3], function(num, i) {
|
||||
equal(num, i + 1, 'each iterators provide value and iteration count');
|
||||
});
|
||||
|
||||
var answers = [];
|
||||
_.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5});
|
||||
equal(answers.join(', '), '5, 10, 15', 'context object property accessed');
|
||||
|
||||
answers = [];
|
||||
_.forEach([1, 2, 3], function(num){ answers.push(num); });
|
||||
equal(answers.join(', '), '1, 2, 3', 'aliased as "forEach"');
|
||||
|
||||
answers = [];
|
||||
var obj = {one : 1, two : 2, three : 3};
|
||||
obj.constructor.prototype.four = 4;
|
||||
_.each(obj, function(value, key){ answers.push(key); });
|
||||
equal(answers.join(", "), 'one, two, three', 'iterating over objects works, and ignores the object prototype.');
|
||||
delete obj.constructor.prototype.four;
|
||||
|
||||
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('collections: map', function() {
|
||||
var doubled = _.map([1, 2, 3], function(num){ return num * 2; });
|
||||
equal(doubled.join(', '), '2, 4, 6', 'doubled numbers');
|
||||
|
||||
doubled = _.collect([1, 2, 3], function(num){ return num * 2; });
|
||||
equal(doubled.join(', '), '2, 4, 6', 'aliased as "collect"');
|
||||
|
||||
var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3});
|
||||
equal(tripled.join(', '), '3, 6, 9', 'tripled numbers with context');
|
||||
|
||||
var doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
|
||||
equal(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers');
|
||||
|
||||
var ids = _.map($('div.underscore-test').children(), function(n){ return n.id; });
|
||||
ok(_.include(ids, 'qunit-header'), 'can use collection methods on NodeLists');
|
||||
|
||||
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');
|
||||
|
||||
var length = _.map(Array(2), function(v) { return v; }).length;
|
||||
equal(length, 2, "can preserve a sparse array's length");
|
||||
});
|
||||
|
||||
test('collections: reduce', function() {
|
||||
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }, 0);
|
||||
equal(sum, 6, 'can sum up an array');
|
||||
|
||||
var context = {multiplier : 3};
|
||||
sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num * this.multiplier; }, 0, context);
|
||||
equal(sum, 18, 'can reduce with a context object');
|
||||
|
||||
sum = _.inject([1, 2, 3], function(sum, num){ return sum + num; }, 0);
|
||||
equal(sum, 6, 'aliased as "inject"');
|
||||
|
||||
sum = _([1, 2, 3]).reduce(function(sum, num){ return sum + num; }, 0);
|
||||
equal(sum, 6, 'OO-style reduce');
|
||||
|
||||
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');
|
||||
|
||||
var sparseArray = [];
|
||||
sparseArray[0] = 20;
|
||||
sparseArray[2] = -5;
|
||||
equal(_.reduce(sparseArray, function(a, b){ return a - b; }), 25, 'initially-sparse arrays with no memo');
|
||||
});
|
||||
|
||||
test('collections: reduceRight', function() {
|
||||
var list = _.reduceRight(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
|
||||
equal(list, 'bazbarfoo', 'can perform right folds');
|
||||
|
||||
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
|
||||
equal(list, 'bazbarfoo', 'aliased as "foldr"');
|
||||
|
||||
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');
|
||||
|
||||
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');
|
||||
|
||||
var sparseArray = [];
|
||||
sparseArray[0] = 20;
|
||||
sparseArray[2] = -5;
|
||||
equal(_.reduceRight(sparseArray, function(a, b){ return a - b; }), -25, 'initially-sparse arrays with no memo');
|
||||
});
|
||||
|
||||
test('collections: detect', function() {
|
||||
var result = _.detect([1, 2, 3], function(num){ return num * 2 == 4; });
|
||||
equal(result, 2, 'found the first "2" and broke the loop');
|
||||
});
|
||||
|
||||
test('collections: select', function() {
|
||||
var evens = _.select([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
|
||||
equal(evens.join(', '), '2, 4, 6', 'selected each even number');
|
||||
|
||||
evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
|
||||
equal(evens.join(', '), '2, 4, 6', 'aliased as "filter"');
|
||||
});
|
||||
|
||||
test('collections: reject', function() {
|
||||
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
|
||||
equal(odds.join(', '), '1, 3, 5', 'rejected each even number');
|
||||
});
|
||||
|
||||
test('collections: all', function() {
|
||||
ok(_.all([], _.identity), 'the empty set');
|
||||
ok(_.all([true, true, true], _.identity), 'all true values');
|
||||
ok(!_.all([true, false, true], _.identity), 'one false value');
|
||||
ok(_.all([0, 10, 28], function(num){ return num % 2 == 0; }), 'even numbers');
|
||||
ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number');
|
||||
ok(_.all([1], _.identity) === true, 'cast to boolean - true');
|
||||
ok(_.all([0], _.identity) === false, 'cast to boolean - false');
|
||||
ok(_.every([true, true, true], _.identity), 'aliased as "every"');
|
||||
});
|
||||
|
||||
test('collections: any', function() {
|
||||
var nativeSome = Array.prototype.some;
|
||||
Array.prototype.some = null;
|
||||
ok(!_.any([]), 'the empty set');
|
||||
ok(!_.any([false, false, false]), 'all false values');
|
||||
ok(_.any([false, false, true]), 'one true value');
|
||||
ok(_.any([null, 0, 'yes', false]), 'a string');
|
||||
ok(!_.any([null, 0, '', false]), 'falsy values');
|
||||
ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers');
|
||||
ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number');
|
||||
ok(_.any([1], _.identity) === true, 'cast to boolean - true');
|
||||
ok(_.any([0], _.identity) === false, 'cast to boolean - false');
|
||||
ok(_.some([false, false, true]), 'aliased as "some"');
|
||||
Array.prototype.some = nativeSome;
|
||||
});
|
||||
|
||||
test('collections: include', function() {
|
||||
ok(_.include([1,2,3], 2), 'two is in the array');
|
||||
ok(!_.include([1,3,9], 2), 'two is not in the array');
|
||||
ok(_.contains({moe:1, larry:3, curly:9}, 3) === true, '_.include on objects checks their values');
|
||||
ok(_([1,2,3]).include(2), 'OO-style include');
|
||||
});
|
||||
|
||||
test('collections: invoke', function() {
|
||||
var list = [[5, 1, 7], [3, 2, 1]];
|
||||
var result = _.invoke(list, 'sort');
|
||||
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
|
||||
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
|
||||
});
|
||||
|
||||
test('collections: invoke w/ function reference', function() {
|
||||
var list = [[5, 1, 7], [3, 2, 1]];
|
||||
var result = _.invoke(list, Array.prototype.sort);
|
||||
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
|
||||
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
|
||||
});
|
||||
|
||||
// Relevant when using ClojureScript
|
||||
test('collections: invoke when strings have a call method', function() {
|
||||
String.prototype.call = function() {
|
||||
return 42;
|
||||
};
|
||||
var list = [[5, 1, 7], [3, 2, 1]];
|
||||
var s = "foo";
|
||||
equal(s.call(), 42, "call function exists");
|
||||
var result = _.invoke(list, 'sort');
|
||||
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
|
||||
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
|
||||
delete String.prototype.call;
|
||||
equal(s.call, undefined, "call function removed");
|
||||
});
|
||||
|
||||
test('collections: pluck', function() {
|
||||
var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}];
|
||||
equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'pulls names out of objects');
|
||||
});
|
||||
|
||||
test('collections: max', function() {
|
||||
equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max');
|
||||
|
||||
var neg = _.max([1, 2, 3], function(num){ return -num; });
|
||||
equal(neg, 1, 'can perform a computation-based max');
|
||||
|
||||
equal(-Infinity, _.max({}), 'Maximum value of an empty object');
|
||||
equal(-Infinity, _.max([]), 'Maximum value of an empty array');
|
||||
});
|
||||
|
||||
test('collections: min', function() {
|
||||
equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min');
|
||||
|
||||
var neg = _.min([1, 2, 3], function(num){ return -num; });
|
||||
equal(neg, 3, 'can perform a computation-based min');
|
||||
|
||||
equal(Infinity, _.min({}), 'Minimum value of an empty object');
|
||||
equal(Infinity, _.min([]), 'Minimum value of an empty array');
|
||||
|
||||
var now = new Date(9999999999);
|
||||
var then = new Date(0);
|
||||
equal(_.min([now, then]), then);
|
||||
});
|
||||
|
||||
test('collections: sortBy', function() {
|
||||
var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}];
|
||||
people = _.sortBy(people, function(person){ return person.age; });
|
||||
equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
|
||||
|
||||
var list = [undefined, 4, 1, undefined, 3, 2];
|
||||
equal(_.sortBy(list, _.identity).join(','), '1,2,3,4,,', 'sortBy with undefined values');
|
||||
|
||||
var list = ["one", "two", "three", "four", "five"];
|
||||
var sorted = _.sortBy(list, 'length');
|
||||
equal(sorted.join(' '), 'one two four five three', 'sorted by length');
|
||||
});
|
||||
|
||||
test('collections: groupBy', function() {
|
||||
var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
|
||||
ok('0' in parity && '1' in parity, 'created a group for each value');
|
||||
equal(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
|
||||
|
||||
var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
|
||||
var grouped = _.groupBy(list, 'length');
|
||||
equal(grouped['3'].join(' '), 'one two six ten');
|
||||
equal(grouped['4'].join(' '), 'four five nine');
|
||||
equal(grouped['5'].join(' '), 'three seven eight');
|
||||
});
|
||||
|
||||
test('collections: sortedIndex', function() {
|
||||
var numbers = [10, 20, 30, 40, 50], num = 35;
|
||||
var indexForNum = _.sortedIndex(numbers, num);
|
||||
equal(indexForNum, 3, '35 should be inserted at index 3');
|
||||
|
||||
var indexFor30 = _.sortedIndex(numbers, 30);
|
||||
equal(indexFor30, 2, '30 should be inserted at index 2');
|
||||
});
|
||||
|
||||
test('collections: shuffle', function() {
|
||||
var numbers = _.range(10);
|
||||
var shuffled = _.shuffle(numbers).sort();
|
||||
notStrictEqual(numbers, shuffled, 'original object is unmodified');
|
||||
equal(shuffled.join(','), numbers.join(','), 'contains the same members before and after shuffle');
|
||||
});
|
||||
|
||||
test('collections: toArray', function() {
|
||||
ok(!_.isArray(arguments), 'arguments object is not an array');
|
||||
ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array');
|
||||
var a = [1,2,3];
|
||||
ok(_.toArray(a) !== a, 'array is cloned');
|
||||
equal(_.toArray(a).join(', '), '1, 2, 3', 'cloned array contains same elements');
|
||||
|
||||
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('collections: size', function() {
|
||||
equal(_.size({one : 1, two : 2, three : 3}), 3, 'can compute the size of an object');
|
||||
equal(_.size([1, 2, 3]), 3, 'can compute the size of an array');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,215 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
module("Functions");
|
||||
|
||||
test("functions: bind", function() {
|
||||
var context = {name : 'moe'};
|
||||
var func = function(arg) { return "name: " + (this.name || arg); };
|
||||
var bound = _.bind(func, context);
|
||||
equal(bound(), 'name: moe', 'can bind a function to a context');
|
||||
|
||||
bound = _(func).bind(context);
|
||||
equal(bound(), 'name: moe', 'can do OO-style binding');
|
||||
|
||||
bound = _.bind(func, null, 'curly');
|
||||
equal(bound(), 'name: curly', 'can bind without specifying a context');
|
||||
|
||||
func = function(salutation, name) { return salutation + ': ' + name; };
|
||||
func = _.bind(func, this, 'hello');
|
||||
equal(func('moe'), 'hello: moe', 'the function was partially applied in advance');
|
||||
|
||||
var func = _.bind(func, this, 'curly');
|
||||
equal(func(), 'hello: curly', 'the function was completely applied in advance');
|
||||
|
||||
var func = function(salutation, firstname, lastname) { return salutation + ': ' + firstname + ' ' + lastname; };
|
||||
func = _.bind(func, this, 'hello', 'moe', 'curly');
|
||||
equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments');
|
||||
|
||||
func = function(context, message) { equal(this, context, message); };
|
||||
_.bind(func, 0, 0, 'can bind a function to `0`')();
|
||||
_.bind(func, '', '', 'can bind a function to an empty string')();
|
||||
_.bind(func, false, false, 'can bind a function to `false`')();
|
||||
|
||||
// These tests are only meaningful when using a browser without a native bind function
|
||||
// To test this with a modern browser, set underscore's nativeBind to undefined
|
||||
var F = function () { return this; };
|
||||
var Boundf = _.bind(F, {hello: "moe curly"});
|
||||
equal(new Boundf().hello, undefined, "function should not be bound to the context, to comply with ECMAScript 5");
|
||||
equal(Boundf().hello, "moe curly", "When called without the new operator, it's OK to be bound to the context");
|
||||
});
|
||||
|
||||
test("functions: bindAll", function() {
|
||||
var curly = {name : 'curly'}, moe = {
|
||||
name : 'moe',
|
||||
getName : function() { return 'name: ' + this.name; },
|
||||
sayHi : function() { return 'hi: ' + this.name; }
|
||||
};
|
||||
curly.getName = moe.getName;
|
||||
_.bindAll(moe, 'getName', 'sayHi');
|
||||
curly.sayHi = moe.sayHi;
|
||||
equal(curly.getName(), 'name: curly', 'unbound function is bound to current object');
|
||||
equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object');
|
||||
|
||||
curly = {name : 'curly'};
|
||||
moe = {
|
||||
name : 'moe',
|
||||
getName : function() { return 'name: ' + this.name; },
|
||||
sayHi : function() { return 'hi: ' + this.name; }
|
||||
};
|
||||
_.bindAll(moe);
|
||||
curly.sayHi = moe.sayHi;
|
||||
equal(curly.sayHi(), 'hi: moe', 'calling bindAll with no arguments binds all functions to the object');
|
||||
});
|
||||
|
||||
test("functions: memoize", function() {
|
||||
var fib = function(n) {
|
||||
return n < 2 ? n : fib(n - 1) + fib(n - 2);
|
||||
};
|
||||
var fastFib = _.memoize(fib);
|
||||
equal(fib(10), 55, 'a memoized version of fibonacci produces identical results');
|
||||
equal(fastFib(10), 55, 'a memoized version of fibonacci produces identical results');
|
||||
|
||||
var o = function(str) {
|
||||
return str;
|
||||
};
|
||||
var fastO = _.memoize(o);
|
||||
equal(o('toString'), 'toString', 'checks hasOwnProperty');
|
||||
equal(fastO('toString'), 'toString', 'checks hasOwnProperty');
|
||||
});
|
||||
|
||||
asyncTest("functions: delay", 2, function() {
|
||||
var delayed = false;
|
||||
_.delay(function(){ delayed = true; }, 100);
|
||||
setTimeout(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
|
||||
setTimeout(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
|
||||
});
|
||||
|
||||
asyncTest("functions: defer", 1, function() {
|
||||
var deferred = false;
|
||||
_.defer(function(bool){ deferred = bool; }, true);
|
||||
_.delay(function(){ ok(deferred, "deferred the function"); start(); }, 50);
|
||||
});
|
||||
|
||||
asyncTest("functions: throttle", 2, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ counter++; };
|
||||
var throttledIncr = _.throttle(incr, 100);
|
||||
throttledIncr(); throttledIncr(); throttledIncr();
|
||||
setTimeout(throttledIncr, 70);
|
||||
setTimeout(throttledIncr, 120);
|
||||
setTimeout(throttledIncr, 140);
|
||||
setTimeout(throttledIncr, 190);
|
||||
setTimeout(throttledIncr, 220);
|
||||
setTimeout(throttledIncr, 240);
|
||||
_.delay(function(){ equal(counter, 1, "incr was called immediately"); }, 30);
|
||||
_.delay(function(){ equal(counter, 4, "incr was throttled"); start(); }, 400);
|
||||
});
|
||||
|
||||
asyncTest("functions: throttle arguments", 2, function() {
|
||||
var value = 0;
|
||||
var update = function(val){ value = val; };
|
||||
var throttledUpdate = _.throttle(update, 100);
|
||||
throttledUpdate(1); throttledUpdate(2); throttledUpdate(3);
|
||||
setTimeout(function(){ throttledUpdate(4); }, 120);
|
||||
setTimeout(function(){ throttledUpdate(5); }, 140);
|
||||
setTimeout(function(){ throttledUpdate(6); }, 250);
|
||||
_.delay(function(){ equal(value, 1, "updated to latest value"); }, 40);
|
||||
_.delay(function(){ equal(value, 6, "updated to latest value"); start(); }, 400);
|
||||
});
|
||||
|
||||
asyncTest("functions: throttle once", 2, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ return ++counter; };
|
||||
var throttledIncr = _.throttle(incr, 100);
|
||||
var result = throttledIncr();
|
||||
_.delay(function(){
|
||||
equal(result, 1, "throttled functions return their value");
|
||||
equal(counter, 1, "incr was called once"); start();
|
||||
}, 220);
|
||||
});
|
||||
|
||||
asyncTest("functions: throttle twice", 1, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ counter++; };
|
||||
var throttledIncr = _.throttle(incr, 100);
|
||||
throttledIncr(); throttledIncr();
|
||||
_.delay(function(){ equal(counter, 2, "incr was called twice"); start(); }, 220);
|
||||
});
|
||||
|
||||
asyncTest("functions: debounce", 1, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ counter++; };
|
||||
var debouncedIncr = _.debounce(incr, 50);
|
||||
debouncedIncr(); debouncedIncr(); debouncedIncr();
|
||||
setTimeout(debouncedIncr, 30);
|
||||
setTimeout(debouncedIncr, 60);
|
||||
setTimeout(debouncedIncr, 90);
|
||||
setTimeout(debouncedIncr, 120);
|
||||
setTimeout(debouncedIncr, 150);
|
||||
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 220);
|
||||
});
|
||||
|
||||
asyncTest("functions: debounce asap", 2, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ counter++; };
|
||||
var debouncedIncr = _.debounce(incr, 50, true);
|
||||
debouncedIncr(); debouncedIncr(); debouncedIncr();
|
||||
equal(counter, 1, 'incr was called immediately');
|
||||
setTimeout(debouncedIncr, 30);
|
||||
setTimeout(debouncedIncr, 60);
|
||||
setTimeout(debouncedIncr, 90);
|
||||
setTimeout(debouncedIncr, 120);
|
||||
setTimeout(debouncedIncr, 150);
|
||||
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 220);
|
||||
});
|
||||
|
||||
test("functions: once", function() {
|
||||
var num = 0;
|
||||
var increment = _.once(function(){ num++; });
|
||||
increment();
|
||||
increment();
|
||||
equal(num, 1);
|
||||
});
|
||||
|
||||
test("functions: wrap", function() {
|
||||
var greet = function(name){ return "hi: " + name; };
|
||||
var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); });
|
||||
equal(backwards('moe'), 'hi: moe eom', 'wrapped the saluation function');
|
||||
|
||||
var inner = function(){ return "Hello "; };
|
||||
var obj = {name : "Moe"};
|
||||
obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; });
|
||||
equal(obj.hi(), "Hello Moe");
|
||||
|
||||
var noop = function(){};
|
||||
var wrapped = _.wrap(noop, function(fn){ return Array.prototype.slice.call(arguments, 0); });
|
||||
var ret = wrapped(['whats', 'your'], 'vector', 'victor');
|
||||
same(ret, [noop, ['whats', 'your'], 'vector', 'victor']);
|
||||
});
|
||||
|
||||
test("functions: compose", function() {
|
||||
var greet = function(name){ return "hi: " + name; };
|
||||
var exclaim = function(sentence){ return sentence + '!'; };
|
||||
var composed = _.compose(exclaim, greet);
|
||||
equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another');
|
||||
|
||||
composed = _.compose(greet, exclaim);
|
||||
equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative');
|
||||
});
|
||||
|
||||
test("functions: after", function() {
|
||||
var testAfter = function(afterAmount, timesCalled) {
|
||||
var afterCalled = 0;
|
||||
var after = _.after(afterAmount, function() {
|
||||
afterCalled++;
|
||||
});
|
||||
while (timesCalled--) after();
|
||||
return afterCalled;
|
||||
};
|
||||
|
||||
equal(testAfter(5, 5), 1, "after(N) should fire after being called N times");
|
||||
equal(testAfter(5, 4), 0, "after(N) should not fire unless called N times");
|
||||
equal(testAfter(0, 0), 1, "after(0) should fire immediately");
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Underscore Test Suite</title>
|
||||
<link rel="stylesheet" href="vendor/qunit.css" type="text/css" media="screen" />
|
||||
<script type="text/javascript" src="vendor/jquery.js"></script>
|
||||
<script type="text/javascript" src="vendor/qunit.js"></script>
|
||||
<script type="text/javascript" src="vendor/jslitmus.js"></script>
|
||||
<script type="text/javascript" src="../../lodash.js"></script>
|
||||
<script type="text/javascript" src="collections.js"></script>
|
||||
<script type="text/javascript" src="arrays.js"></script>
|
||||
<script type="text/javascript" src="functions.js"></script>
|
||||
<script type="text/javascript" src="objects.js"></script>
|
||||
<script type="text/javascript" src="utility.js"></script>
|
||||
<script type="text/javascript" src="chaining.js"></script>
|
||||
<script type="text/javascript" src="speed.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="underscore-test">
|
||||
<h1 id="qunit-header">Underscore Test Suite</h1>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<br />
|
||||
<h1 class="qunit-header">Underscore Speed Suite</h1>
|
||||
<p>
|
||||
A representative sample of the functions are benchmarked here, to provide
|
||||
a sense of how fast they might run in different browsers.
|
||||
Each iteration runs on an array of 1000 elements.<br /><br />
|
||||
For example, the 'intersect' test measures the number of times you can
|
||||
find the intersection of two thousand-element arrays in one second.
|
||||
</p>
|
||||
<br />
|
||||
|
||||
<script type="text/html" id="template">
|
||||
<%
|
||||
// a comment
|
||||
if (data) { data += 12345; }; %>
|
||||
<li><%= data %></li>
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,558 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
module("Objects");
|
||||
|
||||
test("objects: keys", function() {
|
||||
equal(_.keys({one : 1, two : 2}).join(', '), 'one, two', 'can extract the keys from an object');
|
||||
// the test above is not safe because it relies on for-in enumeration order
|
||||
var a = []; a[1] = 0;
|
||||
equal(_.keys(a).join(', '), '1', 'is not fooled by sparse arrays; see issue #95');
|
||||
raises(function() { _.keys(null); }, TypeError, 'throws an error for `null` values');
|
||||
raises(function() { _.keys(void 0); }, TypeError, 'throws an error for `undefined` values');
|
||||
raises(function() { _.keys(1); }, TypeError, 'throws an error for number primitives');
|
||||
raises(function() { _.keys('a'); }, TypeError, 'throws an error for string primitives');
|
||||
raises(function() { _.keys(true); }, TypeError, 'throws an error for boolean primitives');
|
||||
});
|
||||
|
||||
test("objects: values", function() {
|
||||
equal(_.values({one : 1, two : 2}).join(', '), '1, 2', 'can extract the values from an object');
|
||||
});
|
||||
|
||||
test("objects: functions", function() {
|
||||
var obj = {a : 'dash', b : _.map, c : (/yo/), d : _.reduce};
|
||||
ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object');
|
||||
|
||||
var Animal = function(){};
|
||||
Animal.prototype.run = function(){};
|
||||
equal(_.functions(new Animal).join(''), 'run', 'also looks up functions on the prototype');
|
||||
});
|
||||
|
||||
test("objects: extend", function() {
|
||||
var result;
|
||||
equal(_.extend({}, {a:'b'}).a, 'b', 'can extend an object with the attributes of another');
|
||||
equal(_.extend({a:'x'}, {a:'b'}).a, 'b', 'properties in source override destination');
|
||||
equal(_.extend({x:'x'}, {a:'b'}).x, 'x', 'properties not in source dont get overriden');
|
||||
result = _.extend({x:'x'}, {a:'a'}, {b:'b'});
|
||||
ok(_.isEqual(result, {x:'x', a:'a', b:'b'}), 'can extend from multiple source objects');
|
||||
result = _.extend({x:'x'}, {a:'a', x:2}, {a:'b'});
|
||||
ok(_.isEqual(result, {x:2, a:'b'}), 'extending from multiple source objects last property trumps');
|
||||
result = _.extend({}, {a: void 0, b: null});
|
||||
equal(_.keys(result).join(''), 'ab', 'extend does not copy undefined values');
|
||||
});
|
||||
|
||||
test("objects: pick", function() {
|
||||
var result;
|
||||
result = _.pick({a:1, b:2, c:3}, 'a', 'c');
|
||||
ok(_.isEqual(result, {a:1, c:3}), 'can restrict properties to those named');
|
||||
result = _.pick({a:1, b:2, c:3}, ['b', 'c']);
|
||||
ok(_.isEqual(result, {b:2, c:3}), 'can restrict properties to those named in an array');
|
||||
result = _.pick({a:1, b:2, c:3}, ['a'], 'b');
|
||||
ok(_.isEqual(result, {a:1, b:2}), 'can restrict properties to those named in mixed args');
|
||||
});
|
||||
|
||||
test("objects: defaults", function() {
|
||||
var result;
|
||||
var options = {zero: 0, one: 1, empty: "", nan: NaN, string: "string"};
|
||||
|
||||
_.defaults(options, {zero: 1, one: 10, twenty: 20});
|
||||
equal(options.zero, 0, 'value exists');
|
||||
equal(options.one, 1, 'value exists');
|
||||
equal(options.twenty, 20, 'default applied');
|
||||
|
||||
_.defaults(options, {empty: "full"}, {nan: "nan"}, {word: "word"}, {word: "dog"});
|
||||
equal(options.empty, "", 'value exists');
|
||||
ok(_.isNaN(options.nan), "NaN isn't overridden");
|
||||
equal(options.word, "word", 'new value is added, first one wins');
|
||||
});
|
||||
|
||||
test("objects: clone", function() {
|
||||
var moe = {name : 'moe', lucky : [13, 27, 34]};
|
||||
var clone = _.clone(moe);
|
||||
equal(clone.name, 'moe', 'the clone as the attributes of the original');
|
||||
|
||||
clone.name = 'curly';
|
||||
ok(clone.name == 'curly' && moe.name == 'moe', 'clones can change shallow attributes without affecting the original');
|
||||
|
||||
clone.lucky.push(101);
|
||||
equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original');
|
||||
|
||||
equal(_.clone(undefined), void 0, 'non objects should not be changed by clone');
|
||||
equal(_.clone(1), 1, 'non objects should not be changed by clone');
|
||||
equal(_.clone(null), null, 'non objects should not be changed by clone');
|
||||
});
|
||||
|
||||
test("objects: isEqual", function() {
|
||||
function First() {
|
||||
this.value = 1;
|
||||
}
|
||||
First.prototype.value = 1;
|
||||
function Second() {
|
||||
this.value = 1;
|
||||
}
|
||||
Second.prototype.value = 2;
|
||||
|
||||
// Basic equality and identity comparisons.
|
||||
ok(_.isEqual(null, null), "`null` is equal to `null`");
|
||||
ok(_.isEqual(), "`undefined` is equal to `undefined`");
|
||||
|
||||
ok(!_.isEqual(0, -0), "`0` is not equal to `-0`");
|
||||
ok(!_.isEqual(-0, 0), "Commutative equality is implemented for `0` and `-0`");
|
||||
ok(!_.isEqual(null, undefined), "`null` is not equal to `undefined`");
|
||||
ok(!_.isEqual(undefined, null), "Commutative equality is implemented for `null` and `undefined`");
|
||||
|
||||
// String object and primitive comparisons.
|
||||
ok(_.isEqual("Curly", "Curly"), "Identical string primitives are equal");
|
||||
ok(_.isEqual(new String("Curly"), new String("Curly")), "String objects with identical primitive values are equal");
|
||||
ok(_.isEqual(new String("Curly"), "Curly"), "String primitives and their corresponding object wrappers are equal");
|
||||
ok(_.isEqual("Curly", new String("Curly")), "Commutative equality is implemented for string objects and primitives");
|
||||
|
||||
ok(!_.isEqual("Curly", "Larry"), "String primitives with different values are not equal");
|
||||
ok(!_.isEqual(new String("Curly"), new String("Larry")), "String objects with different primitive values are not equal");
|
||||
ok(!_.isEqual(new String("Curly"), {toString: function(){ return "Curly"; }}), "String objects and objects with a custom `toString` method are not equal");
|
||||
|
||||
// Number object and primitive comparisons.
|
||||
ok(_.isEqual(75, 75), "Identical number primitives are equal");
|
||||
ok(_.isEqual(new Number(75), new Number(75)), "Number objects with identical primitive values are equal");
|
||||
ok(_.isEqual(75, new Number(75)), "Number primitives and their corresponding object wrappers are equal");
|
||||
ok(_.isEqual(new Number(75), 75), "Commutative equality is implemented for number objects and primitives");
|
||||
ok(!_.isEqual(new Number(0), -0), "`new Number(0)` and `-0` are not equal");
|
||||
ok(!_.isEqual(0, new Number(-0)), "Commutative equality is implemented for `new Number(0)` and `-0`");
|
||||
|
||||
ok(!_.isEqual(new Number(75), new Number(63)), "Number objects with different primitive values are not equal");
|
||||
ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), "Number objects and objects with a `valueOf` method are not equal");
|
||||
|
||||
// Comparisons involving `NaN`.
|
||||
ok(_.isEqual(NaN, NaN), "`NaN` is equal to `NaN`");
|
||||
ok(!_.isEqual(61, NaN), "A number primitive is not equal to `NaN`");
|
||||
ok(!_.isEqual(new Number(79), NaN), "A number object is not equal to `NaN`");
|
||||
ok(!_.isEqual(Infinity, NaN), "`Infinity` is not equal to `NaN`");
|
||||
|
||||
// Boolean object and primitive comparisons.
|
||||
ok(_.isEqual(true, true), "Identical boolean primitives are equal");
|
||||
ok(_.isEqual(new Boolean, new Boolean), "Boolean objects with identical primitive values are equal");
|
||||
ok(_.isEqual(true, new Boolean(true)), "Boolean primitives and their corresponding object wrappers are equal");
|
||||
ok(_.isEqual(new Boolean(true), true), "Commutative equality is implemented for booleans");
|
||||
ok(!_.isEqual(new Boolean(true), new Boolean), "Boolean objects with different primitive values are not equal");
|
||||
|
||||
// Common type coercions.
|
||||
ok(!_.isEqual(true, new Boolean(false)), "Boolean objects are not equal to the boolean primitive `true`");
|
||||
ok(!_.isEqual("75", 75), "String and number primitives with like values are not equal");
|
||||
ok(!_.isEqual(new Number(63), new String(63)), "String and number objects with like values are not equal");
|
||||
ok(!_.isEqual(75, "75"), "Commutative equality is implemented for like string and number values");
|
||||
ok(!_.isEqual(0, ""), "Number and string primitives with like values are not equal");
|
||||
ok(!_.isEqual(1, true), "Number and boolean primitives with like values are not equal");
|
||||
ok(!_.isEqual(new Boolean(false), new Number(0)), "Boolean and number objects with like values are not equal");
|
||||
ok(!_.isEqual(false, new String("")), "Boolean primitives and string objects with like values are not equal");
|
||||
ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), "Dates and their corresponding numeric primitive values are not equal");
|
||||
|
||||
// Dates.
|
||||
ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), "Date objects referencing identical times are equal");
|
||||
ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), "Date objects referencing different times are not equal");
|
||||
ok(!_.isEqual(new Date(2009, 11, 13), {
|
||||
getTime: function(){
|
||||
return 12606876e5;
|
||||
}
|
||||
}), "Date objects and objects with a `getTime` method are not equal");
|
||||
ok(!_.isEqual(new Date("Curly"), new Date("Curly")), "Invalid dates are not equal");
|
||||
|
||||
// Functions.
|
||||
ok(!_.isEqual(First, Second), "Different functions with identical bodies and source code representations are not equal");
|
||||
|
||||
// RegExps.
|
||||
ok(_.isEqual(/(?:)/gim, /(?:)/gim), "RegExps with equivalent patterns and flags are equal");
|
||||
ok(!_.isEqual(/(?:)/g, /(?:)/gi), "RegExps with equivalent patterns and different flags are not equal");
|
||||
ok(!_.isEqual(/Moe/gim, /Curly/gim), "RegExps with different patterns and equivalent flags are not equal");
|
||||
ok(!_.isEqual(/(?:)/gi, /(?:)/g), "Commutative equality is implemented for RegExps");
|
||||
ok(!_.isEqual(/Curly/g, {source: "Larry", global: true, ignoreCase: false, multiline: false}), "RegExps and RegExp-like objects are not equal");
|
||||
|
||||
// Empty arrays, array-like objects, and object literals.
|
||||
ok(_.isEqual({}, {}), "Empty object literals are equal");
|
||||
ok(_.isEqual([], []), "Empty array literals are equal");
|
||||
ok(_.isEqual([{}], [{}]), "Empty nested arrays and objects are equal");
|
||||
ok(!_.isEqual({length: 0}, []), "Array-like objects and arrays are not equal.");
|
||||
ok(!_.isEqual([], {length: 0}), "Commutative equality is implemented for array-like objects");
|
||||
|
||||
ok(!_.isEqual({}, []), "Object literals and array literals are not equal");
|
||||
ok(!_.isEqual([], {}), "Commutative equality is implemented for objects and arrays");
|
||||
|
||||
// Arrays with primitive and object values.
|
||||
ok(_.isEqual([1, "Larry", true], [1, "Larry", true]), "Arrays containing identical primitives are equal");
|
||||
ok(_.isEqual([(/Moe/g), new Date(2009, 9, 25)], [(/Moe/g), new Date(2009, 9, 25)]), "Arrays containing equivalent elements are equal");
|
||||
|
||||
// Multi-dimensional arrays.
|
||||
var a = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
|
||||
var b = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
|
||||
ok(_.isEqual(a, b), "Arrays containing nested arrays and objects are recursively compared");
|
||||
|
||||
// Overwrite the methods defined in ES 5.1 section 15.4.4.
|
||||
a.forEach = a.map = a.filter = a.every = a.indexOf = a.lastIndexOf = a.some = a.reduce = a.reduceRight = null;
|
||||
b.join = b.pop = b.reverse = b.shift = b.slice = b.splice = b.concat = b.sort = b.unshift = null;
|
||||
|
||||
// Array elements and properties.
|
||||
ok(_.isEqual(a, b), "Arrays containing equivalent elements and different non-numeric properties are equal");
|
||||
a.push("White Rocks");
|
||||
ok(!_.isEqual(a, b), "Arrays of different lengths are not equal");
|
||||
a.push("East Boulder");
|
||||
b.push("Gunbarrel Ranch", "Teller Farm");
|
||||
ok(!_.isEqual(a, b), "Arrays of identical lengths containing different elements are not equal");
|
||||
|
||||
// Sparse arrays.
|
||||
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");
|
||||
ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), "Objects of identical sizes with different values are not equal");
|
||||
ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), "Objects of identical sizes with different property names are not equal");
|
||||
ok(!_.isEqual({a: 1, b: 2}, {a: 1}), "Objects of different sizes are not equal");
|
||||
ok(!_.isEqual({a: 1}, {a: 1, b: 2}), "Commutative equality is implemented for objects");
|
||||
ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), "Objects with identical keys and different values are not equivalent");
|
||||
|
||||
// `A` contains nested objects and arrays.
|
||||
a = {
|
||||
name: new String("Moe Howard"),
|
||||
age: new Number(77),
|
||||
stooge: true,
|
||||
hobbies: ["acting"],
|
||||
film: {
|
||||
name: "Sing a Song of Six Pants",
|
||||
release: new Date(1947, 9, 30),
|
||||
stars: [new String("Larry Fine"), "Shemp Howard"],
|
||||
minutes: new Number(16),
|
||||
seconds: 54
|
||||
}
|
||||
};
|
||||
|
||||
// `B` contains equivalent nested objects and arrays.
|
||||
b = {
|
||||
name: new String("Moe Howard"),
|
||||
age: new Number(77),
|
||||
stooge: true,
|
||||
hobbies: ["acting"],
|
||||
film: {
|
||||
name: "Sing a Song of Six Pants",
|
||||
release: new Date(1947, 9, 30),
|
||||
stars: [new String("Larry Fine"), "Shemp Howard"],
|
||||
minutes: new Number(16),
|
||||
seconds: 54
|
||||
}
|
||||
};
|
||||
ok(_.isEqual(a, b), "Objects with nested equivalent members are recursively compared");
|
||||
|
||||
// Instances.
|
||||
ok(_.isEqual(new First, new First), "Object instances are equal");
|
||||
ok(!_.isEqual(new First, new Second), "Objects with different constructors and identical own properties are not equal");
|
||||
ok(!_.isEqual({value: 1}, new First), "Object instances and objects sharing equivalent properties are not equal");
|
||||
ok(!_.isEqual({value: 2}, new Second), "The prototype chain of objects should not be examined");
|
||||
|
||||
// Circular Arrays.
|
||||
(a = []).push(a);
|
||||
(b = []).push(b);
|
||||
ok(_.isEqual(a, b), "Arrays containing circular references are equal");
|
||||
a.push(new String("Larry"));
|
||||
b.push(new String("Larry"));
|
||||
ok(_.isEqual(a, b), "Arrays containing circular references and equivalent properties are equal");
|
||||
a.push("Shemp");
|
||||
b.push("Curly");
|
||||
ok(!_.isEqual(a, b), "Arrays containing circular references and different properties are not equal");
|
||||
|
||||
// Circular Objects.
|
||||
a = {abc: null};
|
||||
b = {abc: null};
|
||||
a.abc = a;
|
||||
b.abc = b;
|
||||
ok(_.isEqual(a, b), "Objects containing circular references are equal");
|
||||
a.def = 75;
|
||||
b.def = 75;
|
||||
ok(_.isEqual(a, b), "Objects containing circular references and equivalent properties are equal");
|
||||
a.def = new Number(75);
|
||||
b.def = new Number(63);
|
||||
ok(!_.isEqual(a, b), "Objects containing circular references and different properties are not equal");
|
||||
|
||||
// Cyclic Structures.
|
||||
a = [{abc: null}];
|
||||
b = [{abc: null}];
|
||||
(a[0].abc = a).push(a);
|
||||
(b[0].abc = b).push(b);
|
||||
ok(_.isEqual(a, b), "Cyclic structures are equal");
|
||||
a[0].def = "Larry";
|
||||
b[0].def = "Larry";
|
||||
ok(_.isEqual(a, b), "Cyclic structures containing equivalent properties are equal");
|
||||
a[0].def = new String("Larry");
|
||||
b[0].def = new String("Curly");
|
||||
ok(!_.isEqual(a, b), "Cyclic structures containing different properties are not equal");
|
||||
|
||||
// Complex Circular References.
|
||||
a = {foo: {b: {foo: {c: {foo: null}}}}};
|
||||
b = {foo: {b: {foo: {c: {foo: null}}}}};
|
||||
a.foo.b.foo.c.foo = a;
|
||||
b.foo.b.foo.c.foo = b;
|
||||
ok(_.isEqual(a, b), "Cyclic structures with nested and identically-named properties are equal");
|
||||
|
||||
// Chaining.
|
||||
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal');
|
||||
equal(_({x: 1, y: 2}).chain().isEqual(_({x: 1, y: 2}).chain()).value(), true, '`isEqual` can be chained');
|
||||
|
||||
// Custom `isEqual` methods.
|
||||
var isEqualObj = {isEqual: function (o) { return o.isEqual == this.isEqual; }, unique: {}};
|
||||
var isEqualObjClone = {isEqual: isEqualObj.isEqual, unique: {}};
|
||||
|
||||
ok(_.isEqual(isEqualObj, isEqualObjClone), 'Both objects implement identical `isEqual` methods');
|
||||
ok(_.isEqual(isEqualObjClone, isEqualObj), 'Commutative equality is implemented for objects with custom `isEqual` methods');
|
||||
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');
|
||||
});
|
||||
|
||||
test("objects: isEmpty", function() {
|
||||
ok(!_([1]).isEmpty(), '[1] is not empty');
|
||||
ok(_.isEmpty([]), '[] is empty');
|
||||
ok(!_.isEmpty({one : 1}), '{one : 1} is not empty');
|
||||
ok(_.isEmpty({}), '{} is empty');
|
||||
ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty');
|
||||
ok(_.isEmpty(null), 'null is empty');
|
||||
ok(_.isEmpty(), 'undefined is empty');
|
||||
ok(_.isEmpty(''), 'the empty string is empty');
|
||||
ok(!_.isEmpty('moe'), 'but other strings are not');
|
||||
|
||||
var obj = {one : 1};
|
||||
delete obj.one;
|
||||
ok(_.isEmpty(obj), 'deleting all the keys from an object empties it');
|
||||
});
|
||||
|
||||
// Setup remote variables for iFrame tests.
|
||||
var iframe = document.createElement('iframe');
|
||||
jQuery(iframe).appendTo(document.body);
|
||||
var iDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
iDoc.write(
|
||||
"<script>\
|
||||
parent.iElement = document.createElement('div');\
|
||||
parent.iArguments = (function(){ return arguments; })(1, 2, 3);\
|
||||
parent.iArray = [1, 2, 3];\
|
||||
parent.iString = new String('hello');\
|
||||
parent.iNumber = new Number(100);\
|
||||
parent.iFunction = (function(){});\
|
||||
parent.iDate = new Date();\
|
||||
parent.iRegExp = /hi/;\
|
||||
parent.iNaN = NaN;\
|
||||
parent.iNull = null;\
|
||||
parent.iBoolean = new Boolean(false);\
|
||||
parent.iUndefined = undefined;\
|
||||
</script>"
|
||||
);
|
||||
iDoc.close();
|
||||
|
||||
test("objects: isElement", function() {
|
||||
ok(!_.isElement('div'), 'strings are not dom elements');
|
||||
ok(_.isElement($('html')[0]), 'the html tag is a DOM element');
|
||||
ok(_.isElement(iElement), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isArguments", function() {
|
||||
var args = (function(){ return arguments; })(1, 2, 3);
|
||||
ok(!_.isArguments('string'), 'a string is not an arguments object');
|
||||
ok(!_.isArguments(_.isArguments), 'a function is not an arguments object');
|
||||
ok(_.isArguments(args), 'but the arguments object is an arguments object');
|
||||
ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array');
|
||||
ok(!_.isArguments([1,2,3]), 'and not vanilla arrays.');
|
||||
ok(_.isArguments(iArguments), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isObject", function() {
|
||||
ok(_.isObject(arguments), 'the arguments object is object');
|
||||
ok(_.isObject([1, 2, 3]), 'and arrays');
|
||||
ok(_.isObject($('html')[0]), 'and DOM element');
|
||||
ok(_.isObject(iElement), 'even from another frame');
|
||||
ok(_.isObject(function () {}), 'and functions');
|
||||
ok(_.isObject(iFunction), 'even from another frame');
|
||||
ok(!_.isObject(null), 'but not null');
|
||||
ok(!_.isObject(undefined), 'and not undefined');
|
||||
ok(!_.isObject('string'), 'and not string');
|
||||
ok(!_.isObject(12), 'and not number');
|
||||
ok(!_.isObject(true), 'and not boolean');
|
||||
ok(_.isObject(new String('string')), 'but new String()');
|
||||
});
|
||||
|
||||
test("objects: isArray", function() {
|
||||
ok(!_.isArray(arguments), 'the arguments object is not an array');
|
||||
ok(_.isArray([1, 2, 3]), 'but arrays are');
|
||||
ok(_.isArray(iArray), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isString", function() {
|
||||
ok(!_.isString(document.body), 'the document body is not a string');
|
||||
ok(_.isString([1, 2, 3].join(', ')), 'but strings are');
|
||||
ok(_.isString(iString), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isNumber", function() {
|
||||
ok(!_.isNumber('string'), 'a string is not a number');
|
||||
ok(!_.isNumber(arguments), 'the arguments object is not a number');
|
||||
ok(!_.isNumber(undefined), 'undefined is not a number');
|
||||
ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are');
|
||||
ok(_.isNumber(NaN), 'NaN *is* a number');
|
||||
ok(_.isNumber(Infinity), 'Infinity is a number');
|
||||
ok(_.isNumber(iNumber), 'even from another frame');
|
||||
ok(!_.isNumber('1'), 'numeric strings are not numbers');
|
||||
});
|
||||
|
||||
test("objects: isBoolean", function() {
|
||||
ok(!_.isBoolean(2), 'a number is not a boolean');
|
||||
ok(!_.isBoolean("string"), 'a string is not a boolean');
|
||||
ok(!_.isBoolean("false"), 'the string "false" is not a boolean');
|
||||
ok(!_.isBoolean("true"), 'the string "true" is not a boolean');
|
||||
ok(!_.isBoolean(arguments), 'the arguments object is not a boolean');
|
||||
ok(!_.isBoolean(undefined), 'undefined is not a boolean');
|
||||
ok(!_.isBoolean(NaN), 'NaN is not a boolean');
|
||||
ok(!_.isBoolean(null), 'null is not a boolean');
|
||||
ok(_.isBoolean(true), 'but true is');
|
||||
ok(_.isBoolean(false), 'and so is false');
|
||||
ok(_.isBoolean(iBoolean), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isFunction", function() {
|
||||
ok(!_.isFunction([1, 2, 3]), 'arrays are not functions');
|
||||
ok(!_.isFunction('moe'), 'strings are not functions');
|
||||
ok(_.isFunction(_.isFunction), 'but functions are');
|
||||
ok(_.isFunction(iFunction), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isDate", function() {
|
||||
ok(!_.isDate(100), 'numbers are not dates');
|
||||
ok(!_.isDate({}), 'objects are not dates');
|
||||
ok(_.isDate(new Date()), 'but dates are');
|
||||
ok(_.isDate(iDate), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isRegExp", function() {
|
||||
ok(!_.isRegExp(_.identity), 'functions are not RegExps');
|
||||
ok(_.isRegExp(/identity/), 'but RegExps are');
|
||||
ok(_.isRegExp(iRegExp), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isFinite", function() {
|
||||
ok(!_.isFinite(undefined), 'undefined is not Finite');
|
||||
ok(!_.isFinite(null), 'null is not Finite');
|
||||
ok(!_.isFinite(NaN), 'NaN is not Finite');
|
||||
ok(!_.isFinite(Infinity), 'Infinity is not Finite');
|
||||
ok(!_.isFinite(-Infinity), '-Infinity is not Finite');
|
||||
ok(!_.isFinite('12'), 'Strings are not numbers');
|
||||
var obj = new Number(5);
|
||||
ok(_.isFinite(obj), 'Number instances can be finite');
|
||||
ok(_.isFinite(0), '0 is Finite');
|
||||
ok(_.isFinite(123), 'Ints are Finite');
|
||||
ok(_.isFinite(-12.44), 'Floats are Finite');
|
||||
});
|
||||
|
||||
test("objects: isNaN", function() {
|
||||
ok(!_.isNaN(undefined), 'undefined is not NaN');
|
||||
ok(!_.isNaN(null), 'null is not NaN');
|
||||
ok(!_.isNaN(0), '0 is not NaN');
|
||||
ok(_.isNaN(NaN), 'but NaN is');
|
||||
ok(_.isNaN(iNaN), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isNull", function() {
|
||||
ok(!_.isNull(undefined), 'undefined is not null');
|
||||
ok(!_.isNull(NaN), 'NaN is not null');
|
||||
ok(_.isNull(null), 'but null is');
|
||||
ok(_.isNull(iNull), 'even from another frame');
|
||||
});
|
||||
|
||||
test("objects: isUndefined", function() {
|
||||
ok(!_.isUndefined(1), 'numbers are defined');
|
||||
ok(!_.isUndefined(null), 'null is defined');
|
||||
ok(!_.isUndefined(false), 'false is defined');
|
||||
ok(!_.isUndefined(NaN), 'NaN is defined');
|
||||
ok(_.isUndefined(), 'nothing is undefined');
|
||||
ok(_.isUndefined(undefined), 'undefined is undefined');
|
||||
ok(_.isUndefined(iUndefined), 'even from another frame');
|
||||
});
|
||||
|
||||
if (window.ActiveXObject) {
|
||||
test("objects: IE host objects", function() {
|
||||
var xml = new ActiveXObject("Msxml2.DOMDocument.3.0");
|
||||
ok(!_.isNumber(xml));
|
||||
ok(!_.isBoolean(xml));
|
||||
ok(!_.isNaN(xml));
|
||||
ok(!_.isFunction(xml));
|
||||
ok(!_.isNull(xml));
|
||||
ok(!_.isUndefined(xml));
|
||||
});
|
||||
}
|
||||
|
||||
test("objects: tap", function() {
|
||||
var intercepted = null;
|
||||
var interceptor = function(obj) { intercepted = obj; };
|
||||
var returned = _.tap(1, interceptor);
|
||||
equal(intercepted, 1, "passes tapped object to interceptor");
|
||||
equal(returned, 1, "returns tapped object");
|
||||
|
||||
returned = _([1,2,3]).chain().
|
||||
map(function(n){ return n * 2; }).
|
||||
max().
|
||||
tap(interceptor).
|
||||
value();
|
||||
ok(returned == 6 && intercepted == 6, 'can use tapped objects in a chain');
|
||||
});
|
||||
});
|
||||
@@ -1,70 +0,0 @@
|
||||
(function() {
|
||||
|
||||
var numbers = [];
|
||||
for (var i=0; i<1000; i++) numbers.push(i);
|
||||
var objects = _.map(numbers, function(n){ return {num : n}; });
|
||||
var randomized = _.sortBy(numbers, function(){ return Math.random(); });
|
||||
|
||||
JSLitmus.test('_.each()', function() {
|
||||
var timesTwo = [];
|
||||
_.each(numbers, function(num){ timesTwo.push(num * 2); });
|
||||
return timesTwo;
|
||||
});
|
||||
|
||||
JSLitmus.test('_(list).each()', function() {
|
||||
var timesTwo = [];
|
||||
_(numbers).each(function(num){ timesTwo.push(num * 2); });
|
||||
return timesTwo;
|
||||
});
|
||||
|
||||
JSLitmus.test('jQuery.each()', function() {
|
||||
var timesTwo = [];
|
||||
jQuery.each(numbers, function(){ timesTwo.push(this * 2); });
|
||||
return timesTwo;
|
||||
});
|
||||
|
||||
JSLitmus.test('_.map()', function() {
|
||||
return _.map(objects, function(obj){ return obj.num; });
|
||||
});
|
||||
|
||||
JSLitmus.test('jQuery.map()', function() {
|
||||
return jQuery.map(objects, function(obj){ return obj.num; });
|
||||
});
|
||||
|
||||
JSLitmus.test('_.pluck()', function() {
|
||||
return _.pluck(objects, 'num');
|
||||
});
|
||||
|
||||
JSLitmus.test('_.uniq()', function() {
|
||||
return _.uniq(randomized);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.uniq() (sorted)', function() {
|
||||
return _.uniq(numbers, true);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.sortBy()', function() {
|
||||
return _.sortBy(numbers, function(num){ return -num; });
|
||||
});
|
||||
|
||||
JSLitmus.test('_.isEqual()', function() {
|
||||
return _.isEqual(numbers, randomized);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.keys()', function() {
|
||||
return _.keys(objects);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.values()', function() {
|
||||
return _.values(objects);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.intersect()', function() {
|
||||
return _.intersect(numbers, randomized);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.range()', function() {
|
||||
return _.range(1000);
|
||||
});
|
||||
|
||||
})();
|
||||
@@ -1,223 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
var templateSettings;
|
||||
|
||||
module("Utility", {
|
||||
|
||||
setup: function() {
|
||||
templateSettings = _.clone(_.templateSettings);
|
||||
},
|
||||
|
||||
teardown: function() {
|
||||
_.templateSettings = templateSettings;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
test("utility: noConflict", function() {
|
||||
var underscore = _.noConflict();
|
||||
ok(underscore.isUndefined(_), "The '_' variable has been returned to its previous state.");
|
||||
var intersection = underscore.intersect([-1, 0, 1, 2], [1, 2, 3, 4]);
|
||||
equal(intersection.join(', '), '1, 2', 'but the intersection function still works');
|
||||
window._ = underscore;
|
||||
});
|
||||
|
||||
test("utility: identity", function() {
|
||||
var moe = {name : 'moe'};
|
||||
equal(_.identity(moe), moe, 'moe is the same as his identity');
|
||||
});
|
||||
|
||||
test("utility: uniqueId", function() {
|
||||
var ids = [], i = 0;
|
||||
while(i++ < 100) ids.push(_.uniqueId());
|
||||
equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids');
|
||||
});
|
||||
|
||||
test("utility: times", function() {
|
||||
var vals = [];
|
||||
_.times(3, function (i) { vals.push(i); });
|
||||
ok(_.isEqual(vals, [0,1,2]), "is 0 indexed");
|
||||
//
|
||||
vals = [];
|
||||
_(3).times(function (i) { vals.push(i); });
|
||||
ok(_.isEqual(vals, [0,1,2]), "works as a wrapper");
|
||||
});
|
||||
|
||||
test("utility: mixin", function() {
|
||||
_.mixin({
|
||||
myReverse: function(string) {
|
||||
return string.split('').reverse().join('');
|
||||
}
|
||||
});
|
||||
equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _');
|
||||
equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper');
|
||||
});
|
||||
|
||||
test("utility: _.escape", function() {
|
||||
equal(_.escape("Curly & Moe"), "Curly & Moe");
|
||||
equal(_.escape("Curly & Moe"), "Curly &amp; Moe");
|
||||
});
|
||||
|
||||
test("utility: template", function() {
|
||||
var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");
|
||||
var result = basicTemplate({thing : 'This'});
|
||||
equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation');
|
||||
|
||||
var sansSemicolonTemplate = _.template("A <% this %> B");
|
||||
equal(sansSemicolonTemplate(), "A B");
|
||||
|
||||
var backslashTemplate = _.template("<%= thing %> is \\ridanculous");
|
||||
equal(backslashTemplate({thing: 'This'}), "This is \\ridanculous");
|
||||
|
||||
var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>');
|
||||
equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.');
|
||||
|
||||
var fancyTemplate = _.template("<ul><% \
|
||||
for (key in people) { \
|
||||
%><li><%= people[key] %></li><% } %></ul>");
|
||||
result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
|
||||
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
|
||||
|
||||
var escapedCharsInJavascriptTemplate = _.template("<ul><% _.each(numbers.split('\\n'), function(item) { %><li><%= item %></li><% }) %></ul>");
|
||||
result = escapedCharsInJavascriptTemplate({numbers: "one\ntwo\nthree\nfour"});
|
||||
equal(result, "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>", 'Can use escaped characters (e.g. \\n) in Javascript');
|
||||
|
||||
var namespaceCollisionTemplate = _.template("<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><div class=\"thumbnail\" rel=\"<%= p %>\"></div><% }); %>");
|
||||
result = namespaceCollisionTemplate({
|
||||
pageCount: 3,
|
||||
thumbnails: {
|
||||
1: "p1-thumbnail.gif",
|
||||
2: "p2-thumbnail.gif",
|
||||
3: "p3-thumbnail.gif"
|
||||
}
|
||||
});
|
||||
equal(result, "3 p3-thumbnail.gif <div class=\"thumbnail\" rel=\"p1-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p2-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p3-thumbnail.gif\"></div>");
|
||||
|
||||
var noInterpolateTemplate = _.template("<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
|
||||
result = noInterpolateTemplate();
|
||||
equal(result, "<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
|
||||
|
||||
var quoteTemplate = _.template("It's its, not it's");
|
||||
equal(quoteTemplate({}), "It's its, not it's");
|
||||
|
||||
var quoteInStatementAndBody = _.template("<%\
|
||||
if(foo == 'bar'){ \
|
||||
%>Statement quotes and 'quotes'.<% } %>");
|
||||
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
|
||||
|
||||
var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.');
|
||||
equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.');
|
||||
|
||||
var template = _.template("<i><%- value %></i>");
|
||||
var result = template({value: "<script>"});
|
||||
equal(result, '<i><script></i>');
|
||||
|
||||
var stooge = {
|
||||
name: "Moe",
|
||||
template: _.template("I'm <%= this.name %>")
|
||||
};
|
||||
equal(stooge.template(), "I'm Moe");
|
||||
|
||||
if (!$.browser.msie) {
|
||||
var fromHTML = _.template($('#template').html());
|
||||
equal(fromHTML({data : 12345}).replace(/\s/g, ''), '<li>24690</li>');
|
||||
}
|
||||
|
||||
_.templateSettings = {
|
||||
evaluate : /\{\{([\s\S]+?)\}\}/g,
|
||||
interpolate : /\{\{=([\s\S]+?)\}\}/g
|
||||
};
|
||||
|
||||
var custom = _.template("<ul>{{ for (key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>");
|
||||
result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
|
||||
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
|
||||
|
||||
var customQuote = _.template("It's its, not it's");
|
||||
equal(customQuote({}), "It's its, not it's");
|
||||
|
||||
var quoteInStatementAndBody = _.template("{{ if(foo == 'bar'){ }}Statement quotes and 'quotes'.{{ } }}");
|
||||
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
|
||||
|
||||
_.templateSettings = {
|
||||
evaluate : /<\?([\s\S]+?)\?>/g,
|
||||
interpolate : /<\?=([\s\S]+?)\?>/g
|
||||
};
|
||||
|
||||
var customWithSpecialChars = _.template("<ul><? for (key in people) { ?><li><?= people[key] ?></li><? } ?></ul>");
|
||||
result = customWithSpecialChars({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
|
||||
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
|
||||
|
||||
var customWithSpecialCharsQuote = _.template("It's its, not it's");
|
||||
equal(customWithSpecialCharsQuote({}), "It's its, not it's");
|
||||
|
||||
var quoteInStatementAndBody = _.template("<? if(foo == 'bar'){ ?>Statement quotes and 'quotes'.<? } ?>");
|
||||
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
|
||||
|
||||
_.templateSettings = {
|
||||
interpolate : /\{\{(.+?)\}\}/g
|
||||
};
|
||||
|
||||
var mustache = _.template("Hello {{planet}}!");
|
||||
equal(mustache({planet : "World"}), "Hello World!", "can mimic mustache.js");
|
||||
|
||||
var templateWithNull = _.template("a null undefined {{planet}}");
|
||||
equal(templateWithNull({planet : "world"}), "a null undefined world", "can handle missing escape and evaluate settings");
|
||||
});
|
||||
|
||||
test('_.template handles \\u2028 & \\u2029', function() {
|
||||
var tmpl = _.template('<p>\u2028<%= "\\u2028\\u2029" %>\u2029</p>');
|
||||
strictEqual(tmpl(), '<p>\u2028\u2028\u2029\u2029</p>');
|
||||
});
|
||||
|
||||
test('result calls functions and returns primitives', function() {
|
||||
var obj = {w: '', x: 'x', y: function(){ return this.x; }};
|
||||
strictEqual(_.result(obj, 'w'), '');
|
||||
strictEqual(_.result(obj, 'x'), 'x');
|
||||
strictEqual(_.result(obj, 'y'), 'x');
|
||||
strictEqual(_.result(obj, 'z'), undefined);
|
||||
strictEqual(_.result(null, 'x'), null);
|
||||
});
|
||||
|
||||
test('_.templateSettings.variable', function() {
|
||||
var s = '<%=data.x%>';
|
||||
var data = {x: 'x'};
|
||||
strictEqual(_.template(s, data, {variable: 'data'}), 'x')
|
||||
_.templateSettings.variable = 'data';
|
||||
strictEqual(_.template(s)(data), 'x')
|
||||
});
|
||||
|
||||
test('#547 - _.templateSettings is unchanged by custom settings.', function() {
|
||||
ok(!_.templateSettings.variable);
|
||||
_.template('', {}, {variable: 'x'});
|
||||
ok(!_.templateSettings.variable);
|
||||
});
|
||||
|
||||
test('#556 - undefined template variables.', function() {
|
||||
var template = _.template('<%=x%>');
|
||||
strictEqual(template({x: null}), '');
|
||||
strictEqual(template({x: undefined}), '');
|
||||
|
||||
var templateEscaped = _.template('<%-x%>');
|
||||
strictEqual(templateEscaped({x: null}), '');
|
||||
strictEqual(templateEscaped({x: undefined}), '');
|
||||
|
||||
var templateWithProperty = _.template('<%=x.foo%>');
|
||||
strictEqual(templateWithProperty({x: {} }), '');
|
||||
strictEqual(templateWithProperty({x: {} }), '');
|
||||
|
||||
var templateWithPropertyEscaped = _.template('<%-x.foo%>');
|
||||
strictEqual(templateWithPropertyEscaped({x: {} }), '');
|
||||
strictEqual(templateWithPropertyEscaped({x: {} }), '');
|
||||
});
|
||||
|
||||
test('interpolate evaluates code only once.', 2, function() {
|
||||
var count = 0;
|
||||
var template = _.template('<%= f() %>');
|
||||
template({f: function(){ ok(!(count++)); }});
|
||||
|
||||
var countEscaped = 0;
|
||||
var templateEscaped = _.template('<%- f() %>');
|
||||
templateEscaped({f: function(){ ok(!(countEscaped++)); }});
|
||||
});
|
||||
|
||||
});
|
||||
19
test/underscore/vendor/jquery.js
vendored
670
test/underscore/vendor/jslitmus.js
vendored
@@ -1,670 +0,0 @@
|
||||
// JSLitmus.js
|
||||
//
|
||||
// History:
|
||||
// 2008-10-27: Initial release
|
||||
// 2008-11-09: Account for iteration loop overhead
|
||||
// 2008-11-13: Added OS detection
|
||||
// 2009-02-25: Create tinyURL automatically, shift-click runs tests in reverse
|
||||
//
|
||||
// Copyright (c) 2008-2009, Robert Kieffer
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the
|
||||
// Software), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(function() {
|
||||
// Private methods and state
|
||||
|
||||
// Get platform info but don't go crazy trying to recognize everything
|
||||
// that's out there. This is just for the major platforms and OSes.
|
||||
var platform = 'unknown platform', ua = navigator.userAgent;
|
||||
|
||||
// Detect OS
|
||||
var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
|
||||
var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
|
||||
if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
|
||||
|
||||
// Detect browser
|
||||
var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
|
||||
|
||||
// Detect version
|
||||
var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
|
||||
var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
|
||||
var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
|
||||
|
||||
/**
|
||||
* A smattering of methods that are needed to implement the JSLitmus testbed.
|
||||
*/
|
||||
var jsl = {
|
||||
/**
|
||||
* Enhanced version of escape()
|
||||
*/
|
||||
escape: function(s) {
|
||||
s = s.replace(/,/g, '\\,');
|
||||
s = escape(s);
|
||||
s = s.replace(/\+/g, '%2b');
|
||||
s = s.replace(/ /g, '+');
|
||||
return s;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get an element by ID.
|
||||
*/
|
||||
$: function(id) {
|
||||
return document.getElementById(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Null function
|
||||
*/
|
||||
F: function() {},
|
||||
|
||||
/**
|
||||
* Set the status shown in the UI
|
||||
*/
|
||||
status: function(msg) {
|
||||
var el = jsl.$('jsl_status');
|
||||
if (el) el.innerHTML = msg || '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a number to an abbreviated string like, "15K" or "10M"
|
||||
*/
|
||||
toLabel: function(n) {
|
||||
if (n == Infinity) {
|
||||
return 'Infinity';
|
||||
} else if (n > 1e9) {
|
||||
n = Math.round(n/1e8);
|
||||
return n/10 + 'B';
|
||||
} else if (n > 1e6) {
|
||||
n = Math.round(n/1e5);
|
||||
return n/10 + 'M';
|
||||
} else if (n > 1e3) {
|
||||
n = Math.round(n/1e2);
|
||||
return n/10 + 'K';
|
||||
}
|
||||
return n;
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy properties from src to dst
|
||||
*/
|
||||
extend: function(dst, src) {
|
||||
for (var k in src) dst[k] = src[k]; return dst;
|
||||
},
|
||||
|
||||
/**
|
||||
* Like Array.join(), but for the key-value pairs in an object
|
||||
*/
|
||||
join: function(o, delimit1, delimit2) {
|
||||
if (o.join) return o.join(delimit1); // If it's an array
|
||||
var pairs = [];
|
||||
for (var k in o) pairs.push(k + delimit1 + o[k]);
|
||||
return pairs.join(delimit2);
|
||||
},
|
||||
|
||||
/**
|
||||
* Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
|
||||
*/
|
||||
indexOf: function(arr, o) {
|
||||
if (arr.indexOf) return arr.indexOf(o);
|
||||
for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test manages a single test (created with
|
||||
* JSLitmus.test())
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
var Test = function (name, f) {
|
||||
if (!f) throw new Error('Undefined test function');
|
||||
if (!(/function[^\(]*\(([^,\)]*)/).test(f.toString())) {
|
||||
throw new Error('"' + name + '" test: Test is not a valid Function object');
|
||||
}
|
||||
this.loopArg = RegExp.$1;
|
||||
this.name = name;
|
||||
this.f = f;
|
||||
};
|
||||
|
||||
jsl.extend(Test, /** @lends Test */ {
|
||||
/** Calibration tests for establishing iteration loop overhead */
|
||||
CALIBRATIONS: [
|
||||
new Test('calibrating loop', function(count) {while (count--);}),
|
||||
new Test('calibrating function', jsl.F)
|
||||
],
|
||||
|
||||
/**
|
||||
* Run calibration tests. Returns true if calibrations are not yet
|
||||
* complete (in which case calling code should run the tests yet again).
|
||||
* onCalibrated - Callback to invoke when calibrations have finished
|
||||
*/
|
||||
calibrate: function(onCalibrated) {
|
||||
for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
|
||||
var cal = Test.CALIBRATIONS[i];
|
||||
if (cal.running) return true;
|
||||
if (!cal.count) {
|
||||
cal.isCalibration = true;
|
||||
cal.onStop = onCalibrated;
|
||||
//cal.MIN_TIME = .1; // Do calibrations quickly
|
||||
cal.run(2e4);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
jsl.extend(Test.prototype, {/** @lends Test.prototype */
|
||||
/** Initial number of iterations */
|
||||
INIT_COUNT: 10,
|
||||
/** Max iterations allowed (i.e. used to detect bad looping functions) */
|
||||
MAX_COUNT: 1e9,
|
||||
/** Minimum time a test should take to get valid results (secs) */
|
||||
MIN_TIME: .5,
|
||||
|
||||
/** Callback invoked when test state changes */
|
||||
onChange: jsl.F,
|
||||
|
||||
/** Callback invoked when test is finished */
|
||||
onStop: jsl.F,
|
||||
|
||||
/**
|
||||
* Reset test state
|
||||
*/
|
||||
reset: function() {
|
||||
delete this.count;
|
||||
delete this.time;
|
||||
delete this.running;
|
||||
delete this.error;
|
||||
},
|
||||
|
||||
/**
|
||||
* Run the test (in a timeout). We use a timeout to make sure the browser
|
||||
* has a chance to finish rendering any UI changes we've made, like
|
||||
* updating the status message.
|
||||
*/
|
||||
run: function(count) {
|
||||
count = count || this.INIT_COUNT;
|
||||
jsl.status(this.name + ' x ' + count);
|
||||
this.running = true;
|
||||
var me = this;
|
||||
setTimeout(function() {me._run(count);}, 200);
|
||||
},
|
||||
|
||||
/**
|
||||
* The nuts and bolts code that actually runs a test
|
||||
*/
|
||||
_run: function(count) {
|
||||
var me = this;
|
||||
|
||||
// Make sure calibration tests have run
|
||||
if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
|
||||
this.error = null;
|
||||
|
||||
try {
|
||||
var start, f = this.f, now, i = count;
|
||||
|
||||
// Start the timer
|
||||
start = new Date();
|
||||
|
||||
// Now for the money shot. If this is a looping function ...
|
||||
if (this.loopArg) {
|
||||
// ... let it do the iteration itself
|
||||
f(count);
|
||||
} else {
|
||||
// ... otherwise do the iteration for it
|
||||
while (i--) f();
|
||||
}
|
||||
|
||||
// Get time test took (in secs)
|
||||
this.time = Math.max(1,new Date() - start)/1000;
|
||||
|
||||
// Store iteration count and per-operation time taken
|
||||
this.count = count;
|
||||
this.period = this.time/count;
|
||||
|
||||
// Do we need to do another run?
|
||||
this.running = this.time <= this.MIN_TIME;
|
||||
|
||||
// ... if so, compute how many times we should iterate
|
||||
if (this.running) {
|
||||
// Bump the count to the nearest power of 2
|
||||
var x = this.MIN_TIME/this.time;
|
||||
var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
|
||||
count *= pow;
|
||||
if (count > this.MAX_COUNT) {
|
||||
throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Exceptions are caught and displayed in the test UI
|
||||
this.reset();
|
||||
this.error = e;
|
||||
}
|
||||
|
||||
// Figure out what to do next
|
||||
if (this.running) {
|
||||
me.run(count);
|
||||
} else {
|
||||
jsl.status('');
|
||||
me.onStop(me);
|
||||
}
|
||||
|
||||
// Finish up
|
||||
this.onChange(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the number of operations per second for this test.
|
||||
*
|
||||
* @param normalize if true, iteration loop overhead taken into account
|
||||
*/
|
||||
getHz: function(/**Boolean*/ normalize) {
|
||||
var p = this.period;
|
||||
|
||||
// Adjust period based on the calibration test time
|
||||
if (normalize && !this.isCalibration) {
|
||||
var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
|
||||
|
||||
// If the period is within 20% of the calibration time, then zero the
|
||||
// it out
|
||||
p = p < cal.period*1.2 ? 0 : p - cal.period;
|
||||
}
|
||||
|
||||
return Math.round(1/p);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a friendly string describing the test
|
||||
*/
|
||||
toString: function() {
|
||||
return this.name + ' - ' + this.time/this.count + ' secs';
|
||||
}
|
||||
});
|
||||
|
||||
// CSS we need for the UI
|
||||
var STYLESHEET = '<style> \
|
||||
#jslitmus {font-family:sans-serif; font-size: 12px;} \
|
||||
#jslitmus a {text-decoration: none;} \
|
||||
#jslitmus a:hover {text-decoration: underline;} \
|
||||
#jsl_status { \
|
||||
margin-top: 10px; \
|
||||
font-size: 10px; \
|
||||
color: #888; \
|
||||
} \
|
||||
A IMG {border:none} \
|
||||
#test_results { \
|
||||
margin-top: 10px; \
|
||||
font-size: 12px; \
|
||||
font-family: sans-serif; \
|
||||
border-collapse: collapse; \
|
||||
border-spacing: 0px; \
|
||||
} \
|
||||
#test_results th, #test_results td { \
|
||||
border: solid 1px #ccc; \
|
||||
vertical-align: top; \
|
||||
padding: 3px; \
|
||||
} \
|
||||
#test_results th { \
|
||||
vertical-align: bottom; \
|
||||
background-color: #ccc; \
|
||||
padding: 1px; \
|
||||
font-size: 10px; \
|
||||
} \
|
||||
#test_results #test_platform { \
|
||||
color: #444; \
|
||||
text-align:center; \
|
||||
} \
|
||||
#test_results .test_row { \
|
||||
color: #006; \
|
||||
cursor: pointer; \
|
||||
} \
|
||||
#test_results .test_nonlooping { \
|
||||
border-left-style: dotted; \
|
||||
border-left-width: 2px; \
|
||||
} \
|
||||
#test_results .test_looping { \
|
||||
border-left-style: solid; \
|
||||
border-left-width: 2px; \
|
||||
} \
|
||||
#test_results .test_name {white-space: nowrap;} \
|
||||
#test_results .test_pending { \
|
||||
} \
|
||||
#test_results .test_running { \
|
||||
font-style: italic; \
|
||||
} \
|
||||
#test_results .test_done {} \
|
||||
#test_results .test_done { \
|
||||
text-align: right; \
|
||||
font-family: monospace; \
|
||||
} \
|
||||
#test_results .test_error {color: #600;} \
|
||||
#test_results .test_error .error_head {font-weight:bold;} \
|
||||
#test_results .test_error .error_body {font-size:85%;} \
|
||||
#test_results .test_row:hover td { \
|
||||
background-color: #ffc; \
|
||||
text-decoration: underline; \
|
||||
} \
|
||||
#chart { \
|
||||
margin: 10px 0px; \
|
||||
width: 250px; \
|
||||
} \
|
||||
#chart img { \
|
||||
border: solid 1px #ccc; \
|
||||
margin-bottom: 5px; \
|
||||
} \
|
||||
#chart #tiny_url { \
|
||||
height: 40px; \
|
||||
width: 250px; \
|
||||
} \
|
||||
#jslitmus_credit { \
|
||||
font-size: 10px; \
|
||||
color: #888; \
|
||||
margin-top: 8px; \
|
||||
} \
|
||||
</style>';
|
||||
|
||||
// HTML markup for the UI
|
||||
var MARKUP = '<div id="jslitmus"> \
|
||||
<button onclick="JSLitmus.runAll(event)">Run Tests</button> \
|
||||
<button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
|
||||
<br \> \
|
||||
<br \> \
|
||||
<input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
|
||||
<table id="test_results"> \
|
||||
<colgroup> \
|
||||
<col /> \
|
||||
<col width="100" /> \
|
||||
</colgroup> \
|
||||
<tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
|
||||
<tr><th>Test</th><th>Ops/sec</th></tr> \
|
||||
<tr id="test_row_template" class="test_row" style="display:none"> \
|
||||
<td class="test_name"></td> \
|
||||
<td class="test_result">Ready</td> \
|
||||
</tr> \
|
||||
</table> \
|
||||
<div id="jsl_status"></div> \
|
||||
<div id="chart" style="display:none"> \
|
||||
<a id="chart_link" target="_blank"><img id="chart_image"></a> \
|
||||
TinyURL (for chart): \
|
||||
<iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
|
||||
</div> \
|
||||
<a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
|
||||
</div>';
|
||||
|
||||
/**
|
||||
* The public API for creating and running tests
|
||||
*/
|
||||
window.JSLitmus = {
|
||||
/** The list of all tests that have been registered with JSLitmus.test */
|
||||
_tests: [],
|
||||
/** The queue of tests that need to be run */
|
||||
_queue: [],
|
||||
|
||||
/**
|
||||
* The parsed query parameters the current page URL. This is provided as a
|
||||
* convenience for test functions - it's not used by JSLitmus proper
|
||||
*/
|
||||
params: {},
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
_init: function() {
|
||||
// Parse query params into JSLitmus.params[] hash
|
||||
var match = (location + '').match(/([^?#]*)(#.*)?$/);
|
||||
if (match) {
|
||||
var pairs = match[1].split('&');
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
var pair = pairs[i].split('=');
|
||||
if (pair.length > 1) {
|
||||
var key = pair.shift();
|
||||
var value = pair.length > 1 ? pair.join('=') : pair[0];
|
||||
this.params[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the stylesheet. We have to do this here because IE
|
||||
// doesn't honor sheets written after the document has loaded.
|
||||
document.write(STYLESHEET);
|
||||
|
||||
// Setup the rest of the UI once the document is loaded
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('load', this._setup, false);
|
||||
} else if (document.addEventListener) {
|
||||
document.addEventListener('load', this._setup, false);
|
||||
} else if (window.attachEvent) {
|
||||
window.attachEvent('onload', this._setup);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set up the UI
|
||||
*/
|
||||
_setup: function() {
|
||||
var el = jsl.$('jslitmus_container');
|
||||
if (!el) document.body.appendChild(el = document.createElement('div'));
|
||||
|
||||
el.innerHTML = MARKUP;
|
||||
|
||||
// Render the UI for all our tests
|
||||
for (var i=0; i < JSLitmus._tests.length; i++)
|
||||
JSLitmus.renderTest(JSLitmus._tests[i]);
|
||||
},
|
||||
|
||||
/**
|
||||
* (Re)render all the test results
|
||||
*/
|
||||
renderAll: function() {
|
||||
for (var i = 0; i < JSLitmus._tests.length; i++)
|
||||
JSLitmus.renderTest(JSLitmus._tests[i]);
|
||||
JSLitmus.renderChart();
|
||||
},
|
||||
|
||||
/**
|
||||
* (Re)render the chart graphics
|
||||
*/
|
||||
renderChart: function() {
|
||||
var url = JSLitmus.chartUrl();
|
||||
jsl.$('chart_link').href = url;
|
||||
jsl.$('chart_image').src = url;
|
||||
jsl.$('chart').style.display = '';
|
||||
|
||||
// Update the tiny URL
|
||||
jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
|
||||
},
|
||||
|
||||
/**
|
||||
* (Re)render the results for a specific test
|
||||
*/
|
||||
renderTest: function(test) {
|
||||
// Make a new row if needed
|
||||
if (!test._row) {
|
||||
var trow = jsl.$('test_row_template');
|
||||
if (!trow) return;
|
||||
|
||||
test._row = trow.cloneNode(true);
|
||||
test._row.style.display = '';
|
||||
test._row.id = '';
|
||||
test._row.onclick = function() {JSLitmus._queueTest(test);};
|
||||
test._row.title = 'Run ' + test.name + ' test';
|
||||
trow.parentNode.appendChild(test._row);
|
||||
test._row.cells[0].innerHTML = test.name;
|
||||
}
|
||||
|
||||
var cell = test._row.cells[1];
|
||||
var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
|
||||
|
||||
if (test.error) {
|
||||
cns.push('test_error');
|
||||
cell.innerHTML =
|
||||
'<div class="error_head">' + test.error + '</div>' +
|
||||
'<ul class="error_body"><li>' +
|
||||
jsl.join(test.error, ': ', '</li><li>') +
|
||||
'</li></ul>';
|
||||
} else {
|
||||
if (test.running) {
|
||||
cns.push('test_running');
|
||||
cell.innerHTML = 'running';
|
||||
} else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
|
||||
cns.push('test_pending');
|
||||
cell.innerHTML = 'pending';
|
||||
} else if (test.count) {
|
||||
cns.push('test_done');
|
||||
var hz = test.getHz(jsl.$('test_normalize').checked);
|
||||
cell.innerHTML = hz != Infinity ? hz : '∞';
|
||||
} else {
|
||||
cell.innerHTML = 'ready';
|
||||
}
|
||||
}
|
||||
cell.className = cns.join(' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new test
|
||||
*/
|
||||
test: function(name, f) {
|
||||
// Create the Test object
|
||||
var test = new Test(name, f);
|
||||
JSLitmus._tests.push(test);
|
||||
|
||||
// Re-render if the test state changes
|
||||
test.onChange = JSLitmus.renderTest;
|
||||
|
||||
// Run the next test if this one finished
|
||||
test.onStop = function(test) {
|
||||
if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
|
||||
JSLitmus.currentTest = null;
|
||||
JSLitmus._nextTest();
|
||||
};
|
||||
|
||||
// Render the new test
|
||||
this.renderTest(test);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add all tests to the run queue
|
||||
*/
|
||||
runAll: function(e) {
|
||||
e = e || window.event;
|
||||
var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all tests from the run queue. The current test has to finish on
|
||||
* it's own though
|
||||
*/
|
||||
stop: function() {
|
||||
while (JSLitmus._queue.length) {
|
||||
var test = JSLitmus._queue.shift();
|
||||
JSLitmus.renderTest(test);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Run the next test in the run queue
|
||||
*/
|
||||
_nextTest: function() {
|
||||
if (!JSLitmus.currentTest) {
|
||||
var test = JSLitmus._queue.shift();
|
||||
if (test) {
|
||||
jsl.$('stop_button').disabled = false;
|
||||
JSLitmus.currentTest = test;
|
||||
test.run();
|
||||
JSLitmus.renderTest(test);
|
||||
if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
|
||||
} else {
|
||||
jsl.$('stop_button').disabled = true;
|
||||
JSLitmus.renderChart();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a test to the run queue
|
||||
*/
|
||||
_queueTest: function(test) {
|
||||
if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
|
||||
JSLitmus._queue.push(test);
|
||||
JSLitmus.renderTest(test);
|
||||
JSLitmus._nextTest();
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a Google Chart URL that shows the data for all tests
|
||||
*/
|
||||
chartUrl: function() {
|
||||
var n = JSLitmus._tests.length, markers = [], data = [];
|
||||
var d, min = 0, max = -1e10;
|
||||
var normalize = jsl.$('test_normalize').checked;
|
||||
|
||||
// Gather test data
|
||||
for (var i=0; i < JSLitmus._tests.length; i++) {
|
||||
var test = JSLitmus._tests[i];
|
||||
if (test.count) {
|
||||
var hz = test.getHz(normalize);
|
||||
var v = hz != Infinity ? hz : 0;
|
||||
data.push(v);
|
||||
markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
|
||||
markers.length + ',10');
|
||||
max = Math.max(v, max);
|
||||
}
|
||||
}
|
||||
if (markers.length <= 0) return null;
|
||||
|
||||
// Build chart title
|
||||
var title = document.getElementsByTagName('title');
|
||||
title = (title && title.length) ? title[0].innerHTML : null;
|
||||
var chart_title = [];
|
||||
if (title) chart_title.push(title);
|
||||
chart_title.push('Ops/sec (' + platform + ')');
|
||||
|
||||
// Build labels
|
||||
var labels = [jsl.toLabel(min), jsl.toLabel(max)];
|
||||
|
||||
var w = 250, bw = 15;
|
||||
var bs = 5;
|
||||
var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
|
||||
|
||||
var params = {
|
||||
chtt: escape(chart_title.join('|')),
|
||||
chts: '000000,10',
|
||||
cht: 'bhg', // chart type
|
||||
chd: 't:' + data.join(','), // data set
|
||||
chds: min + ',' + max, // max/min of data
|
||||
chxt: 'x', // label axes
|
||||
chxl: '0:|' + labels.join('|'), // labels
|
||||
chsp: '0,1',
|
||||
chm: markers.join('|'), // test names
|
||||
chbh: [bw, 0, bs].join(','), // bar widths
|
||||
// chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
|
||||
chs: w + 'x' + h
|
||||
};
|
||||
return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
|
||||
}
|
||||
};
|
||||
|
||||
JSLitmus._init();
|
||||
})();
|
||||
226
test/underscore/vendor/qunit.css
vendored
@@ -1,226 +0,0 @@
|
||||
/**
|
||||
* QUnit v1.2.0 - A JavaScript Unit Testing Framework
|
||||
*
|
||||
* http://docs.jquery.com/QUnit
|
||||
*
|
||||
* Copyright (c) 2011 John Resig, Jörn Zaefferer
|
||||
* Dual licensed under the MIT (MIT-LICENSE.txt)
|
||||
* or GPL (GPL-LICENSE.txt) licenses.
|
||||
*/
|
||||
|
||||
/** Font Family and Sizes */
|
||||
|
||||
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
|
||||
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
|
||||
#qunit-tests { font-size: smaller; }
|
||||
|
||||
|
||||
/** Resets */
|
||||
|
||||
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
/** Header */
|
||||
|
||||
#qunit-header {
|
||||
padding: 0.5em 0 0.5em 1em;
|
||||
|
||||
color: #8699a4;
|
||||
background-color: #0d3349;
|
||||
|
||||
font-size: 1.5em;
|
||||
line-height: 1em;
|
||||
font-weight: normal;
|
||||
|
||||
border-radius: 15px 15px 0 0;
|
||||
-moz-border-radius: 15px 15px 0 0;
|
||||
-webkit-border-top-right-radius: 15px;
|
||||
-webkit-border-top-left-radius: 15px;
|
||||
}
|
||||
|
||||
#qunit-header a {
|
||||
text-decoration: none;
|
||||
color: #c2ccd1;
|
||||
}
|
||||
|
||||
#qunit-header a:hover,
|
||||
#qunit-header a:focus {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#qunit-banner {
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar {
|
||||
padding: 0.5em 0 0.5em 2em;
|
||||
color: #5E740B;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#qunit-userAgent {
|
||||
padding: 0.5em 0 0.5em 2.5em;
|
||||
background-color: #2b81af;
|
||||
color: #fff;
|
||||
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
|
||||
}
|
||||
|
||||
|
||||
/** Tests: Pass/Fail */
|
||||
|
||||
#qunit-tests {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#qunit-tests li {
|
||||
padding: 0.4em 0.5em 0.4em 2.5em;
|
||||
border-bottom: 1px solid #fff;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#qunit-tests li strong {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#qunit-tests li a {
|
||||
padding: 0.5em;
|
||||
color: #c2ccd1;
|
||||
text-decoration: none;
|
||||
}
|
||||
#qunit-tests li a:hover,
|
||||
#qunit-tests li a:focus {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#qunit-tests ol {
|
||||
margin-top: 0.5em;
|
||||
padding: 0.5em;
|
||||
|
||||
background-color: #fff;
|
||||
|
||||
border-radius: 15px;
|
||||
-moz-border-radius: 15px;
|
||||
-webkit-border-radius: 15px;
|
||||
|
||||
box-shadow: inset 0px 2px 13px #999;
|
||||
-moz-box-shadow: inset 0px 2px 13px #999;
|
||||
-webkit-box-shadow: inset 0px 2px 13px #999;
|
||||
}
|
||||
|
||||
#qunit-tests table {
|
||||
border-collapse: collapse;
|
||||
margin-top: .2em;
|
||||
}
|
||||
|
||||
#qunit-tests th {
|
||||
text-align: right;
|
||||
vertical-align: top;
|
||||
padding: 0 .5em 0 0;
|
||||
}
|
||||
|
||||
#qunit-tests td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#qunit-tests pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#qunit-tests del {
|
||||
background-color: #e0f2be;
|
||||
color: #374e0c;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#qunit-tests ins {
|
||||
background-color: #ffcaca;
|
||||
color: #500;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*** Test Counts */
|
||||
|
||||
#qunit-tests b.counts { color: black; }
|
||||
#qunit-tests b.passed { color: #5E740B; }
|
||||
#qunit-tests b.failed { color: #710909; }
|
||||
|
||||
#qunit-tests li li {
|
||||
margin: 0.5em;
|
||||
padding: 0.4em 0.5em 0.4em 0.5em;
|
||||
background-color: #fff;
|
||||
border-bottom: none;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
/*** Passing Styles */
|
||||
|
||||
#qunit-tests li li.pass {
|
||||
color: #5E740B;
|
||||
background-color: #fff;
|
||||
border-left: 26px solid #C6E746;
|
||||
}
|
||||
|
||||
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
|
||||
#qunit-tests .pass .test-name { color: #366097; }
|
||||
|
||||
#qunit-tests .pass .test-actual,
|
||||
#qunit-tests .pass .test-expected { color: #999999; }
|
||||
|
||||
#qunit-banner.qunit-pass { background-color: #C6E746; }
|
||||
|
||||
/*** Failing Styles */
|
||||
|
||||
#qunit-tests li li.fail {
|
||||
color: #710909;
|
||||
background-color: #fff;
|
||||
border-left: 26px solid #EE5757;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#qunit-tests > li:last-child {
|
||||
border-radius: 0 0 15px 15px;
|
||||
-moz-border-radius: 0 0 15px 15px;
|
||||
-webkit-border-bottom-right-radius: 15px;
|
||||
-webkit-border-bottom-left-radius: 15px;
|
||||
}
|
||||
|
||||
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
|
||||
#qunit-tests .fail .test-name,
|
||||
#qunit-tests .fail .module-name { color: #000000; }
|
||||
|
||||
#qunit-tests .fail .test-actual { color: #EE5757; }
|
||||
#qunit-tests .fail .test-expected { color: green; }
|
||||
|
||||
#qunit-banner.qunit-fail { background-color: #EE5757; }
|
||||
|
||||
|
||||
/** Result */
|
||||
|
||||
#qunit-testresult {
|
||||
padding: 0.5em 0.5em 0.5em 2.5em;
|
||||
|
||||
color: #2b81af;
|
||||
background-color: #D2E0E6;
|
||||
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
|
||||
/** Fixture */
|
||||
|
||||
#qunit-fixture {
|
||||
position: absolute;
|
||||
top: -10000px;
|
||||
left: -10000px;
|
||||
}
|
||||
1597
test/underscore/vendor/qunit.js
vendored
1
vendor/backbone
vendored
Submodule
2
vendor/benchmark.js
vendored
2
vendor/docdown
vendored
1049
vendor/firebug-lite/changelog.txt
vendored
Normal file
30
vendor/firebug-lite/license.txt
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2007, Parakey Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of Parakey Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of Parakey Inc.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
BIN
vendor/firebug-lite/skin/xp/blank.gif
vendored
Normal file
|
After Width: | Height: | Size: 43 B |
BIN
vendor/firebug-lite/skin/xp/buttonBg.png
vendored
Normal file
|
After Width: | Height: | Size: 167 B |
BIN
vendor/firebug-lite/skin/xp/buttonBgHover.png
vendored
Normal file
|
After Width: | Height: | Size: 171 B |
331
vendor/firebug-lite/skin/xp/debugger.css
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
/* See license.txt for terms of usage */
|
||||
|
||||
.panelNode-script {
|
||||
overflow: hidden;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
|
||||
.scriptTooltip {
|
||||
position: fixed;
|
||||
z-index: 2147483647;
|
||||
padding: 2px 3px;
|
||||
border: 1px solid #CBE087;
|
||||
background: LightYellow;
|
||||
font-family: monospace;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
|
||||
.sourceBox {
|
||||
/* TODO: xxxpedro problem with sourceBox and scrolling elements */
|
||||
/*overflow: scroll; /* see issue 1479 */
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sourceRow {
|
||||
white-space: nowrap;
|
||||
-moz-user-select: text;
|
||||
}
|
||||
|
||||
.sourceRow.hovered {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
|
||||
.sourceLine {
|
||||
-moz-user-select: none;
|
||||
margin-right: 10px;
|
||||
border-right: 1px solid #CCCCCC;
|
||||
padding: 0px 4px 0 20px;
|
||||
background: #EEEEEE no-repeat 2px 0px;
|
||||
color: #888888;
|
||||
white-space: pre;
|
||||
font-family: monospace; /* see issue 2953 */
|
||||
}
|
||||
|
||||
.noteInToolTip { /* below sourceLine, so it overrides it */
|
||||
background-color: #FFD472;
|
||||
}
|
||||
|
||||
.useA11y .sourceBox .sourceViewport:focus .sourceLine {
|
||||
background-color: #FFFFC0;
|
||||
color: navy;
|
||||
border-right: 1px solid black;
|
||||
}
|
||||
|
||||
.useA11y .sourceBox .sourceViewport:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.a11y1emSize {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.useA11y .panelStatusLabel:focus {
|
||||
outline-offset: -2px !important;
|
||||
}
|
||||
|
||||
.sourceBox > .sourceRow > .sourceLine {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sourceLine:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sourceRowText {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.sourceRow[exe_line="true"] {
|
||||
outline: 1px solid #D9D9B6;
|
||||
margin-right: 1px;
|
||||
background-color: lightgoldenrodyellow;
|
||||
}
|
||||
|
||||
.sourceRow[executable="true"] > .sourceLine {
|
||||
content: "-";
|
||||
color: #4AA02C; /* Spring Green */
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sourceRow[exe_line="true"] > .sourceLine {
|
||||
background-image: url(chrome://firebug/skin/exe.png);
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.sourceRow[breakpoint="true"] > .sourceLine {
|
||||
background-image: url(chrome://firebug/skin/breakpoint.png);
|
||||
}
|
||||
|
||||
.sourceRow[breakpoint="true"][condition="true"] > .sourceLine {
|
||||
background-image: url(chrome://firebug/skin/breakpointCondition.png);
|
||||
}
|
||||
|
||||
.sourceRow[breakpoint="true"][disabledBreakpoint="true"] > .sourceLine {
|
||||
background-image: url(chrome://firebug/skin/breakpointDisabled.png);
|
||||
}
|
||||
|
||||
.sourceRow[breakpoint="true"][exe_line="true"] > .sourceLine {
|
||||
background-image: url(chrome://firebug/skin/breakpointExe.png);
|
||||
}
|
||||
|
||||
.sourceRow[breakpoint="true"][exe_line="true"][disabledBreakpoint="true"] > .sourceLine {
|
||||
background-image: url(chrome://firebug/skin/breakpointDisabledExe.png);
|
||||
}
|
||||
|
||||
.sourceLine.editing {
|
||||
background-image: url(chrome://firebug/skin/breakpoint.png);
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
|
||||
.conditionEditor {
|
||||
z-index: 2147483647;
|
||||
position: absolute;
|
||||
margin-top: 0;
|
||||
left: 2px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.conditionEditorInner {
|
||||
position: relative;
|
||||
top: -26px;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.conditionCaption {
|
||||
margin-bottom: 2px;
|
||||
font-family: Lucida Grande, sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
color: #226679;
|
||||
}
|
||||
|
||||
.conditionInput {
|
||||
width: 100%;
|
||||
border: 1px solid #0096C0;
|
||||
font-family: monospace;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.conditionEditorInner1 {
|
||||
padding-left: 37px;
|
||||
background: url(condBorders.png) repeat-y;
|
||||
}
|
||||
|
||||
.conditionEditorInner2 {
|
||||
padding-right: 25px;
|
||||
background: url(condBorders.png) repeat-y 100% 0;
|
||||
}
|
||||
|
||||
.conditionEditorTop1 {
|
||||
background: url(condCorners.png) no-repeat 100% 0;
|
||||
margin-left: 37px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.conditionEditorTop2 {
|
||||
position: relative;
|
||||
left: -37px;
|
||||
width: 37px;
|
||||
height: 35px;
|
||||
background: url(condCorners.png) no-repeat;
|
||||
}
|
||||
|
||||
.conditionEditorBottom1 {
|
||||
background: url(condCorners.png) no-repeat 100% 100%;
|
||||
margin-left: 37px;
|
||||
height: 33px;
|
||||
}
|
||||
|
||||
.conditionEditorBottom2 {
|
||||
position: relative; left: -37px;
|
||||
width: 37px;
|
||||
height: 33px;
|
||||
background: url(condCorners.png) no-repeat 0 100%;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.upsideDown {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.upsideDown .conditionEditorInner {
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
.upsideDown .conditionEditorInner1 {
|
||||
padding-left: 33px;
|
||||
background: url(condBordersUps.png) repeat-y;
|
||||
}
|
||||
|
||||
.upsideDown .conditionEditorInner2 {
|
||||
padding-right: 25px;
|
||||
background: url(condBordersUps.png) repeat-y 100% 0;
|
||||
}
|
||||
|
||||
.upsideDown .conditionEditorTop1 {
|
||||
background: url(condCornersUps.png) no-repeat 100% 0;
|
||||
margin-left: 33px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.upsideDown .conditionEditorTop2 {
|
||||
position: relative;
|
||||
left: -33px;
|
||||
width: 33px;
|
||||
height: 25px;
|
||||
background: url(condCornersUps.png) no-repeat;
|
||||
}
|
||||
|
||||
.upsideDown .conditionEditorBottom1 {
|
||||
background: url(condCornersUps.png) no-repeat 100% 100%;
|
||||
margin-left: 33px;
|
||||
height: 43px;
|
||||
}
|
||||
|
||||
.upsideDown .conditionEditorBottom2 {
|
||||
position: relative;
|
||||
left: -33px;
|
||||
width: 33px;
|
||||
height: 43px;
|
||||
background: url(condCornersUps.png) no-repeat 0 100%;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
|
||||
.breakpointsGroupListBox {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.breakpointBlockHead {
|
||||
position: relative;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.breakpointBlockHead > .checkbox {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.breakpointBlockHead > .objectLink-sourceLink {
|
||||
top: 4px;
|
||||
right: 20px;
|
||||
background-color: #FFFFFF; /* issue 3308 */
|
||||
}
|
||||
|
||||
.breakpointBlockHead > .closeButton {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.breakpointCheckbox {
|
||||
margin-top: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.breakpointName {
|
||||
margin-left: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.breakpointRow[aria-checked="false"] > .breakpointBlockHead > *,
|
||||
.breakpointRow[aria-checked="false"] > .breakpointCode {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.breakpointRow[aria-checked="false"] .breakpointCheckbox,
|
||||
.breakpointRow[aria-checked="false"] .objectLink-sourceLink,
|
||||
.breakpointRow[aria-checked="false"] .closeButton,
|
||||
.breakpointRow[aria-checked="false"] .breakpointMutationType {
|
||||
opacity: 1.0 !important;
|
||||
}
|
||||
|
||||
.breakpointCode {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
padding-left: 24px;
|
||||
padding-bottom: 2px;
|
||||
border-bottom: 1px solid #D7D7D7;
|
||||
font-family: monospace;
|
||||
color: DarkGreen;
|
||||
}
|
||||
|
||||
.breakpointCondition {
|
||||
white-space: nowrap;
|
||||
padding-left: 24px;
|
||||
padding-bottom: 2px;
|
||||
border-bottom: 1px solid #D7D7D7;
|
||||
font-family: monospace;
|
||||
color: Gray;
|
||||
}
|
||||
|
||||
.breakpointBlock-breakpoints > .groupHeader {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.breakpointBlock-monitors > .breakpointCode {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breakpointBlock-errorBreakpoints .breakpointCheckbox,
|
||||
.breakpointBlock-monitors .breakpointCheckbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.breakpointHeader {
|
||||
margin: 0 !important;
|
||||
border-top: none !important;
|
||||
}
|
||||
BIN
vendor/firebug-lite/skin/xp/detach.png
vendored
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
vendor/firebug-lite/skin/xp/detachHover.png
vendored
Normal file
|
After Width: | Height: | Size: 586 B |
BIN
vendor/firebug-lite/skin/xp/disable.gif
vendored
Normal file
|
After Width: | Height: | Size: 340 B |
BIN
vendor/firebug-lite/skin/xp/disable.png
vendored
Normal file
|
After Width: | Height: | Size: 543 B |
BIN
vendor/firebug-lite/skin/xp/disableHover.gif
vendored
Normal file
|
After Width: | Height: | Size: 344 B |
BIN
vendor/firebug-lite/skin/xp/disableHover.png
vendored
Normal file
|
After Width: | Height: | Size: 512 B |
BIN
vendor/firebug-lite/skin/xp/down.png
vendored
Normal file
|
After Width: | Height: | Size: 637 B |
BIN
vendor/firebug-lite/skin/xp/downActive.png
vendored
Normal file
|
After Width: | Height: | Size: 543 B |
BIN
vendor/firebug-lite/skin/xp/downHover.png
vendored
Normal file
|
After Width: | Height: | Size: 526 B |
BIN
vendor/firebug-lite/skin/xp/errorIcon-sm.png
vendored
Normal file
|
After Width: | Height: | Size: 447 B |
BIN
vendor/firebug-lite/skin/xp/errorIcon.gif
vendored
Normal file
|
After Width: | Height: | Size: 365 B |
BIN
vendor/firebug-lite/skin/xp/errorIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 457 B |
817
vendor/firebug-lite/skin/xp/firebug-1.3a2.css
vendored
Normal file
@@ -0,0 +1,817 @@
|
||||
.fbBtnPressed {
|
||||
background: #ECEBE3;
|
||||
padding: 3px 6px 2px 7px !important;
|
||||
margin: 1px 0 0 1px;
|
||||
_margin: 1px -1px 0 1px;
|
||||
border: 1px solid #ACA899 !important;
|
||||
border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;
|
||||
}
|
||||
|
||||
.fbToolbarButtons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fbStatusBarBox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
Error Popup
|
||||
*************************************************************************************************/
|
||||
#fbErrorPopup {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 19px;
|
||||
width: 75px;
|
||||
background: url(sprite.png) #f1f2ee 0 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
#fbErrorPopupContent {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 1px;
|
||||
height: 18px;
|
||||
width: 75px;
|
||||
_width: 74px;
|
||||
border-left: 1px solid #aca899;
|
||||
}
|
||||
|
||||
#fbErrorIndicator {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.fbBtnInspectActive {
|
||||
background: #aaa;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
General
|
||||
*************************************************************************************************/
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Lucida Grande, Tahoma, sans-serif;
|
||||
font-size: 11px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
Mini Chrome
|
||||
*************************************************************************************************/
|
||||
#fbMiniChrome {
|
||||
display: none;
|
||||
right: 0;
|
||||
height: 27px;
|
||||
background: url(sprite.png) #f1f2ee 0 0;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
#fbMiniContent {
|
||||
display: block;
|
||||
position: relative;
|
||||
left: -1px;
|
||||
right: 0;
|
||||
top: 1px;
|
||||
height: 25px;
|
||||
border-left: 1px solid #aca899;
|
||||
}
|
||||
|
||||
#fbToolbarSearch {
|
||||
float: right;
|
||||
border: 1px solid #ccc;
|
||||
margin: 0 5px 0 0;
|
||||
background: #fff url(search.png) no-repeat 4px 2px;
|
||||
padding-left: 20px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#fbToolbarErrors {
|
||||
float: right;
|
||||
margin: 1px 4px 0 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#fbLeftToolbarErrors {
|
||||
float: left;
|
||||
margin: 7px 0px 0 5px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.fbErrors {
|
||||
padding-left: 20px;
|
||||
height: 14px;
|
||||
background: url(errorIcon.png) no-repeat;
|
||||
color: #f00;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#fbMiniErrors {
|
||||
display: inline;
|
||||
display: none;
|
||||
float: right;
|
||||
margin: 5px 2px 0 5px;
|
||||
}
|
||||
|
||||
#fbMiniIcon {
|
||||
float: right;
|
||||
margin: 3px 4px 0;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
float: right;
|
||||
background: url(sprite.png) 0 -135px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
Master Layout
|
||||
*************************************************************************************************/
|
||||
#fbChrome {
|
||||
position: fixed;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#fbTop {
|
||||
height: 49px;
|
||||
}
|
||||
|
||||
#fbToolbar {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background: url(sprite.png) #f1f2ee 0 0;
|
||||
height: 27px;
|
||||
font-size: 11px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#fbPanelBarBox {
|
||||
top: 27px;
|
||||
position: absolute;
|
||||
z-index: 8;
|
||||
width: 100%;
|
||||
background: url(sprite.png) #dbd9c9 0 -27px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
#fbContent {
|
||||
height: 100%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#fbBottom {
|
||||
height: 18px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
Sub-Layout
|
||||
*************************************************************************************************/
|
||||
|
||||
/* fbToolbar
|
||||
*************************************************************************************************/
|
||||
#fbToolbarIcon {
|
||||
float: left;
|
||||
padding: 4px 5px 0;
|
||||
}
|
||||
|
||||
#fbToolbarIcon a {
|
||||
display: block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: url(sprite.png) 0 -135px;
|
||||
text-decoration: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#fbToolbarButtons {
|
||||
float: left;
|
||||
padding: 4px 2px 0 5px;
|
||||
}
|
||||
|
||||
#fbToolbarButtons a {
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
float: left;
|
||||
color: #000;
|
||||
padding: 4px 8px 4px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#fbToolbarButtons a:hover {
|
||||
color: #333;
|
||||
padding: 3px 7px 3px;
|
||||
border: 1px solid #fff;
|
||||
border-bottom: 1px solid #bbb;
|
||||
border-right: 1px solid #bbb;
|
||||
}
|
||||
|
||||
#fbStatusBarBox {
|
||||
position: relative;
|
||||
top: 5px;
|
||||
line-height: 19px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.fbToolbarSeparator{
|
||||
overflow: hidden;
|
||||
border: 1px solid;
|
||||
border-color: transparent #fff transparent #777;
|
||||
_border-color: #eee #fff #eee #777;
|
||||
height: 7px;
|
||||
margin: 10px 6px 0 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.fbStatusBar span {
|
||||
color: #808080;
|
||||
padding: 0 4px 0 0;
|
||||
}
|
||||
|
||||
.fbStatusBar span a {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.fbStatusBar span a:hover {
|
||||
color: blue;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
#fbWindowButtons {
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 17px;
|
||||
_width: 50px;
|
||||
padding: 5px 0 5px 5px;
|
||||
z-index: 6;
|
||||
background: url(sprite.png) #f1f2ee 0 0;
|
||||
}
|
||||
|
||||
/* fbPanelBarBox
|
||||
*************************************************************************************************/
|
||||
|
||||
#fbPanelBar1 {
|
||||
width: 255px; /* fixed width to avoid tabs breaking line */
|
||||
z-index: 8;
|
||||
left: 0;
|
||||
white-space: nowrap;
|
||||
background: url(sprite.png) #dbd9c9 0 -27px;
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
#fbPanelBar2Box {
|
||||
background: url(sprite.png) #dbd9c9 0 -27px;
|
||||
position: absolute;
|
||||
height: 22px;
|
||||
width: 300px; /* fixed width to avoid tabs breaking line */
|
||||
z-index: 9;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#fbPanelBar2 {
|
||||
position: absolute;
|
||||
width: 290px; /* fixed width to avoid tabs breaking line */
|
||||
height: 22px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
/* body
|
||||
*************************************************************************************************/
|
||||
.fbPanel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fbPanelBox1, #fbPanelBox2 {
|
||||
max-height: inherit;
|
||||
height: 100%;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#fbPanelBox2 {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#fbPanelBox2 {
|
||||
width: 300px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#fbPanel2 {
|
||||
padding-left: 6px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.hide {
|
||||
overflow: hidden !important;
|
||||
position: fixed !important;
|
||||
display: none !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
/* fbBottom
|
||||
*************************************************************************************************/
|
||||
|
||||
#fbCommand {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
#fbCommandBox {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
z-index: 9;
|
||||
background: #fff;
|
||||
border: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
#fbCommandIcon {
|
||||
position: absolute;
|
||||
color: #00f;
|
||||
top: 2px;
|
||||
left: 7px;
|
||||
display: inline;
|
||||
font: 11px Monaco, monospace;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
#fbCommandLine {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 2px 0 2px 32px;
|
||||
font: 11px Monaco, monospace;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
div.fbFitHeight {
|
||||
overflow: auto;
|
||||
_position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
Layout Controls
|
||||
*************************************************************************************************/
|
||||
|
||||
/* fbToolbar buttons
|
||||
*************************************************************************************************/
|
||||
#fbWindowButtons a {
|
||||
font-size: 1px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: block;
|
||||
float: right;
|
||||
margin-right: 4px;
|
||||
text-decoration: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#fbWindow_btClose {
|
||||
background: url(sprite.png) 0 -119px;
|
||||
}
|
||||
|
||||
#fbWindow_btClose:hover {
|
||||
background: url(sprite.png) -16px -119px;
|
||||
}
|
||||
|
||||
#fbWindow_btDetach {
|
||||
background: url(sprite.png) -32px -119px;
|
||||
}
|
||||
|
||||
#fbWindow_btDetach:hover {
|
||||
background: url(sprite.png) -48px -119px;
|
||||
}
|
||||
|
||||
/* fbPanelBarBox tabs
|
||||
*************************************************************************************************/
|
||||
.fbTab {
|
||||
text-decoration: none;
|
||||
display: none;
|
||||
float: left;
|
||||
width: auto;
|
||||
float: left;
|
||||
cursor: default;
|
||||
font-family: Lucida Grande, Tahoma, sans-serif;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
height: 22px;
|
||||
color: #565656;
|
||||
}
|
||||
|
||||
.fbPanelBar span {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.fbPanelBar .fbTabL,.fbPanelBar .fbTabR {
|
||||
height: 22px;
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.fbPanelBar .fbTabText {
|
||||
padding: 4px 1px 0;
|
||||
}
|
||||
|
||||
a.fbTab:hover {
|
||||
background: url(sprite.png) 0 -73px;
|
||||
}
|
||||
|
||||
a.fbTab:hover .fbTabL {
|
||||
background: url(sprite.png) -16px -96px;
|
||||
}
|
||||
|
||||
a.fbTab:hover .fbTabR {
|
||||
background: url(sprite.png) -24px -96px;
|
||||
}
|
||||
|
||||
.fbSelectedTab {
|
||||
background: url(sprite.png) #f1f2ee 0 -50px !important;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.fbSelectedTab .fbTabL {
|
||||
background: url(sprite.png) 0 -96px !important;
|
||||
}
|
||||
|
||||
.fbSelectedTab .fbTabR {
|
||||
background: url(sprite.png) -8px -96px !important;
|
||||
}
|
||||
|
||||
/* splitters
|
||||
*************************************************************************************************/
|
||||
#fbHSplitter {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
overflow: hidden;
|
||||
cursor: n-resize !important;
|
||||
background: url(pixel_transparent.gif);
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
#fbHSplitter.fbOnMovingHSplitter {
|
||||
height: 100%;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.fbVSplitter {
|
||||
background: #ece9d8;
|
||||
color: #000;
|
||||
border: 1px solid #716f64;
|
||||
border-width: 0 1px;
|
||||
border-left-color: #aca899;
|
||||
width: 4px;
|
||||
cursor: e-resize;
|
||||
overflow: hidden;
|
||||
right: 294px;
|
||||
text-decoration: none;
|
||||
z-index: 9;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
top: 27px;
|
||||
_width: 6px;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
div.lineNo {
|
||||
font: 11px Monaco, monospace;
|
||||
float: left;
|
||||
display: inline;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0 5px 0 20px;
|
||||
background: #eee;
|
||||
color: #888;
|
||||
border-right: 1px solid #ccc;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
pre.nodeCode {
|
||||
font: 11px Monaco, monospace;
|
||||
margin: 0;
|
||||
padding-left: 10px;
|
||||
overflow: hidden;
|
||||
/*
|
||||
_width: 100%;
|
||||
/**/
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
.nodeControl {
|
||||
margin-top: 3px;
|
||||
margin-left: -14px;
|
||||
float: left;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
overflow: hidden;
|
||||
cursor: default;
|
||||
background: url(tree_open.gif);
|
||||
_float: none;
|
||||
_display: inline;
|
||||
_position: absolute;
|
||||
}
|
||||
|
||||
div.nodeMaximized {
|
||||
background: url(tree_close.gif);
|
||||
}
|
||||
|
||||
div.objectBox-element {
|
||||
padding: 1px 3px;
|
||||
}
|
||||
.objectBox-selector{
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.selectedElement{
|
||||
background: highlight;
|
||||
/* background: url(roundCorner.svg); Opera */
|
||||
color: #fff !important;
|
||||
}
|
||||
.selectedElement span{
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* Webkit CSS Hack - bug in "highlight" named color */
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
.selectedElement{
|
||||
background: #316AC5;
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
.logRow * {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.logRow {
|
||||
position: relative;
|
||||
border-bottom: 1px solid #D7D7D7;
|
||||
padding: 2px 4px 1px 6px;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.logRow-command {
|
||||
font-family: Monaco, monospace;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.objectBox-string,
|
||||
.objectBox-text,
|
||||
.objectBox-number,
|
||||
.objectBox-function,
|
||||
.objectLink-element,
|
||||
.objectLink-textNode,
|
||||
.objectLink-function,
|
||||
.objectBox-stackTrace,
|
||||
.objectLink-profile {
|
||||
font-family: Monaco, monospace;
|
||||
}
|
||||
|
||||
.objectBox-null {
|
||||
padding: 0 2px;
|
||||
border: 1px solid #666666;
|
||||
background-color: #888888;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.objectBox-string {
|
||||
color: red;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.objectBox-number {
|
||||
color: #000088;
|
||||
}
|
||||
|
||||
.objectBox-function {
|
||||
color: DarkGreen;
|
||||
}
|
||||
|
||||
.objectBox-object {
|
||||
color: DarkGreen;
|
||||
font-weight: bold;
|
||||
font-family: Lucida Grande, sans-serif;
|
||||
}
|
||||
|
||||
.objectBox-array {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
.logRow-info,.logRow-error,.logRow-warning {
|
||||
background: #fff no-repeat 2px 2px;
|
||||
padding-left: 20px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.logRow-info {
|
||||
background-image: url(infoIcon.png);
|
||||
}
|
||||
|
||||
.logRow-warning {
|
||||
background-color: cyan;
|
||||
background-image: url(warningIcon.png);
|
||||
}
|
||||
|
||||
.logRow-error {
|
||||
background-color: LightYellow;
|
||||
background-image: url(errorIcon.png);
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
vertical-align: top;
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
.objectBox-sourceLink {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 2px;
|
||||
padding-left: 8px;
|
||||
font-family: Lucida Grande, sans-serif;
|
||||
font-weight: bold;
|
||||
color: #0000FF;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
.logRow-group {
|
||||
background: #EEEEEE;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.logGroup {
|
||||
background: #EEEEEE;
|
||||
}
|
||||
|
||||
.logGroupBox {
|
||||
margin-left: 24px;
|
||||
border-top: 1px solid #D7D7D7;
|
||||
border-left: 1px solid #D7D7D7;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
.selectorTag,.selectorId,.selectorClass {
|
||||
font-family: Monaco, monospace;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.selectorTag {
|
||||
color: #0000FF;
|
||||
}
|
||||
|
||||
.selectorId {
|
||||
color: DarkBlue;
|
||||
}
|
||||
|
||||
.selectorClass {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
.objectBox-element {
|
||||
font-family: Monaco, monospace;
|
||||
color: #000088;
|
||||
}
|
||||
|
||||
.nodeChildren {
|
||||
padding-left: 26px;
|
||||
}
|
||||
|
||||
.nodeTag {
|
||||
color: blue;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nodeValue {
|
||||
color: #FF0000;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.nodeText,.nodeComment {
|
||||
margin: 0 2px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.nodeText {
|
||||
color: #333333;
|
||||
font-family: Monaco, monospace;
|
||||
}
|
||||
|
||||
.nodeComment {
|
||||
color: DarkGreen;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.nodeHidden, .nodeHidden * {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.nodeHidden .nodeTag {
|
||||
color: #5F82D9;
|
||||
}
|
||||
|
||||
.nodeHidden .nodeValue {
|
||||
color: #D86060;
|
||||
}
|
||||
|
||||
.selectedElement .nodeHidden, .selectedElement .nodeHidden * {
|
||||
color: SkyBlue !important;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************/
|
||||
.log-object {
|
||||
/*
|
||||
_position: relative;
|
||||
_height: 100%;
|
||||
/**/
|
||||
}
|
||||
|
||||
.property {
|
||||
position: relative;
|
||||
clear: both;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.propertyNameCell {
|
||||
vertical-align: top;
|
||||
float: left;
|
||||
width: 28%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.propertyValueCell {
|
||||
float: right;
|
||||
width: 68%;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
padding-left: 5px;
|
||||
display: table-cell;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
/*
|
||||
_position: relative;
|
||||
/**/
|
||||
}
|
||||
|
||||
.propertyName {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.FirebugPopup {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.FirebugPopup #fbWindowButtons {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.FirebugPopup #fbHSplitter {
|
||||
display: none !important;
|
||||
}
|
||||
20
vendor/firebug-lite/skin/xp/firebug.IE6.css
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/************************************************************************************************/
|
||||
#fbToolbarSearch {
|
||||
background-image: url(search.gif) !important;
|
||||
}
|
||||
/************************************************************************************************/
|
||||
.fbErrors {
|
||||
background-image: url(errorIcon.gif) !important;
|
||||
}
|
||||
/************************************************************************************************/
|
||||
.logRow-info {
|
||||
background-image: url(infoIcon.gif) !important;
|
||||
}
|
||||
|
||||
.logRow-warning {
|
||||
background-image: url(warningIcon.gif) !important;
|
||||
}
|
||||
|
||||
.logRow-error {
|
||||
background-image: url(errorIcon.gif) !important;
|
||||
}
|
||||
3147
vendor/firebug-lite/skin/xp/firebug.css
vendored
Normal file
215
vendor/firebug-lite/skin/xp/firebug.html
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/DTD/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Firebug Lite</title>
|
||||
<!-- An empty script to avoid FOUC when loading the stylesheet -->
|
||||
<script type="text/javascript"></script>
|
||||
<style type="text/css" media="screen">@import "firebug.css";</style>
|
||||
<style>html,body{margin:0;padding:0;overflow:hidden;}</style>
|
||||
</head>
|
||||
<body class="fbBody">
|
||||
<table id="fbChrome" cellpadding="0" cellspacing="0" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<!-- Interface - Top Area -->
|
||||
<td id="fbTop" colspan="2">
|
||||
|
||||
<!--
|
||||
<div>
|
||||
--><!-- <span id="fbToolbarErrors" class="fbErrors">2 errors</span> --><!--
|
||||
<input type="text" id="fbToolbarSearch" />
|
||||
</div>
|
||||
-->
|
||||
|
||||
<!-- Window Buttons -->
|
||||
<div id="fbWindowButtons">
|
||||
<a id="fbWindow_btDeactivate" class="fbSmallButton fbHover" title="Deactivate Firebug for this web page"> </a>
|
||||
<a id="fbWindow_btDetach" class="fbSmallButton fbHover" title="Open Firebug in popup window"> </a>
|
||||
<a id="fbWindow_btClose" class="fbSmallButton fbHover" title="Minimize Firebug"> </a>
|
||||
</div>
|
||||
|
||||
<!-- Toolbar buttons and Status Bar -->
|
||||
<div id="fbToolbar">
|
||||
<div id="fbToolbarContent">
|
||||
|
||||
<!-- Firebug Button -->
|
||||
<span id="fbToolbarIcon">
|
||||
<a id="fbFirebugButton" class="fbIconButton" class="fbHover" target="_blank"> </a>
|
||||
</span>
|
||||
|
||||
<!--
|
||||
<span id="fbLeftToolbarErrors" class="fbErrors">2 errors</span>
|
||||
-->
|
||||
|
||||
<!-- Toolbar Buttons -->
|
||||
<span id="fbToolbarButtons">
|
||||
<!-- Fixed Toolbar Buttons -->
|
||||
<span id="fbFixedButtons">
|
||||
<a id="fbChrome_btInspect" class="fbButton fbHover" title="Click an element in the page to inspect">Inspect</a>
|
||||
</span>
|
||||
|
||||
<!-- Console Panel Toolbar Buttons -->
|
||||
<span id="fbConsoleButtons" class="fbToolbarButtons">
|
||||
<a id="fbConsole_btClear" class="fbButton fbHover" title="Clear the console">Clear</a>
|
||||
</span>
|
||||
|
||||
<!-- HTML Panel Toolbar Buttons -->
|
||||
<!--
|
||||
<span id="fbHTMLButtons" class="fbToolbarButtons">
|
||||
<a id="fbHTML_btEdit" class="fbHover" title="Edit this HTML">Edit</a>
|
||||
</span>
|
||||
-->
|
||||
</span>
|
||||
|
||||
<!-- Status Bar -->
|
||||
<span id="fbStatusBarBox">
|
||||
<span class="fbToolbarSeparator"></span>
|
||||
<!-- HTML Panel Status Bar -->
|
||||
<!--
|
||||
<span id="fbHTMLStatusBar" class="fbStatusBar fbToolbarButtons">
|
||||
</span>
|
||||
-->
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- PanelBars -->
|
||||
<div id="fbPanelBarBox">
|
||||
|
||||
<!-- Main PanelBar -->
|
||||
<div id="fbPanelBar1" class="fbPanelBar">
|
||||
<a id="fbConsoleTab" class="fbTab fbHover">
|
||||
<span class="fbTabL"></span>
|
||||
<span class="fbTabText">Console</span>
|
||||
<span class="fbTabMenuTarget"></span>
|
||||
<span class="fbTabR"></span>
|
||||
</a>
|
||||
<a id="fbHTMLTab" class="fbTab fbHover">
|
||||
<span class="fbTabL"></span>
|
||||
<span class="fbTabText">HTML</span>
|
||||
<span class="fbTabR"></span>
|
||||
</a>
|
||||
<a class="fbTab fbHover">
|
||||
<span class="fbTabL"></span>
|
||||
<span class="fbTabText">CSS</span>
|
||||
<span class="fbTabR"></span>
|
||||
</a>
|
||||
<a class="fbTab fbHover">
|
||||
<span class="fbTabL"></span>
|
||||
<span class="fbTabText">Script</span>
|
||||
<span class="fbTabR"></span>
|
||||
</a>
|
||||
<a class="fbTab fbHover">
|
||||
<span class="fbTabL"></span>
|
||||
<span class="fbTabText">DOM</span>
|
||||
<span class="fbTabR"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Side PanelBars -->
|
||||
<div id="fbPanelBar2Box" class="hide">
|
||||
<div id="fbPanelBar2" class="fbPanelBar">
|
||||
<!--
|
||||
<a class="fbTab fbHover">
|
||||
<span class="fbTabL"></span>
|
||||
<span class="fbTabText">Style</span>
|
||||
<span class="fbTabR"></span>
|
||||
</a>
|
||||
<a class="fbTab fbHover">
|
||||
<span class="fbTabL"></span>
|
||||
<span class="fbTabText">Layout</span>
|
||||
<span class="fbTabR"></span>
|
||||
</a>
|
||||
<a class="fbTab fbHover">
|
||||
<span class="fbTabL"></span>
|
||||
<span class="fbTabText">DOM</span>
|
||||
<span class="fbTabR"></span>
|
||||
</a>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Horizontal Splitter -->
|
||||
<div id="fbHSplitter"> </div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Interface - Main Area -->
|
||||
<tr id="fbContent">
|
||||
|
||||
<!-- Panels -->
|
||||
<td id="fbPanelBox1">
|
||||
<div id="fbPanel1" class="fbFitHeight">
|
||||
<div id="fbConsole" class="fbPanel"></div>
|
||||
<div id="fbHTML" class="fbPanel"></div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Side Panel Box -->
|
||||
<td id="fbPanelBox2" class="hide">
|
||||
|
||||
<!-- VerticalSplitter -->
|
||||
<div id="fbVSplitter" class="fbVSplitter"> </div>
|
||||
|
||||
<!-- Side Panels -->
|
||||
<div id="fbPanel2" class="fbFitHeight">
|
||||
|
||||
<!-- HTML Side Panels -->
|
||||
<div id="fbHTML_Style" class="fbPanel"></div>
|
||||
<div id="fbHTML_Layout" class="fbPanel"></div>
|
||||
<div id="fbHTML_DOM" class="fbPanel"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Large Command Line -->
|
||||
<textarea id="fbLargeCommandLine" class="fbFitHeight"></textarea>
|
||||
|
||||
<!-- Large Command Line Buttons -->
|
||||
<div id="fbLargeCommandButtons">
|
||||
<a id="fbCommand_btRun" class="fbButton fbHover">Run</a>
|
||||
<a id="fbCommand_btClear" class="fbButton fbHover">Clear</a>
|
||||
|
||||
<a id="fbSmallCommandLineIcon" class="fbSmallButton fbHover"></a>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<!-- Interface - Bottom Area -->
|
||||
<tr id="fbBottom" class="hide">
|
||||
|
||||
<!-- Command Line -->
|
||||
<td id="fbCommand" colspan="2">
|
||||
<div id="fbCommandBox">
|
||||
<div id="fbCommandIcon">>>></div>
|
||||
<input id="fbCommandLine" name="fbCommandLine" type="text" />
|
||||
<a id="fbLargeCommandLineIcon" class="fbSmallButton fbHover"></a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<span id="fbMiniChrome">
|
||||
<span id="fbMiniContent">
|
||||
<span id="fbMiniIcon" title="Open Firebug Lite"></span>
|
||||
<span id="fbMiniErrors" class="fbErrors"><!-- 2 errors --></span>
|
||||
</span>
|
||||
</span>
|
||||
<!--
|
||||
<div id="fbErrorPopup">
|
||||
<div id="fbErrorPopupContent">
|
||||
<div id="fbErrorIndicator" class="fbErrors">2 errors</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
BIN
vendor/firebug-lite/skin/xp/firebug.png
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
vendor/firebug-lite/skin/xp/group.gif
vendored
Normal file
|
After Width: | Height: | Size: 158 B |
272
vendor/firebug-lite/skin/xp/html.css
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
/* See license.txt for terms of usage */
|
||||
|
||||
.panelNode-html {
|
||||
-moz-box-sizing: padding-box;
|
||||
padding: 4px 0 0 2px;
|
||||
}
|
||||
|
||||
.nodeBox {
|
||||
position: relative;
|
||||
font-family: Monaco, monospace;
|
||||
padding-left: 13px;
|
||||
-moz-user-select: -moz-none;
|
||||
}
|
||||
.nodeBox.search-selection {
|
||||
-moz-user-select: text;
|
||||
}
|
||||
.twisty {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.nodeChildBox {
|
||||
margin-left: 12px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nodeLabel,
|
||||
.nodeCloseLabel {
|
||||
margin: -2px 2px 0 2px;
|
||||
border: 2px solid transparent;
|
||||
-moz-border-radius: 3px;
|
||||
padding: 0 2px;
|
||||
color: #000088;
|
||||
}
|
||||
|
||||
.nodeCloseLabel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nodeTag {
|
||||
cursor: pointer;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.nodeValue {
|
||||
color: #FF0000;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.nodeText,
|
||||
.nodeComment {
|
||||
margin: 0 2px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.nodeText {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.nodeWhiteSpace {
|
||||
border: 1px solid LightGray;
|
||||
white-space: pre; /* otherwise the border will be collapsed around zero pixels */
|
||||
margin-left: 1px;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
|
||||
.nodeWhiteSpace_Space {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.nodeTextEntity {
|
||||
border: 1px solid gray;
|
||||
white-space: pre; /* otherwise the border will be collapsed around zero pixels */
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.nodeComment {
|
||||
color: DarkGreen;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.nodeBox.highlightOpen > .nodeLabel {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
|
||||
.nodeBox.highlightOpen > .nodeCloseLabel,
|
||||
.nodeBox.highlightOpen > .nodeChildBox,
|
||||
.nodeBox.open > .nodeCloseLabel,
|
||||
.nodeBox.open > .nodeChildBox {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
|
||||
.nodeBox.selected > .nodeLabel {
|
||||
border-color: Highlight;
|
||||
background-color: Highlight;
|
||||
color: HighlightText !important;
|
||||
}
|
||||
|
||||
.nodeBox.selected > .nodeLabel > .nodeLabelBox,
|
||||
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
|
||||
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
|
||||
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText {
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.nodeBox.highlighted > .nodeLabel {
|
||||
border-color: Highlight !important;
|
||||
background-color: cyan !important;
|
||||
color: #000000 !important;
|
||||
}
|
||||
|
||||
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox,
|
||||
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeTag,
|
||||
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
|
||||
.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeText {
|
||||
color: #000000 !important;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox,
|
||||
.nodeBox.nodeHidden .nodeCloseLabel,
|
||||
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeText,
|
||||
.nodeBox.nodeHidden .nodeText {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeTag,
|
||||
.nodeBox.nodeHidden .nodeCloseLabel > .nodeCloseLabelBox > .nodeTag {
|
||||
color: #5F82D9;
|
||||
}
|
||||
|
||||
.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue {
|
||||
color: #D86060;
|
||||
}
|
||||
|
||||
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox,
|
||||
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeTag,
|
||||
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue,
|
||||
.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeText {
|
||||
color: SkyBlue !important;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
.nodeBox.mutated > .nodeLabel,
|
||||
.nodeAttr.mutated,
|
||||
.nodeValue.mutated,
|
||||
.nodeText.mutated,
|
||||
.nodeBox.mutated > .nodeText {
|
||||
background-color: #EFFF79;
|
||||
color: #FF0000 !important;
|
||||
}
|
||||
|
||||
.nodeBox.selected.mutated > .nodeLabel,
|
||||
.nodeBox.selected.mutated > .nodeLabel > .nodeLabelBox,
|
||||
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr.mutated > .nodeValue,
|
||||
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue.mutated,
|
||||
.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText.mutated {
|
||||
background-color: #EFFF79;
|
||||
border-color: #EFFF79;
|
||||
color: #FF0000 !important;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
|
||||
.logRow-dirxml {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.soloElement > .nodeBox {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.useA11y .nodeLabel.focused {
|
||||
outline: 2px solid #FF9933;
|
||||
-moz-outline-radius: 3px;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.useA11y .nodeLabelBox:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
|
||||
.breakpointCode .twisty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.breakpointCode .nodeBox.containerNodeBox,
|
||||
.breakpointCode .nodeLabel {
|
||||
padding-left: 0px;
|
||||
margin-left: 0px;
|
||||
font-family: Monaco, monospace !important;
|
||||
}
|
||||
|
||||
.breakpointCode .nodeTag,
|
||||
.breakpointCode .nodeAttr,
|
||||
.breakpointCode .nodeText,
|
||||
.breakpointCode .nodeValue,
|
||||
.breakpointCode .nodeLabel {
|
||||
color: DarkGreen !important;
|
||||
}
|
||||
|
||||
.breakpointMutationType {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 20px;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
|
||||
|
||||
|
||||
/************************************************************************************************/
|
||||
/* Twisties */
|
||||
|
||||
.twisty,
|
||||
.logRow-errorMessage > .hasTwisty > .errorTitle,
|
||||
.logRow-log > .objectBox-array.hasTwisty,
|
||||
.logRow-spy .spyHead .spyTitle,
|
||||
.logGroup > .logRow,
|
||||
.memberRow.hasChildren > .memberLabelCell > .memberLabel,
|
||||
.hasHeaders .netHrefLabel,
|
||||
.netPageRow > .netCol > .netPageTitle {
|
||||
background-image: url(twistyClosed.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px 2px;
|
||||
min-height: 12px;
|
||||
}
|
||||
|
||||
.logRow-errorMessage > .hasTwisty.opened > .errorTitle,
|
||||
.logRow-log > .objectBox-array.hasTwisty.opened,
|
||||
.logRow-spy.opened .spyHead .spyTitle,
|
||||
.logGroup.opened > .logRow,
|
||||
.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,
|
||||
.nodeBox.highlightOpen > .nodeLabel > .twisty,
|
||||
.nodeBox.open > .nodeLabel > .twisty,
|
||||
.netRow.opened > .netCol > .netHrefLabel,
|
||||
.netPageRow.opened > .netCol > .netPageTitle {
|
||||
background-image: url(twistyOpen.png);
|
||||
}
|
||||
|
||||
.twisty {
|
||||
background-position: 4px 4px;
|
||||
}
|
||||
BIN
vendor/firebug-lite/skin/xp/infoIcon.gif
vendored
Normal file
|
After Width: | Height: | Size: 359 B |
BIN
vendor/firebug-lite/skin/xp/infoIcon.png
vendored
Normal file
|
After Width: | Height: | Size: 524 B |
BIN
vendor/firebug-lite/skin/xp/loading_16.gif
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
vendor/firebug-lite/skin/xp/min.png
vendored
Normal file
|
After Width: | Height: | Size: 552 B |
BIN
vendor/firebug-lite/skin/xp/minHover.png
vendored
Normal file
|
After Width: | Height: | Size: 485 B |
BIN
vendor/firebug-lite/skin/xp/off.png
vendored
Normal file
|
After Width: | Height: | Size: 742 B |
BIN
vendor/firebug-lite/skin/xp/offHover.png
vendored
Normal file
|
After Width: | Height: | Size: 680 B |
BIN
vendor/firebug-lite/skin/xp/pixel_transparent.gif
vendored
Normal file
|
After Width: | Height: | Size: 43 B |
6
vendor/firebug-lite/skin/xp/roundCorner.svg
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<rect fill="white" x="0" y="0" width="100%" height="100%" />
|
||||
<rect fill="highlight" x="0" y="0" width="100%" height="100%" rx="2px"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 234 B |
BIN
vendor/firebug-lite/skin/xp/search.gif
vendored
Normal file
|
After Width: | Height: | Size: 550 B |
BIN
vendor/firebug-lite/skin/xp/search.png
vendored
Normal file
|
After Width: | Height: | Size: 685 B |
BIN
vendor/firebug-lite/skin/xp/shadow.gif
vendored
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
vendor/firebug-lite/skin/xp/shadow2.gif
vendored
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
vendor/firebug-lite/skin/xp/shadowAlpha.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
vendor/firebug-lite/skin/xp/sprite.png
vendored
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
vendor/firebug-lite/skin/xp/tabHoverLeft.png
vendored
Normal file
|
After Width: | Height: | Size: 438 B |
BIN
vendor/firebug-lite/skin/xp/tabHoverMid.png
vendored
Normal file
|
After Width: | Height: | Size: 261 B |
BIN
vendor/firebug-lite/skin/xp/tabHoverRight.png
vendored
Normal file
|
After Width: | Height: | Size: 436 B |
BIN
vendor/firebug-lite/skin/xp/tabLeft.png
vendored
Normal file
|
After Width: | Height: | Size: 449 B |
BIN
vendor/firebug-lite/skin/xp/tabMenuCheckbox.png
vendored
Normal file
|
After Width: | Height: | Size: 220 B |
BIN
vendor/firebug-lite/skin/xp/tabMenuPin.png
vendored
Normal file
|
After Width: | Height: | Size: 207 B |
BIN
vendor/firebug-lite/skin/xp/tabMenuRadio.png
vendored
Normal file
|
After Width: | Height: | Size: 192 B |
BIN
vendor/firebug-lite/skin/xp/tabMenuTarget.png
vendored
Normal file
|
After Width: | Height: | Size: 142 B |
BIN
vendor/firebug-lite/skin/xp/tabMenuTargetHover.png
vendored
Normal file
|
After Width: | Height: | Size: 148 B |
BIN
vendor/firebug-lite/skin/xp/tabMid.png
vendored
Normal file
|
After Width: | Height: | Size: 262 B |
BIN
vendor/firebug-lite/skin/xp/tabRight.png
vendored
Normal file
|
After Width: | Height: | Size: 448 B |
BIN
vendor/firebug-lite/skin/xp/textEditorBorders.gif
vendored
Normal file
|
After Width: | Height: | Size: 117 B |
BIN
vendor/firebug-lite/skin/xp/textEditorBorders.png
vendored
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
vendor/firebug-lite/skin/xp/textEditorCorners.gif
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/firebug-lite/skin/xp/textEditorCorners.png
vendored
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
vendor/firebug-lite/skin/xp/titlebarMid.png
vendored
Normal file
|
After Width: | Height: | Size: 273 B |
BIN
vendor/firebug-lite/skin/xp/toolbarMid.png
vendored
Normal file
|
After Width: | Height: | Size: 242 B |
BIN
vendor/firebug-lite/skin/xp/tree_close.gif
vendored
Normal file
|
After Width: | Height: | Size: 300 B |
BIN
vendor/firebug-lite/skin/xp/tree_open.gif
vendored
Normal file
|
After Width: | Height: | Size: 202 B |
BIN
vendor/firebug-lite/skin/xp/twistyClosed.png
vendored
Normal file
|
After Width: | Height: | Size: 334 B |
BIN
vendor/firebug-lite/skin/xp/twistyOpen.png
vendored
Normal file
|
After Width: | Height: | Size: 309 B |
BIN
vendor/firebug-lite/skin/xp/up.png
vendored
Normal file
|
After Width: | Height: | Size: 619 B |
BIN
vendor/firebug-lite/skin/xp/upActive.png
vendored
Normal file
|
After Width: | Height: | Size: 551 B |
BIN
vendor/firebug-lite/skin/xp/upHover.png
vendored
Normal file
|
After Width: | Height: | Size: 526 B |