deku 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +5 -0
- data/LICENSE +25 -0
- data/README.md +28 -0
- data/Rakefile +1 -0
- data/deku.gemspec +23 -0
- data/deps/node_modules/deku.js +2 -0
- data/deps/node_modules/deku/.editorconfig +16 -0
- data/deps/node_modules/deku/.zuul.yml +15 -0
- data/deps/node_modules/deku/History.md +290 -0
- data/deps/node_modules/deku/LICENSE.md +7 -0
- data/deps/node_modules/deku/Makefile +91 -0
- data/deps/node_modules/deku/README.md +293 -0
- data/deps/node_modules/deku/index.js +4072 -0
- data/deps/node_modules/deku/lib/application.js +85 -0
- data/deps/node_modules/deku/lib/index.js +28 -0
- data/deps/node_modules/deku/lib/render.js +1300 -0
- data/deps/node_modules/deku/lib/stringify.js +105 -0
- data/deps/node_modules/deku/lib/svg.js +107 -0
- data/deps/node_modules/deku/lib/utils.js +18 -0
- data/deps/node_modules/deku/lib/virtual.js +247 -0
- data/deps/node_modules/deku/node_modules/array-flatten/LICENSE +21 -0
- data/deps/node_modules/deku/node_modules/array-flatten/README.md +43 -0
- data/deps/node_modules/deku/node_modules/array-flatten/array-flatten.js +57 -0
- data/deps/node_modules/deku/node_modules/array-flatten/package.json +62 -0
- data/deps/node_modules/deku/node_modules/component-emitter/History.md +63 -0
- data/deps/node_modules/deku/node_modules/component-emitter/LICENSE +24 -0
- data/deps/node_modules/deku/node_modules/component-emitter/Readme.md +74 -0
- data/deps/node_modules/deku/node_modules/component-emitter/index.js +161 -0
- data/deps/node_modules/deku/node_modules/component-emitter/package.json +174 -0
- data/deps/node_modules/deku/node_modules/component-raf/.npmignore +2 -0
- data/deps/node_modules/deku/node_modules/component-raf/History.md +26 -0
- data/deps/node_modules/deku/node_modules/component-raf/Makefile +11 -0
- data/deps/node_modules/deku/node_modules/component-raf/Readme.md +46 -0
- data/deps/node_modules/deku/node_modules/component-raf/component.json +16 -0
- data/deps/node_modules/deku/node_modules/component-raf/example.html +43 -0
- data/deps/node_modules/deku/node_modules/component-raf/index.js +34 -0
- data/deps/node_modules/deku/node_modules/component-raf/package.json +164 -0
- data/deps/node_modules/deku/node_modules/component-type/.npmignore +3 -0
- data/deps/node_modules/deku/node_modules/component-type/Makefile +14 -0
- data/deps/node_modules/deku/node_modules/component-type/Readme.md +37 -0
- data/deps/node_modules/deku/node_modules/component-type/component.json +13 -0
- data/deps/node_modules/deku/node_modules/component-type/index.js +34 -0
- data/deps/node_modules/deku/node_modules/component-type/package.json +120 -0
- data/deps/node_modules/deku/node_modules/component-type/test/index.html +17 -0
- data/deps/node_modules/deku/node_modules/component-type/test/mocha.css +231 -0
- data/deps/node_modules/deku/node_modules/component-type/test/mocha.js +5340 -0
- data/deps/node_modules/deku/node_modules/component-type/test/tests.js +72 -0
- data/deps/node_modules/deku/node_modules/dom-pool/.npmignore +1 -0
- data/deps/node_modules/deku/node_modules/dom-pool/Pool.js +52 -0
- data/deps/node_modules/deku/node_modules/dom-pool/README.md +42 -0
- data/deps/node_modules/deku/node_modules/dom-pool/authors.txt +4 -0
- data/deps/node_modules/deku/node_modules/dom-pool/bower.json +26 -0
- data/deps/node_modules/deku/node_modules/dom-pool/package.json +46 -0
- data/deps/node_modules/deku/node_modules/dom-pool/tests.html +16 -0
- data/deps/node_modules/deku/node_modules/dom-pool/tests.js +102 -0
- data/deps/node_modules/deku/node_modules/dom-walk/.npmignore +3 -0
- data/deps/node_modules/deku/node_modules/dom-walk/LICENCE +19 -0
- data/deps/node_modules/deku/node_modules/dom-walk/Makefile +2 -0
- data/deps/node_modules/deku/node_modules/dom-walk/README.md +23 -0
- data/deps/node_modules/deku/node_modules/dom-walk/example/index.js +5 -0
- data/deps/node_modules/deku/node_modules/dom-walk/example/static/bundle.js +211 -0
- data/deps/node_modules/deku/node_modules/dom-walk/example/static/index.html +16 -0
- data/deps/node_modules/deku/node_modules/dom-walk/index.js +24 -0
- data/deps/node_modules/deku/node_modules/dom-walk/package.json +57 -0
- data/deps/node_modules/deku/node_modules/fast.js/.jshintignore +7 -0
- data/deps/node_modules/deku/node_modules/fast.js/.jshintrc +80 -0
- data/deps/node_modules/deku/node_modules/fast.js/.npmignore +6 -0
- data/deps/node_modules/deku/node_modules/fast.js/.travis.yml +3 -0
- data/deps/node_modules/deku/node_modules/fast.js/LICENSE.md +21 -0
- data/deps/node_modules/deku/node_modules/fast.js/README.md +552 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/clone.js +21 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/concat.js +32 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/every.js +25 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/fill.js +29 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/filter.js +26 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/forEach.js +21 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/index.js +15 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/indexOf.js +33 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/lastIndexOf.js +29 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/map.js +24 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/pluck.js +24 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/reduce.js +35 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/reduceRight.js +35 -0
- data/deps/node_modules/deku/node_modules/fast.js/array/some.js +25 -0
- data/deps/node_modules/deku/node_modules/fast.js/bower.json +28 -0
- data/deps/node_modules/deku/node_modules/fast.js/clone.js +27 -0
- data/deps/node_modules/deku/node_modules/fast.js/dist/bench.html +15 -0
- data/deps/node_modules/deku/node_modules/fast.js/dist/bench.js +19900 -0
- data/deps/node_modules/deku/node_modules/fast.js/dist/fast.js +1450 -0
- data/deps/node_modules/deku/node_modules/fast.js/dist/fast.min.js +1 -0
- data/deps/node_modules/deku/node_modules/fast.js/filter.js +23 -0
- data/deps/node_modules/deku/node_modules/fast.js/forEach.js +22 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/apply.js +19 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/applyNoContext.js +29 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/applyWithContext.js +29 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/bind.js +71 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/bindInternal3.js +11 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/bindInternal4.js +11 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/index.js +7 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/partial.js +42 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/partialConstructor.js +45 -0
- data/deps/node_modules/deku/node_modules/fast.js/function/try.js +35 -0
- data/deps/node_modules/deku/node_modules/fast.js/index.js +241 -0
- data/deps/node_modules/deku/node_modules/fast.js/map.js +23 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/assign.js +34 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/clone.js +25 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/filter.js +28 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/forEach.js +23 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/index.js +11 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/keys.js +17 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/map.js +26 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/reduce.js +37 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/reduceRight.js +37 -0
- data/deps/node_modules/deku/node_modules/fast.js/object/values.js +20 -0
- data/deps/node_modules/deku/node_modules/fast.js/package.json +73 -0
- data/deps/node_modules/deku/node_modules/fast.js/reduce.js +24 -0
- data/deps/node_modules/deku/node_modules/fast.js/reduceRight.js +24 -0
- data/deps/node_modules/deku/node_modules/fast.js/string/index.js +3 -0
- data/deps/node_modules/deku/node_modules/fast.js/string/intern.js +56 -0
- data/deps/node_modules/deku/node_modules/get-uid/README.md +44 -0
- data/deps/node_modules/deku/node_modules/get-uid/index.js +6 -0
- data/deps/node_modules/deku/node_modules/get-uid/package.json +56 -0
- data/deps/node_modules/deku/node_modules/is-dom/HISTORY.md +2 -0
- data/deps/node_modules/deku/node_modules/is-dom/LICENSE +21 -0
- data/deps/node_modules/deku/node_modules/is-dom/README.md +32 -0
- data/deps/node_modules/deku/node_modules/is-dom/index.js +15 -0
- data/deps/node_modules/deku/node_modules/is-dom/package.json +62 -0
- data/deps/node_modules/deku/node_modules/object-path/.npmignore +7 -0
- data/deps/node_modules/deku/node_modules/object-path/.travis.yml +6 -0
- data/deps/node_modules/deku/node_modules/object-path/LICENSE +21 -0
- data/deps/node_modules/deku/node_modules/object-path/README.md +96 -0
- data/deps/node_modules/deku/node_modules/object-path/bower.json +17 -0
- data/deps/node_modules/deku/node_modules/object-path/component.json +22 -0
- data/deps/node_modules/deku/node_modules/object-path/index.js +269 -0
- data/deps/node_modules/deku/node_modules/object-path/package.json +89 -0
- data/deps/node_modules/deku/node_modules/object-path/test.js +510 -0
- data/deps/node_modules/deku/node_modules/per-frame/.npmignore +68 -0
- data/deps/node_modules/deku/node_modules/per-frame/History.md +32 -0
- data/deps/node_modules/deku/node_modules/per-frame/README.md +44 -0
- data/deps/node_modules/deku/node_modules/per-frame/component.json +13 -0
- data/deps/node_modules/deku/node_modules/per-frame/index.js +37 -0
- data/deps/node_modules/deku/node_modules/per-frame/package.json +143 -0
- data/deps/node_modules/deku/node_modules/per-frame/test/test.js +94 -0
- data/deps/node_modules/deku/node_modules/sliced/.npmignore +2 -0
- data/deps/node_modules/deku/node_modules/sliced/.travis.yml +4 -0
- data/deps/node_modules/deku/node_modules/sliced/History.md +30 -0
- data/deps/node_modules/deku/node_modules/sliced/LICENSE +22 -0
- data/deps/node_modules/deku/node_modules/sliced/Makefile +5 -0
- data/deps/node_modules/deku/node_modules/sliced/README.md +62 -0
- data/deps/node_modules/deku/node_modules/sliced/bench.js +95 -0
- data/deps/node_modules/deku/node_modules/sliced/component.json +14 -0
- data/deps/node_modules/deku/node_modules/sliced/index.js +1 -0
- data/deps/node_modules/deku/node_modules/sliced/lib/sliced.js +33 -0
- data/deps/node_modules/deku/node_modules/sliced/package.json +52 -0
- data/deps/node_modules/deku/node_modules/sliced/test/index.js +80 -0
- data/deps/node_modules/deku/package.json +67 -0
- data/lib/deku.rb +11 -0
- data/lib/deku/application.rb +16 -0
- data/lib/deku/component.rb +36 -0
- data/lib/deku/context.rb +38 -0
- data/lib/deku/element_node.rb +17 -0
- data/lib/deku/version.rb +4 -0
- metadata +278 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
The MIT License (MIT) Copyright (c) 2015 Anthony Short
|
|
2
|
+
|
|
3
|
+
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:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
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.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
|
|
2
|
+
#
|
|
3
|
+
# Binaries.
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
export PATH := ./node_modules/.bin:${PATH}
|
|
7
|
+
BIN := ./node_modules/.bin
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Wildcards.
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
lib = $(shell find lib/*.js)
|
|
14
|
+
js = $(shell find lib/*.js test/*.js)
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
# Default.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
default: index.js
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Targets.
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
build.js: node_modules $(js)
|
|
27
|
+
@browserify test/index.js -t babelify > build.js
|
|
28
|
+
|
|
29
|
+
tests.js: node_modules $(js)
|
|
30
|
+
@browserify test/index.js -t babelify | bfc > tests.js
|
|
31
|
+
|
|
32
|
+
index.js: node_modules $(js)
|
|
33
|
+
@browserify -s deku lib/index.js | bfc > index.js
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# Tests.
|
|
37
|
+
#
|
|
38
|
+
|
|
39
|
+
test: build.js
|
|
40
|
+
@$(BIN)/duo-test browser --commands 'make build.js'
|
|
41
|
+
|
|
42
|
+
test-phantom:
|
|
43
|
+
@$(BIN)/mochify --transform babelify --ui bdd ./test/index.js
|
|
44
|
+
.PHONY: test
|
|
45
|
+
|
|
46
|
+
test-cloud: tests.js
|
|
47
|
+
@TRAVIS_BUILD_NUMBER=$(CIRCLE_BUILD_NUM) zuul -- tests.js
|
|
48
|
+
|
|
49
|
+
test-lint: $(lib)
|
|
50
|
+
@$(BIN)/standard lib/*
|
|
51
|
+
.PHONY: test-lint
|
|
52
|
+
|
|
53
|
+
test-watch:
|
|
54
|
+
@$(BIN)/mochify --watch
|
|
55
|
+
.PHONY: watch
|
|
56
|
+
|
|
57
|
+
test-coverage:
|
|
58
|
+
@$(BIN)/mochify --cover
|
|
59
|
+
.PHONY: coverage
|
|
60
|
+
|
|
61
|
+
test-size: index.js
|
|
62
|
+
$(BIN)/minify index.js | gzip -9 | wc -c
|
|
63
|
+
.PHONY: test-size
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# Tasks.
|
|
67
|
+
#
|
|
68
|
+
|
|
69
|
+
node_modules: package.json
|
|
70
|
+
@npm install
|
|
71
|
+
|
|
72
|
+
clean:
|
|
73
|
+
@-rm -rf build.js index.js tests.js
|
|
74
|
+
.PHONY: clean
|
|
75
|
+
|
|
76
|
+
distclean: clean
|
|
77
|
+
@-rm -rf components node_modules
|
|
78
|
+
.PHONY: distclean
|
|
79
|
+
|
|
80
|
+
#
|
|
81
|
+
# Releases.
|
|
82
|
+
#
|
|
83
|
+
|
|
84
|
+
release: clean index.js
|
|
85
|
+
bump $$VERSION && \
|
|
86
|
+
git changelog --tag $$VERSION && \
|
|
87
|
+
git commit --all -m "Release $$VERSION" && \
|
|
88
|
+
git tag $$VERSION && \
|
|
89
|
+
git push origin master --tags && \
|
|
90
|
+
npm publish
|
|
91
|
+
.PHONY: release
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<br>
|
|
3
|
+
<img width="237" src="http://f.cl.ly/items/1s0T2Z3F2z190M1x1x1Y/deku-logo.png" alt="got">
|
|
4
|
+
<br>
|
|
5
|
+
<br>
|
|
6
|
+
<br>
|
|
7
|
+
</h1>
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/deku) [](https://circleci.com/gh/segmentio/deku) [](https://github.com/feross/standard)
|
|
10
|
+
|
|
11
|
+
A library for creating UI components using virtual DOM as an alternative to [React](https://github.com/facebook/react). Deku has a smaller footprint (~10kb), a functional API, and doesn't support legacy browsers.
|
|
12
|
+
|
|
13
|
+
To install:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
npm install deku
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
> You can also use Duo, Bower or [download the files manually](https://github.com/segmentio/deku/releases).
|
|
20
|
+
|
|
21
|
+
[Components](https://github.com/segmentio/deku/blob/master/docs/guides/components.md) are just plain objects that have a render function instead of using classes or constructors:
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
// button.js
|
|
25
|
+
let propTypes = {
|
|
26
|
+
kind: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
expects: ['submit', 'button']
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function render (component) {
|
|
33
|
+
let {props, state} = component
|
|
34
|
+
return <button class="Button" type={props.kind}>{props.children}</button>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function afterUpdate (component, prevProps, prevState, setState) {
|
|
38
|
+
let {props, state} = component
|
|
39
|
+
if (!state.clicked) {
|
|
40
|
+
setState({ clicked: true })
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default {propTypes, render, afterUpdate}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Components are then rendered by mounting it in a tree:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
import Button from './button'
|
|
51
|
+
import {tree,render,renderString} from 'deku'
|
|
52
|
+
|
|
53
|
+
let app = tree(
|
|
54
|
+
<Button kind="submit">Hello World!</Button>
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
render(app, document.body)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Trees can be rendered on the server too:
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
let str = renderString(app)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Docs
|
|
67
|
+
|
|
68
|
+
* [Installing](https://github.com/segmentio/deku/blob/master/docs/guides/install.md)
|
|
69
|
+
* [Component Spec](https://github.com/segmentio/deku/blob/master/docs/guides/components.md)
|
|
70
|
+
* [Using JSX](https://github.com/segmentio/deku/blob/master/docs/guides/jsx.md)
|
|
71
|
+
|
|
72
|
+
## Components
|
|
73
|
+
|
|
74
|
+
Each element of your UI can be broken into encapsulated components. These components manage the state for the UI element and tell it how to render. In Deku components are just plain objects:
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
function render (component) {
|
|
78
|
+
let {props, state} = component
|
|
79
|
+
return <button class="Button">{props.children}</button>
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default {render}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
There is no concept of classes or use of `this`. We can import this component using the standard module syntax:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
import Button from './button'
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
[Read more about components](https://github.com/segmentio/deku/blob/master/docs/guides/components.md)
|
|
92
|
+
|
|
93
|
+
## Rendering Components
|
|
94
|
+
|
|
95
|
+
To render this to the DOM we need to create a `tree`. This is one of the other main differences between React and Deku. The `tree` will manage loading data, communicating between components and allows us to use plugins on the entire application.
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
import {element,tree} from 'deku'
|
|
99
|
+
var app = tree(<Button>Hello World</Button>)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The `app` object has only a couple of methods:
|
|
103
|
+
|
|
104
|
+
* `.set(name, value)` to set environment data
|
|
105
|
+
* `.option(name, value)` to set rendering options
|
|
106
|
+
* `.mount(vnode)` to change the virtual element currently mounted
|
|
107
|
+
* `.use(fn)` to use a plugin. The function is called with the `app` object.
|
|
108
|
+
|
|
109
|
+
You can render this tree anyway you like, you just need a renderer for it. Let's use the DOM renderer for the client:
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import Button from './button'
|
|
113
|
+
import {element,tree,render} from 'deku'
|
|
114
|
+
|
|
115
|
+
var app = tree(<Button>Hello World</Button>)
|
|
116
|
+
render(app, document.body)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
And render the same thing to a string on the server:
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
import koa from 'koa'
|
|
123
|
+
import {element,tree,renderString} from 'deku'
|
|
124
|
+
|
|
125
|
+
let app = koa()
|
|
126
|
+
|
|
127
|
+
app.use(function *() {
|
|
128
|
+
this.body = renderString(tree(<Button>Hello World</Button>))
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
And you can isolate functionality by using plugins. These plugins can call `set` to add data to the tree that your components can then access through their props:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
app.use(analytics)
|
|
136
|
+
app.use(router)
|
|
137
|
+
app.use(api(writeKey))
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Composition
|
|
141
|
+
|
|
142
|
+
You can compose components easily by just requiring them and using them in the render function:
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
import Button from './button'
|
|
146
|
+
import Sheet from './sheet'
|
|
147
|
+
|
|
148
|
+
function render (component) {
|
|
149
|
+
return (
|
|
150
|
+
<div class="MyCoolApp">
|
|
151
|
+
<Sheet>
|
|
152
|
+
<Button style="danger">One</Button>
|
|
153
|
+
<Button style="happy">Two</Button>
|
|
154
|
+
</Sheet>
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Event handlers
|
|
161
|
+
|
|
162
|
+
Deku doesn't use any form of synthetic events because we can just capture every event in newer browsers. There are special attributes you can add to virtual elements that act as hooks to add event listeners:
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
function render (component) {
|
|
166
|
+
let {props, state} = component
|
|
167
|
+
return <button onClick={clicked}>{props.children}</button>
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function clicked () {
|
|
171
|
+
alert('You clicked it')
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
You can [view all event handlers](https://github.com/segmentio/deku/blob/master/lib/render.js#L25) in code.
|
|
176
|
+
|
|
177
|
+
## Lifecycle hooks
|
|
178
|
+
|
|
179
|
+
Just like the `render` function, component lifecycle hooks are just plain functions:
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
function afterUpdate (component, prevProps, prevState, setState) {
|
|
183
|
+
let {props, state} = component
|
|
184
|
+
if (!state.clicked) {
|
|
185
|
+
setState({ clicked: true })
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
We have hooks for `beforeMount`, `afterMount`, `beforeUpdate`, `afterUpdate`, `beforeUnmount` and two new hooks - `beforeRender` and `afterRender` that are called on every pass, unlike the update hooks. We've found that these extra hooks have allowed us to write cleaner code and worry less about the state of the component.
|
|
191
|
+
|
|
192
|
+
[Learn more about the lifecycle hooks](https://github.com/segmentio/deku/blob/master/docs/guides/components.md)
|
|
193
|
+
|
|
194
|
+
## Validation
|
|
195
|
+
|
|
196
|
+
You can validate the props sent to your component by defining a `propTypes` object:
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
let propTypes = {
|
|
200
|
+
style: {
|
|
201
|
+
type: 'string',
|
|
202
|
+
expects: ['submit', 'button']
|
|
203
|
+
},
|
|
204
|
+
danger: {
|
|
205
|
+
type: 'boolean',
|
|
206
|
+
optional: true
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
To enable validation you just need to enable it on the tree:
|
|
212
|
+
|
|
213
|
+
```js
|
|
214
|
+
app.option('validateProps', true)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
This is off by default and we've made it an option so that you can enable it just during development without needing a separate build.
|
|
218
|
+
|
|
219
|
+
Props can originate from anywhere in the outside world, it's useful to validate them. When validation is enabled you'll only be able to pass in props that are defined and they must conform to the `propTypes` spec.
|
|
220
|
+
|
|
221
|
+
## External data and communication
|
|
222
|
+
|
|
223
|
+
It's often useful for components to have access to data from the outside world without needing to pass it down through components. You can set data on your `tree` and components can ask for it using `propTypes`.
|
|
224
|
+
|
|
225
|
+
First we set some data on the app:
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
app.set('currentUser', {
|
|
229
|
+
id: 12435,
|
|
230
|
+
username: 'anthonyshort',
|
|
231
|
+
name: 'Anthony Short'
|
|
232
|
+
})
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Then in our components we define the prop using the `source` option:
|
|
236
|
+
|
|
237
|
+
```js
|
|
238
|
+
let propTypes = {
|
|
239
|
+
user: {
|
|
240
|
+
source: 'currentUser'
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Whenever we change that value in our app all components that depend on it will be re-rendered with the latest value. We use this pattern to pass functions down to interact with the API:
|
|
246
|
+
|
|
247
|
+
```js
|
|
248
|
+
app.set('updateProject', function (project, updates) {
|
|
249
|
+
api.projects.update(project, updates)
|
|
250
|
+
})
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Which the component can access using `props.updateProject`. Although it may not be as complex or optimized as Relay and GraphQL it's extremely simple and covers most use cases we've run into so far. We even use this pattern to treat the router as a data source:
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
router.on('/projects/:id', function (params) {
|
|
257
|
+
let project = api.projects.get(params.id)
|
|
258
|
+
app.set('currentRoute', {
|
|
259
|
+
name: 'view project',
|
|
260
|
+
project: project
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
This means we don't need to use some complex routing library. We just treat it like all other types of external data and components will render as needed.
|
|
266
|
+
|
|
267
|
+
## Keys
|
|
268
|
+
|
|
269
|
+
Sometimes when you're rendering a list of items you want them to be moved instead of trashed during the diff. Deku supports this using the `key` attribute on components:
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
function render (component) {
|
|
273
|
+
let {items} = component.props
|
|
274
|
+
let projects = items.map(function (project) {
|
|
275
|
+
return <ProjectItem key={project.id} project={project} />
|
|
276
|
+
})
|
|
277
|
+
return <div class="ProjectsList">{projects}</div>
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
At the moment we only support the `key` attribute on components for simplicity. Things become slightly more hairy when moving elements around within components. So far we haven't ran into a case where this has been a major problem.
|
|
282
|
+
|
|
283
|
+
## Tests
|
|
284
|
+
|
|
285
|
+
[](https://saucelabs.com/u/deku)
|
|
286
|
+
|
|
287
|
+
## Developing
|
|
288
|
+
|
|
289
|
+
Deku is built with Browserify. You can run the tests in a browser by running `make test`.
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
MIT. See [LICENSE.md](http://github.com/segmentio/deku/blob/master/LICENSE.md)
|
|
@@ -0,0 +1,4072 @@
|
|
|
1
|
+
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.deku=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof _require=="function"&&_require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof _require=="function"&&_require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_require,module,exports){
|
|
2
|
+
/**
|
|
3
|
+
* Module dependencies.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
var Emitter = _require('component-emitter')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Expose `scene`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
module.exports = Application
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create a new `Application`.
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} element Optional initial element
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function Application (element) {
|
|
21
|
+
if (!(this instanceof Application)) return new Application(element)
|
|
22
|
+
this.options = {}
|
|
23
|
+
this.sources = {}
|
|
24
|
+
this.element = element
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Mixin `Emitter`.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
Emitter(Application.prototype)
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Add a plugin
|
|
35
|
+
*
|
|
36
|
+
* @param {Function} plugin
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
Application.prototype.use = function (plugin) {
|
|
40
|
+
plugin(this)
|
|
41
|
+
return this
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Set an option
|
|
46
|
+
*
|
|
47
|
+
* @param {String} name
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
Application.prototype.option = function (name, val) {
|
|
51
|
+
this.options[name] = val
|
|
52
|
+
return this
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Set value used somewhere in the IO network.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
Application.prototype.set = function (name, data) {
|
|
60
|
+
this.sources[name] = data
|
|
61
|
+
this.emit('source', name, data)
|
|
62
|
+
return this
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Mount a virtual element.
|
|
67
|
+
*
|
|
68
|
+
* @param {VirtualElement} element
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
Application.prototype.mount = function (element) {
|
|
72
|
+
this.element = element
|
|
73
|
+
this.emit('mount', element)
|
|
74
|
+
return this
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Remove the world. Unmount everything.
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
Application.prototype.unmount = function () {
|
|
82
|
+
if (!this.element) return
|
|
83
|
+
this.element = null
|
|
84
|
+
this.emit('unmount')
|
|
85
|
+
return this
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
},{"component-emitter":9}],2:[function(_require,module,exports){
|
|
89
|
+
/**
|
|
90
|
+
* Create the application.
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
exports.tree =
|
|
94
|
+
exports.scene =
|
|
95
|
+
exports.deku = _require('./application')
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Render scenes to the DOM.
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
if (typeof document !== 'undefined') {
|
|
102
|
+
exports.render = _require('./render')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Render scenes to a string
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
exports.renderString = _require('./stringify')
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Create virtual elements.
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
exports.element =
|
|
116
|
+
exports.dom = _require('./virtual')
|
|
117
|
+
|
|
118
|
+
},{"./application":1,"./render":3,"./stringify":4,"./virtual":7}],3:[function(_require,module,exports){
|
|
119
|
+
/**
|
|
120
|
+
* Dependencies.
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
var raf = _require('component-raf')
|
|
124
|
+
var Pool = _require('dom-pool')
|
|
125
|
+
var walk = _require('dom-walk')
|
|
126
|
+
var isDom = _require('is-dom')
|
|
127
|
+
var uid = _require('get-uid')
|
|
128
|
+
var throttle = _require('per-frame')
|
|
129
|
+
var keypath = _require('object-path')
|
|
130
|
+
var type = _require('component-type')
|
|
131
|
+
var fast = _require('fast.js')
|
|
132
|
+
var utils = _require('./utils')
|
|
133
|
+
var svg = _require('./svg')
|
|
134
|
+
var defaults = utils.defaults
|
|
135
|
+
var forEach = fast.forEach
|
|
136
|
+
var assign = fast.assign
|
|
137
|
+
var reduce = fast.reduce
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* All of the events can bind to
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
var events = {
|
|
144
|
+
onBlur: 'blur',
|
|
145
|
+
onChange: 'change',
|
|
146
|
+
onClick: 'click',
|
|
147
|
+
onContextMenu: 'contextmenu',
|
|
148
|
+
onCopy: 'copy',
|
|
149
|
+
onCut: 'cut',
|
|
150
|
+
onDoubleClick: 'dblclick',
|
|
151
|
+
onDrag: 'drag',
|
|
152
|
+
onDragEnd: 'dragend',
|
|
153
|
+
onDragEnter: 'dragenter',
|
|
154
|
+
onDragExit: 'dragexit',
|
|
155
|
+
onDragLeave: 'dragleave',
|
|
156
|
+
onDragOver: 'dragover',
|
|
157
|
+
onDragStart: 'dragstart',
|
|
158
|
+
onDrop: 'drop',
|
|
159
|
+
onFocus: 'focus',
|
|
160
|
+
onInput: 'input',
|
|
161
|
+
onKeyDown: 'keydown',
|
|
162
|
+
onKeyUp: 'keyup',
|
|
163
|
+
onMouseDown: 'mousedown',
|
|
164
|
+
onMouseMove: 'mousemove',
|
|
165
|
+
onMouseOut: 'mouseout',
|
|
166
|
+
onMouseOver: 'mouseover',
|
|
167
|
+
onMouseUp: 'mouseup',
|
|
168
|
+
onPaste: 'paste',
|
|
169
|
+
onScroll: 'scroll',
|
|
170
|
+
onSubmit: 'submit',
|
|
171
|
+
onTouchCancel: 'touchcancel',
|
|
172
|
+
onTouchEnd: 'touchend',
|
|
173
|
+
onTouchMove: 'touchmove',
|
|
174
|
+
onTouchStart: 'touchstart'
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* These elements won't be pooled
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
var avoidPooling = ['input', 'textarea'];
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Expose `dom`.
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
module.exports = render
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Render an app to the DOM
|
|
191
|
+
*
|
|
192
|
+
* @param {Application} app
|
|
193
|
+
* @param {HTMLElement} container
|
|
194
|
+
* @param {Object} opts
|
|
195
|
+
*
|
|
196
|
+
* @return {Object}
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
function render (app, container, opts) {
|
|
200
|
+
var frameId
|
|
201
|
+
var isRendering
|
|
202
|
+
var rootId = 'root'
|
|
203
|
+
var currentElement
|
|
204
|
+
var currentNativeElement
|
|
205
|
+
var connections = {}
|
|
206
|
+
var entities = {}
|
|
207
|
+
var pools = {}
|
|
208
|
+
var handlers = {}
|
|
209
|
+
var children = {}
|
|
210
|
+
children[rootId] = {}
|
|
211
|
+
|
|
212
|
+
if (!isDom(container)) {
|
|
213
|
+
throw new Error('Container element must be a DOM element')
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Rendering options. Batching is only ever really disabled
|
|
218
|
+
* when running tests, and pooling can be disabled if the user
|
|
219
|
+
* is doing something stupid with the DOM in their components.
|
|
220
|
+
*/
|
|
221
|
+
|
|
222
|
+
var options = defaults(assign({}, app.options || {}, opts || {}), {
|
|
223
|
+
pooling: true,
|
|
224
|
+
batching: true,
|
|
225
|
+
validateProps: false
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Listen to DOM events
|
|
230
|
+
*/
|
|
231
|
+
|
|
232
|
+
addNativeEventListeners()
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Watch for changes to the app so that we can update
|
|
236
|
+
* the DOM as needed.
|
|
237
|
+
*/
|
|
238
|
+
|
|
239
|
+
app.on('unmount', onunmount)
|
|
240
|
+
app.on('mount', onmount)
|
|
241
|
+
app.on('source', onupdate)
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* If the app has already mounted an element, we can just
|
|
245
|
+
* render that straight away.
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
if (app.element) render()
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Teardown the DOM rendering so that it stops
|
|
252
|
+
* rendering and everything can be garbage collected.
|
|
253
|
+
*/
|
|
254
|
+
|
|
255
|
+
function teardown () {
|
|
256
|
+
removeNativeEventListeners()
|
|
257
|
+
removeNativeElement()
|
|
258
|
+
app.off('unmount', onunmount)
|
|
259
|
+
app.off('mount', onmount)
|
|
260
|
+
app.off('source', onupdate)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Swap the current rendered node with a new one that is rendered
|
|
265
|
+
* from the new virtual element mounted on the app.
|
|
266
|
+
*
|
|
267
|
+
* @param {VirtualElement} element
|
|
268
|
+
*/
|
|
269
|
+
|
|
270
|
+
function onmount () {
|
|
271
|
+
invalidate()
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* If the app unmounts an element, we should clear out the current
|
|
276
|
+
* rendered element. This will remove all the entities.
|
|
277
|
+
*/
|
|
278
|
+
|
|
279
|
+
function onunmount () {
|
|
280
|
+
removeNativeElement()
|
|
281
|
+
currentElement = null
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Update all components that are bound to the source
|
|
286
|
+
*
|
|
287
|
+
* @param {String} name
|
|
288
|
+
* @param {*} data
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
function onupdate (name, data) {
|
|
292
|
+
connections[name](data)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Render and mount a component to the native dom.
|
|
297
|
+
*
|
|
298
|
+
* @param {Entity} entity
|
|
299
|
+
* @return {HTMLElement}
|
|
300
|
+
*/
|
|
301
|
+
|
|
302
|
+
function mountEntity (entity) {
|
|
303
|
+
register(entity)
|
|
304
|
+
setSources(entity)
|
|
305
|
+
children[entity.id] = {}
|
|
306
|
+
entities[entity.id] = entity
|
|
307
|
+
|
|
308
|
+
// commit initial state and props.
|
|
309
|
+
commit(entity)
|
|
310
|
+
|
|
311
|
+
// callback before mounting.
|
|
312
|
+
trigger('beforeMount', entity, [entity.context])
|
|
313
|
+
trigger('beforeRender', entity, [entity.context])
|
|
314
|
+
|
|
315
|
+
// render virtual element.
|
|
316
|
+
var virtualElement = renderEntity(entity)
|
|
317
|
+
// create native element.
|
|
318
|
+
var nativeElement = toNative(entity.id, '0', virtualElement)
|
|
319
|
+
|
|
320
|
+
entity.virtualElement = virtualElement
|
|
321
|
+
entity.nativeElement = nativeElement
|
|
322
|
+
|
|
323
|
+
// callback after mounting.
|
|
324
|
+
trigger('afterRender', entity, [entity.context, nativeElement])
|
|
325
|
+
trigger('afterMount', entity, [entity.context, nativeElement, setState(entity)])
|
|
326
|
+
|
|
327
|
+
return nativeElement
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Remove a component from the native dom.
|
|
332
|
+
*
|
|
333
|
+
* @param {Entity} entity
|
|
334
|
+
*/
|
|
335
|
+
|
|
336
|
+
function unmountEntity (entityId) {
|
|
337
|
+
var entity = entities[entityId]
|
|
338
|
+
if (!entity) return
|
|
339
|
+
trigger('beforeUnmount', entity, [entity.context, entity.nativeElement])
|
|
340
|
+
unmountChildren(entityId)
|
|
341
|
+
removeAllEvents(entityId)
|
|
342
|
+
delete entities[entityId]
|
|
343
|
+
delete children[entityId]
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Render the entity and make sure it returns a node
|
|
348
|
+
*
|
|
349
|
+
* @param {Entity} entity
|
|
350
|
+
*
|
|
351
|
+
* @return {VirtualTree}
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
function renderEntity (entity) {
|
|
355
|
+
var component = entity.component
|
|
356
|
+
if (!component.render) throw new Error('Component needs a render function')
|
|
357
|
+
var result = component.render(entity.context, setState(entity))
|
|
358
|
+
if (!result) throw new Error('Render function must return an element.')
|
|
359
|
+
return result
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Whenever setState or setProps is called, we mark the entity
|
|
364
|
+
* as dirty in the renderer. This lets us optimize the re-rendering
|
|
365
|
+
* and skip components that definitely haven't changed.
|
|
366
|
+
*
|
|
367
|
+
* @param {Entity} entity
|
|
368
|
+
*
|
|
369
|
+
* @return {Function} A curried function for updating the state of an entity
|
|
370
|
+
*/
|
|
371
|
+
|
|
372
|
+
function setState (entity) {
|
|
373
|
+
return function (nextState) {
|
|
374
|
+
updateEntityState(entity, nextState)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Tell the app it's dirty and needs to re-render. If batching is disabled
|
|
380
|
+
* we can just trigger a render immediately, otherwise we'll wait until
|
|
381
|
+
* the next available frame.
|
|
382
|
+
*/
|
|
383
|
+
|
|
384
|
+
function invalidate () {
|
|
385
|
+
if (!options.batching) {
|
|
386
|
+
if (!isRendering) render()
|
|
387
|
+
} else {
|
|
388
|
+
if (!frameId) frameId = raf(render)
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Update the DOM. If the update fails we stop the loop
|
|
394
|
+
* so we don't get errors on every frame.
|
|
395
|
+
*
|
|
396
|
+
* @api public
|
|
397
|
+
*/
|
|
398
|
+
|
|
399
|
+
function render () {
|
|
400
|
+
// If this is called synchronously we need to
|
|
401
|
+
// cancel any pending future updates
|
|
402
|
+
clearFrame()
|
|
403
|
+
|
|
404
|
+
// If the rendering from the previous frame is still going,
|
|
405
|
+
// we'll just wait until the next frame. Ideally renders should
|
|
406
|
+
// not take over 16ms to stay within a single frame, but this should
|
|
407
|
+
// catch it if it does.
|
|
408
|
+
if (isRendering) {
|
|
409
|
+
frameId = raf(render)
|
|
410
|
+
return
|
|
411
|
+
} else {
|
|
412
|
+
isRendering = true
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// 1. If there isn't a native element rendered for the current mounted element
|
|
416
|
+
// then we need to create it from scratch.
|
|
417
|
+
// 2. If a new element has been mounted, we should diff them.
|
|
418
|
+
// 3. We should update check all child components for changes.
|
|
419
|
+
if (!currentNativeElement) {
|
|
420
|
+
currentElement = app.element
|
|
421
|
+
currentNativeElement = toNative(rootId, '0', currentElement)
|
|
422
|
+
container.appendChild(currentNativeElement)
|
|
423
|
+
} else if (currentElement !== app.element) {
|
|
424
|
+
currentNativeElement = patch(rootId, currentElement, app.element, currentNativeElement)
|
|
425
|
+
currentElement = app.element
|
|
426
|
+
updateChildren(rootId)
|
|
427
|
+
} else {
|
|
428
|
+
updateChildren(rootId)
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Allow rendering again.
|
|
432
|
+
isRendering = false
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Clear the current scheduled frame
|
|
437
|
+
*/
|
|
438
|
+
|
|
439
|
+
function clearFrame () {
|
|
440
|
+
if (!frameId) return
|
|
441
|
+
raf.cancel(frameId)
|
|
442
|
+
frameId = 0
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Update a component.
|
|
447
|
+
*
|
|
448
|
+
* The entity is just the data object for a component instance.
|
|
449
|
+
*
|
|
450
|
+
* @param {String} id Component instance id.
|
|
451
|
+
*/
|
|
452
|
+
|
|
453
|
+
function updateEntity (entityId) {
|
|
454
|
+
var entity = entities[entityId]
|
|
455
|
+
setSources(entity)
|
|
456
|
+
|
|
457
|
+
if (!shouldUpdate(entity)) return updateChildren(entityId)
|
|
458
|
+
|
|
459
|
+
var currentTree = entity.virtualElement
|
|
460
|
+
var nextProps = entity.pendingProps
|
|
461
|
+
var nextState = entity.pendingState
|
|
462
|
+
var previousState = entity.context.state
|
|
463
|
+
var previousProps = entity.context.props
|
|
464
|
+
|
|
465
|
+
// hook before rendering. could modify state just before the render occurs.
|
|
466
|
+
trigger('beforeUpdate', entity, [entity.context, nextProps, nextState])
|
|
467
|
+
trigger('beforeRender', entity, [entity.context])
|
|
468
|
+
|
|
469
|
+
// commit state and props.
|
|
470
|
+
commit(entity)
|
|
471
|
+
|
|
472
|
+
// re-render.
|
|
473
|
+
var nextTree = renderEntity(entity)
|
|
474
|
+
|
|
475
|
+
// if the tree is the same we can just skip this component
|
|
476
|
+
// but we should still check the children to see if they're dirty.
|
|
477
|
+
// This allows us to memoize the render function of components.
|
|
478
|
+
if (nextTree === currentTree) return updateChildren(entityId)
|
|
479
|
+
|
|
480
|
+
// apply new virtual tree to native dom.
|
|
481
|
+
entity.nativeElement = patch(entityId, currentTree, nextTree, entity.nativeElement)
|
|
482
|
+
entity.virtualElement = nextTree
|
|
483
|
+
updateChildren(entityId)
|
|
484
|
+
|
|
485
|
+
// trigger render hook
|
|
486
|
+
trigger('afterRender', entity, [entity.context, entity.nativeElement])
|
|
487
|
+
|
|
488
|
+
// trigger afterUpdate after all children have updated.
|
|
489
|
+
trigger('afterUpdate', entity, [entity.context, previousProps, previousState, setState(entity)])
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Update all the children of an entity.
|
|
494
|
+
*
|
|
495
|
+
* @param {String} id Component instance id.
|
|
496
|
+
*/
|
|
497
|
+
|
|
498
|
+
function updateChildren (entityId) {
|
|
499
|
+
forEach(children[entityId], function (childId) {
|
|
500
|
+
updateEntity(childId)
|
|
501
|
+
})
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Remove all of the child entities of an entity
|
|
506
|
+
*
|
|
507
|
+
* @param {Entity} entity
|
|
508
|
+
*/
|
|
509
|
+
|
|
510
|
+
function unmountChildren (entityId) {
|
|
511
|
+
forEach(children[entityId], function (childId) {
|
|
512
|
+
unmountEntity(childId)
|
|
513
|
+
})
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Remove the root element. If this is called synchronously we need to
|
|
518
|
+
* cancel any pending future updates.
|
|
519
|
+
*/
|
|
520
|
+
|
|
521
|
+
function removeNativeElement () {
|
|
522
|
+
clearFrame()
|
|
523
|
+
removeElement(rootId, '0', currentNativeElement)
|
|
524
|
+
currentNativeElement = null
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Create a native element from a virtual element.
|
|
529
|
+
*
|
|
530
|
+
* @param {String} entityId
|
|
531
|
+
* @param {String} path
|
|
532
|
+
* @param {Object} vnode
|
|
533
|
+
*
|
|
534
|
+
* @return {HTMLDocumentFragment}
|
|
535
|
+
*/
|
|
536
|
+
|
|
537
|
+
function toNative (entityId, path, vnode) {
|
|
538
|
+
switch (vnode.type) {
|
|
539
|
+
case 'text': return toNativeText(vnode)
|
|
540
|
+
case 'element': return toNativeElement(entityId, path, vnode)
|
|
541
|
+
case 'component': return toNativeComponent(entityId, path, vnode)
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Create a native text element from a virtual element.
|
|
547
|
+
*
|
|
548
|
+
* @param {Object} vnode
|
|
549
|
+
*/
|
|
550
|
+
|
|
551
|
+
function toNativeText (vnode) {
|
|
552
|
+
return document.createTextNode(vnode.data)
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Create a native element from a virtual element.
|
|
557
|
+
*/
|
|
558
|
+
|
|
559
|
+
function toNativeElement (entityId, path, vnode) {
|
|
560
|
+
var attributes = vnode.attributes
|
|
561
|
+
var children = vnode.children
|
|
562
|
+
var tagName = vnode.tagName
|
|
563
|
+
var el
|
|
564
|
+
|
|
565
|
+
// create element either from pool or fresh.
|
|
566
|
+
if (!options.pooling || !canPool(tagName)) {
|
|
567
|
+
if (svg.isElement(tagName)) {
|
|
568
|
+
el = document.createElementNS(svg.namespace, tagName)
|
|
569
|
+
} else {
|
|
570
|
+
el = document.createElement(tagName)
|
|
571
|
+
}
|
|
572
|
+
} else {
|
|
573
|
+
var pool = getPool(tagName)
|
|
574
|
+
el = cleanup(pool.pop())
|
|
575
|
+
if (el.parentNode) el.parentNode.removeChild(el)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// set attributes.
|
|
579
|
+
forEach(attributes, function (value, name) {
|
|
580
|
+
setAttribute(entityId, path, el, name, value)
|
|
581
|
+
})
|
|
582
|
+
|
|
583
|
+
// store keys on the native element for fast event handling.
|
|
584
|
+
el.__entity__ = entityId
|
|
585
|
+
el.__path__ = path
|
|
586
|
+
|
|
587
|
+
// add children.
|
|
588
|
+
forEach(children, function (child, i) {
|
|
589
|
+
var childEl = toNative(entityId, path + '.' + i, child)
|
|
590
|
+
if (!childEl.parentNode) el.appendChild(childEl)
|
|
591
|
+
})
|
|
592
|
+
|
|
593
|
+
return el
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Create a native element from a component.
|
|
598
|
+
*/
|
|
599
|
+
|
|
600
|
+
function toNativeComponent (entityId, path, vnode) {
|
|
601
|
+
var child = new Entity(vnode.component, vnode.props)
|
|
602
|
+
children[entityId][path] = child.id
|
|
603
|
+
return mountEntity(child)
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Patch an element with the diff from two trees.
|
|
608
|
+
*/
|
|
609
|
+
|
|
610
|
+
function patch (entityId, prev, next, el) {
|
|
611
|
+
return diffNode('0', entityId, prev, next, el)
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Create a diff between two tress of nodes.
|
|
616
|
+
*/
|
|
617
|
+
|
|
618
|
+
function diffNode (path, entityId, prev, next, el) {
|
|
619
|
+
// Type changed. This could be from element->text, text->ComponentA,
|
|
620
|
+
// ComponentA->ComponentB etc. But NOT div->span. These are the same type
|
|
621
|
+
// (ElementNode) but different tag name.
|
|
622
|
+
if (prev.type !== next.type) return replaceElement(entityId, path, el, next)
|
|
623
|
+
|
|
624
|
+
switch (next.type) {
|
|
625
|
+
case 'text': return diffText(prev, next, el)
|
|
626
|
+
case 'element': return diffElement(path, entityId, prev, next, el)
|
|
627
|
+
case 'component': return diffComponent(path, entityId, prev, next, el)
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Diff two text nodes and update the element.
|
|
633
|
+
*/
|
|
634
|
+
|
|
635
|
+
function diffText (previous, current, el) {
|
|
636
|
+
if (current.data !== previous.data) el.data = current.data
|
|
637
|
+
return el
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Diff the children of an ElementNode.
|
|
642
|
+
*/
|
|
643
|
+
|
|
644
|
+
function diffChildren (path, entityId, prev, next, el) {
|
|
645
|
+
var positions = []
|
|
646
|
+
var hasKeys = false
|
|
647
|
+
var childNodes = Array.prototype.slice.apply(el.childNodes)
|
|
648
|
+
var leftKeys = reduce(prev.children, keyMapReducer, {})
|
|
649
|
+
var rightKeys = reduce(next.children, keyMapReducer, {})
|
|
650
|
+
var currentChildren = assign({}, children[entityId])
|
|
651
|
+
|
|
652
|
+
function keyMapReducer (acc, child) {
|
|
653
|
+
if (child.key != null) {
|
|
654
|
+
acc[child.key] = child
|
|
655
|
+
hasKeys = true
|
|
656
|
+
}
|
|
657
|
+
return acc
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Diff all of the nodes that have keys. This lets us re-used elements
|
|
661
|
+
// instead of overriding them and lets us move them around.
|
|
662
|
+
if (hasKeys) {
|
|
663
|
+
|
|
664
|
+
// Removals
|
|
665
|
+
forEach(leftKeys, function (leftNode, key) {
|
|
666
|
+
if (rightKeys[key] == null) {
|
|
667
|
+
var leftPath = path + '.' + leftNode.index
|
|
668
|
+
removeElement(
|
|
669
|
+
entityId,
|
|
670
|
+
leftPath,
|
|
671
|
+
childNodes[leftNode.index]
|
|
672
|
+
)
|
|
673
|
+
}
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
// Update nodes
|
|
677
|
+
forEach(rightKeys, function (rightNode, key) {
|
|
678
|
+
var leftNode = leftKeys[key]
|
|
679
|
+
|
|
680
|
+
// We only want updates for now
|
|
681
|
+
if (leftNode == null) return
|
|
682
|
+
|
|
683
|
+
var leftPath = path + '.' + leftNode.index
|
|
684
|
+
|
|
685
|
+
// Updated
|
|
686
|
+
positions[rightNode.index] = diffNode(
|
|
687
|
+
leftPath,
|
|
688
|
+
entityId,
|
|
689
|
+
leftNode,
|
|
690
|
+
rightNode,
|
|
691
|
+
childNodes[leftNode.index]
|
|
692
|
+
)
|
|
693
|
+
})
|
|
694
|
+
|
|
695
|
+
// Update the positions of all child components and event handlers
|
|
696
|
+
forEach(rightKeys, function (rightNode, key) {
|
|
697
|
+
var leftNode = leftKeys[key]
|
|
698
|
+
|
|
699
|
+
// We just want elements that have moved around
|
|
700
|
+
if (leftNode == null || leftNode.index === rightNode.index) return
|
|
701
|
+
|
|
702
|
+
var rightPath = path + '.' + rightNode.index
|
|
703
|
+
var leftPath = path + '.' + leftNode.index
|
|
704
|
+
|
|
705
|
+
// Update all the child component path positions to match
|
|
706
|
+
// the latest positions if they've changed. This is a bit hacky.
|
|
707
|
+
forEach(currentChildren, function (childId, childPath) {
|
|
708
|
+
if (leftPath === childPath) {
|
|
709
|
+
delete children[entityId][childPath]
|
|
710
|
+
children[entityId][rightPath] = childId
|
|
711
|
+
}
|
|
712
|
+
})
|
|
713
|
+
})
|
|
714
|
+
|
|
715
|
+
// Now add all of the new nodes last in case their path
|
|
716
|
+
// would have conflicted with one of the previous paths.
|
|
717
|
+
forEach(rightKeys, function (rightNode, key) {
|
|
718
|
+
var rightPath = path + '.' + rightNode.index
|
|
719
|
+
if (leftKeys[key] == null) {
|
|
720
|
+
positions[rightNode.index] = toNative(
|
|
721
|
+
entityId,
|
|
722
|
+
rightPath,
|
|
723
|
+
rightNode
|
|
724
|
+
)
|
|
725
|
+
}
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
} else {
|
|
729
|
+
var maxLength = Math.max(prev.children.length, next.children.length)
|
|
730
|
+
|
|
731
|
+
// Now diff all of the nodes that don't have keys
|
|
732
|
+
for (var i = 0; i < maxLength; i++) {
|
|
733
|
+
var leftNode = prev.children[i]
|
|
734
|
+
var rightNode = next.children[i]
|
|
735
|
+
|
|
736
|
+
// Removals
|
|
737
|
+
if (rightNode == null) {
|
|
738
|
+
removeElement(
|
|
739
|
+
entityId,
|
|
740
|
+
path + '.' + leftNode.index,
|
|
741
|
+
childNodes[leftNode.index]
|
|
742
|
+
)
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// New Node
|
|
746
|
+
if (leftNode == null) {
|
|
747
|
+
positions[rightNode.index] = toNative(
|
|
748
|
+
entityId,
|
|
749
|
+
path + '.' + rightNode.index,
|
|
750
|
+
rightNode
|
|
751
|
+
)
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// Updated
|
|
755
|
+
if (leftNode && rightNode) {
|
|
756
|
+
positions[leftNode.index] = diffNode(
|
|
757
|
+
path + '.' + leftNode.index,
|
|
758
|
+
entityId,
|
|
759
|
+
leftNode,
|
|
760
|
+
rightNode,
|
|
761
|
+
childNodes[leftNode.index]
|
|
762
|
+
)
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Reposition all the elements
|
|
768
|
+
forEach(positions, function (childEl, newPosition) {
|
|
769
|
+
var target = el.childNodes[newPosition]
|
|
770
|
+
if (childEl !== target) {
|
|
771
|
+
if (target) {
|
|
772
|
+
el.insertBefore(childEl, target)
|
|
773
|
+
} else {
|
|
774
|
+
el.appendChild(childEl)
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
})
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Diff the attributes and add/remove them.
|
|
782
|
+
*/
|
|
783
|
+
|
|
784
|
+
function diffAttributes (prev, next, el, entityId, path) {
|
|
785
|
+
var nextAttrs = next.attributes
|
|
786
|
+
var prevAttrs = prev.attributes
|
|
787
|
+
|
|
788
|
+
// add new attrs
|
|
789
|
+
forEach(nextAttrs, function (value, name) {
|
|
790
|
+
if (events[name] || !(name in prevAttrs) || prevAttrs[name] !== value) {
|
|
791
|
+
setAttribute(entityId, path, el, name, value)
|
|
792
|
+
}
|
|
793
|
+
})
|
|
794
|
+
|
|
795
|
+
// remove old attrs
|
|
796
|
+
forEach(prevAttrs, function (value, name) {
|
|
797
|
+
if (!(name in nextAttrs)) {
|
|
798
|
+
removeAttribute(entityId, path, el, name)
|
|
799
|
+
}
|
|
800
|
+
})
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Update a component with the props from the next node. If
|
|
805
|
+
* the component type has changed, we'll just remove the old one
|
|
806
|
+
* and replace it with the new component.
|
|
807
|
+
*/
|
|
808
|
+
|
|
809
|
+
function diffComponent (path, entityId, prev, next, el) {
|
|
810
|
+
if (next.component !== prev.component) {
|
|
811
|
+
return replaceElement(entityId, path, el, next)
|
|
812
|
+
} else {
|
|
813
|
+
var targetId = children[entityId][path]
|
|
814
|
+
|
|
815
|
+
// This is a hack for now
|
|
816
|
+
if (targetId) {
|
|
817
|
+
updateEntityProps(targetId, next.props)
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
return el
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Diff two element nodes.
|
|
826
|
+
*/
|
|
827
|
+
|
|
828
|
+
function diffElement (path, entityId, prev, next, el) {
|
|
829
|
+
if (next.tagName !== prev.tagName) return replaceElement(entityId, path, el, next)
|
|
830
|
+
diffAttributes(prev, next, el, entityId, path)
|
|
831
|
+
diffChildren(path, entityId, prev, next, el)
|
|
832
|
+
return el
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Removes an element from the DOM and unmounts and components
|
|
837
|
+
* that are within that branch
|
|
838
|
+
*
|
|
839
|
+
* side effects:
|
|
840
|
+
* - removes element from the DOM
|
|
841
|
+
* - removes internal references
|
|
842
|
+
*
|
|
843
|
+
* @param {String} entityId
|
|
844
|
+
* @param {String} path
|
|
845
|
+
* @param {HTMLElement} el
|
|
846
|
+
*/
|
|
847
|
+
|
|
848
|
+
function removeElement (entityId, path, el) {
|
|
849
|
+
var childrenByPath = children[entityId]
|
|
850
|
+
var childId = childrenByPath[path]
|
|
851
|
+
var entityHandlers = handlers[entityId] || {}
|
|
852
|
+
var removals = []
|
|
853
|
+
|
|
854
|
+
// If the path points to a component we should use that
|
|
855
|
+
// components element instead, because it might have moved it.
|
|
856
|
+
if (childId) {
|
|
857
|
+
var child = entities[childId]
|
|
858
|
+
el = child.nativeElement
|
|
859
|
+
unmountEntity(childId)
|
|
860
|
+
removals.push(path)
|
|
861
|
+
} else {
|
|
862
|
+
|
|
863
|
+
// Just remove the text node
|
|
864
|
+
if (!isElement(el)) return el.parentNode.removeChild(el)
|
|
865
|
+
|
|
866
|
+
// Then we need to find any components within this
|
|
867
|
+
// branch and unmount them.
|
|
868
|
+
forEach(childrenByPath, function (childId, childPath) {
|
|
869
|
+
if (childPath === path || isWithinPath(path, childPath)) {
|
|
870
|
+
unmountEntity(childId)
|
|
871
|
+
removals.push(childPath)
|
|
872
|
+
}
|
|
873
|
+
})
|
|
874
|
+
|
|
875
|
+
// Remove all events at this path or below it
|
|
876
|
+
forEach(entityHandlers, function (fn, handlerPath) {
|
|
877
|
+
if (handlerPath === path || isWithinPath(path, handlerPath)) {
|
|
878
|
+
removeEvent(entityId, handlerPath)
|
|
879
|
+
}
|
|
880
|
+
})
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// Remove the paths from the object without touching the
|
|
884
|
+
// old object. This keeps the object using fast properties.
|
|
885
|
+
forEach(removals, function (path) {
|
|
886
|
+
delete children[entityId][path]
|
|
887
|
+
})
|
|
888
|
+
|
|
889
|
+
// Remove it from the DOM
|
|
890
|
+
el.parentNode.removeChild(el)
|
|
891
|
+
|
|
892
|
+
// Return all of the elements in this node tree to the pool
|
|
893
|
+
// so that the elements can be re-used.
|
|
894
|
+
if (options.pooling) {
|
|
895
|
+
walk(el, function (node) {
|
|
896
|
+
if (!isElement(node) || !canPool(node.tagName)) return
|
|
897
|
+
getPool(node.tagName.toLowerCase()).push(node)
|
|
898
|
+
})
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Replace an element in the DOM. Removing all components
|
|
904
|
+
* within that element and re-rendering the new virtual node.
|
|
905
|
+
*
|
|
906
|
+
* @param {Entity} entity
|
|
907
|
+
* @param {String} path
|
|
908
|
+
* @param {HTMLElement} el
|
|
909
|
+
* @param {Object} vnode
|
|
910
|
+
*
|
|
911
|
+
* @return {void}
|
|
912
|
+
*/
|
|
913
|
+
|
|
914
|
+
function replaceElement (entityId, path, el, vnode) {
|
|
915
|
+
var parent = el.parentNode
|
|
916
|
+
var index = Array.prototype.indexOf.call(parent.childNodes, el)
|
|
917
|
+
|
|
918
|
+
// remove the previous element and all nested components. This
|
|
919
|
+
// needs to happen before we create the new element so we don't
|
|
920
|
+
// get clashes on the component paths.
|
|
921
|
+
removeElement(entityId, path, el)
|
|
922
|
+
|
|
923
|
+
// then add the new element in there
|
|
924
|
+
var newEl = toNative(entityId, path, vnode)
|
|
925
|
+
var target = parent.childNodes[index]
|
|
926
|
+
|
|
927
|
+
if (target) {
|
|
928
|
+
parent.insertBefore(newEl, target)
|
|
929
|
+
} else {
|
|
930
|
+
parent.appendChild(newEl)
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// update all `entity.nativeElement` references.
|
|
934
|
+
forEach(entities, function (entity) {
|
|
935
|
+
if (entity.nativeElement === el) {
|
|
936
|
+
entity.nativeElement = newEl
|
|
937
|
+
}
|
|
938
|
+
})
|
|
939
|
+
|
|
940
|
+
return newEl
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Set the attribute of an element, performing additional transformations
|
|
945
|
+
* dependning on the attribute name
|
|
946
|
+
*
|
|
947
|
+
* @param {HTMLElement} el
|
|
948
|
+
* @param {String} name
|
|
949
|
+
* @param {String} value
|
|
950
|
+
*/
|
|
951
|
+
|
|
952
|
+
function setAttribute (entityId, path, el, name, value) {
|
|
953
|
+
if (events[name]) {
|
|
954
|
+
addEvent(entityId, path, events[name], value)
|
|
955
|
+
return
|
|
956
|
+
}
|
|
957
|
+
switch (name) {
|
|
958
|
+
case 'value':
|
|
959
|
+
el.value = value
|
|
960
|
+
break
|
|
961
|
+
case 'innerHTML':
|
|
962
|
+
el.innerHTML = value
|
|
963
|
+
break
|
|
964
|
+
case svg.isAttribute(name):
|
|
965
|
+
el.setAttributeNS(svg.namespace, name, value)
|
|
966
|
+
break
|
|
967
|
+
default:
|
|
968
|
+
el.setAttribute(name, value)
|
|
969
|
+
break
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* Remove an attribute, performing additional transformations
|
|
975
|
+
* dependning on the attribute name
|
|
976
|
+
*
|
|
977
|
+
* @param {HTMLElement} el
|
|
978
|
+
* @param {String} name
|
|
979
|
+
*/
|
|
980
|
+
|
|
981
|
+
function removeAttribute (entityId, path, el, name) {
|
|
982
|
+
if (events[name]) {
|
|
983
|
+
removeEvent(entityId, path, events[name])
|
|
984
|
+
return
|
|
985
|
+
}
|
|
986
|
+
el.removeAttribute(name)
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* Checks to see if one tree path is within
|
|
991
|
+
* another tree path. Example:
|
|
992
|
+
*
|
|
993
|
+
* 0.1 vs 0.1.1 = true
|
|
994
|
+
* 0.2 vs 0.3.5 = false
|
|
995
|
+
*
|
|
996
|
+
* @param {String} target
|
|
997
|
+
* @param {String} path
|
|
998
|
+
*
|
|
999
|
+
* @return {Boolean}
|
|
1000
|
+
*/
|
|
1001
|
+
|
|
1002
|
+
function isWithinPath (target, path) {
|
|
1003
|
+
return path.indexOf(target + '.') === 0
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Is the DOM node an element node
|
|
1008
|
+
*
|
|
1009
|
+
* @param {HTMLElement} el
|
|
1010
|
+
*
|
|
1011
|
+
* @return {Boolean}
|
|
1012
|
+
*/
|
|
1013
|
+
|
|
1014
|
+
function isElement (el) {
|
|
1015
|
+
return !!el.tagName
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Get the pool for a tagName, creating it if it
|
|
1020
|
+
* doesn't exist.
|
|
1021
|
+
*
|
|
1022
|
+
* @param {String} tagName
|
|
1023
|
+
*
|
|
1024
|
+
* @return {Pool}
|
|
1025
|
+
*/
|
|
1026
|
+
|
|
1027
|
+
function getPool (tagName) {
|
|
1028
|
+
var pool = pools[tagName]
|
|
1029
|
+
if (!pool) {
|
|
1030
|
+
var poolOpts = svg.isElement(tagName) ?
|
|
1031
|
+
{ namespace: svg.namespace, tagName: tagName } :
|
|
1032
|
+
{ tagName: tagName }
|
|
1033
|
+
pool = pools[tagName] = new Pool(poolOpts)
|
|
1034
|
+
}
|
|
1035
|
+
return pool
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* Clean up previously used native element for reuse.
|
|
1040
|
+
*
|
|
1041
|
+
* @param {HTMLElement} el
|
|
1042
|
+
*/
|
|
1043
|
+
|
|
1044
|
+
function cleanup (el) {
|
|
1045
|
+
removeAllChildren(el)
|
|
1046
|
+
removeAllAttributes(el)
|
|
1047
|
+
return el
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Remove all the attributes from a node
|
|
1052
|
+
*
|
|
1053
|
+
* @param {HTMLElement} el
|
|
1054
|
+
*/
|
|
1055
|
+
|
|
1056
|
+
function removeAllAttributes (el) {
|
|
1057
|
+
for (var i = el.attributes.length - 1; i >= 0; i--) {
|
|
1058
|
+
var name = el.attributes[i].name
|
|
1059
|
+
el.removeAttribute(name)
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Remove all the child nodes from an element
|
|
1065
|
+
*
|
|
1066
|
+
* @param {HTMLElement} el
|
|
1067
|
+
*/
|
|
1068
|
+
|
|
1069
|
+
function removeAllChildren (el) {
|
|
1070
|
+
while (el.firstChild) el.removeChild(el.firstChild)
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
/**
|
|
1074
|
+
* Trigger a hook on a component.
|
|
1075
|
+
*
|
|
1076
|
+
* @param {String} name Name of hook.
|
|
1077
|
+
* @param {Entity} entity The component instance.
|
|
1078
|
+
* @param {Array} args To pass along to hook.
|
|
1079
|
+
*/
|
|
1080
|
+
|
|
1081
|
+
function trigger (name, entity, args) {
|
|
1082
|
+
if (typeof entity.component[name] !== 'function') return
|
|
1083
|
+
entity.component[name].apply(null, args)
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Update an entity to match the latest rendered vode. We always
|
|
1088
|
+
* replace the props on the component when composing them. This
|
|
1089
|
+
* will trigger a re-render on all children below this point.
|
|
1090
|
+
*
|
|
1091
|
+
* @param {Entity} entity
|
|
1092
|
+
* @param {String} path
|
|
1093
|
+
* @param {Object} vnode
|
|
1094
|
+
*
|
|
1095
|
+
* @return {void}
|
|
1096
|
+
*/
|
|
1097
|
+
|
|
1098
|
+
function updateEntityProps (entityId, nextProps) {
|
|
1099
|
+
var entity = entities[entityId]
|
|
1100
|
+
entity.pendingProps = nextProps
|
|
1101
|
+
entity.dirty = true
|
|
1102
|
+
invalidate()
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* Update component instance state.
|
|
1107
|
+
*/
|
|
1108
|
+
|
|
1109
|
+
function updateEntityState (entity, nextState) {
|
|
1110
|
+
entity.pendingState = assign(entity.pendingState, nextState)
|
|
1111
|
+
entity.dirty = true
|
|
1112
|
+
invalidate()
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* Commit props and state changes to an entity.
|
|
1117
|
+
*/
|
|
1118
|
+
|
|
1119
|
+
function commit (entity) {
|
|
1120
|
+
entity.context = {
|
|
1121
|
+
state: entity.pendingState,
|
|
1122
|
+
props: entity.pendingProps,
|
|
1123
|
+
id: entity.id
|
|
1124
|
+
}
|
|
1125
|
+
entity.pendingState = assign({}, entity.context.state)
|
|
1126
|
+
entity.pendingProps = assign({}, entity.context.props)
|
|
1127
|
+
validateProps(entity.context.props, entity.propTypes)
|
|
1128
|
+
entity.dirty = false
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* Try to avoid creating new virtual dom if possible.
|
|
1133
|
+
*
|
|
1134
|
+
* Later we may expose this so you can override, but not there yet.
|
|
1135
|
+
*/
|
|
1136
|
+
|
|
1137
|
+
function shouldUpdate (entity) {
|
|
1138
|
+
if (!entity.dirty) return false
|
|
1139
|
+
if (!entity.component.shouldUpdate) return true
|
|
1140
|
+
var nextProps = entity.pendingProps
|
|
1141
|
+
var nextState = entity.pendingState
|
|
1142
|
+
var bool = entity.component.shouldUpdate(entity.context, nextProps, nextState)
|
|
1143
|
+
return bool
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
/**
|
|
1147
|
+
* Register an entity.
|
|
1148
|
+
*
|
|
1149
|
+
* This is mostly to pre-preprocess component properties and values chains.
|
|
1150
|
+
*
|
|
1151
|
+
* The end result is for every component that gets mounted,
|
|
1152
|
+
* you create a set of IO nodes in the network from the `value` definitions.
|
|
1153
|
+
*
|
|
1154
|
+
* @param {Component} component
|
|
1155
|
+
*/
|
|
1156
|
+
|
|
1157
|
+
function register (entity) {
|
|
1158
|
+
var component = entity.component
|
|
1159
|
+
// all entities for this component type.
|
|
1160
|
+
var entities = component.entities = component.entities || {}
|
|
1161
|
+
// add entity to component list
|
|
1162
|
+
entities[entity.id] = entity
|
|
1163
|
+
|
|
1164
|
+
// get 'class-level' sources.
|
|
1165
|
+
var sources = component.sources
|
|
1166
|
+
if (sources) return
|
|
1167
|
+
|
|
1168
|
+
var map = component.sourceToPropertyName = {}
|
|
1169
|
+
component.sources = sources = []
|
|
1170
|
+
var propTypes = component.propTypes
|
|
1171
|
+
for (var name in propTypes) {
|
|
1172
|
+
var data = propTypes[name]
|
|
1173
|
+
if (!data) continue
|
|
1174
|
+
if (!data.source) continue
|
|
1175
|
+
sources.push(data.source)
|
|
1176
|
+
map[data.source] = name
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// send value updates to all component instances.
|
|
1180
|
+
sources.forEach(function (source) {
|
|
1181
|
+
connections[source] = update
|
|
1182
|
+
|
|
1183
|
+
function update (data) {
|
|
1184
|
+
var prop = map[source]
|
|
1185
|
+
for (var entityId in entities) {
|
|
1186
|
+
var entity = entities[entityId]
|
|
1187
|
+
var changes = {}
|
|
1188
|
+
changes[prop] = data
|
|
1189
|
+
updateEntityProps(entityId, assign(entity.pendingProps, changes))
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
})
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* Set the initial source value on the entity
|
|
1197
|
+
*
|
|
1198
|
+
* @param {Entity} entity
|
|
1199
|
+
*/
|
|
1200
|
+
|
|
1201
|
+
function setSources (entity) {
|
|
1202
|
+
var component = entity.component
|
|
1203
|
+
var map = component.sourceToPropertyName
|
|
1204
|
+
var sources = component.sources
|
|
1205
|
+
sources.forEach(function (source) {
|
|
1206
|
+
var name = map[source]
|
|
1207
|
+
if (entity.pendingProps[name] != null) return
|
|
1208
|
+
entity.pendingProps[name] = app.sources[source] // get latest value plugged into global store
|
|
1209
|
+
})
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* Add all of the DOM event listeners
|
|
1214
|
+
*/
|
|
1215
|
+
|
|
1216
|
+
function addNativeEventListeners () {
|
|
1217
|
+
forEach(events, function (eventType) {
|
|
1218
|
+
document.body.addEventListener(eventType, handleEvent, true)
|
|
1219
|
+
})
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
/**
|
|
1223
|
+
* Add all of the DOM event listeners
|
|
1224
|
+
*/
|
|
1225
|
+
|
|
1226
|
+
function removeNativeEventListeners () {
|
|
1227
|
+
forEach(events, function (eventType) {
|
|
1228
|
+
document.body.removeEventListener(eventType, handleEvent, true)
|
|
1229
|
+
})
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* Handle an event that has occured within the container
|
|
1234
|
+
*
|
|
1235
|
+
* @param {Event} event
|
|
1236
|
+
*/
|
|
1237
|
+
|
|
1238
|
+
function handleEvent (event) {
|
|
1239
|
+
var target = event.target
|
|
1240
|
+
var entityId = target.__entity__
|
|
1241
|
+
var eventType = event.type
|
|
1242
|
+
|
|
1243
|
+
// Walk up the DOM tree and see if there is a handler
|
|
1244
|
+
// for this event type higher up.
|
|
1245
|
+
while (target && target.__entity__ === entityId) {
|
|
1246
|
+
var fn = keypath.get(handlers, [entityId, target.__path__, eventType])
|
|
1247
|
+
if (fn) {
|
|
1248
|
+
event.delegateTarget = target
|
|
1249
|
+
fn(event)
|
|
1250
|
+
break
|
|
1251
|
+
}
|
|
1252
|
+
target = target.parentNode
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
* Bind events for an element, and all it's rendered child elements.
|
|
1258
|
+
*
|
|
1259
|
+
* @param {String} path
|
|
1260
|
+
* @param {String} event
|
|
1261
|
+
* @param {Function} fn
|
|
1262
|
+
*/
|
|
1263
|
+
|
|
1264
|
+
function addEvent (entityId, path, eventType, fn) {
|
|
1265
|
+
keypath.set(handlers, [entityId, path, eventType], throttle(function (e) {
|
|
1266
|
+
var entity = entities[entityId]
|
|
1267
|
+
if (entity) {
|
|
1268
|
+
fn.call(null, e, entity.context, setState(entity))
|
|
1269
|
+
} else {
|
|
1270
|
+
fn.call(null, e)
|
|
1271
|
+
}
|
|
1272
|
+
}))
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* Unbind events for a entityId
|
|
1277
|
+
*
|
|
1278
|
+
* @param {String} entityId
|
|
1279
|
+
*/
|
|
1280
|
+
|
|
1281
|
+
function removeEvent (entityId, path, eventType) {
|
|
1282
|
+
var args = [entityId]
|
|
1283
|
+
if (path) args.push(path)
|
|
1284
|
+
if (eventType) args.push(eventType)
|
|
1285
|
+
keypath.del(handlers, args)
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Unbind all events from an entity
|
|
1290
|
+
*
|
|
1291
|
+
* @param {Entity} entity
|
|
1292
|
+
*/
|
|
1293
|
+
|
|
1294
|
+
function removeAllEvents (entityId) {
|
|
1295
|
+
keypath.del(handlers, [entityId])
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* Validate the current properties. These simple validations
|
|
1300
|
+
* make it easier to ensure the correct props are passed in.
|
|
1301
|
+
*
|
|
1302
|
+
* Available rules include:
|
|
1303
|
+
*
|
|
1304
|
+
* type: string | array | object | boolean | number | date | function
|
|
1305
|
+
* expects: [] An array of values this prop could equal
|
|
1306
|
+
* optional: Boolean
|
|
1307
|
+
*/
|
|
1308
|
+
|
|
1309
|
+
function validateProps (props, rules) {
|
|
1310
|
+
if (!options.validateProps) return
|
|
1311
|
+
|
|
1312
|
+
// TODO: Only validate in dev mode
|
|
1313
|
+
forEach(rules, function (options, name) {
|
|
1314
|
+
if (name === 'children') return
|
|
1315
|
+
var value = props[name]
|
|
1316
|
+
var optional = (options.optional === true)
|
|
1317
|
+
if (optional && value == null) {
|
|
1318
|
+
return
|
|
1319
|
+
}
|
|
1320
|
+
if (!optional && value == null) {
|
|
1321
|
+
throw new Error('Missing prop named: ' + name)
|
|
1322
|
+
}
|
|
1323
|
+
if (options.type && type(value) !== options.type) {
|
|
1324
|
+
throw new Error('Invalid type for prop named: ' + name)
|
|
1325
|
+
}
|
|
1326
|
+
if (options.expects && options.expects.indexOf(value) < 0) {
|
|
1327
|
+
throw new Error('Invalid value for prop named: ' + name + '. Must be one of ' + options.expects.toString())
|
|
1328
|
+
}
|
|
1329
|
+
})
|
|
1330
|
+
|
|
1331
|
+
// Now check for props that haven't been defined
|
|
1332
|
+
forEach(props, function (value, key) {
|
|
1333
|
+
if (key === 'children') return
|
|
1334
|
+
if (!rules[key]) throw new Error('Unexpected prop named: ' + key)
|
|
1335
|
+
})
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
/**
|
|
1339
|
+
* Used for debugging to inspect the current state without
|
|
1340
|
+
* us needing to explicitly manage storing/updating references.
|
|
1341
|
+
*
|
|
1342
|
+
* @return {Object}
|
|
1343
|
+
*/
|
|
1344
|
+
|
|
1345
|
+
function inspect () {
|
|
1346
|
+
return {
|
|
1347
|
+
entities: entities,
|
|
1348
|
+
pools: pools,
|
|
1349
|
+
handlers: handlers,
|
|
1350
|
+
connections: connections,
|
|
1351
|
+
currentElement: currentElement,
|
|
1352
|
+
options: options,
|
|
1353
|
+
app: app,
|
|
1354
|
+
container: container,
|
|
1355
|
+
children: children
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
/**
|
|
1360
|
+
* Return an object that lets us completely remove the automatic
|
|
1361
|
+
* DOM rendering and export debugging tools.
|
|
1362
|
+
*/
|
|
1363
|
+
|
|
1364
|
+
return {
|
|
1365
|
+
remove: teardown,
|
|
1366
|
+
inspect: inspect
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
/**
|
|
1371
|
+
* A rendered component instance.
|
|
1372
|
+
*
|
|
1373
|
+
* This manages the lifecycle, props and state of the component.
|
|
1374
|
+
* It's basically just a data object for more straightfoward lookup.
|
|
1375
|
+
*
|
|
1376
|
+
* @param {Component} component
|
|
1377
|
+
* @param {Object} props
|
|
1378
|
+
*/
|
|
1379
|
+
|
|
1380
|
+
function Entity (component, props) {
|
|
1381
|
+
this.id = uid()
|
|
1382
|
+
this.component = component
|
|
1383
|
+
this.propTypes = component.propTypes || {}
|
|
1384
|
+
this.context = {}
|
|
1385
|
+
this.context.id = this.id;
|
|
1386
|
+
this.context.props = defaults(props || {}, component.defaultProps || {})
|
|
1387
|
+
this.context.state = this.component.initialState ? this.component.initialState() : {}
|
|
1388
|
+
this.pendingProps = assign({}, this.context.props)
|
|
1389
|
+
this.pendingState = assign({}, this.context.state)
|
|
1390
|
+
this.dirty = false
|
|
1391
|
+
this.virtualElement = null
|
|
1392
|
+
this.nativeElement = null
|
|
1393
|
+
this.displayName = component.name || 'Component'
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
/**
|
|
1397
|
+
* Should we pool an element?
|
|
1398
|
+
*/
|
|
1399
|
+
|
|
1400
|
+
function canPool(tagName) {
|
|
1401
|
+
return avoidPooling.indexOf(tagName) < 0
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
/**
|
|
1405
|
+
* Get a nested node using a path
|
|
1406
|
+
*
|
|
1407
|
+
* @param {HTMLElement} el The root node '0'
|
|
1408
|
+
* @param {String} path The path string eg. '0.2.43'
|
|
1409
|
+
*/
|
|
1410
|
+
|
|
1411
|
+
function getNodeAtPath(el, path) {
|
|
1412
|
+
var parts = path.split('.')
|
|
1413
|
+
parts.shift()
|
|
1414
|
+
while (parts.length) {
|
|
1415
|
+
el = el.childNodes[parts.pop()]
|
|
1416
|
+
}
|
|
1417
|
+
return el
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
},{"./svg":5,"./utils":6,"component-raf":10,"component-type":11,"dom-pool":12,"dom-walk":13,"fast.js":41,"get-uid":57,"is-dom":58,"object-path":59,"per-frame":60}],4:[function(_require,module,exports){
|
|
1421
|
+
var utils = _require('./utils')
|
|
1422
|
+
var defaults = utils.defaults
|
|
1423
|
+
|
|
1424
|
+
/**
|
|
1425
|
+
* Expose `stringify`.
|
|
1426
|
+
*/
|
|
1427
|
+
|
|
1428
|
+
module.exports = function (app) {
|
|
1429
|
+
if (!app.element) {
|
|
1430
|
+
throw new Error('No element mounted')
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
/**
|
|
1434
|
+
* Render to string.
|
|
1435
|
+
*
|
|
1436
|
+
* @param {Component} component
|
|
1437
|
+
* @param {Object} [props]
|
|
1438
|
+
* @return {String}
|
|
1439
|
+
*/
|
|
1440
|
+
|
|
1441
|
+
function stringify (component, optProps) {
|
|
1442
|
+
var propTypes = component.propTypes || {}
|
|
1443
|
+
var state = component.initialState ? component.initialState() : {}
|
|
1444
|
+
var props = defaults(optProps, component.defaultProps || {})
|
|
1445
|
+
|
|
1446
|
+
for (var name in propTypes) {
|
|
1447
|
+
var options = propTypes[name]
|
|
1448
|
+
if (options.source) {
|
|
1449
|
+
props[name] = app.sources[options.source]
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
if (component.beforeMount) component.beforeMount({ props: props, state: state })
|
|
1454
|
+
if (component.beforeRender) component.beforeRender({ props: props, state: state })
|
|
1455
|
+
var node = component.render({ props: props, state: state })
|
|
1456
|
+
return stringifyNode(node, '0')
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* Render a node to a string
|
|
1461
|
+
*
|
|
1462
|
+
* @param {Node} node
|
|
1463
|
+
* @param {Tree} tree
|
|
1464
|
+
*
|
|
1465
|
+
* @return {String}
|
|
1466
|
+
*/
|
|
1467
|
+
|
|
1468
|
+
function stringifyNode (node, path) {
|
|
1469
|
+
switch (node.type) {
|
|
1470
|
+
case 'text': return node.data
|
|
1471
|
+
case 'element':
|
|
1472
|
+
var children = node.children
|
|
1473
|
+
var attributes = node.attributes
|
|
1474
|
+
var tagName = node.tagName
|
|
1475
|
+
var innerHTML = attributes.innerHTML
|
|
1476
|
+
var str = '<' + tagName + attrs(attributes) + '>'
|
|
1477
|
+
|
|
1478
|
+
if (innerHTML) {
|
|
1479
|
+
str += innerHTML
|
|
1480
|
+
} else {
|
|
1481
|
+
for (var i = 0, n = children.length; i < n; i++) {
|
|
1482
|
+
str += stringifyNode(children[i], path + '.' + i)
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
str += '</' + tagName + '>'
|
|
1487
|
+
return str
|
|
1488
|
+
case 'component': return stringify(node.component, node.props)
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
throw new Error('Invalid type')
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
return stringifyNode(app.element, '0')
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
/**
|
|
1498
|
+
* HTML attributes to string.
|
|
1499
|
+
*
|
|
1500
|
+
* @param {Object} attributes
|
|
1501
|
+
* @return {String}
|
|
1502
|
+
* @api private
|
|
1503
|
+
*/
|
|
1504
|
+
|
|
1505
|
+
function attrs (attributes) {
|
|
1506
|
+
var str = ''
|
|
1507
|
+
for (var key in attributes) {
|
|
1508
|
+
if (key === 'innerHTML') continue
|
|
1509
|
+
str += attr(key, attributes[key])
|
|
1510
|
+
}
|
|
1511
|
+
return str
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
/**
|
|
1515
|
+
* HTML attribute to string.
|
|
1516
|
+
*
|
|
1517
|
+
* @param {String} key
|
|
1518
|
+
* @param {String} val
|
|
1519
|
+
* @return {String}
|
|
1520
|
+
* @api private
|
|
1521
|
+
*/
|
|
1522
|
+
|
|
1523
|
+
function attr (key, val) {
|
|
1524
|
+
return ' ' + key + '="' + val + '"'
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
},{"./utils":6}],5:[function(_require,module,exports){
|
|
1528
|
+
var fast = _require('fast.js')
|
|
1529
|
+
var indexOf = fast.indexOf
|
|
1530
|
+
|
|
1531
|
+
/**
|
|
1532
|
+
* This file lists the supported SVG elements used by the
|
|
1533
|
+
* renderer. We may add better SVG support in the future
|
|
1534
|
+
* that doesn't require whitelisting elements.
|
|
1535
|
+
*/
|
|
1536
|
+
|
|
1537
|
+
exports.namespace = 'http://www.w3.org/2000/svg'
|
|
1538
|
+
|
|
1539
|
+
/**
|
|
1540
|
+
* Supported SVG elements
|
|
1541
|
+
*
|
|
1542
|
+
* @type {Array}
|
|
1543
|
+
*/
|
|
1544
|
+
|
|
1545
|
+
exports.elements = [
|
|
1546
|
+
'circle',
|
|
1547
|
+
'defs',
|
|
1548
|
+
'ellipse',
|
|
1549
|
+
'g',
|
|
1550
|
+
'line',
|
|
1551
|
+
'linearGradient',
|
|
1552
|
+
'mask',
|
|
1553
|
+
'path',
|
|
1554
|
+
'pattern',
|
|
1555
|
+
'polygon',
|
|
1556
|
+
'polyline',
|
|
1557
|
+
'radialGradient',
|
|
1558
|
+
'rect',
|
|
1559
|
+
'stop',
|
|
1560
|
+
'svg',
|
|
1561
|
+
'text',
|
|
1562
|
+
'tspan'
|
|
1563
|
+
]
|
|
1564
|
+
|
|
1565
|
+
/**
|
|
1566
|
+
* Supported SVG attributes
|
|
1567
|
+
*/
|
|
1568
|
+
|
|
1569
|
+
exports.attributes = [
|
|
1570
|
+
'cx',
|
|
1571
|
+
'cy',
|
|
1572
|
+
'd',
|
|
1573
|
+
'dx',
|
|
1574
|
+
'dy',
|
|
1575
|
+
'fill',
|
|
1576
|
+
'fillOpacity',
|
|
1577
|
+
'fontFamily',
|
|
1578
|
+
'fontSize',
|
|
1579
|
+
'fx',
|
|
1580
|
+
'fy',
|
|
1581
|
+
'gradientTransform',
|
|
1582
|
+
'gradientUnits',
|
|
1583
|
+
'markerEnd',
|
|
1584
|
+
'markerMid',
|
|
1585
|
+
'markerStart',
|
|
1586
|
+
'offset',
|
|
1587
|
+
'opacity',
|
|
1588
|
+
'patternContentUnits',
|
|
1589
|
+
'patternUnits',
|
|
1590
|
+
'points',
|
|
1591
|
+
'preserveAspectRatio',
|
|
1592
|
+
'r',
|
|
1593
|
+
'rx',
|
|
1594
|
+
'ry',
|
|
1595
|
+
'spreadMethod',
|
|
1596
|
+
'stopColor',
|
|
1597
|
+
'stopOpacity',
|
|
1598
|
+
'stroke',
|
|
1599
|
+
'strokeDasharray',
|
|
1600
|
+
'strokeLinecap',
|
|
1601
|
+
'strokeOpacity',
|
|
1602
|
+
'strokeWidth',
|
|
1603
|
+
'textAnchor',
|
|
1604
|
+
'transform',
|
|
1605
|
+
'version',
|
|
1606
|
+
'viewBox',
|
|
1607
|
+
'x1',
|
|
1608
|
+
'x2',
|
|
1609
|
+
'x',
|
|
1610
|
+
'y1',
|
|
1611
|
+
'y2',
|
|
1612
|
+
'y'
|
|
1613
|
+
]
|
|
1614
|
+
|
|
1615
|
+
/**
|
|
1616
|
+
* Is element's namespace SVG?
|
|
1617
|
+
*
|
|
1618
|
+
* @param {String} name
|
|
1619
|
+
*/
|
|
1620
|
+
|
|
1621
|
+
exports.isElement = function (name) {
|
|
1622
|
+
return indexOf(exports.elements, name) !== -1
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
/**
|
|
1626
|
+
* Are element's attributes SVG?
|
|
1627
|
+
*
|
|
1628
|
+
* @param {String} attr
|
|
1629
|
+
*/
|
|
1630
|
+
|
|
1631
|
+
exports.isAttribute = function (attr) {
|
|
1632
|
+
return indexOf(exports.attributes, attr) !== -1
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
|
|
1636
|
+
},{"fast.js":41}],6:[function(_require,module,exports){
|
|
1637
|
+
/**
|
|
1638
|
+
* The npm 'defaults' module but without clone because
|
|
1639
|
+
* it was requiring the 'Buffer' module which is huge.
|
|
1640
|
+
*
|
|
1641
|
+
* @param {Object} options
|
|
1642
|
+
* @param {Object} defaults
|
|
1643
|
+
*
|
|
1644
|
+
* @return {Object}
|
|
1645
|
+
*/
|
|
1646
|
+
|
|
1647
|
+
exports.defaults = function(options, defaults) {
|
|
1648
|
+
Object.keys(defaults).forEach(function(key) {
|
|
1649
|
+
if (typeof options[key] === 'undefined') {
|
|
1650
|
+
options[key] = defaults[key]
|
|
1651
|
+
}
|
|
1652
|
+
})
|
|
1653
|
+
return options
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
},{}],7:[function(_require,module,exports){
|
|
1657
|
+
/**
|
|
1658
|
+
* Module dependencies.
|
|
1659
|
+
*/
|
|
1660
|
+
|
|
1661
|
+
var type = _require('component-type')
|
|
1662
|
+
var slice = _require('sliced')
|
|
1663
|
+
var flatten = _require('array-flatten')
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* This function lets us create virtual nodes using a simple
|
|
1667
|
+
* syntax. It is compatible with JSX transforms so you can use
|
|
1668
|
+
* JSX to write nodes that will compile to this function.
|
|
1669
|
+
*
|
|
1670
|
+
* let node = virtual('div', { id: 'foo' }, [
|
|
1671
|
+
* virtual('a', { href: 'http://google.com' }, 'Google')
|
|
1672
|
+
* ])
|
|
1673
|
+
*
|
|
1674
|
+
* You can leave out the attributes or the children if either
|
|
1675
|
+
* of them aren't needed and it will figure out what you're
|
|
1676
|
+
* trying to do.
|
|
1677
|
+
*/
|
|
1678
|
+
|
|
1679
|
+
module.exports = virtual
|
|
1680
|
+
|
|
1681
|
+
/**
|
|
1682
|
+
* Create virtual DOM trees.
|
|
1683
|
+
*
|
|
1684
|
+
* This creates the nicer API for the user.
|
|
1685
|
+
* It translates that friendly API into an actual tree of nodes.
|
|
1686
|
+
*
|
|
1687
|
+
* @param {String|Function} type
|
|
1688
|
+
* @param {Object} props
|
|
1689
|
+
* @param {Array} children
|
|
1690
|
+
* @return {Node}
|
|
1691
|
+
* @api public
|
|
1692
|
+
*/
|
|
1693
|
+
|
|
1694
|
+
function virtual (type, props, children) {
|
|
1695
|
+
// Default to div with no args
|
|
1696
|
+
if (!type) {
|
|
1697
|
+
throw new Error('Element needs a type. https://gist.github.com/anthonyshort/77ced43b5defe39908af')
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
// Skipped adding attributes and we're passing
|
|
1701
|
+
// in children instead.
|
|
1702
|
+
if (arguments.length === 2 && (typeof props === 'string' || Array.isArray(props))) {
|
|
1703
|
+
children = props
|
|
1704
|
+
props = {}
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
// Account for JSX putting the children as multiple arguments.
|
|
1708
|
+
// This is essentially just the ES6 rest param
|
|
1709
|
+
if (arguments.length > 2 && Array.isArray(arguments[2]) === false) {
|
|
1710
|
+
children = slice(arguments, 2)
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
children = children || []
|
|
1714
|
+
props = props || {}
|
|
1715
|
+
|
|
1716
|
+
// passing in a single child, you can skip
|
|
1717
|
+
// using the array
|
|
1718
|
+
if (!Array.isArray(children)) {
|
|
1719
|
+
children = [ children ]
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
children = flatten(children, 1).reduce(normalize, [])
|
|
1723
|
+
|
|
1724
|
+
// pull the key out from the data.
|
|
1725
|
+
var key = 'key' in props ? String(props.key) : null
|
|
1726
|
+
delete props['key']
|
|
1727
|
+
|
|
1728
|
+
// if you pass in a function, it's a `Component` constructor.
|
|
1729
|
+
// otherwise it's an element.
|
|
1730
|
+
var node
|
|
1731
|
+
if (typeof type === 'string') {
|
|
1732
|
+
node = new ElementNode(type, props, key, children)
|
|
1733
|
+
} else {
|
|
1734
|
+
node = new ComponentNode(type, props, key, children)
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
// set the unique ID
|
|
1738
|
+
node.index = 0
|
|
1739
|
+
|
|
1740
|
+
return node
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* Parse nodes into real `Node` objects.
|
|
1745
|
+
*
|
|
1746
|
+
* @param {Mixed} node
|
|
1747
|
+
* @param {Integer} index
|
|
1748
|
+
* @return {Node}
|
|
1749
|
+
* @api private
|
|
1750
|
+
*/
|
|
1751
|
+
|
|
1752
|
+
function normalize (acc, node) {
|
|
1753
|
+
if (node == null) {
|
|
1754
|
+
return acc
|
|
1755
|
+
}
|
|
1756
|
+
if (typeof node === 'string' || typeof node === 'number') {
|
|
1757
|
+
var newNode = new TextNode(String(node))
|
|
1758
|
+
newNode.index = acc.length
|
|
1759
|
+
acc.push(newNode)
|
|
1760
|
+
} else {
|
|
1761
|
+
node.index = acc.length
|
|
1762
|
+
acc.push(node)
|
|
1763
|
+
}
|
|
1764
|
+
return acc
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* Initialize a new `ComponentNode`.
|
|
1769
|
+
*
|
|
1770
|
+
* @param {Component} component
|
|
1771
|
+
* @param {Object} props
|
|
1772
|
+
* @param {String} key Used for sorting/replacing during diffing.
|
|
1773
|
+
* @param {Array} children Child virtual nodes
|
|
1774
|
+
* @api public
|
|
1775
|
+
*/
|
|
1776
|
+
|
|
1777
|
+
function ComponentNode (component, props, key, children) {
|
|
1778
|
+
this.key = key
|
|
1779
|
+
this.props = props
|
|
1780
|
+
this.type = 'component'
|
|
1781
|
+
this.component = component
|
|
1782
|
+
this.props.children = children || []
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
/**
|
|
1786
|
+
* Initialize a new `ElementNode`.
|
|
1787
|
+
*
|
|
1788
|
+
* @param {String} tagName
|
|
1789
|
+
* @param {Object} attributes
|
|
1790
|
+
* @param {String} key Used for sorting/replacing during diffing.
|
|
1791
|
+
* @param {Array} children Child virtual dom nodes.
|
|
1792
|
+
* @api public
|
|
1793
|
+
*/
|
|
1794
|
+
|
|
1795
|
+
function ElementNode (tagName, attributes, key, children) {
|
|
1796
|
+
this.type = 'element'
|
|
1797
|
+
this.attributes = parseAttributes(attributes)
|
|
1798
|
+
this.tagName = tagName
|
|
1799
|
+
this.children = children || []
|
|
1800
|
+
this.key = key
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
/**
|
|
1804
|
+
* Initialize a new `TextNode`.
|
|
1805
|
+
*
|
|
1806
|
+
* This is just a virtual HTML text object.
|
|
1807
|
+
*
|
|
1808
|
+
* @param {String} text
|
|
1809
|
+
* @api public
|
|
1810
|
+
*/
|
|
1811
|
+
|
|
1812
|
+
function TextNode (text) {
|
|
1813
|
+
this.type = 'text'
|
|
1814
|
+
this.data = String(text)
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
/**
|
|
1818
|
+
* Parse attributes for some special cases.
|
|
1819
|
+
*
|
|
1820
|
+
* TODO: This could be more functional and allow hooks
|
|
1821
|
+
* into the processing of the attributes at a component-level
|
|
1822
|
+
*
|
|
1823
|
+
* @param {Object} attributes
|
|
1824
|
+
*
|
|
1825
|
+
* @return {Object}
|
|
1826
|
+
*/
|
|
1827
|
+
|
|
1828
|
+
function parseAttributes (attributes) {
|
|
1829
|
+
// style: { 'text-align': 'left' }
|
|
1830
|
+
if (attributes.style) {
|
|
1831
|
+
attributes.style = parseStyle(attributes.style)
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// class: { foo: true, bar: false, baz: true }
|
|
1835
|
+
// class: ['foo', 'bar', 'baz']
|
|
1836
|
+
if (attributes.class) {
|
|
1837
|
+
attributes.class = parseClass(attributes.class)
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// Remove attributes with false values
|
|
1841
|
+
var filteredAttributes = {}
|
|
1842
|
+
for (var key in attributes) {
|
|
1843
|
+
var value = attributes[key]
|
|
1844
|
+
if (value == null || value === false) continue
|
|
1845
|
+
filteredAttributes[key] = value
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
return filteredAttributes
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
/**
|
|
1852
|
+
* Parse a block of styles into a string.
|
|
1853
|
+
*
|
|
1854
|
+
* TODO: this could do a lot more with vendor prefixing,
|
|
1855
|
+
* number values etc. Maybe there's a way to allow users
|
|
1856
|
+
* to hook into this?
|
|
1857
|
+
*
|
|
1858
|
+
* @param {Object} styles
|
|
1859
|
+
*
|
|
1860
|
+
* @return {String}
|
|
1861
|
+
*/
|
|
1862
|
+
|
|
1863
|
+
function parseStyle (styles) {
|
|
1864
|
+
if (type(styles) === 'string') {
|
|
1865
|
+
return styles
|
|
1866
|
+
}
|
|
1867
|
+
var str = ''
|
|
1868
|
+
for (var name in styles) {
|
|
1869
|
+
var value = styles[name]
|
|
1870
|
+
str = str + name + ':' + value + ';'
|
|
1871
|
+
}
|
|
1872
|
+
return str;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
/**
|
|
1876
|
+
* Parse the class attribute so it's able to be
|
|
1877
|
+
* set in a more user-friendly way
|
|
1878
|
+
*
|
|
1879
|
+
* @param {String|Object|Array} value
|
|
1880
|
+
*
|
|
1881
|
+
* @return {String}
|
|
1882
|
+
*/
|
|
1883
|
+
|
|
1884
|
+
function parseClass (value) {
|
|
1885
|
+
// { foo: true, bar: false, baz: true }
|
|
1886
|
+
if (type(value) === 'object') {
|
|
1887
|
+
var matched = []
|
|
1888
|
+
for (var key in value) {
|
|
1889
|
+
if (value[key]) matched.push(key)
|
|
1890
|
+
}
|
|
1891
|
+
value = matched
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
// ['foo', 'bar', 'baz']
|
|
1895
|
+
if (type(value) === 'array') {
|
|
1896
|
+
if (value.length === 0) {
|
|
1897
|
+
return
|
|
1898
|
+
}
|
|
1899
|
+
value = value.join(' ')
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
return value
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
},{"array-flatten":8,"component-type":11,"sliced":61}],8:[function(_require,module,exports){
|
|
1906
|
+
/**
|
|
1907
|
+
* Recursive flatten function. Fastest implementation for array flattening.
|
|
1908
|
+
*
|
|
1909
|
+
* @param {Array} array
|
|
1910
|
+
* @param {Array} result
|
|
1911
|
+
* @param {Number} depth
|
|
1912
|
+
* @return {Array}
|
|
1913
|
+
*/
|
|
1914
|
+
function flatten (array, result, depth) {
|
|
1915
|
+
for (var i = 0; i < array.length; i++) {
|
|
1916
|
+
if (depth > 0 && Array.isArray(array[i])) {
|
|
1917
|
+
flatten(array[i], result, depth - 1);
|
|
1918
|
+
} else {
|
|
1919
|
+
result.push(array[i]);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
return result;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
/**
|
|
1927
|
+
* Flatten an array, with the ability to define a depth.
|
|
1928
|
+
*
|
|
1929
|
+
* @param {Array} array
|
|
1930
|
+
* @param {Number} depth
|
|
1931
|
+
* @return {Array}
|
|
1932
|
+
*/
|
|
1933
|
+
module.exports = function (array, depth) {
|
|
1934
|
+
return flatten(array, [], depth || Infinity);
|
|
1935
|
+
};
|
|
1936
|
+
|
|
1937
|
+
},{}],9:[function(_require,module,exports){
|
|
1938
|
+
|
|
1939
|
+
/**
|
|
1940
|
+
* Expose `Emitter`.
|
|
1941
|
+
*/
|
|
1942
|
+
|
|
1943
|
+
module.exports = Emitter;
|
|
1944
|
+
|
|
1945
|
+
/**
|
|
1946
|
+
* Initialize a new `Emitter`.
|
|
1947
|
+
*
|
|
1948
|
+
* @api public
|
|
1949
|
+
*/
|
|
1950
|
+
|
|
1951
|
+
function Emitter(obj) {
|
|
1952
|
+
if (obj) return mixin(obj);
|
|
1953
|
+
};
|
|
1954
|
+
|
|
1955
|
+
/**
|
|
1956
|
+
* Mixin the emitter properties.
|
|
1957
|
+
*
|
|
1958
|
+
* @param {Object} obj
|
|
1959
|
+
* @return {Object}
|
|
1960
|
+
* @api private
|
|
1961
|
+
*/
|
|
1962
|
+
|
|
1963
|
+
function mixin(obj) {
|
|
1964
|
+
for (var key in Emitter.prototype) {
|
|
1965
|
+
obj[key] = Emitter.prototype[key];
|
|
1966
|
+
}
|
|
1967
|
+
return obj;
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
/**
|
|
1971
|
+
* Listen on the given `event` with `fn`.
|
|
1972
|
+
*
|
|
1973
|
+
* @param {String} event
|
|
1974
|
+
* @param {Function} fn
|
|
1975
|
+
* @return {Emitter}
|
|
1976
|
+
* @api public
|
|
1977
|
+
*/
|
|
1978
|
+
|
|
1979
|
+
Emitter.prototype.on =
|
|
1980
|
+
Emitter.prototype.addEventListener = function(event, fn){
|
|
1981
|
+
this._callbacks = this._callbacks || {};
|
|
1982
|
+
(this._callbacks['$' + event] = this._callbacks['$' + event] || [])
|
|
1983
|
+
.push(fn);
|
|
1984
|
+
return this;
|
|
1985
|
+
};
|
|
1986
|
+
|
|
1987
|
+
/**
|
|
1988
|
+
* Adds an `event` listener that will be invoked a single
|
|
1989
|
+
* time then automatically removed.
|
|
1990
|
+
*
|
|
1991
|
+
* @param {String} event
|
|
1992
|
+
* @param {Function} fn
|
|
1993
|
+
* @return {Emitter}
|
|
1994
|
+
* @api public
|
|
1995
|
+
*/
|
|
1996
|
+
|
|
1997
|
+
Emitter.prototype.once = function(event, fn){
|
|
1998
|
+
function on() {
|
|
1999
|
+
this.off(event, on);
|
|
2000
|
+
fn.apply(this, arguments);
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
on.fn = fn;
|
|
2004
|
+
this.on(event, on);
|
|
2005
|
+
return this;
|
|
2006
|
+
};
|
|
2007
|
+
|
|
2008
|
+
/**
|
|
2009
|
+
* Remove the given callback for `event` or all
|
|
2010
|
+
* registered callbacks.
|
|
2011
|
+
*
|
|
2012
|
+
* @param {String} event
|
|
2013
|
+
* @param {Function} fn
|
|
2014
|
+
* @return {Emitter}
|
|
2015
|
+
* @api public
|
|
2016
|
+
*/
|
|
2017
|
+
|
|
2018
|
+
Emitter.prototype.off =
|
|
2019
|
+
Emitter.prototype.removeListener =
|
|
2020
|
+
Emitter.prototype.removeAllListeners =
|
|
2021
|
+
Emitter.prototype.removeEventListener = function(event, fn){
|
|
2022
|
+
this._callbacks = this._callbacks || {};
|
|
2023
|
+
|
|
2024
|
+
// all
|
|
2025
|
+
if (0 == arguments.length) {
|
|
2026
|
+
this._callbacks = {};
|
|
2027
|
+
return this;
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
// specific event
|
|
2031
|
+
var callbacks = this._callbacks['$' + event];
|
|
2032
|
+
if (!callbacks) return this;
|
|
2033
|
+
|
|
2034
|
+
// remove all handlers
|
|
2035
|
+
if (1 == arguments.length) {
|
|
2036
|
+
delete this._callbacks['$' + event];
|
|
2037
|
+
return this;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
// remove specific handler
|
|
2041
|
+
var cb;
|
|
2042
|
+
for (var i = 0; i < callbacks.length; i++) {
|
|
2043
|
+
cb = callbacks[i];
|
|
2044
|
+
if (cb === fn || cb.fn === fn) {
|
|
2045
|
+
callbacks.splice(i, 1);
|
|
2046
|
+
break;
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
return this;
|
|
2050
|
+
};
|
|
2051
|
+
|
|
2052
|
+
/**
|
|
2053
|
+
* Emit `event` with the given args.
|
|
2054
|
+
*
|
|
2055
|
+
* @param {String} event
|
|
2056
|
+
* @param {Mixed} ...
|
|
2057
|
+
* @return {Emitter}
|
|
2058
|
+
*/
|
|
2059
|
+
|
|
2060
|
+
Emitter.prototype.emit = function(event){
|
|
2061
|
+
this._callbacks = this._callbacks || {};
|
|
2062
|
+
var args = [].slice.call(arguments, 1)
|
|
2063
|
+
, callbacks = this._callbacks['$' + event];
|
|
2064
|
+
|
|
2065
|
+
if (callbacks) {
|
|
2066
|
+
callbacks = callbacks.slice(0);
|
|
2067
|
+
for (var i = 0, len = callbacks.length; i < len; ++i) {
|
|
2068
|
+
callbacks[i].apply(this, args);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
return this;
|
|
2073
|
+
};
|
|
2074
|
+
|
|
2075
|
+
/**
|
|
2076
|
+
* Return array of callbacks for `event`.
|
|
2077
|
+
*
|
|
2078
|
+
* @param {String} event
|
|
2079
|
+
* @return {Array}
|
|
2080
|
+
* @api public
|
|
2081
|
+
*/
|
|
2082
|
+
|
|
2083
|
+
Emitter.prototype.listeners = function(event){
|
|
2084
|
+
this._callbacks = this._callbacks || {};
|
|
2085
|
+
return this._callbacks['$' + event] || [];
|
|
2086
|
+
};
|
|
2087
|
+
|
|
2088
|
+
/**
|
|
2089
|
+
* Check if this emitter has `event` handlers.
|
|
2090
|
+
*
|
|
2091
|
+
* @param {String} event
|
|
2092
|
+
* @return {Boolean}
|
|
2093
|
+
* @api public
|
|
2094
|
+
*/
|
|
2095
|
+
|
|
2096
|
+
Emitter.prototype.hasListeners = function(event){
|
|
2097
|
+
return !! this.listeners(event).length;
|
|
2098
|
+
};
|
|
2099
|
+
|
|
2100
|
+
},{}],10:[function(_require,module,exports){
|
|
2101
|
+
/**
|
|
2102
|
+
* Expose `requestAnimationFrame()`.
|
|
2103
|
+
*/
|
|
2104
|
+
|
|
2105
|
+
exports = module.exports = window.requestAnimationFrame
|
|
2106
|
+
|| window.webkitRequestAnimationFrame
|
|
2107
|
+
|| window.mozRequestAnimationFrame
|
|
2108
|
+
|| fallback;
|
|
2109
|
+
|
|
2110
|
+
/**
|
|
2111
|
+
* Fallback implementation.
|
|
2112
|
+
*/
|
|
2113
|
+
|
|
2114
|
+
var prev = new Date().getTime();
|
|
2115
|
+
function fallback(fn) {
|
|
2116
|
+
var curr = new Date().getTime();
|
|
2117
|
+
var ms = Math.max(0, 16 - (curr - prev));
|
|
2118
|
+
var req = setTimeout(fn, ms);
|
|
2119
|
+
prev = curr;
|
|
2120
|
+
return req;
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* Cancel.
|
|
2125
|
+
*/
|
|
2126
|
+
|
|
2127
|
+
var cancel = window.cancelAnimationFrame
|
|
2128
|
+
|| window.webkitCancelAnimationFrame
|
|
2129
|
+
|| window.mozCancelAnimationFrame
|
|
2130
|
+
|| window.clearTimeout;
|
|
2131
|
+
|
|
2132
|
+
exports.cancel = function(id){
|
|
2133
|
+
cancel.call(window, id);
|
|
2134
|
+
};
|
|
2135
|
+
|
|
2136
|
+
},{}],11:[function(_require,module,exports){
|
|
2137
|
+
/**
|
|
2138
|
+
* toString ref.
|
|
2139
|
+
*/
|
|
2140
|
+
|
|
2141
|
+
var toString = Object.prototype.toString;
|
|
2142
|
+
|
|
2143
|
+
/**
|
|
2144
|
+
* Return the type of `val`.
|
|
2145
|
+
*
|
|
2146
|
+
* @param {Mixed} val
|
|
2147
|
+
* @return {String}
|
|
2148
|
+
* @api public
|
|
2149
|
+
*/
|
|
2150
|
+
|
|
2151
|
+
module.exports = function(val){
|
|
2152
|
+
switch (toString.call(val)) {
|
|
2153
|
+
case '[object Date]': return 'date';
|
|
2154
|
+
case '[object RegExp]': return 'regexp';
|
|
2155
|
+
case '[object Arguments]': return 'arguments';
|
|
2156
|
+
case '[object Array]': return 'array';
|
|
2157
|
+
case '[object Error]': return 'error';
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
if (val === null) return 'null';
|
|
2161
|
+
if (val === undefined) return 'undefined';
|
|
2162
|
+
if (val !== val) return 'nan';
|
|
2163
|
+
if (val && val.nodeType === 1) return 'element';
|
|
2164
|
+
|
|
2165
|
+
val = val.valueOf
|
|
2166
|
+
? val.valueOf()
|
|
2167
|
+
: Object.prototype.valueOf.apply(val)
|
|
2168
|
+
|
|
2169
|
+
return typeof val;
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
},{}],12:[function(_require,module,exports){
|
|
2173
|
+
function Pool(params) {
|
|
2174
|
+
if (typeof params !== 'object') {
|
|
2175
|
+
throw new Error("Please pass parameters. Example -> new Pool({ tagName: \"div\" })");
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
if (typeof params.tagName !== 'string') {
|
|
2179
|
+
throw new Error("Please specify a tagName. Example -> new Pool({ tagName: \"div\" })");
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
this.storage = [];
|
|
2183
|
+
this.tagName = params.tagName.toLowerCase();
|
|
2184
|
+
this.namespace = params.namespace;
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
Pool.prototype.push = function(el) {
|
|
2188
|
+
if (el.tagName.toLowerCase() !== this.tagName) {
|
|
2189
|
+
return;
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
this.storage.push(el);
|
|
2193
|
+
};
|
|
2194
|
+
|
|
2195
|
+
Pool.prototype.pop = function(argument) {
|
|
2196
|
+
if (this.storage.length === 0) {
|
|
2197
|
+
return this.create();
|
|
2198
|
+
} else {
|
|
2199
|
+
return this.storage.pop();
|
|
2200
|
+
}
|
|
2201
|
+
};
|
|
2202
|
+
|
|
2203
|
+
Pool.prototype.create = function() {
|
|
2204
|
+
if (this.namespace) {
|
|
2205
|
+
return document.createElementNS(this.namespace, this.tagName);
|
|
2206
|
+
} else {
|
|
2207
|
+
return document.createElement(this.tagName);
|
|
2208
|
+
}
|
|
2209
|
+
};
|
|
2210
|
+
|
|
2211
|
+
Pool.prototype.allocate = function(size) {
|
|
2212
|
+
if (this.storage.length >= size) {
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
var difference = size - this.storage.length;
|
|
2217
|
+
for (var poolAllocIter = 0; poolAllocIter < difference; poolAllocIter++) {
|
|
2218
|
+
this.storage.push(this.create());
|
|
2219
|
+
}
|
|
2220
|
+
};
|
|
2221
|
+
|
|
2222
|
+
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
2223
|
+
module.exports = Pool;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
},{}],13:[function(_require,module,exports){
|
|
2227
|
+
var slice = Array.prototype.slice
|
|
2228
|
+
|
|
2229
|
+
module.exports = iterativelyWalk
|
|
2230
|
+
|
|
2231
|
+
function iterativelyWalk(nodes, cb) {
|
|
2232
|
+
if (!('length' in nodes)) {
|
|
2233
|
+
nodes = [nodes]
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
nodes = slice.call(nodes)
|
|
2237
|
+
|
|
2238
|
+
while(nodes.length) {
|
|
2239
|
+
var node = nodes.shift(),
|
|
2240
|
+
ret = cb(node)
|
|
2241
|
+
|
|
2242
|
+
if (ret) {
|
|
2243
|
+
return ret
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
if (node.childNodes && node.childNodes.length) {
|
|
2247
|
+
nodes = slice.call(node.childNodes).concat(nodes)
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
},{}],14:[function(_require,module,exports){
|
|
2253
|
+
'use strict';
|
|
2254
|
+
|
|
2255
|
+
/**
|
|
2256
|
+
* # Clone Array
|
|
2257
|
+
*
|
|
2258
|
+
* Clone an array or array like object (e.g. `arguments`).
|
|
2259
|
+
* This is the equivalent of calling `Array.prototype.slice.call(arguments)`, but
|
|
2260
|
+
* significantly faster.
|
|
2261
|
+
*
|
|
2262
|
+
* @param {Array} input The array or array-like object to clone.
|
|
2263
|
+
* @return {Array} The cloned array.
|
|
2264
|
+
*/
|
|
2265
|
+
module.exports = function fastCloneArray (input) {
|
|
2266
|
+
var length = input.length,
|
|
2267
|
+
sliced = new Array(length),
|
|
2268
|
+
i;
|
|
2269
|
+
for (i = 0; i < length; i++) {
|
|
2270
|
+
sliced[i] = input[i];
|
|
2271
|
+
}
|
|
2272
|
+
return sliced;
|
|
2273
|
+
};
|
|
2274
|
+
|
|
2275
|
+
},{}],15:[function(_require,module,exports){
|
|
2276
|
+
'use strict';
|
|
2277
|
+
|
|
2278
|
+
/**
|
|
2279
|
+
* # Concat
|
|
2280
|
+
*
|
|
2281
|
+
* Concatenate multiple arrays.
|
|
2282
|
+
*
|
|
2283
|
+
* > Note: This function is effectively identical to `Array.prototype.concat()`.
|
|
2284
|
+
*
|
|
2285
|
+
*
|
|
2286
|
+
* @param {Array|mixed} item, ... The item(s) to concatenate.
|
|
2287
|
+
* @return {Array} The array containing the concatenated items.
|
|
2288
|
+
*/
|
|
2289
|
+
module.exports = function fastConcat () {
|
|
2290
|
+
var length = arguments.length,
|
|
2291
|
+
arr = [],
|
|
2292
|
+
i, item, childLength, j;
|
|
2293
|
+
|
|
2294
|
+
for (i = 0; i < length; i++) {
|
|
2295
|
+
item = arguments[i];
|
|
2296
|
+
if (Array.isArray(item)) {
|
|
2297
|
+
childLength = item.length;
|
|
2298
|
+
for (j = 0; j < childLength; j++) {
|
|
2299
|
+
arr.push(item[j]);
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
else {
|
|
2303
|
+
arr.push(item);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
return arr;
|
|
2307
|
+
};
|
|
2308
|
+
|
|
2309
|
+
},{}],16:[function(_require,module,exports){
|
|
2310
|
+
'use strict';
|
|
2311
|
+
|
|
2312
|
+
var bindInternal3 = _require('../function/bindInternal3');
|
|
2313
|
+
|
|
2314
|
+
/**
|
|
2315
|
+
* # Every
|
|
2316
|
+
*
|
|
2317
|
+
* A fast `.every()` implementation.
|
|
2318
|
+
*
|
|
2319
|
+
* @param {Array} subject The array (or array-like) to iterate over.
|
|
2320
|
+
* @param {Function} fn The visitor function.
|
|
2321
|
+
* @param {Object} thisContext The context for the visitor.
|
|
2322
|
+
* @return {Boolean} true if all items in the array passes the truth test.
|
|
2323
|
+
*/
|
|
2324
|
+
module.exports = function fastEvery (subject, fn, thisContext) {
|
|
2325
|
+
var length = subject.length,
|
|
2326
|
+
iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
|
|
2327
|
+
i;
|
|
2328
|
+
for (i = 0; i < length; i++) {
|
|
2329
|
+
if (!iterator(subject[i], i, subject)) {
|
|
2330
|
+
return false;
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
return true;
|
|
2334
|
+
};
|
|
2335
|
+
|
|
2336
|
+
},{"../function/bindInternal3":35}],17:[function(_require,module,exports){
|
|
2337
|
+
'use strict';
|
|
2338
|
+
|
|
2339
|
+
/**
|
|
2340
|
+
* # Fill
|
|
2341
|
+
* Fill an array with values, optionally starting and stopping at a given index.
|
|
2342
|
+
*
|
|
2343
|
+
* > Note: unlike the specced Array.prototype.fill(), this version does not support
|
|
2344
|
+
* > negative start / end arguments.
|
|
2345
|
+
*
|
|
2346
|
+
* @param {Array} subject The array to fill.
|
|
2347
|
+
* @param {mixed} value The value to insert.
|
|
2348
|
+
* @param {Integer} start The start position, defaults to 0.
|
|
2349
|
+
* @param {Integer} end The end position, defaults to subject.length
|
|
2350
|
+
* @return {Array} The now filled subject.
|
|
2351
|
+
*/
|
|
2352
|
+
module.exports = function fastFill (subject, value, start, end) {
|
|
2353
|
+
var length = subject.length,
|
|
2354
|
+
i;
|
|
2355
|
+
if (start === undefined) {
|
|
2356
|
+
start = 0;
|
|
2357
|
+
}
|
|
2358
|
+
if (end === undefined) {
|
|
2359
|
+
end = length;
|
|
2360
|
+
}
|
|
2361
|
+
for (i = start; i < end; i++) {
|
|
2362
|
+
subject[i] = value;
|
|
2363
|
+
}
|
|
2364
|
+
return subject;
|
|
2365
|
+
};
|
|
2366
|
+
},{}],18:[function(_require,module,exports){
|
|
2367
|
+
'use strict';
|
|
2368
|
+
|
|
2369
|
+
var bindInternal3 = _require('../function/bindInternal3');
|
|
2370
|
+
|
|
2371
|
+
/**
|
|
2372
|
+
* # Filter
|
|
2373
|
+
*
|
|
2374
|
+
* A fast `.filter()` implementation.
|
|
2375
|
+
*
|
|
2376
|
+
* @param {Array} subject The array (or array-like) to filter.
|
|
2377
|
+
* @param {Function} fn The filter function.
|
|
2378
|
+
* @param {Object} thisContext The context for the filter.
|
|
2379
|
+
* @return {Array} The array containing the results.
|
|
2380
|
+
*/
|
|
2381
|
+
module.exports = function fastFilter (subject, fn, thisContext) {
|
|
2382
|
+
var length = subject.length,
|
|
2383
|
+
result = [],
|
|
2384
|
+
iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
|
|
2385
|
+
i;
|
|
2386
|
+
for (i = 0; i < length; i++) {
|
|
2387
|
+
if (iterator(subject[i], i, subject)) {
|
|
2388
|
+
result.push(subject[i]);
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
return result;
|
|
2392
|
+
};
|
|
2393
|
+
|
|
2394
|
+
},{"../function/bindInternal3":35}],19:[function(_require,module,exports){
|
|
2395
|
+
'use strict';
|
|
2396
|
+
|
|
2397
|
+
var bindInternal3 = _require('../function/bindInternal3');
|
|
2398
|
+
|
|
2399
|
+
/**
|
|
2400
|
+
* # For Each
|
|
2401
|
+
*
|
|
2402
|
+
* A fast `.forEach()` implementation.
|
|
2403
|
+
*
|
|
2404
|
+
* @param {Array} subject The array (or array-like) to iterate over.
|
|
2405
|
+
* @param {Function} fn The visitor function.
|
|
2406
|
+
* @param {Object} thisContext The context for the visitor.
|
|
2407
|
+
*/
|
|
2408
|
+
module.exports = function fastForEach (subject, fn, thisContext) {
|
|
2409
|
+
var length = subject.length,
|
|
2410
|
+
iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
|
|
2411
|
+
i;
|
|
2412
|
+
for (i = 0; i < length; i++) {
|
|
2413
|
+
iterator(subject[i], i, subject);
|
|
2414
|
+
}
|
|
2415
|
+
};
|
|
2416
|
+
|
|
2417
|
+
},{"../function/bindInternal3":35}],20:[function(_require,module,exports){
|
|
2418
|
+
'use strict';
|
|
2419
|
+
|
|
2420
|
+
exports.clone = _require('./clone');
|
|
2421
|
+
exports.concat = _require('./concat');
|
|
2422
|
+
exports.every = _require('./every');
|
|
2423
|
+
exports.filter = _require('./filter');
|
|
2424
|
+
exports.forEach = _require('./forEach');
|
|
2425
|
+
exports.indexOf = _require('./indexOf');
|
|
2426
|
+
exports.lastIndexOf = _require('./lastIndexOf');
|
|
2427
|
+
exports.map = _require('./map');
|
|
2428
|
+
exports.pluck = _require('./pluck');
|
|
2429
|
+
exports.reduce = _require('./reduce');
|
|
2430
|
+
exports.reduceRight = _require('./reduceRight');
|
|
2431
|
+
exports.some = _require('./some');
|
|
2432
|
+
exports.fill = _require('./fill');
|
|
2433
|
+
},{"./clone":14,"./concat":15,"./every":16,"./fill":17,"./filter":18,"./forEach":19,"./indexOf":21,"./lastIndexOf":22,"./map":23,"./pluck":24,"./reduce":25,"./reduceRight":26,"./some":27}],21:[function(_require,module,exports){
|
|
2434
|
+
'use strict';
|
|
2435
|
+
|
|
2436
|
+
/**
|
|
2437
|
+
* # Index Of
|
|
2438
|
+
*
|
|
2439
|
+
* A faster `Array.prototype.indexOf()` implementation.
|
|
2440
|
+
*
|
|
2441
|
+
* @param {Array} subject The array (or array-like) to search within.
|
|
2442
|
+
* @param {mixed} target The target item to search for.
|
|
2443
|
+
* @param {Number} fromIndex The position to start searching from, if known.
|
|
2444
|
+
* @return {Number} The position of the target in the subject, or -1 if it does not exist.
|
|
2445
|
+
*/
|
|
2446
|
+
module.exports = function fastIndexOf (subject, target, fromIndex) {
|
|
2447
|
+
var length = subject.length,
|
|
2448
|
+
i = 0;
|
|
2449
|
+
|
|
2450
|
+
if (typeof fromIndex === 'number') {
|
|
2451
|
+
i = fromIndex;
|
|
2452
|
+
if (i < 0) {
|
|
2453
|
+
i += length;
|
|
2454
|
+
if (i < 0) {
|
|
2455
|
+
i = 0;
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
for (; i < length; i++) {
|
|
2461
|
+
if (subject[i] === target) {
|
|
2462
|
+
return i;
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
return -1;
|
|
2466
|
+
};
|
|
2467
|
+
|
|
2468
|
+
},{}],22:[function(_require,module,exports){
|
|
2469
|
+
'use strict';
|
|
2470
|
+
|
|
2471
|
+
/**
|
|
2472
|
+
* # Last Index Of
|
|
2473
|
+
*
|
|
2474
|
+
* A faster `Array.prototype.lastIndexOf()` implementation.
|
|
2475
|
+
*
|
|
2476
|
+
* @param {Array} subject The array (or array-like) to search within.
|
|
2477
|
+
* @param {mixed} target The target item to search for.
|
|
2478
|
+
* @param {Number} fromIndex The position to start searching backwards from, if known.
|
|
2479
|
+
* @return {Number} The last position of the target in the subject, or -1 if it does not exist.
|
|
2480
|
+
*/
|
|
2481
|
+
module.exports = function fastLastIndexOf (subject, target, fromIndex) {
|
|
2482
|
+
var length = subject.length,
|
|
2483
|
+
i = length - 1;
|
|
2484
|
+
|
|
2485
|
+
if (typeof fromIndex === 'number') {
|
|
2486
|
+
i = fromIndex;
|
|
2487
|
+
if (i < 0) {
|
|
2488
|
+
i += length;
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
for (; i >= 0; i--) {
|
|
2492
|
+
if (subject[i] === target) {
|
|
2493
|
+
return i;
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
return -1;
|
|
2497
|
+
};
|
|
2498
|
+
|
|
2499
|
+
},{}],23:[function(_require,module,exports){
|
|
2500
|
+
'use strict';
|
|
2501
|
+
|
|
2502
|
+
var bindInternal3 = _require('../function/bindInternal3');
|
|
2503
|
+
|
|
2504
|
+
/**
|
|
2505
|
+
* # Map
|
|
2506
|
+
*
|
|
2507
|
+
* A fast `.map()` implementation.
|
|
2508
|
+
*
|
|
2509
|
+
* @param {Array} subject The array (or array-like) to map over.
|
|
2510
|
+
* @param {Function} fn The mapper function.
|
|
2511
|
+
* @param {Object} thisContext The context for the mapper.
|
|
2512
|
+
* @return {Array} The array containing the results.
|
|
2513
|
+
*/
|
|
2514
|
+
module.exports = function fastMap (subject, fn, thisContext) {
|
|
2515
|
+
var length = subject.length,
|
|
2516
|
+
result = new Array(length),
|
|
2517
|
+
iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
|
|
2518
|
+
i;
|
|
2519
|
+
for (i = 0; i < length; i++) {
|
|
2520
|
+
result[i] = iterator(subject[i], i, subject);
|
|
2521
|
+
}
|
|
2522
|
+
return result;
|
|
2523
|
+
};
|
|
2524
|
+
|
|
2525
|
+
},{"../function/bindInternal3":35}],24:[function(_require,module,exports){
|
|
2526
|
+
'use strict';
|
|
2527
|
+
|
|
2528
|
+
/**
|
|
2529
|
+
* # Pluck
|
|
2530
|
+
* Pluck the property with the given name from an array of objects.
|
|
2531
|
+
*
|
|
2532
|
+
* @param {Array} input The values to pluck from.
|
|
2533
|
+
* @param {String} field The name of the field to pluck.
|
|
2534
|
+
* @return {Array} The plucked array of values.
|
|
2535
|
+
*/
|
|
2536
|
+
module.exports = function fastPluck (input, field) {
|
|
2537
|
+
var length = input.length,
|
|
2538
|
+
plucked = [],
|
|
2539
|
+
count = 0,
|
|
2540
|
+
value, i;
|
|
2541
|
+
|
|
2542
|
+
for (i = 0; i < length; i++) {
|
|
2543
|
+
value = input[i];
|
|
2544
|
+
if (value != null && value[field] !== undefined) {
|
|
2545
|
+
plucked[count++] = value[field];
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
return plucked;
|
|
2549
|
+
};
|
|
2550
|
+
},{}],25:[function(_require,module,exports){
|
|
2551
|
+
'use strict';
|
|
2552
|
+
|
|
2553
|
+
var bindInternal4 = _require('../function/bindInternal4');
|
|
2554
|
+
|
|
2555
|
+
/**
|
|
2556
|
+
* # Reduce
|
|
2557
|
+
*
|
|
2558
|
+
* A fast `.reduce()` implementation.
|
|
2559
|
+
*
|
|
2560
|
+
* @param {Array} subject The array (or array-like) to reduce.
|
|
2561
|
+
* @param {Function} fn The reducer function.
|
|
2562
|
+
* @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
|
|
2563
|
+
* @param {Object} thisContext The context for the reducer.
|
|
2564
|
+
* @return {mixed} The final result.
|
|
2565
|
+
*/
|
|
2566
|
+
module.exports = function fastReduce (subject, fn, initialValue, thisContext) {
|
|
2567
|
+
var length = subject.length,
|
|
2568
|
+
iterator = thisContext !== undefined ? bindInternal4(fn, thisContext) : fn,
|
|
2569
|
+
i, result;
|
|
2570
|
+
|
|
2571
|
+
if (initialValue === undefined) {
|
|
2572
|
+
i = 1;
|
|
2573
|
+
result = subject[0];
|
|
2574
|
+
}
|
|
2575
|
+
else {
|
|
2576
|
+
i = 0;
|
|
2577
|
+
result = initialValue;
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
for (; i < length; i++) {
|
|
2581
|
+
result = iterator(result, subject[i], i, subject);
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
return result;
|
|
2585
|
+
};
|
|
2586
|
+
|
|
2587
|
+
},{"../function/bindInternal4":36}],26:[function(_require,module,exports){
|
|
2588
|
+
'use strict';
|
|
2589
|
+
|
|
2590
|
+
var bindInternal4 = _require('../function/bindInternal4');
|
|
2591
|
+
|
|
2592
|
+
/**
|
|
2593
|
+
* # Reduce Right
|
|
2594
|
+
*
|
|
2595
|
+
* A fast `.reduceRight()` implementation.
|
|
2596
|
+
*
|
|
2597
|
+
* @param {Array} subject The array (or array-like) to reduce.
|
|
2598
|
+
* @param {Function} fn The reducer function.
|
|
2599
|
+
* @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
|
|
2600
|
+
* @param {Object} thisContext The context for the reducer.
|
|
2601
|
+
* @return {mixed} The final result.
|
|
2602
|
+
*/
|
|
2603
|
+
module.exports = function fastReduce (subject, fn, initialValue, thisContext) {
|
|
2604
|
+
var length = subject.length,
|
|
2605
|
+
iterator = thisContext !== undefined ? bindInternal4(fn, thisContext) : fn,
|
|
2606
|
+
i, result;
|
|
2607
|
+
|
|
2608
|
+
if (initialValue === undefined) {
|
|
2609
|
+
i = length - 2;
|
|
2610
|
+
result = subject[length - 1];
|
|
2611
|
+
}
|
|
2612
|
+
else {
|
|
2613
|
+
i = length - 1;
|
|
2614
|
+
result = initialValue;
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
for (; i >= 0; i--) {
|
|
2618
|
+
result = iterator(result, subject[i], i, subject);
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
return result;
|
|
2622
|
+
};
|
|
2623
|
+
|
|
2624
|
+
},{"../function/bindInternal4":36}],27:[function(_require,module,exports){
|
|
2625
|
+
'use strict';
|
|
2626
|
+
|
|
2627
|
+
var bindInternal3 = _require('../function/bindInternal3');
|
|
2628
|
+
|
|
2629
|
+
/**
|
|
2630
|
+
* # Some
|
|
2631
|
+
*
|
|
2632
|
+
* A fast `.some()` implementation.
|
|
2633
|
+
*
|
|
2634
|
+
* @param {Array} subject The array (or array-like) to iterate over.
|
|
2635
|
+
* @param {Function} fn The visitor function.
|
|
2636
|
+
* @param {Object} thisContext The context for the visitor.
|
|
2637
|
+
* @return {Boolean} true if at least one item in the array passes the truth test.
|
|
2638
|
+
*/
|
|
2639
|
+
module.exports = function fastSome (subject, fn, thisContext) {
|
|
2640
|
+
var length = subject.length,
|
|
2641
|
+
iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
|
|
2642
|
+
i;
|
|
2643
|
+
for (i = 0; i < length; i++) {
|
|
2644
|
+
if (iterator(subject[i], i, subject)) {
|
|
2645
|
+
return true;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
return false;
|
|
2649
|
+
};
|
|
2650
|
+
|
|
2651
|
+
},{"../function/bindInternal3":35}],28:[function(_require,module,exports){
|
|
2652
|
+
'use strict';
|
|
2653
|
+
|
|
2654
|
+
var cloneArray = _require('./array/clone');
|
|
2655
|
+
var cloneObject = _require('./object/clone');
|
|
2656
|
+
|
|
2657
|
+
/**
|
|
2658
|
+
* # Clone
|
|
2659
|
+
*
|
|
2660
|
+
* Clone an item. Primitive values will be returned directly,
|
|
2661
|
+
* arrays and objects will be shallow cloned. If you know the
|
|
2662
|
+
* type of input you're dealing with, call `.cloneArray()` or `.cloneObject()`
|
|
2663
|
+
* instead.
|
|
2664
|
+
*
|
|
2665
|
+
* @param {mixed} input The input to clone.
|
|
2666
|
+
* @return {mixed} The cloned input.
|
|
2667
|
+
*/
|
|
2668
|
+
module.exports = function clone (input) {
|
|
2669
|
+
if (!input || typeof input !== 'object') {
|
|
2670
|
+
return input;
|
|
2671
|
+
}
|
|
2672
|
+
else if (Array.isArray(input)) {
|
|
2673
|
+
return cloneArray(input);
|
|
2674
|
+
}
|
|
2675
|
+
else {
|
|
2676
|
+
return cloneObject(input);
|
|
2677
|
+
}
|
|
2678
|
+
};
|
|
2679
|
+
|
|
2680
|
+
},{"./array/clone":14,"./object/clone":44}],29:[function(_require,module,exports){
|
|
2681
|
+
'use strict';
|
|
2682
|
+
|
|
2683
|
+
var filterArray = _require('./array/filter'),
|
|
2684
|
+
filterObject = _require('./object/filter');
|
|
2685
|
+
|
|
2686
|
+
/**
|
|
2687
|
+
* # Filter
|
|
2688
|
+
*
|
|
2689
|
+
* A fast `.filter()` implementation.
|
|
2690
|
+
*
|
|
2691
|
+
* @param {Array|Object} subject The array or object to filter.
|
|
2692
|
+
* @param {Function} fn The filter function.
|
|
2693
|
+
* @param {Object} thisContext The context for the filter.
|
|
2694
|
+
* @return {Array|Object} The array or object containing the filtered results.
|
|
2695
|
+
*/
|
|
2696
|
+
module.exports = function fastFilter (subject, fn, thisContext) {
|
|
2697
|
+
if (subject instanceof Array) {
|
|
2698
|
+
return filterArray(subject, fn, thisContext);
|
|
2699
|
+
}
|
|
2700
|
+
else {
|
|
2701
|
+
return filterObject(subject, fn, thisContext);
|
|
2702
|
+
}
|
|
2703
|
+
};
|
|
2704
|
+
},{"./array/filter":18,"./object/filter":45}],30:[function(_require,module,exports){
|
|
2705
|
+
'use strict';
|
|
2706
|
+
|
|
2707
|
+
var forEachArray = _require('./array/forEach'),
|
|
2708
|
+
forEachObject = _require('./object/forEach');
|
|
2709
|
+
|
|
2710
|
+
/**
|
|
2711
|
+
* # ForEach
|
|
2712
|
+
*
|
|
2713
|
+
* A fast `.forEach()` implementation.
|
|
2714
|
+
*
|
|
2715
|
+
* @param {Array|Object} subject The array or object to iterate over.
|
|
2716
|
+
* @param {Function} fn The visitor function.
|
|
2717
|
+
* @param {Object} thisContext The context for the visitor.
|
|
2718
|
+
*/
|
|
2719
|
+
module.exports = function fastForEach (subject, fn, thisContext) {
|
|
2720
|
+
if (subject instanceof Array) {
|
|
2721
|
+
return forEachArray(subject, fn, thisContext);
|
|
2722
|
+
}
|
|
2723
|
+
else {
|
|
2724
|
+
return forEachObject(subject, fn, thisContext);
|
|
2725
|
+
}
|
|
2726
|
+
};
|
|
2727
|
+
},{"./array/forEach":19,"./object/forEach":46}],31:[function(_require,module,exports){
|
|
2728
|
+
'use strict';
|
|
2729
|
+
|
|
2730
|
+
var applyWithContext = _require('./applyWithContext');
|
|
2731
|
+
var applyNoContext = _require('./applyNoContext');
|
|
2732
|
+
|
|
2733
|
+
/**
|
|
2734
|
+
* # Apply
|
|
2735
|
+
*
|
|
2736
|
+
* Faster version of `Function::apply()`, optimised for 8 arguments or fewer.
|
|
2737
|
+
*
|
|
2738
|
+
*
|
|
2739
|
+
* @param {Function} subject The function to apply.
|
|
2740
|
+
* @param {Object} thisContext The context for the function, set to undefined or null if no context is required.
|
|
2741
|
+
* @param {Array} args The arguments for the function.
|
|
2742
|
+
* @return {mixed} The result of the function invocation.
|
|
2743
|
+
*/
|
|
2744
|
+
module.exports = function fastApply (subject, thisContext, args) {
|
|
2745
|
+
return thisContext !== undefined ? applyWithContext(subject, thisContext, args) : applyNoContext(subject, args);
|
|
2746
|
+
};
|
|
2747
|
+
|
|
2748
|
+
},{"./applyNoContext":32,"./applyWithContext":33}],32:[function(_require,module,exports){
|
|
2749
|
+
'use strict';
|
|
2750
|
+
|
|
2751
|
+
/**
|
|
2752
|
+
* Internal helper for applying a function without a context.
|
|
2753
|
+
*/
|
|
2754
|
+
module.exports = function applyNoContext (subject, args) {
|
|
2755
|
+
switch (args.length) {
|
|
2756
|
+
case 0:
|
|
2757
|
+
return subject();
|
|
2758
|
+
case 1:
|
|
2759
|
+
return subject(args[0]);
|
|
2760
|
+
case 2:
|
|
2761
|
+
return subject(args[0], args[1]);
|
|
2762
|
+
case 3:
|
|
2763
|
+
return subject(args[0], args[1], args[2]);
|
|
2764
|
+
case 4:
|
|
2765
|
+
return subject(args[0], args[1], args[2], args[3]);
|
|
2766
|
+
case 5:
|
|
2767
|
+
return subject(args[0], args[1], args[2], args[3], args[4]);
|
|
2768
|
+
case 6:
|
|
2769
|
+
return subject(args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
2770
|
+
case 7:
|
|
2771
|
+
return subject(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
2772
|
+
case 8:
|
|
2773
|
+
return subject(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
|
|
2774
|
+
default:
|
|
2775
|
+
return subject.apply(undefined, args);
|
|
2776
|
+
}
|
|
2777
|
+
};
|
|
2778
|
+
|
|
2779
|
+
},{}],33:[function(_require,module,exports){
|
|
2780
|
+
'use strict';
|
|
2781
|
+
|
|
2782
|
+
/**
|
|
2783
|
+
* Internal helper for applying a function with a context.
|
|
2784
|
+
*/
|
|
2785
|
+
module.exports = function applyWithContext (subject, thisContext, args) {
|
|
2786
|
+
switch (args.length) {
|
|
2787
|
+
case 0:
|
|
2788
|
+
return subject.call(thisContext);
|
|
2789
|
+
case 1:
|
|
2790
|
+
return subject.call(thisContext, args[0]);
|
|
2791
|
+
case 2:
|
|
2792
|
+
return subject.call(thisContext, args[0], args[1]);
|
|
2793
|
+
case 3:
|
|
2794
|
+
return subject.call(thisContext, args[0], args[1], args[2]);
|
|
2795
|
+
case 4:
|
|
2796
|
+
return subject.call(thisContext, args[0], args[1], args[2], args[3]);
|
|
2797
|
+
case 5:
|
|
2798
|
+
return subject.call(thisContext, args[0], args[1], args[2], args[3], args[4]);
|
|
2799
|
+
case 6:
|
|
2800
|
+
return subject.call(thisContext, args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
2801
|
+
case 7:
|
|
2802
|
+
return subject.call(thisContext, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
2803
|
+
case 8:
|
|
2804
|
+
return subject.call(thisContext, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
|
|
2805
|
+
default:
|
|
2806
|
+
return subject.apply(thisContext, args);
|
|
2807
|
+
}
|
|
2808
|
+
};
|
|
2809
|
+
|
|
2810
|
+
},{}],34:[function(_require,module,exports){
|
|
2811
|
+
'use strict';
|
|
2812
|
+
|
|
2813
|
+
var applyWithContext = _require('./applyWithContext');
|
|
2814
|
+
var applyNoContext = _require('./applyNoContext');
|
|
2815
|
+
|
|
2816
|
+
/**
|
|
2817
|
+
* # Bind
|
|
2818
|
+
* Analogue of `Function::bind()`.
|
|
2819
|
+
*
|
|
2820
|
+
* ```js
|
|
2821
|
+
* var bind = require('fast.js').bind;
|
|
2822
|
+
* var bound = bind(myfunc, this, 1, 2, 3);
|
|
2823
|
+
*
|
|
2824
|
+
* bound(4);
|
|
2825
|
+
* ```
|
|
2826
|
+
*
|
|
2827
|
+
*
|
|
2828
|
+
* @param {Function} fn The function which should be bound.
|
|
2829
|
+
* @param {Object} thisContext The context to bind the function to.
|
|
2830
|
+
* @param {mixed} args, ... Additional arguments to pre-bind.
|
|
2831
|
+
* @return {Function} The bound function.
|
|
2832
|
+
*/
|
|
2833
|
+
module.exports = function fastBind (fn, thisContext) {
|
|
2834
|
+
var boundLength = arguments.length - 2,
|
|
2835
|
+
boundArgs;
|
|
2836
|
+
|
|
2837
|
+
if (boundLength > 0) {
|
|
2838
|
+
boundArgs = new Array(boundLength);
|
|
2839
|
+
for (var i = 0; i < boundLength; i++) {
|
|
2840
|
+
boundArgs[i] = arguments[i + 2];
|
|
2841
|
+
}
|
|
2842
|
+
if (thisContext !== undefined) {
|
|
2843
|
+
return function () {
|
|
2844
|
+
var length = arguments.length,
|
|
2845
|
+
args = new Array(boundLength + length),
|
|
2846
|
+
i;
|
|
2847
|
+
for (i = 0; i < boundLength; i++) {
|
|
2848
|
+
args[i] = boundArgs[i];
|
|
2849
|
+
}
|
|
2850
|
+
for (i = 0; i < length; i++) {
|
|
2851
|
+
args[boundLength + i] = arguments[i];
|
|
2852
|
+
}
|
|
2853
|
+
return applyWithContext(fn, thisContext, args);
|
|
2854
|
+
};
|
|
2855
|
+
}
|
|
2856
|
+
else {
|
|
2857
|
+
return function () {
|
|
2858
|
+
var length = arguments.length,
|
|
2859
|
+
args = new Array(boundLength + length),
|
|
2860
|
+
i;
|
|
2861
|
+
for (i = 0; i < boundLength; i++) {
|
|
2862
|
+
args[i] = boundArgs[i];
|
|
2863
|
+
}
|
|
2864
|
+
for (i = 0; i < length; i++) {
|
|
2865
|
+
args[boundLength + i] = arguments[i];
|
|
2866
|
+
}
|
|
2867
|
+
return applyNoContext(fn, args);
|
|
2868
|
+
};
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
if (thisContext !== undefined) {
|
|
2872
|
+
return function () {
|
|
2873
|
+
return applyWithContext(fn, thisContext, arguments);
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2876
|
+
else {
|
|
2877
|
+
return function () {
|
|
2878
|
+
return applyNoContext(fn, arguments);
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2881
|
+
};
|
|
2882
|
+
|
|
2883
|
+
},{"./applyNoContext":32,"./applyWithContext":33}],35:[function(_require,module,exports){
|
|
2884
|
+
'use strict';
|
|
2885
|
+
|
|
2886
|
+
/**
|
|
2887
|
+
* Internal helper to bind a function known to have 3 arguments
|
|
2888
|
+
* to a given context.
|
|
2889
|
+
*/
|
|
2890
|
+
module.exports = function bindInternal3 (func, thisContext) {
|
|
2891
|
+
return function (a, b, c) {
|
|
2892
|
+
return func.call(thisContext, a, b, c);
|
|
2893
|
+
};
|
|
2894
|
+
};
|
|
2895
|
+
|
|
2896
|
+
},{}],36:[function(_require,module,exports){
|
|
2897
|
+
'use strict';
|
|
2898
|
+
|
|
2899
|
+
/**
|
|
2900
|
+
* Internal helper to bind a function known to have 4 arguments
|
|
2901
|
+
* to a given context.
|
|
2902
|
+
*/
|
|
2903
|
+
module.exports = function bindInternal4 (func, thisContext) {
|
|
2904
|
+
return function (a, b, c, d) {
|
|
2905
|
+
return func.call(thisContext, a, b, c, d);
|
|
2906
|
+
};
|
|
2907
|
+
};
|
|
2908
|
+
|
|
2909
|
+
},{}],37:[function(_require,module,exports){
|
|
2910
|
+
'use strict';
|
|
2911
|
+
|
|
2912
|
+
exports.apply = _require('./apply');
|
|
2913
|
+
exports.bind = _require('./bind');
|
|
2914
|
+
exports.partial = _require('./partial');
|
|
2915
|
+
exports.partialConstructor = _require('./partialConstructor');
|
|
2916
|
+
exports.try = _require('./try');
|
|
2917
|
+
|
|
2918
|
+
},{"./apply":31,"./bind":34,"./partial":38,"./partialConstructor":39,"./try":40}],38:[function(_require,module,exports){
|
|
2919
|
+
'use strict';
|
|
2920
|
+
|
|
2921
|
+
var applyWithContext = _require('./applyWithContext');
|
|
2922
|
+
|
|
2923
|
+
/**
|
|
2924
|
+
* # Partial Application
|
|
2925
|
+
*
|
|
2926
|
+
* Partially apply a function. This is similar to `.bind()`,
|
|
2927
|
+
* but with one important difference - the returned function is not bound
|
|
2928
|
+
* to a particular context. This makes it easy to add partially
|
|
2929
|
+
* applied methods to objects. If you need to bind to a context,
|
|
2930
|
+
* use `.bind()` instead.
|
|
2931
|
+
*
|
|
2932
|
+
* > Note: This function does not support partial application for
|
|
2933
|
+
* constructors, for that see `partialConstructor()`
|
|
2934
|
+
*
|
|
2935
|
+
*
|
|
2936
|
+
* @param {Function} fn The function to partially apply.
|
|
2937
|
+
* @param {mixed} args, ... Arguments to pre-bind.
|
|
2938
|
+
* @return {Function} The partially applied function.
|
|
2939
|
+
*/
|
|
2940
|
+
module.exports = function fastPartial (fn) {
|
|
2941
|
+
var boundLength = arguments.length - 1,
|
|
2942
|
+
boundArgs;
|
|
2943
|
+
|
|
2944
|
+
boundArgs = new Array(boundLength);
|
|
2945
|
+
for (var i = 0; i < boundLength; i++) {
|
|
2946
|
+
boundArgs[i] = arguments[i + 1];
|
|
2947
|
+
}
|
|
2948
|
+
return function () {
|
|
2949
|
+
var length = arguments.length,
|
|
2950
|
+
args = new Array(boundLength + length),
|
|
2951
|
+
i;
|
|
2952
|
+
for (i = 0; i < boundLength; i++) {
|
|
2953
|
+
args[i] = boundArgs[i];
|
|
2954
|
+
}
|
|
2955
|
+
for (i = 0; i < length; i++) {
|
|
2956
|
+
args[boundLength + i] = arguments[i];
|
|
2957
|
+
}
|
|
2958
|
+
return applyWithContext(fn, this, args);
|
|
2959
|
+
};
|
|
2960
|
+
};
|
|
2961
|
+
|
|
2962
|
+
},{"./applyWithContext":33}],39:[function(_require,module,exports){
|
|
2963
|
+
'use strict';
|
|
2964
|
+
|
|
2965
|
+
var applyWithContext = _require('./applyWithContext');
|
|
2966
|
+
|
|
2967
|
+
/**
|
|
2968
|
+
* # Partial Constructor
|
|
2969
|
+
*
|
|
2970
|
+
* Partially apply a constructor function. The returned function
|
|
2971
|
+
* will work with or without the `new` keyword.
|
|
2972
|
+
*
|
|
2973
|
+
*
|
|
2974
|
+
* @param {Function} fn The constructor function to partially apply.
|
|
2975
|
+
* @param {mixed} args, ... Arguments to pre-bind.
|
|
2976
|
+
* @return {Function} The partially applied constructor.
|
|
2977
|
+
*/
|
|
2978
|
+
module.exports = function fastPartialConstructor (fn) {
|
|
2979
|
+
var boundLength = arguments.length - 1,
|
|
2980
|
+
boundArgs;
|
|
2981
|
+
|
|
2982
|
+
boundArgs = new Array(boundLength);
|
|
2983
|
+
for (var i = 0; i < boundLength; i++) {
|
|
2984
|
+
boundArgs[i] = arguments[i + 1];
|
|
2985
|
+
}
|
|
2986
|
+
return function partialed () {
|
|
2987
|
+
var length = arguments.length,
|
|
2988
|
+
args = new Array(boundLength + length),
|
|
2989
|
+
i;
|
|
2990
|
+
for (i = 0; i < boundLength; i++) {
|
|
2991
|
+
args[i] = boundArgs[i];
|
|
2992
|
+
}
|
|
2993
|
+
for (i = 0; i < length; i++) {
|
|
2994
|
+
args[boundLength + i] = arguments[i];
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
var thisContext = Object.create(fn.prototype),
|
|
2998
|
+
result = applyWithContext(fn, thisContext, args);
|
|
2999
|
+
|
|
3000
|
+
if (result != null && (typeof result === 'object' || typeof result === 'function')) {
|
|
3001
|
+
return result;
|
|
3002
|
+
}
|
|
3003
|
+
else {
|
|
3004
|
+
return thisContext;
|
|
3005
|
+
}
|
|
3006
|
+
};
|
|
3007
|
+
};
|
|
3008
|
+
|
|
3009
|
+
},{"./applyWithContext":33}],40:[function(_require,module,exports){
|
|
3010
|
+
'use strict';
|
|
3011
|
+
|
|
3012
|
+
/**
|
|
3013
|
+
* # Try
|
|
3014
|
+
*
|
|
3015
|
+
* Allows functions to be optimised by isolating `try {} catch (e) {}` blocks
|
|
3016
|
+
* outside the function declaration. Returns either the result of the function or an Error
|
|
3017
|
+
* object if one was thrown. The caller should then check for `result instanceof Error`.
|
|
3018
|
+
*
|
|
3019
|
+
* ```js
|
|
3020
|
+
* var result = fast.try(myFunction);
|
|
3021
|
+
* if (result instanceof Error) {
|
|
3022
|
+
* console.log('something went wrong');
|
|
3023
|
+
* }
|
|
3024
|
+
* else {
|
|
3025
|
+
* console.log('result:', result);
|
|
3026
|
+
* }
|
|
3027
|
+
* ```
|
|
3028
|
+
*
|
|
3029
|
+
* @param {Function} fn The function to invoke.
|
|
3030
|
+
* @return {mixed} The result of the function, or an `Error` object.
|
|
3031
|
+
*/
|
|
3032
|
+
module.exports = function fastTry (fn) {
|
|
3033
|
+
try {
|
|
3034
|
+
return fn();
|
|
3035
|
+
}
|
|
3036
|
+
catch (e) {
|
|
3037
|
+
if (!(e instanceof Error)) {
|
|
3038
|
+
return new Error(e);
|
|
3039
|
+
}
|
|
3040
|
+
else {
|
|
3041
|
+
return e;
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
};
|
|
3045
|
+
|
|
3046
|
+
},{}],41:[function(_require,module,exports){
|
|
3047
|
+
'use strict';
|
|
3048
|
+
|
|
3049
|
+
/**
|
|
3050
|
+
* # Constructor
|
|
3051
|
+
*
|
|
3052
|
+
* Provided as a convenient wrapper around Fast functions.
|
|
3053
|
+
*
|
|
3054
|
+
* ```js
|
|
3055
|
+
* var arr = fast([1,2,3,4,5,6]);
|
|
3056
|
+
*
|
|
3057
|
+
* var result = arr.filter(function (item) {
|
|
3058
|
+
* return item % 2 === 0;
|
|
3059
|
+
* });
|
|
3060
|
+
*
|
|
3061
|
+
* result instanceof Fast; // true
|
|
3062
|
+
* result.length; // 3
|
|
3063
|
+
* ```
|
|
3064
|
+
*
|
|
3065
|
+
*
|
|
3066
|
+
* @param {Array} value The value to wrap.
|
|
3067
|
+
*/
|
|
3068
|
+
function Fast (value) {
|
|
3069
|
+
if (!(this instanceof Fast)) {
|
|
3070
|
+
return new Fast(value);
|
|
3071
|
+
}
|
|
3072
|
+
this.value = value || [];
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
module.exports = exports = Fast;
|
|
3076
|
+
|
|
3077
|
+
Fast.array = _require('./array');
|
|
3078
|
+
Fast['function'] = Fast.fn = _require('./function');
|
|
3079
|
+
Fast.object = _require('./object');
|
|
3080
|
+
Fast.string = _require('./string');
|
|
3081
|
+
|
|
3082
|
+
|
|
3083
|
+
Fast.apply = Fast['function'].apply;
|
|
3084
|
+
Fast.bind = Fast['function'].bind;
|
|
3085
|
+
Fast.partial = Fast['function'].partial;
|
|
3086
|
+
Fast.partialConstructor = Fast['function'].partialConstructor;
|
|
3087
|
+
Fast['try'] = Fast.attempt = Fast['function']['try'];
|
|
3088
|
+
|
|
3089
|
+
Fast.assign = Fast.object.assign;
|
|
3090
|
+
Fast.cloneObject = Fast.object.clone; // @deprecated use fast.object.clone()
|
|
3091
|
+
Fast.keys = Fast.object.keys;
|
|
3092
|
+
Fast.values = Fast.object.values;
|
|
3093
|
+
|
|
3094
|
+
|
|
3095
|
+
Fast.clone = _require('./clone');
|
|
3096
|
+
Fast.map = _require('./map');
|
|
3097
|
+
Fast.filter = _require('./filter');
|
|
3098
|
+
Fast.forEach = _require('./forEach');
|
|
3099
|
+
Fast.reduce = _require('./reduce');
|
|
3100
|
+
Fast.reduceRight = _require('./reduceRight');
|
|
3101
|
+
|
|
3102
|
+
|
|
3103
|
+
Fast.cloneArray = Fast.array.clone; // @deprecated use fast.array.clone()
|
|
3104
|
+
|
|
3105
|
+
Fast.concat = Fast.array.concat;
|
|
3106
|
+
Fast.some = Fast.array.some;
|
|
3107
|
+
Fast.every = Fast.array.every;
|
|
3108
|
+
Fast.indexOf = Fast.array.indexOf;
|
|
3109
|
+
Fast.lastIndexOf = Fast.array.lastIndexOf;
|
|
3110
|
+
Fast.pluck = Fast.array.pluck;
|
|
3111
|
+
Fast.fill = Fast.array.fill;
|
|
3112
|
+
|
|
3113
|
+
Fast.intern = Fast.string.intern;
|
|
3114
|
+
|
|
3115
|
+
|
|
3116
|
+
/**
|
|
3117
|
+
* # Concat
|
|
3118
|
+
*
|
|
3119
|
+
* Concatenate multiple arrays.
|
|
3120
|
+
*
|
|
3121
|
+
* @param {Array|mixed} item, ... The item(s) to concatenate.
|
|
3122
|
+
* @return {Fast} A new Fast object, containing the results.
|
|
3123
|
+
*/
|
|
3124
|
+
Fast.prototype.concat = function Fast$concat () {
|
|
3125
|
+
var length = this.value.length,
|
|
3126
|
+
arr = new Array(length),
|
|
3127
|
+
i, item, childLength, j;
|
|
3128
|
+
|
|
3129
|
+
for (i = 0; i < length; i++) {
|
|
3130
|
+
arr[i] = this.value[i];
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
length = arguments.length;
|
|
3134
|
+
for (i = 0; i < length; i++) {
|
|
3135
|
+
item = arguments[i];
|
|
3136
|
+
if (Array.isArray(item)) {
|
|
3137
|
+
childLength = item.length;
|
|
3138
|
+
for (j = 0; j < childLength; j++) {
|
|
3139
|
+
arr.push(item[j]);
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
else {
|
|
3143
|
+
arr.push(item);
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
return new Fast(arr);
|
|
3147
|
+
};
|
|
3148
|
+
|
|
3149
|
+
/**
|
|
3150
|
+
* Fast Map
|
|
3151
|
+
*
|
|
3152
|
+
* @param {Function} fn The visitor function.
|
|
3153
|
+
* @param {Object} thisContext The context for the visitor, if any.
|
|
3154
|
+
* @return {Fast} A new Fast object, containing the results.
|
|
3155
|
+
*/
|
|
3156
|
+
Fast.prototype.map = function Fast$map (fn, thisContext) {
|
|
3157
|
+
return new Fast(Fast.map(this.value, fn, thisContext));
|
|
3158
|
+
};
|
|
3159
|
+
|
|
3160
|
+
/**
|
|
3161
|
+
* Fast Filter
|
|
3162
|
+
*
|
|
3163
|
+
* @param {Function} fn The filter function.
|
|
3164
|
+
* @param {Object} thisContext The context for the filter function, if any.
|
|
3165
|
+
* @return {Fast} A new Fast object, containing the results.
|
|
3166
|
+
*/
|
|
3167
|
+
Fast.prototype.filter = function Fast$filter (fn, thisContext) {
|
|
3168
|
+
return new Fast(Fast.filter(this.value, fn, thisContext));
|
|
3169
|
+
};
|
|
3170
|
+
|
|
3171
|
+
/**
|
|
3172
|
+
* Fast Reduce
|
|
3173
|
+
*
|
|
3174
|
+
* @param {Function} fn The reducer function.
|
|
3175
|
+
* @param {mixed} initialValue The initial value, if any.
|
|
3176
|
+
* @param {Object} thisContext The context for the reducer, if any.
|
|
3177
|
+
* @return {mixed} The final result.
|
|
3178
|
+
*/
|
|
3179
|
+
Fast.prototype.reduce = function Fast$reduce (fn, initialValue, thisContext) {
|
|
3180
|
+
return Fast.reduce(this.value, fn, initialValue, thisContext);
|
|
3181
|
+
};
|
|
3182
|
+
|
|
3183
|
+
|
|
3184
|
+
/**
|
|
3185
|
+
* Fast Reduce Right
|
|
3186
|
+
*
|
|
3187
|
+
* @param {Function} fn The reducer function.
|
|
3188
|
+
* @param {mixed} initialValue The initial value, if any.
|
|
3189
|
+
* @param {Object} thisContext The context for the reducer, if any.
|
|
3190
|
+
* @return {mixed} The final result.
|
|
3191
|
+
*/
|
|
3192
|
+
Fast.prototype.reduceRight = function Fast$reduceRight (fn, initialValue, thisContext) {
|
|
3193
|
+
return Fast.reduceRight(this.value, fn, initialValue, thisContext);
|
|
3194
|
+
};
|
|
3195
|
+
|
|
3196
|
+
/**
|
|
3197
|
+
* Fast For Each
|
|
3198
|
+
*
|
|
3199
|
+
* @param {Function} fn The visitor function.
|
|
3200
|
+
* @param {Object} thisContext The context for the visitor, if any.
|
|
3201
|
+
* @return {Fast} The Fast instance.
|
|
3202
|
+
*/
|
|
3203
|
+
Fast.prototype.forEach = function Fast$forEach (fn, thisContext) {
|
|
3204
|
+
Fast.forEach(this.value, fn, thisContext);
|
|
3205
|
+
return this;
|
|
3206
|
+
};
|
|
3207
|
+
|
|
3208
|
+
/**
|
|
3209
|
+
* Fast Some
|
|
3210
|
+
*
|
|
3211
|
+
* @param {Function} fn The matcher predicate.
|
|
3212
|
+
* @param {Object} thisContext The context for the matcher, if any.
|
|
3213
|
+
* @return {Boolean} True if at least one element matches.
|
|
3214
|
+
*/
|
|
3215
|
+
Fast.prototype.some = function Fast$some (fn, thisContext) {
|
|
3216
|
+
return Fast.some(this.value, fn, thisContext);
|
|
3217
|
+
};
|
|
3218
|
+
|
|
3219
|
+
/**
|
|
3220
|
+
* Fast Every
|
|
3221
|
+
*
|
|
3222
|
+
* @param {Function} fn The matcher predicate.
|
|
3223
|
+
* @param {Object} thisContext The context for the matcher, if any.
|
|
3224
|
+
* @return {Boolean} True if at all elements match.
|
|
3225
|
+
*/
|
|
3226
|
+
Fast.prototype.every = function Fast$every (fn, thisContext) {
|
|
3227
|
+
return Fast.some(this.value, fn, thisContext);
|
|
3228
|
+
};
|
|
3229
|
+
|
|
3230
|
+
/**
|
|
3231
|
+
* Fast Index Of
|
|
3232
|
+
*
|
|
3233
|
+
* @param {mixed} target The target to lookup.
|
|
3234
|
+
* @param {Number} fromIndex The index to start searching from, if known.
|
|
3235
|
+
* @return {Number} The index of the item, or -1 if no match found.
|
|
3236
|
+
*/
|
|
3237
|
+
Fast.prototype.indexOf = function Fast$indexOf (target, fromIndex) {
|
|
3238
|
+
return Fast.indexOf(this.value, target, fromIndex);
|
|
3239
|
+
};
|
|
3240
|
+
|
|
3241
|
+
|
|
3242
|
+
/**
|
|
3243
|
+
* Fast Last Index Of
|
|
3244
|
+
*
|
|
3245
|
+
* @param {mixed} target The target to lookup.
|
|
3246
|
+
* @param {Number} fromIndex The index to start searching from, if known.
|
|
3247
|
+
* @return {Number} The last index of the item, or -1 if no match found.
|
|
3248
|
+
*/
|
|
3249
|
+
Fast.prototype.lastIndexOf = function Fast$lastIndexOf (target, fromIndex) {
|
|
3250
|
+
return Fast.lastIndexOf(this.value, target, fromIndex);
|
|
3251
|
+
};
|
|
3252
|
+
|
|
3253
|
+
/**
|
|
3254
|
+
* Reverse
|
|
3255
|
+
*
|
|
3256
|
+
* @return {Fast} A new Fast instance, with the contents reversed.
|
|
3257
|
+
*/
|
|
3258
|
+
Fast.prototype.reverse = function Fast$reverse () {
|
|
3259
|
+
return new Fast(this.value.reverse());
|
|
3260
|
+
};
|
|
3261
|
+
|
|
3262
|
+
/**
|
|
3263
|
+
* Value Of
|
|
3264
|
+
*
|
|
3265
|
+
* @return {Array} The wrapped value.
|
|
3266
|
+
*/
|
|
3267
|
+
Fast.prototype.valueOf = function Fast$valueOf () {
|
|
3268
|
+
return this.value;
|
|
3269
|
+
};
|
|
3270
|
+
|
|
3271
|
+
/**
|
|
3272
|
+
* To JSON
|
|
3273
|
+
*
|
|
3274
|
+
* @return {Array} The wrapped value.
|
|
3275
|
+
*/
|
|
3276
|
+
Fast.prototype.toJSON = function Fast$toJSON () {
|
|
3277
|
+
return this.value;
|
|
3278
|
+
};
|
|
3279
|
+
|
|
3280
|
+
/**
|
|
3281
|
+
* Item Length
|
|
3282
|
+
*/
|
|
3283
|
+
Object.defineProperty(Fast.prototype, 'length', {
|
|
3284
|
+
get: function () {
|
|
3285
|
+
return this.value.length;
|
|
3286
|
+
}
|
|
3287
|
+
});
|
|
3288
|
+
|
|
3289
|
+
},{"./array":20,"./clone":28,"./filter":29,"./forEach":30,"./function":37,"./map":42,"./object":47,"./reduce":53,"./reduceRight":54,"./string":55}],42:[function(_require,module,exports){
|
|
3290
|
+
'use strict';
|
|
3291
|
+
|
|
3292
|
+
var mapArray = _require('./array/map'),
|
|
3293
|
+
mapObject = _require('./object/map');
|
|
3294
|
+
|
|
3295
|
+
/**
|
|
3296
|
+
* # Map
|
|
3297
|
+
*
|
|
3298
|
+
* A fast `.map()` implementation.
|
|
3299
|
+
*
|
|
3300
|
+
* @param {Array|Object} subject The array or object to map over.
|
|
3301
|
+
* @param {Function} fn The mapper function.
|
|
3302
|
+
* @param {Object} thisContext The context for the mapper.
|
|
3303
|
+
* @return {Array|Object} The array or object containing the results.
|
|
3304
|
+
*/
|
|
3305
|
+
module.exports = function fastMap (subject, fn, thisContext) {
|
|
3306
|
+
if (subject instanceof Array) {
|
|
3307
|
+
return mapArray(subject, fn, thisContext);
|
|
3308
|
+
}
|
|
3309
|
+
else {
|
|
3310
|
+
return mapObject(subject, fn, thisContext);
|
|
3311
|
+
}
|
|
3312
|
+
};
|
|
3313
|
+
},{"./array/map":23,"./object/map":49}],43:[function(_require,module,exports){
|
|
3314
|
+
'use strict';
|
|
3315
|
+
|
|
3316
|
+
/**
|
|
3317
|
+
* Analogue of Object.assign().
|
|
3318
|
+
* Copies properties from one or more source objects to
|
|
3319
|
+
* a target object. Existing keys on the target object will be overwritten.
|
|
3320
|
+
*
|
|
3321
|
+
* > Note: This differs from spec in some important ways:
|
|
3322
|
+
* > 1. Will throw if passed non-objects, including `undefined` or `null` values.
|
|
3323
|
+
* > 2. Does not support the curious Exception handling behavior, exceptions are thrown immediately.
|
|
3324
|
+
* > For more details, see:
|
|
3325
|
+
* > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
|
3326
|
+
*
|
|
3327
|
+
*
|
|
3328
|
+
*
|
|
3329
|
+
* @param {Object} target The target object to copy properties to.
|
|
3330
|
+
* @param {Object} source, ... The source(s) to copy properties from.
|
|
3331
|
+
* @return {Object} The updated target object.
|
|
3332
|
+
*/
|
|
3333
|
+
module.exports = function fastAssign (target) {
|
|
3334
|
+
var totalArgs = arguments.length,
|
|
3335
|
+
source, i, totalKeys, keys, key, j;
|
|
3336
|
+
|
|
3337
|
+
for (i = 1; i < totalArgs; i++) {
|
|
3338
|
+
source = arguments[i];
|
|
3339
|
+
keys = Object.keys(source);
|
|
3340
|
+
totalKeys = keys.length;
|
|
3341
|
+
for (j = 0; j < totalKeys; j++) {
|
|
3342
|
+
key = keys[j];
|
|
3343
|
+
target[key] = source[key];
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
return target;
|
|
3347
|
+
};
|
|
3348
|
+
|
|
3349
|
+
},{}],44:[function(_require,module,exports){
|
|
3350
|
+
'use strict';
|
|
3351
|
+
|
|
3352
|
+
/**
|
|
3353
|
+
* # Clone Object
|
|
3354
|
+
*
|
|
3355
|
+
* Shallow clone a simple object.
|
|
3356
|
+
*
|
|
3357
|
+
* > Note: Prototypes and non-enumerable properties will not be copied!
|
|
3358
|
+
*
|
|
3359
|
+
* @param {Object} input The object to clone.
|
|
3360
|
+
* @return {Object} The cloned object.
|
|
3361
|
+
*/
|
|
3362
|
+
module.exports = function fastCloneObject (input) {
|
|
3363
|
+
var keys = Object.keys(input),
|
|
3364
|
+
total = keys.length,
|
|
3365
|
+
cloned = {},
|
|
3366
|
+
i, key;
|
|
3367
|
+
|
|
3368
|
+
for (i = 0; i < total; i++) {
|
|
3369
|
+
key = keys[i];
|
|
3370
|
+
cloned[key] = input[key];
|
|
3371
|
+
}
|
|
3372
|
+
|
|
3373
|
+
return cloned;
|
|
3374
|
+
};
|
|
3375
|
+
|
|
3376
|
+
},{}],45:[function(_require,module,exports){
|
|
3377
|
+
'use strict';
|
|
3378
|
+
|
|
3379
|
+
var bindInternal3 = _require('../function/bindInternal3');
|
|
3380
|
+
|
|
3381
|
+
/**
|
|
3382
|
+
* # Filter
|
|
3383
|
+
*
|
|
3384
|
+
* A fast object `.filter()` implementation.
|
|
3385
|
+
*
|
|
3386
|
+
* @param {Object} subject The object to filter.
|
|
3387
|
+
* @param {Function} fn The filter function.
|
|
3388
|
+
* @param {Object} thisContext The context for the filter.
|
|
3389
|
+
* @return {Object} The new object containing the filtered results.
|
|
3390
|
+
*/
|
|
3391
|
+
module.exports = function fastFilterObject (subject, fn, thisContext) {
|
|
3392
|
+
var keys = Object.keys(subject),
|
|
3393
|
+
length = keys.length,
|
|
3394
|
+
result = {},
|
|
3395
|
+
iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
|
|
3396
|
+
i, key;
|
|
3397
|
+
for (i = 0; i < length; i++) {
|
|
3398
|
+
key = keys[i];
|
|
3399
|
+
if (iterator(subject[key], key, subject)) {
|
|
3400
|
+
result[key] = subject[key];
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
return result;
|
|
3404
|
+
};
|
|
3405
|
+
|
|
3406
|
+
},{"../function/bindInternal3":35}],46:[function(_require,module,exports){
|
|
3407
|
+
'use strict';
|
|
3408
|
+
|
|
3409
|
+
var bindInternal3 = _require('../function/bindInternal3');
|
|
3410
|
+
|
|
3411
|
+
/**
|
|
3412
|
+
* # For Each
|
|
3413
|
+
*
|
|
3414
|
+
* A fast object `.forEach()` implementation.
|
|
3415
|
+
*
|
|
3416
|
+
* @param {Object} subject The object to iterate over.
|
|
3417
|
+
* @param {Function} fn The visitor function.
|
|
3418
|
+
* @param {Object} thisContext The context for the visitor.
|
|
3419
|
+
*/
|
|
3420
|
+
module.exports = function fastForEachObject (subject, fn, thisContext) {
|
|
3421
|
+
var keys = Object.keys(subject),
|
|
3422
|
+
length = keys.length,
|
|
3423
|
+
iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
|
|
3424
|
+
key, i;
|
|
3425
|
+
for (i = 0; i < length; i++) {
|
|
3426
|
+
key = keys[i];
|
|
3427
|
+
iterator(subject[key], key, subject);
|
|
3428
|
+
}
|
|
3429
|
+
};
|
|
3430
|
+
|
|
3431
|
+
},{"../function/bindInternal3":35}],47:[function(_require,module,exports){
|
|
3432
|
+
'use strict';
|
|
3433
|
+
|
|
3434
|
+
exports.assign = _require('./assign');
|
|
3435
|
+
exports.clone = _require('./clone');
|
|
3436
|
+
exports.filter = _require('./filter');
|
|
3437
|
+
exports.forEach = _require('./forEach');
|
|
3438
|
+
exports.map = _require('./map');
|
|
3439
|
+
exports.reduce = _require('./reduce');
|
|
3440
|
+
exports.reduceRight = _require('./reduceRight');
|
|
3441
|
+
exports.keys = _require('./keys');
|
|
3442
|
+
exports.values = _require('./values');
|
|
3443
|
+
},{"./assign":43,"./clone":44,"./filter":45,"./forEach":46,"./keys":48,"./map":49,"./reduce":50,"./reduceRight":51,"./values":52}],48:[function(_require,module,exports){
|
|
3444
|
+
'use strict';
|
|
3445
|
+
|
|
3446
|
+
/**
|
|
3447
|
+
* Object.keys() shim for ES3 environments.
|
|
3448
|
+
*
|
|
3449
|
+
* @param {Object} obj The object to get keys for.
|
|
3450
|
+
* @return {Array} The array of keys.
|
|
3451
|
+
*/
|
|
3452
|
+
module.exports = typeof Object.keys === "function" ? Object.keys : /* istanbul ignore next */ function fastKeys (obj) {
|
|
3453
|
+
var keys = [];
|
|
3454
|
+
for (var key in obj) {
|
|
3455
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
3456
|
+
keys.push(key);
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
return keys;
|
|
3460
|
+
};
|
|
3461
|
+
},{}],49:[function(_require,module,exports){
|
|
3462
|
+
'use strict';
|
|
3463
|
+
|
|
3464
|
+
var bindInternal3 = _require('../function/bindInternal3');
|
|
3465
|
+
|
|
3466
|
+
/**
|
|
3467
|
+
* # Map
|
|
3468
|
+
*
|
|
3469
|
+
* A fast object `.map()` implementation.
|
|
3470
|
+
*
|
|
3471
|
+
* @param {Object} subject The object to map over.
|
|
3472
|
+
* @param {Function} fn The mapper function.
|
|
3473
|
+
* @param {Object} thisContext The context for the mapper.
|
|
3474
|
+
* @return {Object} The new object containing the results.
|
|
3475
|
+
*/
|
|
3476
|
+
module.exports = function fastMapObject (subject, fn, thisContext) {
|
|
3477
|
+
var keys = Object.keys(subject),
|
|
3478
|
+
length = keys.length,
|
|
3479
|
+
result = {},
|
|
3480
|
+
iterator = thisContext !== undefined ? bindInternal3(fn, thisContext) : fn,
|
|
3481
|
+
i, key;
|
|
3482
|
+
for (i = 0; i < length; i++) {
|
|
3483
|
+
key = keys[i];
|
|
3484
|
+
result[key] = iterator(subject[key], key, subject);
|
|
3485
|
+
}
|
|
3486
|
+
return result;
|
|
3487
|
+
};
|
|
3488
|
+
|
|
3489
|
+
},{"../function/bindInternal3":35}],50:[function(_require,module,exports){
|
|
3490
|
+
'use strict';
|
|
3491
|
+
|
|
3492
|
+
var bindInternal4 = _require('../function/bindInternal4');
|
|
3493
|
+
|
|
3494
|
+
/**
|
|
3495
|
+
* # Reduce
|
|
3496
|
+
*
|
|
3497
|
+
* A fast object `.reduce()` implementation.
|
|
3498
|
+
*
|
|
3499
|
+
* @param {Object} subject The object to reduce over.
|
|
3500
|
+
* @param {Function} fn The reducer function.
|
|
3501
|
+
* @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
|
|
3502
|
+
* @param {Object} thisContext The context for the reducer.
|
|
3503
|
+
* @return {mixed} The final result.
|
|
3504
|
+
*/
|
|
3505
|
+
module.exports = function fastReduceObject (subject, fn, initialValue, thisContext) {
|
|
3506
|
+
var keys = Object.keys(subject),
|
|
3507
|
+
length = keys.length,
|
|
3508
|
+
iterator = thisContext !== undefined ? bindInternal4(fn, thisContext) : fn,
|
|
3509
|
+
i, key, result;
|
|
3510
|
+
|
|
3511
|
+
if (initialValue === undefined) {
|
|
3512
|
+
i = 1;
|
|
3513
|
+
result = subject[keys[0]];
|
|
3514
|
+
}
|
|
3515
|
+
else {
|
|
3516
|
+
i = 0;
|
|
3517
|
+
result = initialValue;
|
|
3518
|
+
}
|
|
3519
|
+
|
|
3520
|
+
for (; i < length; i++) {
|
|
3521
|
+
key = keys[i];
|
|
3522
|
+
result = iterator(result, subject[key], key, subject);
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
return result;
|
|
3526
|
+
};
|
|
3527
|
+
|
|
3528
|
+
},{"../function/bindInternal4":36}],51:[function(_require,module,exports){
|
|
3529
|
+
'use strict';
|
|
3530
|
+
|
|
3531
|
+
var bindInternal4 = _require('../function/bindInternal4');
|
|
3532
|
+
|
|
3533
|
+
/**
|
|
3534
|
+
* # Reduce
|
|
3535
|
+
*
|
|
3536
|
+
* A fast object `.reduce()` implementation.
|
|
3537
|
+
*
|
|
3538
|
+
* @param {Object} subject The object to reduce over.
|
|
3539
|
+
* @param {Function} fn The reducer function.
|
|
3540
|
+
* @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
|
|
3541
|
+
* @param {Object} thisContext The context for the reducer.
|
|
3542
|
+
* @return {mixed} The final result.
|
|
3543
|
+
*/
|
|
3544
|
+
module.exports = function fastReduceRightObject (subject, fn, initialValue, thisContext) {
|
|
3545
|
+
var keys = Object.keys(subject),
|
|
3546
|
+
length = keys.length,
|
|
3547
|
+
iterator = thisContext !== undefined ? bindInternal4(fn, thisContext) : fn,
|
|
3548
|
+
i, key, result;
|
|
3549
|
+
|
|
3550
|
+
if (initialValue === undefined) {
|
|
3551
|
+
i = length - 2;
|
|
3552
|
+
result = subject[keys[length - 1]];
|
|
3553
|
+
}
|
|
3554
|
+
else {
|
|
3555
|
+
i = length - 1;
|
|
3556
|
+
result = initialValue;
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3559
|
+
for (; i >= 0; i--) {
|
|
3560
|
+
key = keys[i];
|
|
3561
|
+
result = iterator(result, subject[key], key, subject);
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
return result;
|
|
3565
|
+
};
|
|
3566
|
+
|
|
3567
|
+
},{"../function/bindInternal4":36}],52:[function(_require,module,exports){
|
|
3568
|
+
'use strict';
|
|
3569
|
+
|
|
3570
|
+
/**
|
|
3571
|
+
* # Values
|
|
3572
|
+
* Return all the (enumerable) property values for an object.
|
|
3573
|
+
* Like Object.keys() but for values.
|
|
3574
|
+
*
|
|
3575
|
+
* @param {Object} obj The object to retrieve values from.
|
|
3576
|
+
* @return {Array} An array containing property values.
|
|
3577
|
+
*/
|
|
3578
|
+
module.exports = function fastValues (obj) {
|
|
3579
|
+
var keys = Object.keys(obj),
|
|
3580
|
+
length = keys.length,
|
|
3581
|
+
values = new Array(length);
|
|
3582
|
+
|
|
3583
|
+
for (var i = 0; i < length; i++) {
|
|
3584
|
+
values[i] = obj[keys[i]];
|
|
3585
|
+
}
|
|
3586
|
+
return values;
|
|
3587
|
+
};
|
|
3588
|
+
},{}],53:[function(_require,module,exports){
|
|
3589
|
+
'use strict';
|
|
3590
|
+
|
|
3591
|
+
var reduceArray = _require('./array/reduce'),
|
|
3592
|
+
reduceObject = _require('./object/reduce');
|
|
3593
|
+
|
|
3594
|
+
/**
|
|
3595
|
+
* # Reduce
|
|
3596
|
+
*
|
|
3597
|
+
* A fast `.reduce()` implementation.
|
|
3598
|
+
*
|
|
3599
|
+
* @param {Array|Object} subject The array or object to reduce over.
|
|
3600
|
+
* @param {Function} fn The reducer function.
|
|
3601
|
+
* @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
|
|
3602
|
+
* @param {Object} thisContext The context for the reducer.
|
|
3603
|
+
* @return {Array|Object} The array or object containing the results.
|
|
3604
|
+
*/
|
|
3605
|
+
module.exports = function fastReduce (subject, fn, initialValue, thisContext) {
|
|
3606
|
+
if (subject instanceof Array) {
|
|
3607
|
+
return reduceArray(subject, fn, initialValue, thisContext);
|
|
3608
|
+
}
|
|
3609
|
+
else {
|
|
3610
|
+
return reduceObject(subject, fn, initialValue, thisContext);
|
|
3611
|
+
}
|
|
3612
|
+
};
|
|
3613
|
+
},{"./array/reduce":25,"./object/reduce":50}],54:[function(_require,module,exports){
|
|
3614
|
+
'use strict';
|
|
3615
|
+
|
|
3616
|
+
var reduceRightArray = _require('./array/reduceRight'),
|
|
3617
|
+
reduceRightObject = _require('./object/reduceRight');
|
|
3618
|
+
|
|
3619
|
+
/**
|
|
3620
|
+
* # Reduce Right
|
|
3621
|
+
*
|
|
3622
|
+
* A fast `.reduceRight()` implementation.
|
|
3623
|
+
*
|
|
3624
|
+
* @param {Array|Object} subject The array or object to reduce over.
|
|
3625
|
+
* @param {Function} fn The reducer function.
|
|
3626
|
+
* @param {mixed} initialValue The initial value for the reducer, defaults to subject[0].
|
|
3627
|
+
* @param {Object} thisContext The context for the reducer.
|
|
3628
|
+
* @return {Array|Object} The array or object containing the results.
|
|
3629
|
+
*/
|
|
3630
|
+
module.exports = function fastReduceRight (subject, fn, initialValue, thisContext) {
|
|
3631
|
+
if (subject instanceof Array) {
|
|
3632
|
+
return reduceRightArray(subject, fn, initialValue, thisContext);
|
|
3633
|
+
}
|
|
3634
|
+
else {
|
|
3635
|
+
return reduceRightObject(subject, fn, initialValue, thisContext);
|
|
3636
|
+
}
|
|
3637
|
+
};
|
|
3638
|
+
},{"./array/reduceRight":26,"./object/reduceRight":51}],55:[function(_require,module,exports){
|
|
3639
|
+
'use strict';
|
|
3640
|
+
|
|
3641
|
+
exports.intern = _require('./intern');
|
|
3642
|
+
},{"./intern":56}],56:[function(_require,module,exports){
|
|
3643
|
+
'use strict';
|
|
3644
|
+
|
|
3645
|
+
// Compilers such as V8 use string interning to make string comparison very fast and efficient,
|
|
3646
|
+
// as efficient as comparing two references to the same object.
|
|
3647
|
+
//
|
|
3648
|
+
//
|
|
3649
|
+
// V8 does its best to intern strings automatically where it can, for instance:
|
|
3650
|
+
// ```js
|
|
3651
|
+
// var greeting = "hello world";
|
|
3652
|
+
// ```
|
|
3653
|
+
// With this, comparison will be very fast:
|
|
3654
|
+
// ```js
|
|
3655
|
+
// if (greeting === "hello world") {}
|
|
3656
|
+
// ```
|
|
3657
|
+
// However, there are several cases where V8 cannot intern the string, and instead
|
|
3658
|
+
// must resort to byte-wise comparison. This can be signficantly slower for long strings.
|
|
3659
|
+
// The most common example is string concatenation:
|
|
3660
|
+
// ```js
|
|
3661
|
+
// function subject () { return "world"; };
|
|
3662
|
+
// var greeting = "hello " + subject();
|
|
3663
|
+
// ```
|
|
3664
|
+
// In this case, V8 cannot intern the string. So this comparison is *much* slower:
|
|
3665
|
+
// ```js
|
|
3666
|
+
// if (greeting === "hello world") {}
|
|
3667
|
+
// ```
|
|
3668
|
+
|
|
3669
|
+
|
|
3670
|
+
|
|
3671
|
+
// At the moment, the fastest, safe way of interning a string is to
|
|
3672
|
+
// use it as a key in an object, and then use that key.
|
|
3673
|
+
//
|
|
3674
|
+
// Note: This technique comes courtesy of Petka Antonov - http://jsperf.com/istrn/11
|
|
3675
|
+
//
|
|
3676
|
+
// We create a container object in hash mode.
|
|
3677
|
+
// Most strings being interned will not be valid fast property names,
|
|
3678
|
+
// so we ensure hash mode now to avoid transitioning the object mode at runtime.
|
|
3679
|
+
var container = {'- ': true};
|
|
3680
|
+
delete container['- '];
|
|
3681
|
+
|
|
3682
|
+
|
|
3683
|
+
/**
|
|
3684
|
+
* Intern a string to make comparisons faster.
|
|
3685
|
+
*
|
|
3686
|
+
* > Note: This is a relatively expensive operation, you
|
|
3687
|
+
* shouldn't usually do the actual interning at runtime, instead
|
|
3688
|
+
* use this at compile time to make future work faster.
|
|
3689
|
+
*
|
|
3690
|
+
* @param {String} string The string to intern.
|
|
3691
|
+
* @return {String} The interned string.
|
|
3692
|
+
*/
|
|
3693
|
+
module.exports = function fastIntern (string) {
|
|
3694
|
+
container[string] = true;
|
|
3695
|
+
var interned = Object.keys(container)[0];
|
|
3696
|
+
delete container[interned];
|
|
3697
|
+
return interned;
|
|
3698
|
+
};
|
|
3699
|
+
},{}],57:[function(_require,module,exports){
|
|
3700
|
+
/** generate unique id for selector */
|
|
3701
|
+
var counter = Date.now() % 1e9;
|
|
3702
|
+
|
|
3703
|
+
module.exports = function getUid(){
|
|
3704
|
+
return (Math.random() * 1e9 >>> 0) + (counter++);
|
|
3705
|
+
};
|
|
3706
|
+
},{}],58:[function(_require,module,exports){
|
|
3707
|
+
/*global window*/
|
|
3708
|
+
|
|
3709
|
+
/**
|
|
3710
|
+
* Check if object is dom node.
|
|
3711
|
+
*
|
|
3712
|
+
* @param {Object} val
|
|
3713
|
+
* @return {Boolean}
|
|
3714
|
+
* @api public
|
|
3715
|
+
*/
|
|
3716
|
+
|
|
3717
|
+
module.exports = function isNode(val){
|
|
3718
|
+
if (!val || typeof val !== 'object') return false;
|
|
3719
|
+
if (window && 'object' == typeof window.Node) return val instanceof window.Node;
|
|
3720
|
+
return 'number' == typeof val.nodeType && 'string' == typeof val.nodeName;
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3723
|
+
},{}],59:[function(_require,module,exports){
|
|
3724
|
+
(function (root, factory){
|
|
3725
|
+
'use strict';
|
|
3726
|
+
|
|
3727
|
+
/*istanbul ignore next:cant test*/
|
|
3728
|
+
if (typeof module === 'object' && typeof module.exports === 'object') {
|
|
3729
|
+
module.exports = factory();
|
|
3730
|
+
} else if (typeof define === 'function' && define.amd) {
|
|
3731
|
+
// AMD. Register as an anonymous module.
|
|
3732
|
+
define([], factory);
|
|
3733
|
+
} else {
|
|
3734
|
+
// Browser globals
|
|
3735
|
+
root.objectPath = factory();
|
|
3736
|
+
}
|
|
3737
|
+
})(this, function(){
|
|
3738
|
+
'use strict';
|
|
3739
|
+
|
|
3740
|
+
var
|
|
3741
|
+
toStr = Object.prototype.toString,
|
|
3742
|
+
_hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
3743
|
+
|
|
3744
|
+
function isEmpty(value){
|
|
3745
|
+
if (!value) {
|
|
3746
|
+
return true;
|
|
3747
|
+
}
|
|
3748
|
+
if (isArray(value) && value.length === 0) {
|
|
3749
|
+
return true;
|
|
3750
|
+
} else {
|
|
3751
|
+
for (var i in value) {
|
|
3752
|
+
if (_hasOwnProperty.call(value, i)) {
|
|
3753
|
+
return false;
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
return true;
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
|
|
3760
|
+
function toString(type){
|
|
3761
|
+
return toStr.call(type);
|
|
3762
|
+
}
|
|
3763
|
+
|
|
3764
|
+
function isNumber(value){
|
|
3765
|
+
return typeof value === 'number' || toString(value) === "[object Number]";
|
|
3766
|
+
}
|
|
3767
|
+
|
|
3768
|
+
function isString(obj){
|
|
3769
|
+
return typeof obj === 'string' || toString(obj) === "[object String]";
|
|
3770
|
+
}
|
|
3771
|
+
|
|
3772
|
+
function isObject(obj){
|
|
3773
|
+
return typeof obj === 'object' && toString(obj) === "[object Object]";
|
|
3774
|
+
}
|
|
3775
|
+
|
|
3776
|
+
function isArray(obj){
|
|
3777
|
+
return typeof obj === 'object' && typeof obj.length === 'number' && toString(obj) === '[object Array]';
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3780
|
+
function isBoolean(obj){
|
|
3781
|
+
return typeof obj === 'boolean' || toString(obj) === '[object Boolean]';
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3784
|
+
function getKey(key){
|
|
3785
|
+
var intKey = parseInt(key);
|
|
3786
|
+
if (intKey.toString() === key) {
|
|
3787
|
+
return intKey;
|
|
3788
|
+
}
|
|
3789
|
+
return key;
|
|
3790
|
+
}
|
|
3791
|
+
|
|
3792
|
+
function set(obj, path, value, doNotReplace){
|
|
3793
|
+
if (isNumber(path)) {
|
|
3794
|
+
path = [path];
|
|
3795
|
+
}
|
|
3796
|
+
if (isEmpty(path)) {
|
|
3797
|
+
return obj;
|
|
3798
|
+
}
|
|
3799
|
+
if (isString(path)) {
|
|
3800
|
+
return set(obj, path.split('.').map(getKey), value, doNotReplace);
|
|
3801
|
+
}
|
|
3802
|
+
var currentPath = path[0];
|
|
3803
|
+
|
|
3804
|
+
if (path.length === 1) {
|
|
3805
|
+
var oldVal = obj[currentPath];
|
|
3806
|
+
if (oldVal === void 0 || !doNotReplace) {
|
|
3807
|
+
obj[currentPath] = value;
|
|
3808
|
+
}
|
|
3809
|
+
return oldVal;
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3812
|
+
if (obj[currentPath] === void 0) {
|
|
3813
|
+
//check if we assume an array
|
|
3814
|
+
if(isNumber(path[1])) {
|
|
3815
|
+
obj[currentPath] = [];
|
|
3816
|
+
} else {
|
|
3817
|
+
obj[currentPath] = {};
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
return set(obj[currentPath], path.slice(1), value, doNotReplace);
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3824
|
+
function del(obj, path) {
|
|
3825
|
+
if (isNumber(path)) {
|
|
3826
|
+
path = [path];
|
|
3827
|
+
}
|
|
3828
|
+
|
|
3829
|
+
if (isEmpty(obj)) {
|
|
3830
|
+
return void 0;
|
|
3831
|
+
}
|
|
3832
|
+
|
|
3833
|
+
if (isEmpty(path)) {
|
|
3834
|
+
return obj;
|
|
3835
|
+
}
|
|
3836
|
+
if(isString(path)) {
|
|
3837
|
+
return del(obj, path.split('.'));
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3840
|
+
var currentPath = getKey(path[0]);
|
|
3841
|
+
var oldVal = obj[currentPath];
|
|
3842
|
+
|
|
3843
|
+
if(path.length === 1) {
|
|
3844
|
+
if (oldVal !== void 0) {
|
|
3845
|
+
if (isArray(obj)) {
|
|
3846
|
+
obj.splice(currentPath, 1);
|
|
3847
|
+
} else {
|
|
3848
|
+
delete obj[currentPath];
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
} else {
|
|
3852
|
+
if (obj[currentPath] !== void 0) {
|
|
3853
|
+
return del(obj[currentPath], path.slice(1));
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3857
|
+
return obj;
|
|
3858
|
+
}
|
|
3859
|
+
|
|
3860
|
+
var objectPath = {};
|
|
3861
|
+
|
|
3862
|
+
objectPath.has = function (obj, path) {
|
|
3863
|
+
if (isEmpty(obj)) {
|
|
3864
|
+
return false;
|
|
3865
|
+
}
|
|
3866
|
+
|
|
3867
|
+
if (isNumber(path)) {
|
|
3868
|
+
path = [path];
|
|
3869
|
+
} else if (isString(path)) {
|
|
3870
|
+
path = path.split('.');
|
|
3871
|
+
}
|
|
3872
|
+
|
|
3873
|
+
if (isEmpty(path) || path.length === 0) {
|
|
3874
|
+
return false;
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3877
|
+
for (var i = 0; i < path.length; i++) {
|
|
3878
|
+
var j = path[i];
|
|
3879
|
+
if ((isObject(obj) || isArray(obj)) && _hasOwnProperty.call(obj, j)) {
|
|
3880
|
+
obj = obj[j];
|
|
3881
|
+
} else {
|
|
3882
|
+
return false;
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
return true;
|
|
3887
|
+
};
|
|
3888
|
+
|
|
3889
|
+
objectPath.ensureExists = function (obj, path, value){
|
|
3890
|
+
return set(obj, path, value, true);
|
|
3891
|
+
};
|
|
3892
|
+
|
|
3893
|
+
objectPath.set = function (obj, path, value, doNotReplace){
|
|
3894
|
+
return set(obj, path, value, doNotReplace);
|
|
3895
|
+
};
|
|
3896
|
+
|
|
3897
|
+
objectPath.insert = function (obj, path, value, at){
|
|
3898
|
+
var arr = objectPath.get(obj, path);
|
|
3899
|
+
at = ~~at;
|
|
3900
|
+
if (!isArray(arr)) {
|
|
3901
|
+
arr = [];
|
|
3902
|
+
objectPath.set(obj, path, arr);
|
|
3903
|
+
}
|
|
3904
|
+
arr.splice(at, 0, value);
|
|
3905
|
+
};
|
|
3906
|
+
|
|
3907
|
+
objectPath.empty = function(obj, path) {
|
|
3908
|
+
if (isEmpty(path)) {
|
|
3909
|
+
return obj;
|
|
3910
|
+
}
|
|
3911
|
+
if (isEmpty(obj)) {
|
|
3912
|
+
return void 0;
|
|
3913
|
+
}
|
|
3914
|
+
|
|
3915
|
+
var value, i;
|
|
3916
|
+
if (!(value = objectPath.get(obj, path))) {
|
|
3917
|
+
return obj;
|
|
3918
|
+
}
|
|
3919
|
+
|
|
3920
|
+
if (isString(value)) {
|
|
3921
|
+
return objectPath.set(obj, path, '');
|
|
3922
|
+
} else if (isBoolean(value)) {
|
|
3923
|
+
return objectPath.set(obj, path, false);
|
|
3924
|
+
} else if (isNumber(value)) {
|
|
3925
|
+
return objectPath.set(obj, path, 0);
|
|
3926
|
+
} else if (isArray(value)) {
|
|
3927
|
+
value.length = 0;
|
|
3928
|
+
} else if (isObject(value)) {
|
|
3929
|
+
for (i in value) {
|
|
3930
|
+
if (_hasOwnProperty.call(value, i)) {
|
|
3931
|
+
delete value[i];
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
} else {
|
|
3935
|
+
return objectPath.set(obj, path, null);
|
|
3936
|
+
}
|
|
3937
|
+
};
|
|
3938
|
+
|
|
3939
|
+
objectPath.push = function (obj, path /*, values */){
|
|
3940
|
+
var arr = objectPath.get(obj, path);
|
|
3941
|
+
if (!isArray(arr)) {
|
|
3942
|
+
arr = [];
|
|
3943
|
+
objectPath.set(obj, path, arr);
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3946
|
+
arr.push.apply(arr, Array.prototype.slice.call(arguments, 2));
|
|
3947
|
+
};
|
|
3948
|
+
|
|
3949
|
+
objectPath.coalesce = function (obj, paths, defaultValue) {
|
|
3950
|
+
var value;
|
|
3951
|
+
|
|
3952
|
+
for (var i = 0, len = paths.length; i < len; i++) {
|
|
3953
|
+
if ((value = objectPath.get(obj, paths[i])) !== void 0) {
|
|
3954
|
+
return value;
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
|
|
3958
|
+
return defaultValue;
|
|
3959
|
+
};
|
|
3960
|
+
|
|
3961
|
+
objectPath.get = function (obj, path, defaultValue){
|
|
3962
|
+
if (isNumber(path)) {
|
|
3963
|
+
path = [path];
|
|
3964
|
+
}
|
|
3965
|
+
if (isEmpty(path)) {
|
|
3966
|
+
return obj;
|
|
3967
|
+
}
|
|
3968
|
+
if (isEmpty(obj)) {
|
|
3969
|
+
return defaultValue;
|
|
3970
|
+
}
|
|
3971
|
+
if (isString(path)) {
|
|
3972
|
+
return objectPath.get(obj, path.split('.'), defaultValue);
|
|
3973
|
+
}
|
|
3974
|
+
|
|
3975
|
+
var currentPath = getKey(path[0]);
|
|
3976
|
+
|
|
3977
|
+
if (path.length === 1) {
|
|
3978
|
+
if (obj[currentPath] === void 0) {
|
|
3979
|
+
return defaultValue;
|
|
3980
|
+
}
|
|
3981
|
+
return obj[currentPath];
|
|
3982
|
+
}
|
|
3983
|
+
|
|
3984
|
+
return objectPath.get(obj[currentPath], path.slice(1), defaultValue);
|
|
3985
|
+
};
|
|
3986
|
+
|
|
3987
|
+
objectPath.del = function(obj, path) {
|
|
3988
|
+
return del(obj, path);
|
|
3989
|
+
};
|
|
3990
|
+
|
|
3991
|
+
return objectPath;
|
|
3992
|
+
});
|
|
3993
|
+
|
|
3994
|
+
},{}],60:[function(_require,module,exports){
|
|
3995
|
+
/**
|
|
3996
|
+
* Module Dependencies.
|
|
3997
|
+
*/
|
|
3998
|
+
|
|
3999
|
+
var raf = _require('raf');
|
|
4000
|
+
|
|
4001
|
+
/**
|
|
4002
|
+
* Export `throttle`.
|
|
4003
|
+
*/
|
|
4004
|
+
|
|
4005
|
+
module.exports = throttle;
|
|
4006
|
+
|
|
4007
|
+
/**
|
|
4008
|
+
* Executes a function at most once per animation frame. Kind of like
|
|
4009
|
+
* throttle, but it throttles at ~60Hz.
|
|
4010
|
+
*
|
|
4011
|
+
* @param {Function} fn - the Function to throttle once per animation frame
|
|
4012
|
+
* @return {Function}
|
|
4013
|
+
* @public
|
|
4014
|
+
*/
|
|
4015
|
+
|
|
4016
|
+
function throttle(fn) {
|
|
4017
|
+
var rtn;
|
|
4018
|
+
var ignoring = false;
|
|
4019
|
+
|
|
4020
|
+
return function queue() {
|
|
4021
|
+
if (ignoring) return rtn;
|
|
4022
|
+
ignoring = true;
|
|
4023
|
+
|
|
4024
|
+
raf(function() {
|
|
4025
|
+
ignoring = false;
|
|
4026
|
+
});
|
|
4027
|
+
|
|
4028
|
+
rtn = fn.apply(this, arguments);
|
|
4029
|
+
return rtn;
|
|
4030
|
+
};
|
|
4031
|
+
}
|
|
4032
|
+
|
|
4033
|
+
},{"raf":10}],61:[function(_require,module,exports){
|
|
4034
|
+
module.exports = exports = _require('./lib/sliced');
|
|
4035
|
+
|
|
4036
|
+
},{"./lib/sliced":62}],62:[function(_require,module,exports){
|
|
4037
|
+
|
|
4038
|
+
/**
|
|
4039
|
+
* An Array.prototype.slice.call(arguments) alternative
|
|
4040
|
+
*
|
|
4041
|
+
* @param {Object} args something with a length
|
|
4042
|
+
* @param {Number} slice
|
|
4043
|
+
* @param {Number} sliceEnd
|
|
4044
|
+
* @api public
|
|
4045
|
+
*/
|
|
4046
|
+
|
|
4047
|
+
module.exports = function (args, slice, sliceEnd) {
|
|
4048
|
+
var ret = [];
|
|
4049
|
+
var len = args.length;
|
|
4050
|
+
|
|
4051
|
+
if (0 === len) return ret;
|
|
4052
|
+
|
|
4053
|
+
var start = slice < 0
|
|
4054
|
+
? Math.max(0, slice + len)
|
|
4055
|
+
: slice || 0;
|
|
4056
|
+
|
|
4057
|
+
if (sliceEnd !== undefined) {
|
|
4058
|
+
len = sliceEnd < 0
|
|
4059
|
+
? sliceEnd + len
|
|
4060
|
+
: sliceEnd
|
|
4061
|
+
}
|
|
4062
|
+
|
|
4063
|
+
while (len-- > start) {
|
|
4064
|
+
ret[len - start] = args[len];
|
|
4065
|
+
}
|
|
4066
|
+
|
|
4067
|
+
return ret;
|
|
4068
|
+
}
|
|
4069
|
+
|
|
4070
|
+
|
|
4071
|
+
},{}]},{},[2])(2)
|
|
4072
|
+
});
|