Compare commits
223 Commits
2.0.0-beta
...
2.0.0-beta
Author | SHA1 | Date | |
---|---|---|---|
2f5a2ba671 | |||
c45ec6f1be | |||
530470e0ce | |||
ce72ccf9e8 | |||
46d9c87ddc | |||
d736c31fea | |||
a7e9bc97f6 | |||
265703b950 | |||
ae275fa4e4 | |||
3478d5d450 | |||
e72dc16dbe | |||
40a043275d | |||
f161b5cc28 | |||
117d57e121 | |||
3dcce706fd | |||
efb89b83e1 | |||
3d96c2337f | |||
19cfb4eb12 | |||
3d715a2f7b | |||
c7261c295c | |||
1a26f8edd6 | |||
fc887774da | |||
7cbf88a691 | |||
1cb1c139cf | |||
1fd924f7d5 | |||
eb688f2c8e | |||
61cf499b0b | |||
f1f5b45361 | |||
50548fb565 | |||
8f47aa3530 | |||
df7885c9f5 | |||
0f10624b08 | |||
6f1ef33e32 | |||
231773ea76 | |||
e725542703 | |||
2337469753 | |||
55122cd57a | |||
7e0f02f96e | |||
e7ad03cba6 | |||
74be3d3fde | |||
a15ca23469 | |||
de77700da0 | |||
e73fee7156 | |||
72ab35bceb | |||
0f22dce036 | |||
c6036435f0 | |||
d86be245b8 | |||
a26053d3ff | |||
24d5b665e1 | |||
aa98fad338 | |||
9cb6dbbbab | |||
e21718faa9 | |||
b0f7d59e64 | |||
b86829f492 | |||
22929a1671 | |||
86c40f8474 | |||
16b521794c | |||
2a70f4e4c7 | |||
2f31c4c1c5 | |||
1435763383 | |||
05238df89b | |||
772d60d9fe | |||
24086bf0bb | |||
9b0e10e9a7 | |||
995a9e0cf8 | |||
b55f1764b5 | |||
5e9daed2e8 | |||
aa8c5aa2e2 | |||
f2c7946cca | |||
da1fcfd820 | |||
dbeff6f548 | |||
26e60d658a | |||
c2ceb7fba4 | |||
4bfe49cd42 | |||
cee2318110 | |||
cfef76f683 | |||
f56df65d48 | |||
3a40cd79f0 | |||
6acc99729c | |||
99e6500a2d | |||
5c782d6ba8 | |||
4e43d6f769 | |||
3529ee9973 | |||
29aa6a6c1c | |||
7918f3c1fc | |||
2f4e176054 | |||
d4565fdaf3 | |||
2a302aa73a | |||
31b819e9c2 | |||
27daeaff5e | |||
3e9b532409 | |||
c5aa6d17ef | |||
e480b0798e | |||
8a645d5e44 | |||
321193889f | |||
566d3ede04 | |||
8c36aa866a | |||
ed2dbf2db7 | |||
36a0e04604 | |||
8867afdaab | |||
a199772508 | |||
b008f542fa | |||
a78dcfa5f3 | |||
e1bf3d33f8 | |||
ae7d2ab515 | |||
c6adbf602c | |||
1f7a41c963 | |||
f4f614f3a9 | |||
94139c351f | |||
fc5b128b43 | |||
68a799af2e | |||
16d9c60a0e | |||
c0b5e7a672 | |||
6932b29acb | |||
c2a38c05aa | |||
8bea667a0b | |||
800c8f196f | |||
42231f5719 | |||
db87baeb98 | |||
c4c43f5a77 | |||
0ae77753f3 | |||
5f0baaac73 | |||
b5b6ece65a | |||
4282297c24 | |||
9c96b8affc | |||
132829e5e2 | |||
4a414420e9 | |||
fb6335ab60 | |||
89bd008445 | |||
caafb41eb5 | |||
31b81a7439 | |||
f7b1973358 | |||
32f01da49a | |||
59684c97b0 | |||
a32a0a3a97 | |||
96f5b0929d | |||
8e6cf7fca8 | |||
fdbe8741c9 | |||
775fb2c340 | |||
b60f594798 | |||
cc49790bdb | |||
a4bc19c530 | |||
f7985dbdb7 | |||
0bdcb5c1e0 | |||
a0d25db4a5 | |||
625474c4e2 | |||
1cd2a6328a | |||
d6bafe4fe3 | |||
6a2ef15355 | |||
a8ca560503 | |||
ad361808ec | |||
c47639f2b1 | |||
ba90a85f7b | |||
d3b569557f | |||
c9090ffa31 | |||
341bf39d23 | |||
3778ac26aa | |||
6cfc6f5bb2 | |||
47a3b4d56b | |||
c72ed991ad | |||
78bfdf78ea | |||
a24ee6add4 | |||
df3074fdfe | |||
f7424d5aeb | |||
a593ffa6f3 | |||
761c6d0df7 | |||
3e65d1458e | |||
a4b5cb8376 | |||
c785a1e474 | |||
3adc472f06 | |||
e7081b8b7c | |||
9b3a548f6f | |||
90b3502bb8 | |||
e19b31db29 | |||
bd015f14e8 | |||
ca7ba12fc6 | |||
ae05ec69c4 | |||
92dc3b91d8 | |||
8bd697b316 | |||
eda4c3eb4c | |||
4d0c2ed1f6 | |||
eda6a5d52a | |||
c1c54ed0f2 | |||
6b73d09ba1 | |||
ac85cbb28a | |||
b0cebdba6b | |||
933a9112da | |||
8c37b7e8f2 | |||
c8e909f8c9 | |||
69ae3634c7 | |||
95248f46a1 | |||
b3c7df1783 | |||
c56679e8e1 | |||
041c599511 | |||
6343f71be5 | |||
89f32f808f | |||
7ae23adaff | |||
a08f50badd | |||
0b6e75a85e | |||
4291758079 | |||
b44d36cf95 | |||
a038bb9ae3 | |||
9d28147acb | |||
d116861c8e | |||
9a70f1a1d9 | |||
8516473340 | |||
cab69f689f | |||
822e83ebb0 | |||
b2bc50dbd1 | |||
e748adda2e | |||
630d93150a | |||
76f1f9f1e3 | |||
c47d85b038 | |||
197cf09689 | |||
e67ebb7f70 | |||
3524946581 | |||
9276dad42c | |||
2a2f9a9a19 | |||
909e70bd61 | |||
8ac9719832 | |||
3eff7c6f59 | |||
17fbbfba91 | |||
b232dded77 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -22,6 +22,7 @@ tmp
|
||||
*.js.map
|
||||
|
||||
# Or type definitions we mirror from github
|
||||
# (NB: these lines are removed in publish-build-artifacts.sh)
|
||||
**/typings/**/*.d.ts
|
||||
**/typings/tsd.cached.json
|
||||
|
||||
|
54
.travis.yml
54
.travis.yml
@ -1,17 +1,21 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '4.2.1'
|
||||
- '5.4.1'
|
||||
|
||||
branches:
|
||||
except:
|
||||
- g3sync
|
||||
- g3_v2_0
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- $HOME/.pub-cache
|
||||
|
||||
before_cache:
|
||||
# Undo the pollution of the typescript_next build
|
||||
- npm install typescript
|
||||
|
||||
env:
|
||||
global:
|
||||
- KARMA_BROWSERS=DartiumWithWebPlatform
|
||||
@ -36,28 +40,34 @@ env:
|
||||
matrix:
|
||||
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
|
||||
- MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
- MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=browserstack DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
# Disable dart dev build, which is timing out after 2h. #6823
|
||||
# - MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=saucelabs_required DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=browserstack_required DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=saucelabs_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=browserstack_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=dart_ddc DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=js DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=router DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=build_only DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
- MODE=typescript_next DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
- MODE=lint DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=payload DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: "MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=browserstack DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=saucelabs_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=browserstack_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
# TODO(alxhub): remove when dartdoc #1039 is in dev channel
|
||||
- env: "MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
# Tracked in https://github.com/angular/angular/issues/7050
|
||||
- env: "MODE=typescript_next DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION"
|
||||
|
||||
addons:
|
||||
firefox: "38.0"
|
||||
|
||||
before_install:
|
||||
- npm install -g npm@3.5.3
|
||||
- node tools/analytics/build-analytics start ci job
|
||||
- node tools/analytics/build-analytics start ci before_install
|
||||
- echo ${TSDRC} > .tsdrc
|
||||
@ -75,7 +85,9 @@ install:
|
||||
# Check the size of caches
|
||||
- du -sh ./node_modules || true
|
||||
# Install npm dependecies
|
||||
- npm install
|
||||
# check-node-modules will exit(1) if we don't need to install
|
||||
# we need to manually kick off the postinstall script if check-node-modules exit(0)s
|
||||
- node tools/npm/check-node-modules --purge && npm install || npm run postinstall
|
||||
- node tools/analytics/build-analytics success ci install
|
||||
|
||||
before_script:
|
||||
@ -103,30 +115,10 @@ notifications:
|
||||
- https://webhooks.gitter.im/e/1ef62e23078036f9cee4
|
||||
# trigger Buildtime Trend Service to parse Travis CI log
|
||||
- https://buildtimetrend.herokuapp.com/travis
|
||||
- http://104.197.9.155:8484/hubot/travis/activity
|
||||
on_success: always # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
slack:
|
||||
secure: EP4MzZ8JMyNQJ4S3cd5LEPWSMjC7ZRdzt3veelDiOeorJ6GwZfCDHncR+4BahDzQAuqyE/yNpZqaLbwRWloDi15qIUsm09vgl/1IyNky1Sqc6lEknhzIXpWSalo4/T9ZP8w870EoDvM/UO+LCV99R3wS8Nm9o99eLoWVb2HIUu0=
|
||||
|
||||
deploy:
|
||||
- provider: gcs
|
||||
# This is for project angular-github-babysitter
|
||||
access_key_id: GOOGIOQTDBEOPBUAWFZQ
|
||||
secret_access_key:
|
||||
secure: "MEDggllZ5fw4wI9CEUi8WR6jKsKXqdRF/DLxSNC2JpzM5RlVeBm0uqjntYT1Cf1dASvQ2/+vZCUikL/3A48NcoEYRHXGmxu8D6t/SvleQD8Xv434xFOdsa2QqP/HiCtqCLOI5jJz1JVoB5nNyKKZ33ogTUL1LV1TfcrAioyizW8="
|
||||
# this bucket has a lifecycle to delete after 90 days:
|
||||
# $ echo '{"rule": [{"action": {"type": "Delete"}, "condition": {"age": 90}}]}' > lifecycle.json
|
||||
# $ gsutil lifecycle set lifecycle.json gs://angular2-snapshots
|
||||
bucket: angular2-snapshots
|
||||
# don't delete generated files
|
||||
skip_cleanup: true
|
||||
# serve to public at https://storage.googleapis.com/angular2-snapshots/SHA/dist.tgz
|
||||
acl: public-read
|
||||
# upload the .tgz archive created in scripts/ci/build_and_test.sh
|
||||
local-dir: deploy
|
||||
# create a "subdirectory" for each commit
|
||||
upload-dir: $TRAVIS_COMMIT
|
||||
on:
|
||||
repo: angular/angular
|
||||
condition: "$MODE = build_only"
|
||||
|
267
CHANGELOG.md
267
CHANGELOG.md
@ -1,5 +1,261 @@
|
||||
<a name="2.0.0-beta.7"></a>
|
||||
# 2.0.0-beta.7 (2016-02-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular_1_router:** Added DI string tokens ([3478d5d](https://github.com/angular/angular/commit/3478d5d)), closes [#4269](https://github.com/angular/angular/issues/4269) [#7031](https://github.com/angular/angular/issues/7031)
|
||||
* **typing:** Remove re-export of the Promise built-in type. ([265703b](https://github.com/angular/angular/commit/265703b)), closes [#6468](https://github.com/angular/angular/issues/6468)
|
||||
|
||||
<a name="2.0.0-beta.6"></a>
|
||||
# 2.0.0-beta.6 (2016-02-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **angular1-router:** add missing wrapper methods ([55122cd](https://github.com/angular/angular/commit/55122cd)), closes [#6763](https://github.com/angular/angular/issues/6763) [#6861](https://github.com/angular/angular/issues/6861) [#6861](https://github.com/angular/angular/issues/6861)
|
||||
* **angular1-router:** add support for using the component helper ([d86be24](https://github.com/angular/angular/commit/d86be24)), closes [angular/angular.js#13860](https://github.com/angular/angular.js/issues/13860) [#6076](https://github.com/angular/angular/issues/6076) [#5278](https://github.com/angular/angular/issues/5278)
|
||||
* **async:** handle synchronous initial value in async pipe ([26e60d6](https://github.com/angular/angular/commit/26e60d6)), closes [#5996](https://github.com/angular/angular/issues/5996)
|
||||
* **build:** don't try to copy .d.ts files into the npm distro ([16b5217](https://github.com/angular/angular/commit/16b5217)), closes [#6921](https://github.com/angular/angular/issues/6921)
|
||||
* **compiler:** fix interpolation regexp ([9b0e10e](https://github.com/angular/angular/commit/9b0e10e)), closes [#6056](https://github.com/angular/angular/issues/6056)
|
||||
* **compiler:** use event names for matching directives ([231773e](https://github.com/angular/angular/commit/231773e)), closes [#6870](https://github.com/angular/angular/issues/6870)
|
||||
* **core:** add detail to dehydrated detector exception ([e7ad03c](https://github.com/angular/angular/commit/e7ad03c)), closes [#6939](https://github.com/angular/angular/issues/6939)
|
||||
* **core:** mute mode printing in console in prod mode ([74be3d3](https://github.com/angular/angular/commit/74be3d3)), closes [#6873](https://github.com/angular/angular/issues/6873)
|
||||
* **di:** throw if a token uses more than 20 dependencies. ([de77700](https://github.com/angular/angular/commit/de77700)), closes [#6690](https://github.com/angular/angular/issues/6690) [#6869](https://github.com/angular/angular/issues/6869)
|
||||
* **forms:** add RadioButtonValueAccessor to the list of default value accessors ([8f47aa3](https://github.com/angular/angular/commit/8f47aa3))
|
||||
* **forms:** add support for radio buttons ([e725542](https://github.com/angular/angular/commit/e725542)), closes [#6877](https://github.com/angular/angular/issues/6877)
|
||||
* **forms:** use strict runtimeType checks instead of instanceof ([50548fb](https://github.com/angular/angular/commit/50548fb)), closes [#6981](https://github.com/angular/angular/issues/6981)
|
||||
* **Headers:** serializable toJSON ([b55f176](https://github.com/angular/angular/commit/b55f176)), closes [#6073](https://github.com/angular/angular/issues/6073) [#6714](https://github.com/angular/angular/issues/6714)
|
||||
* **ngFor:** update view locals if identity changes ([0f10624](https://github.com/angular/angular/commit/0f10624)), closes [#6923](https://github.com/angular/angular/issues/6923)
|
||||
* **router:** Added route data to normalized async route ([df7885c](https://github.com/angular/angular/commit/df7885c)), closes [#6802](https://github.com/angular/angular/issues/6802)
|
||||
* **router:** don't prepend `/` unnecessarily to Location paths ([c603643](https://github.com/angular/angular/commit/c603643)), closes [#6729](https://github.com/angular/angular/issues/6729) [#5502](https://github.com/angular/angular/issues/5502)
|
||||
* **router:** fix incorrect url param value coercion of 1 to true ([995a9e0](https://github.com/angular/angular/commit/995a9e0)), closes [#5346](https://github.com/angular/angular/issues/5346) [#6286](https://github.com/angular/angular/issues/6286)
|
||||
* **router:** fix url path for star segment in path recognizer ([6f1ef33](https://github.com/angular/angular/commit/6f1ef33)), closes [#6976](https://github.com/angular/angular/issues/6976)
|
||||
* **router:** fixed the location wrapper for angular1 ([e73fee7](https://github.com/angular/angular/commit/e73fee7)), closes [#6943](https://github.com/angular/angular/issues/6943)
|
||||
* **typings:** Don't expose typing dependencies to users. ([2a70f4e](https://github.com/angular/angular/commit/2a70f4e)), closes [#5973](https://github.com/angular/angular/issues/5973) [#5807](https://github.com/angular/angular/issues/5807) [#6266](https://github.com/angular/angular/issues/6266) [#5242](https://github.com/angular/angular/issues/5242) [#6817](https://github.com/angular/angular/issues/6817) [#6267](https://github.com/angular/angular/issues/6267)
|
||||
* **upgrade:** fix infinite $rootScope.$digest() ([7e0f02f](https://github.com/angular/angular/commit/7e0f02f)), closes [#6385](https://github.com/angular/angular/issues/6385) [#6386](https://github.com/angular/angular/issues/6386)
|
||||
* **Validators:** fix Validators.required marking number zero as invalid ([c2ceb7f](https://github.com/angular/angular/commit/c2ceb7f)), closes [#6617](https://github.com/angular/angular/issues/6617)
|
||||
* **WebWorkers:** Fix flaky WebWorker test ([da1fcfd](https://github.com/angular/angular/commit/da1fcfd)), closes [#6851](https://github.com/angular/angular/issues/6851)
|
||||
|
||||
### Features
|
||||
|
||||
* **angular1_router:** allow component to bind to router ([0f22dce](https://github.com/angular/angular/commit/0f22dce))
|
||||
* **typings:** install es6-shim typings to a location users can reference. ([f1f5b45](https://github.com/angular/angular/commit/f1f5b45))
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
Transitive typings are no longer included in the distribution.
|
||||
|
||||
If you use `--target=es5`, you will need to add a line somewhere in your
|
||||
application (for example, at the top of the `.ts` file where you call `bootstrap`):
|
||||
```
|
||||
///<reference path="node_modules/angular2/typings/browser.d.ts"/>
|
||||
```
|
||||
(Note that if your file is not in the same directory as `node_modules`, you'll
|
||||
need to add one or more `../` to the start of that path.)
|
||||
|
||||
If you have unit tests, you need to install typings in your project using
|
||||
http://github.com/typings/typings
|
||||
And install typings such as `jasmine`, `angular-protractor`, or `selenium-webdriver`
|
||||
to satisfy the type-checker.
|
||||
|
||||
If you rely on es6 APIs other than Promises and Collections, you will need to
|
||||
install the es6-shim typing instead of using the <reference> tag above.
|
||||
Angular previously exposed typings for the entire ES6 API.
|
||||
|
||||
<a name="2.0.0-beta.5"></a>
|
||||
# 2.0.0-beta.5 (2016-02-10)
|
||||
|
||||
This release was incorrect; replaced with beta.6.
|
||||
|
||||
<a name="2.0.0-beta.4"></a>
|
||||
# 2.0.0-beta.4 (2016-02-10)
|
||||
|
||||
This release was incorrect; replaced with beta.6.
|
||||
|
||||
<a name="2.0.0-beta.3"></a>
|
||||
# 2.0.0-beta.3 (2016-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bundle:** add angular2/platform/testing/browser to SystemJS testing bundle ([ae7d2ab](https://github.com/angular/angular/commit/ae7d2ab))
|
||||
* **circle:** pre-dependencies `npm install npm` ([36a0e04](https://github.com/angular/angular/commit/36a0e04)), closes [#6777](https://github.com/angular/angular/issues/6777)
|
||||
* **dart/transform:** Handle edge cases in ReflectionRemover ([3e9b532](https://github.com/angular/angular/commit/3e9b532)), closes [#6749](https://github.com/angular/angular/issues/6749)
|
||||
* **docs:** `rxjs/add/operators/map` -> `rxjs/add/operator/map` (no 's'). ([2a302aa](https://github.com/angular/angular/commit/2a302aa))
|
||||
* **karma:** fix running karma via gulp ([27daeaf](https://github.com/angular/angular/commit/27daeaf))
|
||||
* **query:** don’t cross component boundaries ([c6adbf6](https://github.com/angular/angular/commit/c6adbf6)), closes [#6759](https://github.com/angular/angular/issues/6759)
|
||||
* **query:** update view queries that query directives in embedded views ([1f7a41c](https://github.com/angular/angular/commit/1f7a41c)), closes [#6747](https://github.com/angular/angular/issues/6747)
|
||||
* **WebWorkers:** Add support for transitionend events. ([c2a38c0](https://github.com/angular/angular/commit/c2a38c0)), closes [#6649](https://github.com/angular/angular/issues/6649)
|
||||
* **zone:** correct incorrect calls to zone ([3211938](https://github.com/angular/angular/commit/3211938))
|
||||
|
||||
### Features
|
||||
|
||||
* **change_detection:** allow all legal programs in the dev mode ([42231f5](https://github.com/angular/angular/commit/42231f5))
|
||||
* **dart/transform:** Generate all code into <file>.template.dart ([8c36aa8](https://github.com/angular/angular/commit/8c36aa8))
|
||||
* **debug:** replace DebugElement with new Debug DOM ([e1bf3d3](https://github.com/angular/angular/commit/e1bf3d3))
|
||||
* **ngFor:** add custom trackBy function support ([cee2318](https://github.com/angular/angular/commit/cee2318)), closes [#6779](https://github.com/angular/angular/issues/6779)
|
||||
* **upgrade:** support bindToController with binding definitions ([99e6500](https://github.com/angular/angular/commit/99e6500)), closes [#4784](https://github.com/angular/angular/issues/4784)
|
||||
* **WebWorker:** Add Router Support for WebWorker Apps ([8bea667](https://github.com/angular/angular/commit/8bea667)), closes [#3563](https://github.com/angular/angular/issues/3563)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **dart/transform:** Only process deferred libs when necessary ([f56df65](https://github.com/angular/angular/commit/f56df65)), closes [#6745](https://github.com/angular/angular/issues/6745)
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
This is a breaking change for unit tests. The API for the DebugElement
|
||||
has changed. Now, there is a DebugElement or DebugNode for every node
|
||||
in the DOM, not only nodes with an ElementRef. `componentViewChildren` is
|
||||
removed, and `childNodes` is a list of ElementNodes corresponding to every
|
||||
child in the DOM. `query` no longer takes a scope parameter, since
|
||||
the entire rendered DOM is included in the `childNodes`.
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
componentFixture.debugElement.componentViewChildren[0];
|
||||
```
|
||||
|
||||
After
|
||||
```
|
||||
// Depending on the DOM structure of your component, the
|
||||
// index may have changed or the first component child
|
||||
// may be a sub-child.
|
||||
componentFixture.debugElement.children[0];
|
||||
```
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
debugElement.query(By.css('div'), Scope.all());
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
debugElement.query(By.css('div'));
|
||||
```
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
componentFixture.debugElement.elementRef;
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
componentFixture.elementRef;
|
||||
```
|
||||
|
||||
<a name="2.0.0-beta.2"></a>
|
||||
# 2.0.0-beta.2 (2016-01-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bundles:** testing bundle should include browser platform ([4a41442](https://github.com/angular/angular/commit/4a41442)), closes [#6626](https://github.com/angular/angular/issues/6626)
|
||||
* **ChangeDetection:** chain expressions evaluate to the last expression (codegen) ([933a911](https://github.com/angular/angular/commit/933a911)), closes [#4782](https://github.com/angular/angular/issues/4782) [#5892](https://github.com/angular/angular/issues/5892)
|
||||
* **core:** always remove DOM listeners and stream subscriptions ([0ae7775](https://github.com/angular/angular/commit/0ae7775))
|
||||
* **Dart:** make some playground samples run with Dart Dev Compiler ([3e65d14](https://github.com/angular/angular/commit/3e65d14)), closes [#6441](https://github.com/angular/angular/issues/6441)
|
||||
* **dart/transform:** Ensure template codegen is completed sync ([5f0baaa](https://github.com/angular/angular/commit/5f0baaa)), closes [#6603](https://github.com/angular/angular/issues/6603)
|
||||
* **ddc:** router, compiler, web worker fixes for DDC ([db87bae](https://github.com/angular/angular/commit/db87bae)), closes [#6693](https://github.com/angular/angular/issues/6693)
|
||||
* **ddc:** type fixes necessary to bring DDC severe count to 0 ([4282297](https://github.com/angular/angular/commit/4282297))
|
||||
* **ddc:** use dynamic types in reflection typedefs ([c785a1e](https://github.com/angular/angular/commit/c785a1e)), closes [#6437](https://github.com/angular/angular/issues/6437)
|
||||
* **directive:** throw if output the same event more than once ([8c37b7e](https://github.com/angular/angular/commit/8c37b7e))
|
||||
* **HtmlLexer:** fix for unicode chars ([a24ee6a](https://github.com/angular/angular/commit/a24ee6a)), closes [#6036](https://github.com/angular/angular/issues/6036) [#6061](https://github.com/angular/angular/issues/6061)
|
||||
* **perf:** faster looseIdentical implementation ([761c6d0](https://github.com/angular/angular/commit/761c6d0)), closes [#6364](https://github.com/angular/angular/issues/6364)
|
||||
* **template_compiler:** Fix erroneous cycle detection ([eda4c3e](https://github.com/angular/angular/commit/eda4c3e)), closes [#6404](https://github.com/angular/angular/issues/6404) [#6474](https://github.com/angular/angular/issues/6474)
|
||||
* **testing:** remove test zone for now and rely on returned promises ([c72ed99](https://github.com/angular/angular/commit/c72ed99)), closes [#6359](https://github.com/angular/angular/issues/6359) [#6601](https://github.com/angular/angular/issues/6601)
|
||||
* **transformer:** record HostBinding annotations applied to getters ([a593ffa](https://github.com/angular/angular/commit/a593ffa)), closes [#6283](https://github.com/angular/angular/issues/6283)
|
||||
* **web_workers:** support @AngularEntrypoint in web workers ([ac85cbb](https://github.com/angular/angular/commit/ac85cbb)), closes [#6013](https://github.com/angular/angular/issues/6013)
|
||||
|
||||
### Features
|
||||
|
||||
* **core/application_ref:** Allow asyncronous app initializers. ([df3074f](https://github.com/angular/angular/commit/df3074f)), closes [#5929](https://github.com/angular/angular/issues/5929) [#6063](https://github.com/angular/angular/issues/6063)
|
||||
* **dart/transform:** DirectiveProcessor: do not process generated files ([78bfdf7](https://github.com/angular/angular/commit/78bfdf7)), closes [#6517](https://github.com/angular/angular/issues/6517)
|
||||
* **dart/transform:** Promote missing Directive warning to error ([47a3b4d](https://github.com/angular/angular/commit/47a3b4d)), closes [#6519](https://github.com/angular/angular/issues/6519) [#6568](https://github.com/angular/angular/issues/6568)
|
||||
* **test:** allow tests to specify the platform and application providers used ([b0cebdb](https://github.com/angular/angular/commit/b0cebdb)), closes [#5351](https://github.com/angular/angular/issues/5351) [#5585](https://github.com/angular/angular/issues/5585) [#5975](https://github.com/angular/angular/issues/5975)
|
||||
* **testability:** Expose function frameworkStabilizers ([69ae363](https://github.com/angular/angular/commit/69ae363)), closes [#5485](https://github.com/angular/angular/issues/5485)
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* `Renderer.listen` now has to return a function that
|
||||
removes the event listener.
|
||||
|
||||
* TemplateRef.elementRef is now read-only.
|
||||
|
||||
* Tests are now required to use `setBaseTestProviders`
|
||||
to set up. Assuming your tests are run on a browser, setup would change
|
||||
as follows.
|
||||
Before:
|
||||
```js
|
||||
// Somewhere in test setup
|
||||
import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter';
|
||||
BrowserDomAdapter.makeCurrent
|
||||
```
|
||||
After:
|
||||
```js
|
||||
// Somewhere in the test setup
|
||||
import {setBaseTestProviders} from 'angular2/testing';
|
||||
import {
|
||||
TEST_BROWSER_PLATFORM_PROVIDERS,
|
||||
TEST_BROWSER_APPLICATION_PROVIDERS
|
||||
} from 'angular2/platform/testing/browser';
|
||||
setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS,
|
||||
TEST_BROWSER_APPLICATION_PROVIDERS);
|
||||
```
|
||||
|
||||
|
||||
<a name="2.0.0-beta.1"></a>
|
||||
# 2.0.0-beta.1 catamorphic-involution (2016-01-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **benchpress:** fix flake ([9d28147](https://github.com/angular/angular/commit/9d28147)), closes [#6161](https://github.com/angular/angular/issues/6161)
|
||||
* **CHANGELOG:** typo ([d116861](https://github.com/angular/angular/commit/d116861)), closes [#6075](https://github.com/angular/angular/issues/6075) [#6078](https://github.com/angular/angular/issues/6078)
|
||||
* **code size:** revert previous devMode change to restore size targets ([c47d85b](https://github.com/angular/angular/commit/c47d85b))
|
||||
* **core:** IE only supports parentNode ([630d931](https://github.com/angular/angular/commit/630d931)), closes [#5994](https://github.com/angular/angular/issues/5994)
|
||||
* **docs:** fix an import in TOOLS_DART.md ([3524946](https://github.com/angular/angular/commit/3524946)), closes [#5923](https://github.com/angular/angular/issues/5923)
|
||||
* **forms:** fix SelectControlValueAccessor not to call onChange twice ([b44d36c](https://github.com/angular/angular/commit/b44d36c)), closes [#5969](https://github.com/angular/angular/issues/5969)
|
||||
* **router:** correctly sort route matches with children by specificity ([b2bc50d](https://github.com/angular/angular/commit/b2bc50d)), closes [#5848](https://github.com/angular/angular/issues/5848) [#6011](https://github.com/angular/angular/issues/6011)
|
||||
* **router:** preserve specificity for redirects ([a038bb9](https://github.com/angular/angular/commit/a038bb9)), closes [#5933](https://github.com/angular/angular/issues/5933)
|
||||
* **TemplateParser:** do not match on attrs that are bindings ([9a70f1a](https://github.com/angular/angular/commit/9a70f1a)), closes [#5914](https://github.com/angular/angular/issues/5914)
|
||||
|
||||
### Features
|
||||
|
||||
* **core:** improve NoAnnotationError message ([197cf09](https://github.com/angular/angular/commit/197cf09)), closes [#4866](https://github.com/angular/angular/issues/4866) [#5927](https://github.com/angular/angular/issues/5927)
|
||||
* **core:** improve stringify for dart to handle closures ([e67ebb7](https://github.com/angular/angular/commit/e67ebb7))
|
||||
* **core:** speed up view creation via code gen for view factories. ([7ae23ad](https://github.com/angular/angular/commit/7ae23ad)), closes [#5993](https://github.com/angular/angular/issues/5993)
|
||||
* **router:** support links with just auxiliary routes ([2a2f9a9](https://github.com/angular/angular/commit/2a2f9a9)), closes [#5930](https://github.com/angular/angular/issues/5930)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **dart/transform:** Avoid unnecessary reads for files with no view ([89f32f8](https://github.com/angular/angular/commit/89f32f8)), closes [#6183](https://github.com/angular/angular/issues/6183)
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Platform pipes can only contain types and arrays of types,
|
||||
but no bindings any more.
|
||||
* When using transformers, platform pipes need to be specified explicitly
|
||||
in the pubspec.yaml via the new config option
|
||||
`platform_pipes`.
|
||||
* `Compiler.compileInHost` now returns a `HostViewFactoryRef`
|
||||
* Component view is not yet created when component constructor is called.
|
||||
-> use `onInit` lifecycle callback to access the view of a component
|
||||
* `ViewRef#setLocal` has been moved to new type `EmbeddedViewRef`
|
||||
* `internalView` is gone, use `EmbeddedViewRef.rootNodes` to access
|
||||
the root nodes of an embedded view
|
||||
* `renderer.setElementProperty`, `..setElementStyle`, `..setElementAttribute` now
|
||||
take a native element instead of an ElementRef
|
||||
* `Renderer` interface now operates on plain native nodes,
|
||||
instead of `RenderElementRef`s or `RenderViewRef`s
|
||||
|
||||
<a name="2.0.0-beta.0"></a>
|
||||
# 2.0.0-beta.0 sonambulent-inauguration (2015-12-15)
|
||||
# 2.0.0-beta.0 somnambulant-inauguration (2015-12-15)
|
||||
|
||||
**Enjoy!**
|
||||
|
||||
@ -19,10 +275,7 @@
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* Before
|
||||
Previously Angular would run in dev prod mode by default, and you could enable the dev mode by calling enableDevMode.
|
||||
After
|
||||
Now, Angular runs in the dev mode by default, and you can enable the prod mode by calling enableProdMode.
|
||||
* Previously, Angular would run in dev prod mode by default, and you could enable the dev mode by calling enableDevMode. Now, Angular runs in the dev mode by default, and you can enable the prod mode by calling enableProdMode.
|
||||
|
||||
|
||||
|
||||
@ -154,7 +407,7 @@ Use imports from `angular2/compiler` instead.
|
||||
<my-cmp (myEvent)="action()">
|
||||
<my-cmp [(myProp)]="prop">
|
||||
<input #myInput>`,
|
||||
<template ngFor="#myItem" [ngForOf]=items #myIndex="index">
|
||||
<template ngFor "#myItem" [ngForOf]=items #myIndex="index">
|
||||
```
|
||||
|
||||
The full migration instruction can be found at [angular2/docs/migration/kebab-case.md](https://github.com/angular/angular/blob/master/modules/angular2/docs/migration/kebab-case.md).
|
||||
@ -324,7 +577,7 @@ import * as core from 'angular2/core';
|
||||
* Operators and Observables from RxJS (e.g. .map(), .toArray(), .toPromise(), etc ) now need to be explicitly imported (once per operator in your app)
|
||||
```
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import 'rxjs/add/operators/map';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/observable/interval';
|
||||
|
||||
Observable.interval(1000).subscribe(...);
|
||||
|
@ -11,8 +11,11 @@ Someone with committer access will do the rest.
|
||||
We have automated the process for merging pull requests into master. Our goal is to minimize the disruption for
|
||||
Angular committers and also prevent breakages on master.
|
||||
|
||||
When a PR is ready to merge, a project member in the CoreTeamMember list (see below) can add the special label,
|
||||
`PR: merge`.
|
||||
When a PR has `pr_state: LGTM` and is ready to merge, you should add the `pr_action: merge` label.
|
||||
Currently (late 2015), we need to ensure that each PR will cleanly merge into the Google-internal version control,
|
||||
so the caretaker reviews the changes manually.
|
||||
|
||||
After this review, the caretaker adds `zomg_admin: do_merge` which is restricted to admins only.
|
||||
A robot running as [mary-poppins](https://github.com/mary-poppins)
|
||||
is notified that the label was added by an authorized person,
|
||||
and will create a new branch in the angular project, using the convention `presubmit-{username}-pr-{number}`.
|
||||
@ -26,6 +29,6 @@ Finally, after merge `mary-poppins` removes the presubmit branch.
|
||||
|
||||
## Administration
|
||||
|
||||
The list of users who can trigger a merge by adding the label is stored in our appengine app datastore.
|
||||
The list of users who can trigger a merge by adding the `zomg_admin: do_merge` label is stored in our appengine app datastore.
|
||||
Edit the contents of the [CoreTeamMember Table](
|
||||
https://console.developers.google.com/project/angular2-automation/datastore/query?queryType=KindQuery&namespace=&kind=CoreTeamMember)
|
||||
|
@ -180,7 +180,8 @@ Must be one of the following:
|
||||
* **refactor**: A code change that neither fixes a bug nor adds a feature
|
||||
* **perf**: A code change that improves performance
|
||||
* **test**: Adding missing tests or correcting existing tests
|
||||
* **build** Changes that affect the build system, CI configuration or external dependencies (example scopes: gulp, broccoli, npm)
|
||||
* **build**: Changes that affect the build system, CI configuration or external dependencies (example scopes: gulp, broccoli, npm)
|
||||
* **ci**: Any changes to our CI configuration files and scripts (Travis, Circle CI, BrowserStack, SauceLabs)
|
||||
* **chore**: Other changes that don't modify `src` or `test` files
|
||||
|
||||
### Scope
|
||||
|
44
DEVELOPER.md
44
DEVELOPER.md
@ -9,7 +9,7 @@ JS and Dart versions. It also explains the basic mechanics of using `git`, `node
|
||||
* [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
|
||||
* [Build commands](#build-commands)
|
||||
* [Running Tests Locally](#running-tests-locally)
|
||||
* [Formatting](#clang-format)
|
||||
* [Code Style](#code-style)
|
||||
* [Project Information](#project-information)
|
||||
* [CI using Travis](#ci-using-travis)
|
||||
* [Transforming Dart code](#transforming-dart-code)
|
||||
@ -23,7 +23,16 @@ if you'd like to contribute to Angular.
|
||||
Before you can build and test Angular, you must install and configure the
|
||||
following products on your development machine:
|
||||
|
||||
* [Dart](https://www.dartlang.org) (version ` >=1.12.0 <2.0.0`), specifically the Dart-SDK and
|
||||
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or
|
||||
[Windows](http://windows.github.com)); [GitHub's Guide to Installing
|
||||
Git](https://help.github.com/articles/set-up-git) is a good source of information.
|
||||
|
||||
* [Node.js](http://nodejs.org), (version `>=5.4.1 <6`) which is used to run a development web server,
|
||||
run tests, and generate distributable files. We also use Node's Package Manager, `npm`
|
||||
(version `>=3.5.3 <4.0`), which comes with Node. Depending on your system, you can install Node either from
|
||||
source or as a pre-packaged bundle.
|
||||
|
||||
* *Optional*: [Dart](https://www.dartlang.org) (version ` >=1.13.2 <2.0.0`), specifically the Dart-SDK and
|
||||
Dartium (a version of [Chromium](http://www.chromium.org) with native support for Dart through
|
||||
the Dart VM). One of the **simplest** ways to get both is to install the **Dart Editor bundle**,
|
||||
which includes the editor, SDK and Dartium. See the [Dart tools](https://www.dartlang.org/tools)
|
||||
@ -33,19 +42,6 @@ following products on your development machine:
|
||||
to the `Path` (e.g. `path-to-dart-sdk-folder\bin`) and a new `DARTIUM_BIN` environment variable must be
|
||||
created, pointing to the executable (e.g. `path-to-dartium-folder\chrome.exe).`
|
||||
|
||||
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or
|
||||
[Windows](http://windows.github.com)); [GitHub's Guide to Installing
|
||||
Git](https://help.github.com/articles/set-up-git) is a good source of information.
|
||||
|
||||
* [Node.js](http://nodejs.org), (version `>=4.2.1 <5`) which is used to run a development web server,
|
||||
run tests, and generate distributable files. We also use Node's Package Manager, `npm`
|
||||
(version `>=2.14.7 <3.0`), which comes with Node. Depending on your system, you can install Node either from
|
||||
source or as a pre-packaged bundle.
|
||||
|
||||
* [Chrome Canary](https://www.google.com/chrome/browser/canary.html), a version of Chrome with
|
||||
bleeding edge functionality, built especially for developers (and early adopters).
|
||||
|
||||
* [Bower](http://bower.io/).
|
||||
|
||||
|
||||
## Getting the Sources
|
||||
@ -200,15 +196,15 @@ Then, in another terminal:
|
||||
export SAUCE_USERNAME='my_user'; export SAUCE_ACCESS_KEY='my_key';
|
||||
export BROWSER_STACK_USERNAME='my_user'; export BROWSER_STACK_ACCESS_KEY='my_key';
|
||||
```
|
||||
- Then run `gulp test.unit.js.(saucelabs|browserstack) --browsers=option1,option2,..,optionN`
|
||||
- Then run `gulp test.unit.js.(sauce|browserstack) --browsers=option1,option2,..,optionN`
|
||||
The options are any mix of browsers and aliases which are defined in the [browser-providers.conf.js](https://github.com/angular/angular/blob/master/browser-providers.conf.js) file.
|
||||
They are case insensitive, and the `SL_` or `BS_` prefix must not be added for browsers.
|
||||
|
||||
Some examples of commands:
|
||||
```
|
||||
gulp test.unit.js.saucelabs --browsers=Safari8,ie11 //run in Sauce Labs with Safari 8 and IE11
|
||||
gulp test.unit.js.sauce --browsers=Safari8,ie11 //run in Sauce Labs with Safari 8 and IE11
|
||||
gulp test.unit.js.browserstack --browsers=Safari,IE //run in Browser Stack with Safari 7, Safari 8, Safari 9, IE 9, IE 10 and IE 11
|
||||
gulp test.unit.js.saucelabs --browsers=IOS,safari8,android5.1 //run in Sauce Labs with iOS 7, iOS 8, iOs 9, Safari 8 and Android 5.1
|
||||
gulp test.unit.js.sauce --browsers=IOS,safari8,android5.1 //run in Sauce Labs with iOS 7, iOS 8, iOs 9, Safari 8 and Android 5.1
|
||||
```
|
||||
|
||||
### E2E tests
|
||||
@ -231,7 +227,9 @@ Angular specific command line options when running protractor:
|
||||
Angular specific command line options when running protractor (e.g. force gc, ...):
|
||||
`$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
|
||||
|
||||
## Formatting with <a name="clang-format">clang-format</a>
|
||||
## Code Style
|
||||
|
||||
### Formatting with <a name="clang-format">clang-format</a>
|
||||
|
||||
We use [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to automatically enforce code
|
||||
style for our TypeScript code. This allows us to focus our code reviews more on the content, and
|
||||
@ -277,6 +275,14 @@ to some whitespace difference.
|
||||
* `clang-format` integrations are also available for many popular editors (`vim`, `emacs`,
|
||||
`Sublime Text`, etc.).
|
||||
|
||||
### Linting
|
||||
|
||||
We use [tslint](https://github.com/palantir/tslint) for linting. See linting rules in [gulpfile](gulpfile.js). To lint, run
|
||||
|
||||
```shell
|
||||
$ gulp lint
|
||||
```
|
||||
|
||||
## Generating the API documentation
|
||||
|
||||
The following gulp task will generate the API docs in the `dist/angular.io/partials/api/angular2`:
|
||||
|
215
LICENSE
215
LICENSE
@ -1,202 +1,21 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
The MIT License
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
Copyright (c) 2014-2016 Google, Inc. http://angular.io
|
||||
|
||||
1. Definitions.
|
||||
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:
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
|
13
README.md
13
README.md
@ -12,20 +12,12 @@ Angular
|
||||
Angular is a development platform for building mobile and desktop web applications. This is the
|
||||
repository for [Angular 2][ng2], both the JavaScript (JS) and [Dart][dart] versions.
|
||||
|
||||
Angular 2 is currently in **Developer Preview**. We recommend using Angular 1.X for production
|
||||
applications:
|
||||
|
||||
* [AngularJS][ngJS]: [angular/angular.js](http://github.com/angular/angular.js).
|
||||
* [AngularDart][ngDart]: [angular/angular.dart](http://github.com/angular/angular.dart).
|
||||
Angular 2 is currently in **Beta**.
|
||||
|
||||
## Quickstart
|
||||
|
||||
[Get started in 5 minutes][quickstart].
|
||||
|
||||
## Setup & Install Angular 2
|
||||
|
||||
Follow the instructions given on the [Angular download page][download].
|
||||
|
||||
|
||||
## Want to help?
|
||||
|
||||
@ -36,8 +28,7 @@ guidelines for [contributing][contributing] and then check out one of our issues
|
||||
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
|
||||
[dart]: http://www.dartlang.org
|
||||
[dartium]: http://www.dartlang.org/tools/dartium
|
||||
[download]: http://angular.io/download/
|
||||
[quickstart]: https://angular.io/docs/js/latest/quickstart.html
|
||||
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
|
||||
[ng2]: http://angular.io
|
||||
[ngDart]: http://angulardart.org
|
||||
[ngJS]: http://angularjs.org
|
||||
|
@ -21,7 +21,7 @@ By default the debugging tools are disabled.
|
||||
Enable the debugging tools as follows:
|
||||
|
||||
```dart
|
||||
import 'package:angular2/tools.dart';
|
||||
import 'package:angular2/platform/browser.dart';
|
||||
|
||||
main() async {
|
||||
var appRef = await bootstrap(Application);
|
||||
|
@ -1,3 +1,32 @@
|
||||
// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL) and BrowserStack (BS).
|
||||
// If the target is set to null, then the browser is not run anywhere during CI.
|
||||
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented out in Travis configuration.
|
||||
var CIconfiguration = {
|
||||
'Chrome': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'Firefox': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'ChromeBeta': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'FirefoxBeta': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'ChromeDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
|
||||
'FirefoxDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
|
||||
'IE9': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'IE10': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'IE11': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'Edge': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'Android4.1': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.2': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.3': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.4': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android5': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari7': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'iOS7': { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
|
||||
'iOS8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
// TODO(mlaval): iOS9 deactivated as not reliable, reactivate after https://github.com/angular/angular/issues/5408
|
||||
'iOS9': { unitTest: {target: null, required: false}, e2e: {target: null, required: true}},
|
||||
'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
|
||||
};
|
||||
|
||||
var customLaunchers = {
|
||||
'DartiumWithWebPlatform': {
|
||||
base: 'Dartium',
|
||||
@ -47,7 +76,7 @@ var customLaunchers = {
|
||||
platform: 'OS X 10.10',
|
||||
version: '8'
|
||||
},
|
||||
'SL_SAFARI9.0': {
|
||||
'SL_SAFARI9': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.11',
|
||||
@ -119,7 +148,7 @@ var customLaunchers = {
|
||||
platform: 'Linux',
|
||||
version: '4.4'
|
||||
},
|
||||
'SL_ANDROID5.1': {
|
||||
'SL_ANDROID5': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'android',
|
||||
platform: 'Linux',
|
||||
@ -239,21 +268,18 @@ var customLaunchers = {
|
||||
}
|
||||
};
|
||||
|
||||
// iOS9 deactivated as not reliable in both providers
|
||||
// TODO(mlaval): reactivate after https://github.com/angular/angular/issues/5408
|
||||
|
||||
var sauceAliases = {
|
||||
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
|
||||
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9.0'],
|
||||
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
|
||||
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1'],
|
||||
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
|
||||
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
|
||||
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
|
||||
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
|
||||
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
|
||||
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9.0'],
|
||||
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
|
||||
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
|
||||
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
|
||||
'CI': ['SL_CHROME',' SL_FIREFOX', 'SL_CHROMEDEV', 'SL_FIREFOXBETA', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE',
|
||||
'SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1']
|
||||
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
|
||||
'CI_OPTIONAL': buildConfiguration('unitTest', 'SL', false)
|
||||
};
|
||||
|
||||
var browserstackAliases = {
|
||||
@ -264,7 +290,8 @@ var browserstackAliases = {
|
||||
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
|
||||
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
|
||||
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
|
||||
'CI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_IOS7', 'BS_IOS8', 'BS_WINDOWSPHONE']
|
||||
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
|
||||
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
@ -277,3 +304,14 @@ if (process.env.TRAVIS) {
|
||||
process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');
|
||||
process.env.BROWSER_STACK_ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY.split('').reverse().join('');
|
||||
}
|
||||
|
||||
function buildConfiguration(type, target, required) {
|
||||
return Object.keys(CIconfiguration)
|
||||
.filter((item) => {
|
||||
var conf = CIconfiguration[item][type];
|
||||
return conf.required === required && conf.target === target;
|
||||
})
|
||||
.map((item) => {
|
||||
return target + '_' + item.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
21
circle.yml
Normal file
21
circle.yml
Normal file
@ -0,0 +1,21 @@
|
||||
machine:
|
||||
node:
|
||||
version: 5.4.1
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- npm install -g npm
|
||||
override:
|
||||
- npm install:
|
||||
environment:
|
||||
# Token for tsd to increase github rate limit
|
||||
# See https://github.com/DefinitelyTyped/tsd#tsdrc
|
||||
# This is not hidden using https://circleci.com/docs/fork-pr-builds#details
|
||||
# because those are not visible for pull requests, and those should also be reliable.
|
||||
# This SSO token belongs to github account angular-github-ratelimit-token which has no access
|
||||
# (password is in Valentine)
|
||||
TSD_GITHUB_TOKEN: ef474500309daea53d5991b3079159a29520a40b
|
||||
|
||||
test:
|
||||
override:
|
||||
- npm run build
|
218
gulpfile.js
218
gulpfile.js
@ -3,10 +3,10 @@
|
||||
// THIS CHECK SHOULD BE THE FIRST THING IN THIS FILE
|
||||
// This is to ensure that we catch env issues before we error while requiring other dependencies.
|
||||
require('./tools/check-environment')(
|
||||
{requiredNpmVersion: '>=2.14.7 <3.0.0', requiredNodeVersion: '>=4.2.1 <5.0.0'});
|
||||
{requiredNpmVersion: '>=3.5.3 <4.0.0', requiredNodeVersion: '>=5.4.1 <6.0.0'});
|
||||
|
||||
|
||||
var del = require('del');
|
||||
var fse = require('fs-extra');
|
||||
var gulp = require('gulp');
|
||||
var gulpPlugins = require('gulp-load-plugins')();
|
||||
var merge = require('merge');
|
||||
@ -42,7 +42,7 @@ if (cliArgs.projects) {
|
||||
|
||||
// --projects=angular2,angular2_material => {angular2: true, angular2_material: true}
|
||||
var allProjects =
|
||||
'angular1_router,angular2,angular2_material,benchmarks,benchmarks_external,benchpress,playground,bundle_deps';
|
||||
'angular1_router,angular2,angular2_material,benchmarks,benchmarks_external,benchpress,playground,payload_tests,bundle_deps';
|
||||
var cliArgsProjects = (cliArgs.projects || allProjects)
|
||||
.split(',')
|
||||
.reduce((map, projectName) => {
|
||||
@ -155,7 +155,7 @@ var HTTP_BUNDLE_CONTENT = 'angular2/http - rxjs/* - ' + ANGULAR2_BUNDLE_CONFIG.j
|
||||
var ROUTER_BUNDLE_CONTENT = 'angular2/router + angular2/router/router_link_dsl - rxjs/* - ' +
|
||||
ANGULAR2_BUNDLE_CONFIG.join(' - ');
|
||||
var TESTING_BUNDLE_CONTENT =
|
||||
'angular2/testing + angular2/http/testing + angular2/router/testing - rxjs/* - ' +
|
||||
'angular2/testing + angular2/http/testing + angular2/router/testing + angular2/platform/testing/browser - rxjs/* - ' +
|
||||
ANGULAR2_BUNDLE_CONFIG.join(' - ');
|
||||
var UPGRADE_BUNDLE_CONTENT = 'angular2/upgrade - rxjs/* - ' + ANGULAR2_BUNDLE_CONFIG.join(' - ');
|
||||
|
||||
@ -168,24 +168,36 @@ var BENCHPRESS_BUNDLE_CONFIG = {
|
||||
dest: CONFIG.dest.bundles.benchpress
|
||||
};
|
||||
|
||||
var PAYLOAD_TESTS_CONFIG = {
|
||||
ts: {
|
||||
bundleName: 'app-bundle-deps.min.js',
|
||||
cases: ['hello_world'],
|
||||
dist: function(caseName, packaging) {
|
||||
return path.join(__dirname, CONFIG.dest.js.prod.es5, 'payload_tests', caseName,
|
||||
'ts/' + packaging);
|
||||
},
|
||||
systemjs: {sizeLimits: {'uncompressed': 850 * 1024, 'gzip level=9': 165 * 1024}},
|
||||
webpack: {sizeLimits: {'uncompressed': 550 * 1024, 'gzip level=9': 120 * 1024}}
|
||||
}
|
||||
};
|
||||
|
||||
// ------------
|
||||
// clean
|
||||
|
||||
gulp.task('build/clean.tools', function() { del(path.join('dist', 'tools')); });
|
||||
gulp.task('build/clean.tools', (done) => fse.remove(path.join('dist', 'tools'), done));
|
||||
|
||||
gulp.task('build/clean.js', function(done) { del(CONFIG.dest.js.all, done); });
|
||||
gulp.task('build/clean.js', (done) => fse.remove(CONFIG.dest.js.all, done));
|
||||
|
||||
gulp.task('build/clean.dart', function(done) { del(CONFIG.dest.dart, done); });
|
||||
gulp.task('build/clean.dart', (done) => fse.remove(CONFIG.dest.dart, done));
|
||||
|
||||
gulp.task('build/clean.docs', function(done) { del(CONFIG.dest.docs, done); });
|
||||
gulp.task('build/clean.docs', (done) => fse.remove(CONFIG.dest.docs, done));
|
||||
|
||||
gulp.task('build/clean.docs_angular_io',
|
||||
function(done) { del(CONFIG.dest.docs_angular_io, done); });
|
||||
gulp.task('build/clean.docs_angular_io', (done) => fse.remove(CONFIG.dest.docs_angular_io, done));
|
||||
|
||||
gulp.task('build/clean.bundles', function(done) { del(CONFIG.dest.bundles.all, done); });
|
||||
gulp.task('build/clean.bundles', (done) => fse.remove(CONFIG.dest.bundles.all, done));
|
||||
|
||||
gulp.task('build/clean.bundles.benchpress',
|
||||
function(done) { del(CONFIG.dest.bundles.benchpress, done); });
|
||||
(done) => fse.remove(CONFIG.dest.bundles.benchpress, done));
|
||||
|
||||
// ------------
|
||||
// transpile
|
||||
@ -313,7 +325,9 @@ gulp.task('lint', ['build.tools'], function() {
|
||||
"requireParameterType": true,
|
||||
"requireReturnType": true,
|
||||
"semicolon": true,
|
||||
"variable-name": [true, "ban-keywords"]
|
||||
|
||||
// TODO: find a way to just screen for reserved names
|
||||
"variable-name": false
|
||||
}
|
||||
};
|
||||
return gulp.src(['modules/angular2/src/**/*.ts', '!modules/angular2/src/testing/**'])
|
||||
@ -369,7 +383,7 @@ function proxyServeDart() {
|
||||
|
||||
// ------------------
|
||||
// web servers
|
||||
gulp.task('serve.js.dev', ['build.js'], function(neverDone) {
|
||||
gulp.task('serve.js.dev', ['build.js.dev'], function(neverDone) {
|
||||
var watch = require('./tools/build/watch');
|
||||
|
||||
watch('modules/**', {ignoreInitial: true}, '!broccoli.js.dev');
|
||||
@ -449,7 +463,7 @@ function runKarma(configFile, done) {
|
||||
|
||||
gulp.task('test.js', function(done) {
|
||||
runSequence('test.unit.tools/ci', 'test.transpiler.unittest', 'test.unit.js/ci',
|
||||
'test.unit.cjs/ci', 'test.typings', sequenceComplete(done));
|
||||
'test.unit.cjs/ci', 'test.typings', 'check-public-api', sequenceComplete(done));
|
||||
});
|
||||
|
||||
gulp.task('test.dart', function(done) {
|
||||
@ -613,7 +627,11 @@ gulp.task('!test.unit.router/karma-run', function(done) {
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('buildRouter.dev', function() { buildRouter(); });
|
||||
gulp.task('buildRouter.dev', function() {
|
||||
var modulesSrcDir = __dirname + '/modules';
|
||||
var distDir = __dirname + '/dist';
|
||||
buildRouter(modulesSrcDir, distDir);
|
||||
});
|
||||
|
||||
gulp.task('test.unit.dart', function(done) {
|
||||
printModulesWarning();
|
||||
@ -638,7 +656,7 @@ gulp.task('test.unit.dart', function(done) {
|
||||
// This test will fail if the size of our hello_world app goes beyond one of
|
||||
// these values when compressed at the specified level.
|
||||
// Measure in bytes.
|
||||
var _DART_PAYLOAD_SIZE_LIMITS = {'uncompressed': 375 * 1024, 'gzip level=6': 105 * 1024};
|
||||
var _DART_PAYLOAD_SIZE_LIMITS = {'uncompressed': 320 * 1024, 'gzip level=9': 90 * 1024};
|
||||
gulp.task('test.payload.dart/ci', function(done) {
|
||||
runSequence('build/packages.dart', '!pubget.payload.dart', '!pubbuild.payload.dart',
|
||||
'!checkAndReport.payload.dart', done);
|
||||
@ -658,6 +676,103 @@ gulp.task('!checkAndReport.payload.dart', function() {
|
||||
{failConditions: _DART_PAYLOAD_SIZE_LIMITS, prefix: 'hello_world'});
|
||||
});
|
||||
|
||||
// JS payload size tracking
|
||||
gulp.task('test.payload.js/ci', function(done) {
|
||||
runSequence('build.payload.js', '!checkAndReport.payload.js', sequenceComplete(done));
|
||||
});
|
||||
|
||||
gulp.task('build.payload.js', ['build.js'], function(done) {
|
||||
runSequence('!build.payload.js.webpack', '!build.payload.js.systemjs', sequenceComplete(done));
|
||||
});
|
||||
|
||||
gulp.task('!build.payload.js.webpack', function() {
|
||||
var q = require('q');
|
||||
var webpack = q.denodeify(require('webpack'));
|
||||
|
||||
var ES5_PROD_ROOT = __dirname + '/' + CONFIG.dest.js.prod.es5;
|
||||
|
||||
return q.all(PAYLOAD_TESTS_CONFIG.ts.cases.map(function(caseName) {
|
||||
var CASE_PATH = PAYLOAD_TESTS_CONFIG.ts.dist(caseName, 'webpack');
|
||||
|
||||
return webpack({
|
||||
// bundle app + framework
|
||||
entry: CASE_PATH + '/index.js',
|
||||
output: {path: CASE_PATH, filename: "app-bundle.js"},
|
||||
resolve: {
|
||||
extensions: ['', '.js'],
|
||||
packageAlias: '', // option added to ignore "broken" package.json in our dist folder
|
||||
root: [ES5_PROD_ROOT]
|
||||
}
|
||||
})
|
||||
.then(function() { // pad bundle with mandatory dependencies
|
||||
return new Promise(function(resolve, reject) {
|
||||
gulp.src([
|
||||
'node_modules/zone.js/dist/zone-microtask.js',
|
||||
'node_modules/zone.js/dist/long-stack-trace-zone.js',
|
||||
'node_modules/reflect-metadata/Reflect.js',
|
||||
CASE_PATH + '/app-bundle.js'
|
||||
])
|
||||
.pipe(gulpPlugins.concat(PAYLOAD_TESTS_CONFIG.ts.bundleName))
|
||||
.pipe(gulpPlugins.uglify())
|
||||
.pipe(gulp.dest(CASE_PATH))
|
||||
.on('end', resolve)
|
||||
.on('error', reject);
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('!build.payload.js.systemjs', function() {
|
||||
var bundler = require('./tools/build/bundle');
|
||||
|
||||
return Promise.all(PAYLOAD_TESTS_CONFIG.ts.cases.map(function(caseName) {
|
||||
var CASE_PATH = PAYLOAD_TESTS_CONFIG.ts.dist(caseName, 'systemjs');
|
||||
|
||||
return bundler
|
||||
.bundle(
|
||||
{
|
||||
paths: {'index': CASE_PATH + '/index.js'},
|
||||
meta: {'angular2/core': {build: false}, 'angular2/platform/browser': {build: false}}
|
||||
},
|
||||
'index', CASE_PATH + '/index.register.js', {})
|
||||
.then(function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
gulp.src([
|
||||
'node_modules/systemjs/dist/system.src.js',
|
||||
'dist/js/prod/es5/bundle/angular2-polyfills.js',
|
||||
'dist/js/prod/es5/bundle/angular2.js',
|
||||
'dist/js/prod/es5//rxjs/bundles/Rx.js',
|
||||
CASE_PATH + '/index.register.js',
|
||||
'tools/build/systemjs/payload_tests_import.js'
|
||||
])
|
||||
.pipe(gulpPlugins.concat(PAYLOAD_TESTS_CONFIG.ts.bundleName))
|
||||
.pipe(gulpPlugins.uglify())
|
||||
.pipe(gulp.dest(CASE_PATH))
|
||||
.on('end', resolve)
|
||||
.on('error', reject);
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('!checkAndReport.payload.js', function() {
|
||||
var reportSize = require('./tools/analytics/reportsize');
|
||||
|
||||
function caseSizeStream(caseName, packaging) {
|
||||
return reportSize(PAYLOAD_TESTS_CONFIG.ts.dist(caseName, packaging) + '/' +
|
||||
PAYLOAD_TESTS_CONFIG.ts.bundleName,
|
||||
{
|
||||
failConditions: PAYLOAD_TESTS_CONFIG.ts[packaging].sizeLimits,
|
||||
prefix: caseName + '_' + packaging
|
||||
})
|
||||
}
|
||||
|
||||
return PAYLOAD_TESTS_CONFIG.ts.cases.reduce(function(sizeReportingStreams, caseName) {
|
||||
sizeReportingStreams.add(caseSizeStream(caseName, 'systemjs'));
|
||||
sizeReportingStreams.add(caseSizeStream(caseName, 'webpack'));
|
||||
}, merge2());
|
||||
});
|
||||
|
||||
gulp.task('watch.dart.dev', function(done) {
|
||||
runSequence('build/tree.dart', 'build/pure-packages.dart', '!build/pubget.angular2.dart',
|
||||
'!build/change_detect.dart', '!build/remove-pub-symlinks', 'build.dart.material.css',
|
||||
@ -715,17 +830,24 @@ gulp.task('test.unit.js/ci', function(done) {
|
||||
reporters: ['dots'],
|
||||
browsers: browserConf.browsersToRun
|
||||
},
|
||||
done)
|
||||
function(err) { done(); })
|
||||
.start();
|
||||
});
|
||||
|
||||
gulp.task('test.unit.js.sauce/ci', function(done) {
|
||||
launchKarmaWithExternalBrowsers(['dots', 'saucelabs'], browserProvidersConf.sauceAliases.CI,
|
||||
done);
|
||||
var browsers = browserProvidersConf.sauceAliases.CI_REQUIRED;
|
||||
if (cliArgs.mode && cliArgs.mode == 'saucelabs_optional') {
|
||||
browsers = browserProvidersConf.sauceAliases.CI_OPTIONAL;
|
||||
}
|
||||
launchKarmaWithExternalBrowsers(['dots', 'saucelabs'], browsers, done);
|
||||
});
|
||||
|
||||
gulp.task('test.unit.js.browserstack/ci', function(done) {
|
||||
launchKarmaWithExternalBrowsers(['dots'], browserProvidersConf.browserstackAliases.CI, done);
|
||||
var browsers = browserProvidersConf.browserstackAliases.CI_REQUIRED;
|
||||
if (cliArgs.mode && cliArgs.mode == 'browserstack_optional') {
|
||||
browsers = browserProvidersConf.browserstackAliases.CI_OPTIONAL;
|
||||
}
|
||||
launchKarmaWithExternalBrowsers(['dots'], browsers, done);
|
||||
});
|
||||
|
||||
gulp.task('test.unit.dart/ci', function(done) {
|
||||
@ -748,6 +870,8 @@ gulp.task('test.unit.cjs/ci', function(done) {
|
||||
runJasmineTests(['dist/js/cjs/{angular2,benchpress}/test/**/*_spec.js'], done);
|
||||
});
|
||||
|
||||
gulp.task('check-public-api',
|
||||
function(done) { runJasmineTests(['dist/tools/public_api_guard/**/*_spec.js'], done); });
|
||||
|
||||
gulp.task('test.unit.cjs', ['build/clean.js', 'build.tools'], function(neverDone) {
|
||||
var watch = require('./tools/build/watch');
|
||||
@ -857,15 +981,16 @@ gulp.task('!pre.test.typings.layoutNodeModule', ['build.js.cjs'], function() {
|
||||
.pipe(gulp.dest(path.join(tmpdir, 'node_modules')));
|
||||
});
|
||||
gulp.task('!pre.test.typings.copyTypingsSpec', function() {
|
||||
return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(path.join(tmpdir)));
|
||||
return gulp.src(['typing_spec/*.ts'], {base: 'typing_spec'}).pipe(gulp.dest(tmpdir));
|
||||
});
|
||||
|
||||
gulp.task('test.typings',
|
||||
['!pre.test.typings.layoutNodeModule', '!pre.test.typings.copyTypingsSpec'], function() {
|
||||
var tsc = require('gulp-typescript');
|
||||
|
||||
return gulp.src([tmpdir + '/**'])
|
||||
return gulp.src([tmpdir + '/*.ts'])
|
||||
.pipe(tsc({
|
||||
target: 'ES5',
|
||||
target: 'ES6',
|
||||
module: 'commonjs',
|
||||
experimentalDecorators: true,
|
||||
noImplicitAny: true,
|
||||
@ -899,16 +1024,12 @@ gulp.task('build/pure-packages.dart/standalone', function() {
|
||||
.pipe(gulp.dest(CONFIG.dest.dart));
|
||||
});
|
||||
|
||||
gulp.task('build/pure-packages.dart/license',
|
||||
function() {
|
||||
return gulp.src(['LICENSE'])
|
||||
.pipe(gulp.dest(path.join(CONFIG.dest.dart, 'angular2_testing')));
|
||||
})
|
||||
gulp.task('build/pure-packages.dart/license', function() {
|
||||
return gulp.src(['LICENSE']).pipe(gulp.dest(path.join(CONFIG.dest.dart, 'angular2_testing')));
|
||||
});
|
||||
|
||||
|
||||
gulp.task('build/pure-packages.dart/angular2', function() {
|
||||
var yaml = require('js-yaml');
|
||||
|
||||
return gulp.src([
|
||||
'modules_dart/transform/**/*',
|
||||
'!modules_dart/transform/**/*.proto',
|
||||
@ -973,15 +1094,19 @@ gulp.task('!build.tools', function() {
|
||||
gulp.task('broccoli.js.dev', ['build.tools'],
|
||||
function(done) { runSequence('!broccoli.js.dev', sequenceComplete(done)); });
|
||||
|
||||
gulp.task(
|
||||
'!broccoli.js.dev',
|
||||
() => angularBuilder.rebuildBrowserDevTree(
|
||||
{generateEs6: generateEs6, projects: cliArgsProjects, noTypeChecks: cliArgs.noTypeChecks}));
|
||||
gulp.task('!broccoli.js.dev', () => angularBuilder.rebuildBrowserDevTree({
|
||||
generateEs6: generateEs6,
|
||||
projects: cliArgsProjects,
|
||||
noTypeChecks: cliArgs.noTypeChecks,
|
||||
useBundles: cliArgs.useBundles
|
||||
}));
|
||||
|
||||
gulp.task(
|
||||
'!broccoli.js.prod',
|
||||
() => angularBuilder.rebuildBrowserProdTree(
|
||||
{generateEs6: generateEs6, projects: cliArgsProjects, noTypeChecks: cliArgs.noTypeChecks}));
|
||||
gulp.task('!broccoli.js.prod', () => angularBuilder.rebuildBrowserProdTree({
|
||||
generateEs6: generateEs6,
|
||||
projects: cliArgsProjects,
|
||||
noTypeChecks: cliArgs.noTypeChecks,
|
||||
useBundles: cliArgs.useBundles
|
||||
}));
|
||||
|
||||
gulp.task('build.js.dev', ['build/clean.js'], function(done) {
|
||||
runSequence('broccoli.js.dev', 'build.css.material', sequenceComplete(done));
|
||||
@ -1004,9 +1129,12 @@ var firstBuildJsCjs = true;
|
||||
* private task
|
||||
*/
|
||||
gulp.task('!build.js.cjs', function() {
|
||||
return angularBuilder
|
||||
.rebuildNodeTree(
|
||||
{generateEs6: generateEs6, projects: cliArgsProjects, noTypeChecks: cliArgs.noTypeChecks})
|
||||
return angularBuilder.rebuildNodeTree({
|
||||
generateEs6: generateEs6,
|
||||
projects: cliArgsProjects,
|
||||
noTypeChecks: cliArgs.noTypeChecks,
|
||||
useBundles: cliArgs.useBundles
|
||||
})
|
||||
.then(function() {
|
||||
if (firstBuildJsCjs) {
|
||||
firstBuildJsCjs = false;
|
||||
@ -1113,8 +1241,8 @@ gulp.task('!bundle.testing', ['build.js.dev'], function() {
|
||||
{sourceMaps: true});
|
||||
});
|
||||
|
||||
gulp.task('!bundles.js.docs', function() {
|
||||
gulp.src('modules/angular2/docs/bundles/*').pipe(gulp.dest('dist/js/bundle'));
|
||||
gulp.task('!bundles.js.docs', ['clean'], function() {
|
||||
return gulp.src('modules/angular2/docs/bundles/*').pipe(gulp.dest('dist/js/bundle'));
|
||||
});
|
||||
|
||||
gulp.task('!bundles.js.umd', ['build.js.dev'], function() {
|
||||
@ -1262,7 +1390,7 @@ gulp.task('!bundle.copy', function() {
|
||||
|
||||
gulp.task('!bundles.js.checksize', function(done) {
|
||||
var reportSize = require('./tools/analytics/reportsize');
|
||||
return reportSize('dist/js/bundle/**', {printToConsole: ['gzip level=2']});
|
||||
return reportSize('dist/js/bundle/**/*.js', {printToConsole: ['gzip level=2']});
|
||||
});
|
||||
|
||||
gulp.task('bundles.js',
|
||||
|
@ -79,7 +79,7 @@ module.exports = function(config) {
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
|
||||
if (process.env.MODE === 'saucelabs') {
|
||||
if (process.env.MODE.startsWith('saucelabs')) {
|
||||
config.sauceLabs.build = buildId;
|
||||
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
|
||||
@ -89,7 +89,7 @@ module.exports = function(config) {
|
||||
config.transports = ['polling'];
|
||||
}
|
||||
|
||||
if (process.env.MODE === 'browserstack') {
|
||||
if (process.env.MODE.startsWith('browserstack')) {
|
||||
config.browserStack.build = buildId;
|
||||
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
}
|
||||
|
50
modules/angular1_router/build.js
vendored
50
modules/angular1_router/build.js
vendored
@ -21,18 +21,25 @@ var files = [
|
||||
|
||||
var PRELUDE = '(function(){\n';
|
||||
var POSTLUDE = '\n}());\n';
|
||||
var FACADES = fs.readFileSync(__dirname + '/lib/facades.es5', 'utf8');
|
||||
var DIRECTIVES = fs.readFileSync(__dirname + '/src/ng_outlet.ts', 'utf8');
|
||||
var moduleTemplate = fs.readFileSync(__dirname + '/src/module_template.js', 'utf8');
|
||||
|
||||
function main() {
|
||||
var dir = __dirname + '/../angular2/src/router/';
|
||||
function main(modulesDirectory) {
|
||||
var angular1RouterModuleDirectory = modulesDirectory + '/angular1_router';
|
||||
|
||||
var facades = fs.readFileSync(
|
||||
angular1RouterModuleDirectory + '/lib/facades.es5', 'utf8');
|
||||
var directives = fs.readFileSync(
|
||||
angular1RouterModuleDirectory + '/src/ng_outlet.ts', 'utf8');
|
||||
var moduleTemplate = fs.readFileSync(
|
||||
angular1RouterModuleDirectory + '/src/module_template.js', 'utf8');
|
||||
|
||||
var dir = modulesDirectory + '/angular2/src/router/';
|
||||
var sharedCode = files.reduce(function (prev, file) {
|
||||
return prev + transform(fs.readFileSync(dir + file, 'utf8'));
|
||||
}, '');
|
||||
|
||||
var out = moduleTemplate.replace('//{{FACADES}}', FACADES).replace('//{{SHARED_CODE}}', sharedCode);
|
||||
return PRELUDE + transform(DIRECTIVES) + out + POSTLUDE;
|
||||
var out = moduleTemplate.replace('//{{FACADES}}', facades)
|
||||
.replace('//{{SHARED_CODE}}', sharedCode);
|
||||
return PRELUDE + transform(directives) + out + POSTLUDE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -62,10 +69,29 @@ function isFacadeModule(modulePath) {
|
||||
modulePath === 'angular2/src/core/reflection/reflection';
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
var dist = __dirname + '/../../dist';
|
||||
if (!fs.existsSync(dist)) {
|
||||
fs.mkdirSync(dist);
|
||||
module.exports = function(modulesDirectory, outputDirectory) {
|
||||
if (!fs.existsSync(outputDirectory)) {
|
||||
fs.mkdirSync(outputDirectory);
|
||||
}
|
||||
fs.writeFileSync(dist + '/angular_1_router.js', main());
|
||||
fs.writeFileSync(
|
||||
outputDirectory + '/angular_1_router.js', main(modulesDirectory));
|
||||
};
|
||||
|
||||
// CLI entry point
|
||||
if (require.main === module) {
|
||||
try {
|
||||
var args = process.argv;
|
||||
args.shift(); // node
|
||||
args.shift(); // scriptfile.js
|
||||
if (args.length < 2) {
|
||||
console.log("usage: $0 outFile path/to/modules");
|
||||
process.exit(1);
|
||||
}
|
||||
var outfile = args.shift();
|
||||
var directory = args.shift();
|
||||
fs.writeFileSync(outfile, main(directory));
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -173,6 +173,10 @@ var StringMapWrapper = {
|
||||
|
||||
var List = Array;
|
||||
var ListWrapper = {
|
||||
toJSON: function(l) {
|
||||
return JSON.stringify(l);
|
||||
},
|
||||
|
||||
clear: function (l) {
|
||||
l.length = 0;
|
||||
},
|
||||
@ -195,6 +199,10 @@ var ListWrapper = {
|
||||
return array[0];
|
||||
},
|
||||
|
||||
last: function(array) {
|
||||
return (array && array.length) > 0 ? array[array.length - 1] : null;
|
||||
},
|
||||
|
||||
map: function (l, fn) {
|
||||
return l.map(fn);
|
||||
},
|
||||
@ -243,6 +251,10 @@ var ListWrapper = {
|
||||
};
|
||||
|
||||
var StringWrapper = {
|
||||
charCodeAt: function(s, i) {
|
||||
return s.charCodeAt(i);
|
||||
},
|
||||
|
||||
equals: function (s1, s2) {
|
||||
return s1 === s2;
|
||||
},
|
||||
@ -299,8 +311,8 @@ Location.prototype.subscribe = function () {
|
||||
//TODO: implement
|
||||
};
|
||||
Location.prototype.path = function () {
|
||||
return $location.path();
|
||||
return $location.url();
|
||||
};
|
||||
Location.prototype.go = function (url) {
|
||||
return $location.path(url);
|
||||
Location.prototype.go = function (path, query) {
|
||||
return $location.url(path + query);
|
||||
};
|
||||
|
@ -57,7 +57,7 @@ function routerFactory($q, $location, $$directiveIntrospector, $browser, $rootSc
|
||||
});
|
||||
|
||||
var router = new RootRouter(registry, location, $routerRootComponent);
|
||||
$rootScope.$watch(function () { return $location.path(); }, function (path) {
|
||||
$rootScope.$watch(function () { return $location.url(); }, function (path) {
|
||||
if (router.lastNavigationAttempt !== path) {
|
||||
router.navigateByUrl(path);
|
||||
}
|
||||
|
@ -155,10 +155,12 @@ function ngOutletDirective($animate, $q: ng.IQService, $router) {
|
||||
}
|
||||
|
||||
this.controller.$$routeParams = instruction.params;
|
||||
this.controller.$$template = '<div ' + dashCase(componentName) + '></div>';
|
||||
this.controller.$$template =
|
||||
'<' + dashCase(componentName) + ' router="$$router"></' + dashCase(componentName) + '>';
|
||||
this.controller.$$router = this.router.childRouter(instruction.componentType);
|
||||
|
||||
let newScope = scope.$new();
|
||||
newScope.$$router = this.controller.$$router;
|
||||
|
||||
let clone = $transclude(newScope, clone => {
|
||||
$animate.enter(clone, null, this.currentElement || element);
|
||||
@ -285,13 +287,13 @@ function dashCase(str: string): string {
|
||||
* A module for adding new a routing system Angular 1.
|
||||
*/
|
||||
angular.module('ngComponentRouter', [])
|
||||
.directive('ngOutlet', ngOutletDirective)
|
||||
.directive('ngOutlet', ngOutletFillContentDirective)
|
||||
.directive('ngLink', ngLinkDirective);
|
||||
.directive('ngOutlet', ['$animate', '$q', '$router', ngOutletDirective])
|
||||
.directive('ngOutlet', ['$compile', ngOutletFillContentDirective])
|
||||
.directive('ngLink', ['$router', '$parse', ngLinkDirective]);
|
||||
|
||||
/*
|
||||
* A module for inspecting controller constructors
|
||||
*/
|
||||
angular.module('ng')
|
||||
.provider('$$directiveIntrospector', DirectiveIntrospectorProvider)
|
||||
.config(compilerProviderDecorator);
|
||||
.config(['$compileProvider', '$$directiveIntrospectorProvider', compilerProviderDecorator]);
|
||||
|
2
modules/angular1_router/src/ng_route_shim.js
vendored
2
modules/angular1_router/src/ng_route_shim.js
vendored
@ -1,4 +1,4 @@
|
||||
/** @license Copyright 2014-2015 Google, Inc. http://github.com/angular/angular/LICENSE */
|
||||
/** @license Copyright 2014-2016 Google, Inc. http://github.com/angular/angular/LICENSE */
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
@ -21,17 +21,29 @@ describe('navigation', function () {
|
||||
$router = _$router_;
|
||||
});
|
||||
|
||||
registerComponent('userCmp', {
|
||||
registerDirective('userCmp', {
|
||||
template: '<div>hello {{userCmp.$routeParams.name}}</div>'
|
||||
});
|
||||
registerComponent('oneCmp', {
|
||||
registerDirective('oneCmp', {
|
||||
template: '<div>{{oneCmp.number}}</div>',
|
||||
controller: function () {this.number = 'one'}
|
||||
});
|
||||
registerComponent('twoCmp', {
|
||||
registerDirective('twoCmp', {
|
||||
template: '<div>{{twoCmp.number}}</div>',
|
||||
controller: function () {this.number = 'two'}
|
||||
});
|
||||
registerComponent('threeCmp', {
|
||||
template: '<div>{{$ctrl.number}}</div>',
|
||||
controller: function () {this.number = 'three'}
|
||||
});
|
||||
registerComponent('getParams', {
|
||||
template: '<div>{{$ctrl.params.x}}</div>',
|
||||
controller: function () {
|
||||
this.$routerOnActivate = function(next) {
|
||||
this.params = next.params;
|
||||
};
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
it('should work in a simple case', function () {
|
||||
@ -47,6 +59,21 @@ describe('navigation', function () {
|
||||
expect(elt.text()).toBe('one');
|
||||
});
|
||||
|
||||
|
||||
it('should work with components created by the `mod.component()` helper', function () {
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/', component: 'threeCmp' }
|
||||
]);
|
||||
|
||||
$router.navigateByUrl('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('three');
|
||||
});
|
||||
|
||||
|
||||
it('should navigate between components with different parameters', function () {
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: 'userCmp' }
|
||||
@ -68,7 +95,7 @@ describe('navigation', function () {
|
||||
function ParentController() {
|
||||
instanceCount += 1;
|
||||
}
|
||||
registerComponent('parentCmp', {
|
||||
registerDirective('parentCmp', {
|
||||
template: 'parent { <ng-outlet></ng-outlet> }',
|
||||
$routeConfig: [
|
||||
{ path: '/user/:name', component: 'userCmp' }
|
||||
@ -94,7 +121,7 @@ describe('navigation', function () {
|
||||
|
||||
|
||||
it('should work with nested outlets', function () {
|
||||
registerComponent('childCmp', {
|
||||
registerDirective('childCmp', {
|
||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
||||
$routeConfig: [
|
||||
{ path: '/b', component: 'oneCmp' }
|
||||
@ -112,9 +139,29 @@ describe('navigation', function () {
|
||||
expect(elt.text()).toBe('outer { inner { one } }');
|
||||
});
|
||||
|
||||
it('should work when parent route has empty path', inject(function ($location) {
|
||||
registerComponent('childCmp', {
|
||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
||||
$routeConfig: [
|
||||
{ path: '/b', component: 'oneCmp' }
|
||||
]
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/...', component: 'childCmp' }
|
||||
]);
|
||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
||||
|
||||
$router.navigateByUrl('/b');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('outer { inner { one } }');
|
||||
expect($location.path()).toBe('/b');
|
||||
}));
|
||||
|
||||
|
||||
it('should work with recursive nested outlets', function () {
|
||||
registerComponent('recurCmp', {
|
||||
registerDirective('recurCmp', {
|
||||
template: '<div>recur { <div ng-outlet></div> }</div>',
|
||||
$routeConfig: [
|
||||
{ path: '/recur', component: 'recurCmp' },
|
||||
@ -147,6 +194,21 @@ describe('navigation', function () {
|
||||
}));
|
||||
|
||||
|
||||
it('should pass through query terms to the location', inject(function ($location) {
|
||||
$router.config([
|
||||
{ path: '/user', component: 'userCmp' }
|
||||
]);
|
||||
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigateByUrl('/user?x=y');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/user');
|
||||
expect($location.search()).toEqual({ x: 'y'});
|
||||
}));
|
||||
|
||||
|
||||
it('should change location to the canonical route', inject(function ($location) {
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
@ -163,7 +225,7 @@ describe('navigation', function () {
|
||||
|
||||
|
||||
it('should change location to the canonical route with nested components', inject(function ($location) {
|
||||
registerComponent('childRouter', {
|
||||
registerDirective('childRouter', {
|
||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
||||
$routeConfig: [
|
||||
{ path: '/new-child', component: 'oneCmp', name: 'NewChild'},
|
||||
@ -206,9 +268,22 @@ describe('navigation', function () {
|
||||
}));
|
||||
|
||||
|
||||
it('should navigate when the location query changes', inject(function ($location) {
|
||||
$router.config([
|
||||
{ path: '/get/params', component: 'getParams' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$location.url('/get/params?x=y');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('y');
|
||||
}));
|
||||
|
||||
|
||||
it('should expose a "navigating" property on $router', inject(function ($q) {
|
||||
var defer;
|
||||
registerComponent('pendingActivate', {
|
||||
registerDirective('pendingActivate', {
|
||||
$canActivate: function () {
|
||||
defer = $q.defer();
|
||||
return defer.promise;
|
||||
@ -227,36 +302,54 @@ describe('navigation', function () {
|
||||
expect($router.navigating).toBe(false);
|
||||
}));
|
||||
|
||||
function registerComponent(name, options) {
|
||||
var controller = options.controller || function () {};
|
||||
|
||||
['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
|
||||
if (options[hookName]) {
|
||||
controller.prototype[hookName] = options[hookName];
|
||||
}
|
||||
});
|
||||
|
||||
function registerDirective(name, options) {
|
||||
function factory() {
|
||||
return {
|
||||
template: options.template || '',
|
||||
controllerAs: name,
|
||||
controller: controller
|
||||
controller: getController(options)
|
||||
};
|
||||
}
|
||||
|
||||
if (options.$canActivate) {
|
||||
factory.$canActivate = options.$canActivate;
|
||||
}
|
||||
if (options.$routeConfig) {
|
||||
factory.$routeConfig = options.$routeConfig;
|
||||
}
|
||||
|
||||
applyStaticProperties(factory, options);
|
||||
$compileProvider.directive(name, factory);
|
||||
}
|
||||
|
||||
function registerComponent(name, options) {
|
||||
|
||||
var definition = {
|
||||
template: options.template || '',
|
||||
controller: getController(options),
|
||||
}
|
||||
applyStaticProperties(definition, options);
|
||||
$compileProvider.component(name, definition);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
|
||||
function getController(options) {
|
||||
var controller = options.controller || function () {};
|
||||
[
|
||||
'$routerOnActivate', '$routerOnDeactivate',
|
||||
'$routerOnReuse', '$routerCanReuse',
|
||||
'$routerCanDeactivate'
|
||||
].forEach(function (hookName) {
|
||||
if (options[hookName]) {
|
||||
controller.prototype[hookName] = options[hookName];
|
||||
}
|
||||
});
|
||||
return controller;
|
||||
}
|
||||
|
||||
function applyStaticProperties(target, options) {
|
||||
['$canActivate', '$routeConfig'].forEach(function(property) {
|
||||
if (options[property]) {
|
||||
target[property] = options[property];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -44,36 +44,105 @@ describe('router', function () {
|
||||
expect(elt.text()).toBe('Home');
|
||||
}));
|
||||
|
||||
function registerComponent(name, options) {
|
||||
var controller = options.controller || function () {};
|
||||
it('should bind the component to the current router', inject(function($location) {
|
||||
var router;
|
||||
registerComponent('homeCmp', {
|
||||
bindings: { router: '=' },
|
||||
controller: function($scope, $element) {
|
||||
this.$routerOnActivate = function() {
|
||||
router = this.router;
|
||||
};
|
||||
},
|
||||
template: 'Home'
|
||||
});
|
||||
|
||||
['$onActivate', '$onDeactivate', '$onReuse', '$canReuse', '$canDeactivate'].forEach(function (hookName) {
|
||||
if (options[hookName]) {
|
||||
controller.prototype[hookName] = options[hookName];
|
||||
registerComponent('app', {
|
||||
template: '<div ng-outlet></div>',
|
||||
$routeConfig: [
|
||||
{ path: '/', component: 'homeCmp' }
|
||||
]
|
||||
});
|
||||
|
||||
compile('<app></app>');
|
||||
|
||||
$location.path('/');
|
||||
$rootScope.$digest();
|
||||
var homeElement = elt.find('home-cmp');
|
||||
expect(homeElement.text()).toBe('Home');
|
||||
expect(homeElement.isolateScope().$ctrl.router).toBeDefined();
|
||||
expect(router).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should work when an async route is provided route data', inject(function($location, $q) {
|
||||
registerDirective('homeCmp', {
|
||||
template: 'Home ({{homeCmp.isAdmin}})',
|
||||
$routerOnActivate: function(next, prev) {
|
||||
this.isAdmin = next.routeData.data.isAdmin;
|
||||
}
|
||||
});
|
||||
|
||||
registerDirective('app', {
|
||||
template: '<div ng-outlet></div>',
|
||||
$routeConfig: [
|
||||
{ path: '/', loader: function() { return $q.when('homeCmp'); }, data: { isAdmin: true } }
|
||||
]
|
||||
});
|
||||
|
||||
compile('<app></app>');
|
||||
|
||||
$location.path('/');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('Home (true)');
|
||||
}));
|
||||
|
||||
function registerDirective(name, options) {
|
||||
function factory() {
|
||||
return {
|
||||
template: options.template || '',
|
||||
controllerAs: name,
|
||||
controller: controller
|
||||
controller: getController(options)
|
||||
};
|
||||
}
|
||||
|
||||
if (options.$canActivate) {
|
||||
factory.$canActivate = options.$canActivate;
|
||||
}
|
||||
if (options.$routeConfig) {
|
||||
factory.$routeConfig = options.$routeConfig;
|
||||
}
|
||||
|
||||
applyStaticProperties(factory, options);
|
||||
$compileProvider.directive(name, factory);
|
||||
}
|
||||
|
||||
function registerComponent(name, options) {
|
||||
|
||||
var definition = {
|
||||
bindings: options.bindings,
|
||||
template: options.template || '',
|
||||
controller: getController(options),
|
||||
}
|
||||
applyStaticProperties(definition, options);
|
||||
$compileProvider.component(name, definition);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
|
||||
function getController(options) {
|
||||
var controller = options.controller || function () {};
|
||||
[
|
||||
'$routerOnActivate', '$routerOnDeactivate',
|
||||
'$routerOnReuse', '$routerCanReuse',
|
||||
'$routerCanDeactivate'
|
||||
].forEach(function (hookName) {
|
||||
if (options[hookName]) {
|
||||
controller.prototype[hookName] = options[hookName];
|
||||
}
|
||||
});
|
||||
return controller;
|
||||
}
|
||||
|
||||
function applyStaticProperties(target, options) {
|
||||
['$canActivate', '$routeConfig'].forEach(function(property) {
|
||||
if (options[property]) {
|
||||
target[property] = options[property];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"version": "v4",
|
||||
"repo": "angular/DefinitelyTyped",
|
||||
"repo": "DefinitelyTyped/DefinitelyTyped",
|
||||
"ref": "master",
|
||||
"path": "typings",
|
||||
"bundle": "typings/tsd.d.ts",
|
||||
"installed": {
|
||||
"angularjs/angular.d.ts": {
|
||||
"commit": "746b9a892629060bc853e792afff536e0ec4655e"
|
||||
"commit": "6eebd5e90a1cbd6b47b0705ba72dbcd5baf846f3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,7 @@ library angular2;
|
||||
*
|
||||
* This library does not include `bootstrap`. Import `bootstrap.dart` instead.
|
||||
*/
|
||||
export 'package:angular2/core.dart'
|
||||
hide forwardRef, resolveForwardRef, ForwardRefFn;
|
||||
export 'package:angular2/core.dart';
|
||||
export 'package:angular2/common.dart';
|
||||
export 'package:angular2/instrumentation.dart';
|
||||
export 'package:angular2/src/core/angular_entrypoint.dart' show AngularEntrypoint;
|
||||
|
@ -1,5 +1,6 @@
|
||||
library angular2.core;
|
||||
|
||||
export './src/core/angular_entrypoint.dart' show AngularEntrypoint;
|
||||
export './src/core/metadata.dart';
|
||||
export './src/core/util.dart';
|
||||
export 'package:angular2/src/facade/lang.dart' show enableProdMode;
|
||||
@ -14,9 +15,8 @@ export './src/core/application_tokens.dart' show APP_ID,
|
||||
export './src/core/zone.dart';
|
||||
export './src/core/render.dart';
|
||||
export './src/core/linker.dart';
|
||||
export './src/core/debug/debug_element.dart' show DebugElement,
|
||||
Scope,
|
||||
inspectElement,
|
||||
export './src/core/debug/debug_node.dart' show DebugElement,
|
||||
DebugNode,
|
||||
asNativeElements;
|
||||
export './src/core/testability/testability.dart';
|
||||
export './src/core/change_detection.dart';
|
||||
|
@ -20,12 +20,7 @@ export {
|
||||
export * from './src/core/zone';
|
||||
export * from './src/core/render';
|
||||
export * from './src/core/linker';
|
||||
export {
|
||||
DebugElement,
|
||||
Scope,
|
||||
inspectElement,
|
||||
asNativeElements
|
||||
} from './src/core/debug/debug_element';
|
||||
export {DebugElement, DebugNode, asNativeElements} from './src/core/debug/debug_node';
|
||||
export * from './src/core/testability/testability';
|
||||
export * from './src/core/change_detection';
|
||||
export * from './src/core/platform_directives_and_pipes';
|
||||
|
@ -8,7 +8,7 @@
|
||||
# Modules, barrels and bundles
|
||||
|
||||
Angular2 source code is authored using the ES2015 standardized module format where one module corresponds to exactly one file. Multiple modules (files) can be logically grouped into so-called "barrels".
|
||||
A bundle is a file the contains all the code for one or more barrels.
|
||||
A bundle is a file that contains all the code for one or more barrels.
|
||||
|
||||
Most bundles come in several flavors:
|
||||
* regular and minified (got `.min` in their name);
|
||||
@ -32,7 +32,7 @@ filename | list of barrels | dev/prod | minified?
|
||||
`angular2-all.umd.js` | `angular2/core`, `angular2/common`, `angular2/compiler`, `angular2/platform/browser`, `angular2/platform/common_dom`, `angular2/http`, `angular2/router`, `angular2/instrumentation`, `angular2/upgrade`| prod | no
|
||||
`angular2-all.umd.min.js` | `angular2/core`, `angular2/common`, `angular2/compiler`, `angular2/platform/browser`, `angular2/platform/common_dom`, `angular2/http`, `angular2/router`, `angular2/instrumentation`, `angular2/upgrade` | prod | yes
|
||||
`angular2-all.umd.dev.js` | `angular2/core`, `angular2/common`, `angular2/compiler`, `angular2/platform/browser`, `angular2/platform/common_dom`, `angular2/http`, `angular2/router`, `angular2/instrumentation`, `angular2/upgrade` | dev | no
|
||||
`angular2-all-testing.umd.dev.js` | `angular2/core`, `angular2/common`, `angular2/compiler`, `angular2/platform/browser`, `angular2/platform/common_dom`, `angular2/http`, `angular2/router`, `angular2/instrumentation`, `angular2/upgrade`, `angular2/testing`, `angular2/http/testing`, `angular2/router/testing` | dev | no
|
||||
`angular2-all-testing.umd.dev.js` | `angular2/core`, `angular2/common`, `angular2/compiler`, `angular2/platform/browser`, `angular2/platform/common_dom`, `angular2/http`, `angular2/router`, `angular2/instrumentation`, `angular2/upgrade`, `angular2/testing`, `angular2/http/testing`, `angular2/router/testing`, `angular2/platform/testing/browser` | dev | no
|
||||
|
||||
**Warning**: bundles in the `UMD` format are _not_ "additive". A single application should use only one bundle from the above list.
|
||||
|
||||
@ -55,7 +55,7 @@ filename | list of barrels | dev/prod | minified?
|
||||
`upgrade.js` | `angular2/upgrade` | prod | no
|
||||
`upgrade.min.js` | `angular2/upgrade` | prod | yes
|
||||
`upgrade.dev.js` | `angular2/upgrade` | dev | no
|
||||
`testing.dev.js` | `angular2/testing`, `angular2/http/testing`, `angular2/router/testing` | dev | no
|
||||
`testing.dev.js` | `angular2/testing`, `angular2/http/testing`, `angular2/router/testing`, `angular2/platform/testing/browser` | dev | no
|
||||
|
||||
**Note**: bundles in the `System.register` format are "additive" - it is quite common to include several bundles in one application.
|
||||
For example people using Angular 2 with `http` and `router` would include: `angular2.js`, `http.js` and `router.js`.
|
||||
|
@ -2,8 +2,8 @@
|
||||
Bootstrapping
|
||||
@cheatsheetIndex 0
|
||||
@description
|
||||
{@target ts}`import {bootstrap} from 'angular2/angular2';`{@endtarget}
|
||||
{@target js}Available from the `ng.platform.browser` namespace.{@endtarget}
|
||||
{@target ts}`import {bootstrap} from 'angular2/platform/browser';`{@endtarget}
|
||||
{@target js}Available from the `ng.platform.browser` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/bootstrap.dart';`{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
|
@ -4,7 +4,7 @@ Built-in directives
|
||||
@description
|
||||
{@target ts}`import {NgIf, ...} from 'angular2/common';`{@endtarget}
|
||||
{@target js}Available from the `ng.common` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/common.dart';`{@endtarget}
|
||||
{@target dart}Available using `platform_directives` in pubspec{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
syntax:
|
||||
|
@ -4,7 +4,7 @@ Class decorators
|
||||
@description
|
||||
{@target ts}`import {Directive, ...} from 'angular2/core';`{@endtarget}
|
||||
{@target js}Available from the `ng.core` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts):
|
||||
|
@ -4,7 +4,7 @@ Dependency injection configuration
|
||||
@description
|
||||
{@target ts}`import {provide} from 'angular2/core';`{@endtarget}
|
||||
{@target js}Available from the `ng.core` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts dart):
|
||||
|
@ -4,7 +4,7 @@ Class field decorators for directives and components
|
||||
@description
|
||||
{@target ts}`import {Input, ...} from 'angular2/core';`{@endtarget}
|
||||
{@target js}Available from the `ng.core` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/core.dart';`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts dart):
|
||||
|
@ -4,7 +4,7 @@ Forms
|
||||
@description
|
||||
{@target ts}`import {FORM_DIRECTIVES} from 'angular2/common';`{@endtarget}
|
||||
{@target js}Available from `ng.common.FORM_DIRECTIVES`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/common.dart';`{@endtarget}
|
||||
{@target dart}Available using `platform_directives` in pubspec{@endtarget}
|
||||
|
||||
@cheatsheetItem
|
||||
syntax:
|
||||
|
@ -4,22 +4,22 @@ Routing and navigation
|
||||
@description
|
||||
{@target ts}`import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, ...} from 'angular2/router';`{@endtarget}
|
||||
{@target js}Available from the `ng.router` namespace{@endtarget}
|
||||
{@target dart}`import 'package:angular2/router.dart';`{@endtarget}
|
||||
{@target dart}`import 'package:angular2/angular2.dart';`{@endtarget}
|
||||
|
||||
|
||||
@cheatsheetItem
|
||||
syntax(ts):
|
||||
`@RouteConfig([
|
||||
{ path: '/:myParam', component: MyComponent, as: 'MyCmp' },
|
||||
{ path: '/staticPath', component: ..., as: ...},
|
||||
{ path: '/*wildCardParam', component: ..., as: ...}
|
||||
{ path: '/:myParam', component: MyComponent, name: 'MyCmp' },
|
||||
{ path: '/staticPath', component: ..., name: ...},
|
||||
{ path: '/*wildCardParam', component: ..., name: ...}
|
||||
])
|
||||
class MyComponent() {}`|`@RouteConfig`
|
||||
syntax(js):
|
||||
`var MyComponent = ng.router.RouteConfig([
|
||||
{ path: '/:myParam', component: MyComponent, as: 'MyCmp' },
|
||||
{ path: '/staticPath', component: ..., as: ...},
|
||||
{ path: '/*wildCardParam', component: ..., as: ...}
|
||||
{ path: '/:myParam', component: MyComponent, name: 'MyCmp' },
|
||||
{ path: '/staticPath', component: ..., name: ...},
|
||||
{ path: '/*wildCardParam', component: ..., name: ...}
|
||||
]).Class({
|
||||
constructor: function() {}
|
||||
});`|`ng.router.RouteConfig`
|
||||
|
@ -62,16 +62,16 @@ Creates a local variable `movieplayer` that provides access to the `video` eleme
|
||||
|
||||
@cheatsheetItem
|
||||
syntax:
|
||||
`<p *my-unless="myExpression">...</p>`|`*my-unless`
|
||||
`<p *myUnless="myExpression">...</p>`|`*myUnless`
|
||||
description:
|
||||
The `*` symbol means that the current element will be turned into an embedded template. Equivalent to:
|
||||
`<template [myless]="myExpression"><p>...</p></template>`
|
||||
`<template [myUnless]="myExpression"><p>...</p></template>`
|
||||
|
||||
@cheatsheetItem
|
||||
syntax:
|
||||
`<p>Card No.: {{cardNumber | myCreditCardNumberFormatter}}</p>`|`{{cardNumber | myCreditCardNumberFormatter}}`
|
||||
description:
|
||||
Transforms the current value of expression `cardNumber` via the pipe called `creditCardNumberFormatter`.
|
||||
Transforms the current value of expression `cardNumber` via the pipe called `myCreditCardNumberFormatter`.
|
||||
|
||||
@cheatsheetItem
|
||||
syntax:
|
||||
|
@ -456,7 +456,7 @@ Where
|
||||
* `local` is a local identifier for local variables.
|
||||
* `internal` is an internal variable which the directive exports for binding.
|
||||
* `key` is an attribute name usually only used to trigger a specific directive.
|
||||
* `keyExpression` is an property name to which the expression will be bound to.
|
||||
* `keyExpression` is a property name to which the expression will be bound to.
|
||||
* `varExport` allows exporting of directive internal state as variables for further binding. If no `internal` name
|
||||
is specified, the exporting is to an implicit variable.
|
||||
* `microsyntax` allows you to build a simple microsyntax which can still clearly identify which expressions bind to
|
||||
|
@ -371,14 +371,14 @@ In TypeScript:
|
||||
import {platform, Provider, APP_INITIALIZER, Injector} from 'angular2/core';
|
||||
import {
|
||||
WORKER_RENDER_PLATFORM,
|
||||
WORKER_RENDER_APP_COMMON,
|
||||
WORKER_RENDER_APPLICATION_COMMON,
|
||||
initializeGenericWorkerRenderer,
|
||||
MessageBus
|
||||
} from 'angular2/platform/worker_render';
|
||||
|
||||
var bus = new MyAwesomeMessageBus();
|
||||
platform([WORKER_RENDER_PLATFORM])
|
||||
.application([WORKER_RENDER_APP_COMMON, new Provider(MessageBus, {useValue: bus}),
|
||||
.application([WORKER_RENDER_APPLICATION_COMMON, new Provider(MessageBus, {useValue: bus}),
|
||||
new Provider(APP_INITIALIZER, {
|
||||
useFactory: (injector) => () => initializeGenericWorkerRenderer(injector),
|
||||
deps: [Injector],
|
||||
@ -419,7 +419,7 @@ import 'package:angular2/platform/worker_render.dart';
|
||||
main() {
|
||||
var bus = new MyAwesomeMessageBus();
|
||||
platform([WORKER_RENDER_PLATFORM])
|
||||
.application([WORKER_RENDER_APP_COMMON, new Provider(MessageBus, useValue: bus),
|
||||
.application([WORKER_RENDER_APPLICATION_COMMON, new Provider(MessageBus, useValue: bus),
|
||||
new Provider(APP_INITIALIZER,
|
||||
useFactory: (injector) => () => initializeGenericWorkerRenderer(injector),
|
||||
deps: [Injector],
|
||||
@ -456,9 +456,9 @@ void initAppThread(NgZone zone) {
|
||||
*/
|
||||
}
|
||||
```
|
||||
Notice how we use the `WORKER_RENDER_APP_COMMON` providers instead of the `WORKER_RENDER_APP` providers on the render thread.
|
||||
This is because the `WORKER_RENDER_APP` providers include an application initializer that starts a new WebWorker/Isolate.
|
||||
The `WORKER_RENDER_APP_COMMON` providers make no assumption about where your application code lives.
|
||||
Notice how we use the `WORKER_RENDER_APPLICTION_COMMON` providers instead of the `WORKER_RENDER_APPLICATION` providers on the render thread.
|
||||
This is because the `WORKER_RENDER_APPLICATION` providers include an application initializer that starts a new WebWorker/Isolate.
|
||||
The `WORKER_RENDER_APPLICATION_COMMON` providers make no assumption about where your application code lives.
|
||||
However, we now need to provide our own app initializer. At the very least this initializer needs to call `initializeGenericWorkerRenderer`.
|
||||
|
||||
## MessageBroker
|
||||
|
@ -1,16 +1,8 @@
|
||||
import {DebugElement, Scope} from 'angular2/core';
|
||||
import {DebugElement} from 'angular2/core';
|
||||
|
||||
var debugElement: DebugElement;
|
||||
var predicate;
|
||||
|
||||
// #docregion scope_all
|
||||
debugElement.query(predicate, Scope.all);
|
||||
// #enddocregion
|
||||
|
||||
// #docregion scope_light
|
||||
debugElement.query(predicate, Scope.light);
|
||||
// #enddocregion
|
||||
|
||||
// #docregion scope_view
|
||||
debugElement.query(predicate, Scope.view);
|
||||
debugElement.query(predicate);
|
||||
// #enddocregion
|
||||
|
@ -1,17 +1,17 @@
|
||||
import {By} from 'angular2/platform/browser';
|
||||
import {DebugElement, Scope} from 'angular2/core';
|
||||
import {DebugElement} from 'angular2/core';
|
||||
|
||||
var debugElement: DebugElement;
|
||||
class MyDirective {}
|
||||
|
||||
// #docregion by_all
|
||||
debugElement.query(By.all(), Scope.all);
|
||||
debugElement.query(By.all());
|
||||
// #enddocregion
|
||||
|
||||
// #docregion by_css
|
||||
debugElement.query(By.css('[attribute]'), Scope.all);
|
||||
debugElement.query(By.css('[attribute]'));
|
||||
// #enddocregion
|
||||
|
||||
// #docregion by_directive
|
||||
debugElement.query(By.directive(MyDirective), Scope.all);
|
||||
debugElement.query(By.directive(MyDirective));
|
||||
// #enddocregion
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
|
||||
function waitForElement(selector) {
|
||||
var EC = (<any>protractor).ExpectedConditions;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
|
||||
function waitForElement(selector) {
|
||||
var EC = (<any>protractor).ExpectedConditions;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
|
||||
function waitForElement(selector) {
|
||||
var EC = (<any>protractor).ExpectedConditions;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
|
||||
function waitForElement(selector) {
|
||||
var EC = (<any>protractor).ExpectedConditions;
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
|
||||
function waitForElement(selector) {
|
||||
var EC = (<any>protractor).ExpectedConditions;
|
||||
|
@ -141,6 +141,7 @@ export {URLSearchParams} from './src/http/url_search_params';
|
||||
* // Send a response to the request
|
||||
* connection.mockRespond(response);
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* http.get('people.json').observer({
|
||||
@ -156,7 +157,8 @@ export const HTTP_PROVIDERS: any[] = [
|
||||
// issue: https://github.com/angular/angular/issues/3183
|
||||
provide(Http,
|
||||
{
|
||||
useFactory: (xhrBackend, requestOptions) => new Http(xhrBackend, requestOptions),
|
||||
useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions) =>
|
||||
new Http(xhrBackend, requestOptions),
|
||||
deps: [XHRBackend, RequestOptions]
|
||||
}),
|
||||
BrowserXhr,
|
||||
@ -268,6 +270,7 @@ export const HTTP_BINDINGS = HTTP_PROVIDERS;
|
||||
* // Send a response to the request
|
||||
* connection.mockRespond(response);
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
|
||||
* jsonp.get('people.json').observer({
|
||||
@ -283,7 +286,8 @@ export const JSONP_PROVIDERS: any[] = [
|
||||
// issue: https://github.com/angular/angular/issues/3183
|
||||
provide(Jsonp,
|
||||
{
|
||||
useFactory: (jsonpBackend, requestOptions) => new Jsonp(jsonpBackend, requestOptions),
|
||||
useFactory: (jsonpBackend: JSONPBackend, requestOptions: RequestOptions) =>
|
||||
new Jsonp(jsonpBackend, requestOptions),
|
||||
deps: [JSONPBackend, RequestOptions]
|
||||
}),
|
||||
BrowserJsonp,
|
||||
|
37
modules/angular2/manual_typings/globals-es6.d.ts
vendored
37
modules/angular2/manual_typings/globals-es6.d.ts
vendored
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Declarations angular depends on for compilation to ES6.
|
||||
* This file is also used to propagate our transitive typings
|
||||
* to users.
|
||||
*/
|
||||
|
||||
/// <reference path="../typings/zone/zone.d.ts"/>
|
||||
/// <reference path="../typings/hammerjs/hammerjs.d.ts"/>
|
||||
/// <reference path="../typings/jasmine/jasmine.d.ts"/>
|
||||
/// <reference path="../typings/angular-protractor/angular-protractor.d.ts"/>
|
||||
|
||||
// TODO: ideally the node.d.ts reference should be scoped only for files that need and not to all
|
||||
// the code including client code
|
||||
/// <reference path="../typings/node/node.d.ts" />
|
||||
|
||||
declare var assert: any;
|
||||
|
||||
|
||||
interface BrowserNodeGlobal {
|
||||
Object: typeof Object;
|
||||
Array: typeof Array;
|
||||
Map: typeof Map;
|
||||
Set: typeof Set;
|
||||
Date: typeof Date;
|
||||
RegExp: typeof RegExp;
|
||||
JSON: typeof JSON;
|
||||
Math: typeof Math;
|
||||
assert(condition: any): void;
|
||||
Reflect: any;
|
||||
zone: Zone;
|
||||
getAngularTestability: Function;
|
||||
getAllAngularTestabilities: Function;
|
||||
setTimeout: Function;
|
||||
clearTimeout: Function;
|
||||
setInterval: Function;
|
||||
clearInterval: Function;
|
||||
}
|
55
modules/angular2/manual_typings/globals.d.ts
vendored
55
modules/angular2/manual_typings/globals.d.ts
vendored
@ -1,7 +1,52 @@
|
||||
/**
|
||||
* Declarations angular depends on for compilation to ES6.
|
||||
* This file is also used to propagate our transitive typings
|
||||
* to users.
|
||||
* Subset of es6-shim typings.
|
||||
* Angular should not require use of ES6 runtime but some API usages are already present.
|
||||
* See https://github.com/angular/angular/issues/5242
|
||||
* TODO(alexeagle): remove methods below which may not be present in targeted browser
|
||||
*/
|
||||
/// <reference path="../typings/es6-shim/es6-shim.d.ts"/>
|
||||
/// <reference path="./globals-es6.d.ts"/>
|
||||
|
||||
declare type PromiseConstructor = typeof Promise;
|
||||
|
||||
interface String {
|
||||
/**
|
||||
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||
* same as the corresponding elements of this object (converted to a String) starting at
|
||||
* position. Otherwise returns false.
|
||||
*/
|
||||
startsWith(searchString: string, position?: number): boolean;
|
||||
|
||||
/**
|
||||
* Returns true if the sequence of elements of searchString converted to a String is the
|
||||
* same as the corresponding elements of this object (converted to a String) starting at
|
||||
* endPosition – length(this). Otherwise returns false.
|
||||
*/
|
||||
endsWith(searchString: string, endPosition?: number): boolean;
|
||||
}
|
||||
interface Array<T> {
|
||||
/**
|
||||
* Returns the value of the first element in the array where predicate is true, and undefined
|
||||
* otherwise.
|
||||
* @param predicate find calls predicate once for each element of the array, in ascending
|
||||
* order, until it finds one where predicate returns true. If such an element is found, find
|
||||
* immediately returns that element value. Otherwise, find returns undefined.
|
||||
* @param thisArg If provided, it will be used as the this value for each invocation of
|
||||
* predicate. If it is not provided, undefined is used instead.
|
||||
*/
|
||||
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T;
|
||||
/**
|
||||
* Returns the this object after filling the section identified by start and end with value
|
||||
* @param value value to fill array section with
|
||||
* @param start index to start filling the array at. If start is negative, it is treated as
|
||||
* length+start where length is the length of the array.
|
||||
* @param end index to stop filling the array at. If end is negative, it is treated as
|
||||
* length+end.
|
||||
*/
|
||||
fill(value: T, start?: number, end?: number): T[];
|
||||
}
|
||||
interface NumberConstructor {
|
||||
/**
|
||||
* Returns true if the value passed is an integer, false otherwise.
|
||||
* @param number A numeric value.
|
||||
*/
|
||||
isInteger(number: number): boolean;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
||||
export {
|
||||
BROWSER_PROVIDERS,
|
||||
ELEMENT_PROBE_BINDINGS,
|
||||
ELEMENT_PROBE_PROVIDERS,
|
||||
ELEMENT_PROBE_PROVIDERS_PROD_MODE,
|
||||
inspectNativeElement,
|
||||
BrowserDomAdapter,
|
||||
By,
|
||||
@ -13,7 +13,6 @@ export {
|
||||
} from 'angular2/src/platform/browser_common';
|
||||
|
||||
import {Type, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {Promise} from 'angular2/src/facade/promise';
|
||||
import {
|
||||
BROWSER_PROVIDERS,
|
||||
BROWSER_APP_COMMON_PROVIDERS
|
||||
|
@ -1,8 +1,8 @@
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
||||
export {
|
||||
BROWSER_PROVIDERS,
|
||||
ELEMENT_PROBE_BINDINGS,
|
||||
ELEMENT_PROBE_PROVIDERS,
|
||||
ELEMENT_PROBE_PROVIDERS_PROD_MODE,
|
||||
inspectNativeElement,
|
||||
BrowserDomAdapter,
|
||||
By,
|
||||
@ -12,7 +12,6 @@ export {
|
||||
} from 'angular2/src/platform/browser_common';
|
||||
|
||||
import {Type, isPresent} from 'angular2/src/facade/lang';
|
||||
import {Promise} from 'angular2/src/facade/promise';
|
||||
import {
|
||||
BROWSER_PROVIDERS,
|
||||
BROWSER_APP_COMMON_PROVIDERS
|
||||
|
@ -12,4 +12,4 @@ export {
|
||||
EventManagerPlugin
|
||||
} from 'angular2/src/platform/dom/events/event_manager';
|
||||
export * from 'angular2/src/platform/dom/debug/by';
|
||||
export * from 'angular2/src/platform/dom/debug/debug_element_view_listener';
|
||||
export * from 'angular2/src/platform/dom/debug/ng_probe';
|
||||
|
21
modules/angular2/platform/testing/browser.ts
Normal file
21
modules/angular2/platform/testing/browser.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import {
|
||||
TEST_BROWSER_STATIC_PLATFORM_PROVIDERS,
|
||||
ADDITIONAL_TEST_BROWSER_PROVIDERS
|
||||
} from 'angular2/platform/testing/browser_static';
|
||||
|
||||
import {BROWSER_APP_PROVIDERS} from 'angular2/platform/browser';
|
||||
|
||||
|
||||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
|
||||
/**
|
||||
* Default patform providers for testing.
|
||||
*/
|
||||
export const TEST_BROWSER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
CONST_EXPR([TEST_BROWSER_STATIC_PLATFORM_PROVIDERS]);
|
||||
|
||||
/**
|
||||
* Default application providers for testing.
|
||||
*/
|
||||
export const TEST_BROWSER_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
CONST_EXPR([BROWSER_APP_PROVIDERS, ADDITIONAL_TEST_BROWSER_PROVIDERS]);
|
69
modules/angular2/platform/testing/browser_static.ts
Normal file
69
modules/angular2/platform/testing/browser_static.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import {
|
||||
APP_ID,
|
||||
DirectiveResolver,
|
||||
NgZone,
|
||||
Provider,
|
||||
ViewResolver,
|
||||
PLATFORM_COMMON_PROVIDERS,
|
||||
PLATFORM_INITIALIZER
|
||||
} from 'angular2/core';
|
||||
import {BROWSER_APP_COMMON_PROVIDERS} from 'angular2/src/platform/browser_common';
|
||||
import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter';
|
||||
|
||||
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
||||
import {MockAnimationBuilder} from 'angular2/src/mock/animation_builder_mock';
|
||||
import {MockDirectiveResolver} from 'angular2/src/mock/directive_resolver_mock';
|
||||
import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
|
||||
import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
|
||||
import {LocationStrategy} from 'angular2/src/router/location_strategy';
|
||||
import {MockNgZone} from 'angular2/src/mock/ng_zone_mock';
|
||||
|
||||
import {XHRImpl} from "angular2/src/platform/browser/xhr_impl";
|
||||
import {XHR} from 'angular2/compiler';
|
||||
|
||||
import {TestComponentBuilder} from 'angular2/src/testing/test_component_builder';
|
||||
|
||||
import {BrowserDetection} from 'angular2/src/testing/utils';
|
||||
|
||||
import {ELEMENT_PROBE_PROVIDERS} from 'angular2/platform/common_dom';
|
||||
|
||||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
|
||||
import {Log} from 'angular2/src/testing/utils';
|
||||
|
||||
function initBrowserTests() {
|
||||
BrowserDomAdapter.makeCurrent();
|
||||
BrowserDetection.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default patform providers for testing without a compiler.
|
||||
*/
|
||||
export const TEST_BROWSER_STATIC_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
CONST_EXPR([
|
||||
PLATFORM_COMMON_PROVIDERS,
|
||||
new Provider(PLATFORM_INITIALIZER, {useValue: initBrowserTests, multi: true})
|
||||
]);
|
||||
|
||||
export const ADDITIONAL_TEST_BROWSER_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
CONST_EXPR([
|
||||
new Provider(APP_ID, {useValue: 'a'}),
|
||||
ELEMENT_PROBE_PROVIDERS,
|
||||
new Provider(DirectiveResolver, {useClass: MockDirectiveResolver}),
|
||||
new Provider(ViewResolver, {useClass: MockViewResolver}),
|
||||
Log,
|
||||
TestComponentBuilder,
|
||||
new Provider(NgZone, {useClass: MockNgZone}),
|
||||
new Provider(LocationStrategy, {useClass: MockLocationStrategy}),
|
||||
new Provider(AnimationBuilder, {useClass: MockAnimationBuilder}),
|
||||
]);
|
||||
|
||||
/**
|
||||
* Default application providers for testing without a compiler.
|
||||
*/
|
||||
export const TEST_BROWSER_STATIC_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
CONST_EXPR([
|
||||
BROWSER_APP_COMMON_PROVIDERS,
|
||||
new Provider(XHR, {useClass: XHRImpl}),
|
||||
ADDITIONAL_TEST_BROWSER_PROVIDERS
|
||||
]);
|
1
modules/angular2/platform/testing/server.dart
Normal file
1
modules/angular2/platform/testing/server.dart
Normal file
@ -0,0 +1 @@
|
||||
// Intentionally blank, the Parse5Adapater bindings for JavaScript don't apply.
|
90
modules/angular2/platform/testing/server.ts
Normal file
90
modules/angular2/platform/testing/server.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import {
|
||||
APP_ID,
|
||||
DirectiveResolver,
|
||||
NgZone,
|
||||
Provider,
|
||||
ViewResolver,
|
||||
PLATFORM_COMMON_PROVIDERS,
|
||||
PLATFORM_INITIALIZER,
|
||||
APPLICATION_COMMON_PROVIDERS,
|
||||
Renderer
|
||||
} from 'angular2/core';
|
||||
import {Parse5DomAdapter} from 'angular2/src/platform/server/parse5_adapter';
|
||||
|
||||
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
||||
import {MockAnimationBuilder} from 'angular2/src/mock/animation_builder_mock';
|
||||
import {MockDirectiveResolver} from 'angular2/src/mock/directive_resolver_mock';
|
||||
import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
|
||||
import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
|
||||
import {LocationStrategy} from 'angular2/src/router/location_strategy';
|
||||
import {MockNgZone} from 'angular2/src/mock/ng_zone_mock';
|
||||
|
||||
import {TestComponentBuilder} from 'angular2/src/testing/test_component_builder';
|
||||
import {XHR} from 'angular2/src/compiler/xhr';
|
||||
import {BrowserDetection} from 'angular2/src/testing/utils';
|
||||
|
||||
import {COMPILER_PROVIDERS} from 'angular2/src/compiler/compiler';
|
||||
import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {RootRenderer} from 'angular2/src/core/render/api';
|
||||
import {DomRootRenderer, DomRootRenderer_} from 'angular2/src/platform/dom/dom_renderer';
|
||||
import {DomSharedStylesHost} from 'angular2/src/platform/dom/shared_styles_host';
|
||||
|
||||
import {
|
||||
EventManager,
|
||||
EVENT_MANAGER_PLUGINS,
|
||||
ELEMENT_PROBE_PROVIDERS
|
||||
} from 'angular2/platform/common_dom';
|
||||
import {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events';
|
||||
|
||||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
|
||||
import {Log} from 'angular2/src/testing/utils';
|
||||
|
||||
function initServerTests() {
|
||||
Parse5DomAdapter.makeCurrent();
|
||||
BrowserDetection.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default patform providers for testing.
|
||||
*/
|
||||
export const TEST_SERVER_PLATFORM_PROVIDERS: Array<any /*Type | Provider | any[]*/> = CONST_EXPR([
|
||||
PLATFORM_COMMON_PROVIDERS,
|
||||
new Provider(PLATFORM_INITIALIZER, {useValue: initServerTests, multi: true})
|
||||
]);
|
||||
|
||||
function appDoc() {
|
||||
try {
|
||||
return DOM.defaultDoc();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default application providers for testing.
|
||||
*/
|
||||
export const TEST_SERVER_APPLICATION_PROVIDERS: Array<any /*Type | Provider | any[]*/> =
|
||||
CONST_EXPR([
|
||||
// TODO(julie): when angular2/platform/server is available, use that instead of making our own
|
||||
// list here.
|
||||
APPLICATION_COMMON_PROVIDERS,
|
||||
COMPILER_PROVIDERS,
|
||||
new Provider(DOCUMENT, {useFactory: appDoc}),
|
||||
new Provider(DomRootRenderer, {useClass: DomRootRenderer_}),
|
||||
new Provider(RootRenderer, {useExisting: DomRootRenderer}),
|
||||
EventManager,
|
||||
new Provider(EVENT_MANAGER_PLUGINS, {useClass: DomEventsPlugin, multi: true}),
|
||||
new Provider(XHR, {useClass: XHR}),
|
||||
new Provider(APP_ID, {useValue: 'a'}),
|
||||
DomSharedStylesHost,
|
||||
ELEMENT_PROBE_PROVIDERS,
|
||||
new Provider(DirectiveResolver, {useClass: MockDirectiveResolver}),
|
||||
new Provider(ViewResolver, {useClass: MockViewResolver}),
|
||||
Log,
|
||||
TestComponentBuilder,
|
||||
new Provider(NgZone, {useClass: MockNgZone}),
|
||||
new Provider(LocationStrategy, {useClass: MockLocationStrategy}),
|
||||
new Provider(AnimationBuilder, {useClass: MockAnimationBuilder}),
|
||||
]);
|
@ -12,3 +12,5 @@ export 'package:angular2/src/web_workers/shared/service_message_broker.dart'
|
||||
show ReceivedMessage, ServiceMessageBroker, ServiceMessageBrokerFactory;
|
||||
export 'package:angular2/src/web_workers/shared/serializer.dart' show PRIMITIVE;
|
||||
export 'package:angular2/src/web_workers/shared/message_bus.dart';
|
||||
export 'package:angular2/src/web_workers/worker/router_providers.dart'
|
||||
show WORKER_APP_ROUTER;
|
||||
|
@ -8,12 +8,13 @@ export {
|
||||
ClientMessageBrokerFactory,
|
||||
FnArg,
|
||||
UiArguments
|
||||
} from '../src/web_workers/shared/client_message_broker';
|
||||
} from 'angular2/src/web_workers/shared/client_message_broker';
|
||||
export {
|
||||
ReceivedMessage,
|
||||
ServiceMessageBroker,
|
||||
ServiceMessageBrokerFactory
|
||||
} from '../src/web_workers/shared/service_message_broker';
|
||||
export {PRIMITIVE} from '../src/web_workers/shared/serializer';
|
||||
export * from '../src/web_workers/shared/message_bus';
|
||||
} from 'angular2/src/web_workers/shared/service_message_broker';
|
||||
export {PRIMITIVE} from 'angular2/src/web_workers/shared/serializer';
|
||||
export * from 'angular2/src/web_workers/shared/message_bus';
|
||||
export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
|
||||
export {WORKER_APP_ROUTER} from 'angular2/src/web_workers/worker/router_providers';
|
||||
|
@ -4,11 +4,11 @@ export 'package:angular2/src/platform/worker_render_common.dart'
|
||||
show
|
||||
WORKER_SCRIPT,
|
||||
WORKER_RENDER_PLATFORM,
|
||||
WORKER_RENDER_APP_COMMON,
|
||||
WORKER_RENDER_APPLICATION_COMMON,
|
||||
initializeGenericWorkerRenderer;
|
||||
|
||||
export 'package:angular2/src/platform/worker_render.dart'
|
||||
show WORKER_RENDER_APP, initIsolate, WebWorkerInstance;
|
||||
show WORKER_RENDER_APPLICATION, initIsolate, WebWorkerInstance;
|
||||
|
||||
export '../src/web_workers/shared/client_message_broker.dart'
|
||||
show ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments;
|
||||
@ -18,3 +18,9 @@ export '../src/web_workers/shared/service_message_broker.dart'
|
||||
|
||||
export '../src/web_workers/shared/serializer.dart' show PRIMITIVE;
|
||||
export '../src/web_workers/shared/message_bus.dart';
|
||||
export '../src/web_workers/ui/router_providers.dart' show WORKER_RENDER_ROUTER;
|
||||
|
||||
import 'package:angular2/src/platform/worker_render_common.dart';
|
||||
|
||||
const WORKER_RENDER_APP = WORKER_RENDER_APPLICATION_COMMON;
|
||||
|
||||
|
@ -2,9 +2,9 @@ export {
|
||||
WORKER_SCRIPT,
|
||||
WORKER_RENDER_PLATFORM,
|
||||
initializeGenericWorkerRenderer,
|
||||
WORKER_RENDER_APP_COMMON
|
||||
WORKER_RENDER_APPLICATION_COMMON
|
||||
} from 'angular2/src/platform/worker_render_common';
|
||||
export * from 'angular2/src/platform/worker_render';
|
||||
export {WORKER_RENDER_APPLICATION, WebWorkerInstance} from 'angular2/src/platform/worker_render';
|
||||
export {
|
||||
ClientMessageBroker,
|
||||
ClientMessageBrokerFactory,
|
||||
@ -18,3 +18,10 @@ export {
|
||||
} from '../src/web_workers/shared/service_message_broker';
|
||||
export {PRIMITIVE} from '../src/web_workers/shared/serializer';
|
||||
export * from '../src/web_workers/shared/message_bus';
|
||||
import {WORKER_RENDER_APPLICATION} from 'angular2/src/platform/worker_render';
|
||||
|
||||
/**
|
||||
* @deprecated Use WORKER_RENDER_APPLICATION
|
||||
*/
|
||||
export const WORKER_RENDER_APP = WORKER_RENDER_APPLICATION;
|
||||
export {WORKER_RENDER_ROUTER} from 'angular2/src/web_workers/ui/router_providers';
|
||||
|
@ -9,9 +9,8 @@ homepage: <%= packageJson.homepage %>
|
||||
environment:
|
||||
sdk: '>=1.10.0 <2.0.0'
|
||||
dependencies:
|
||||
analyzer: '>=0.24.4 <0.27.0'
|
||||
analyzer: '>=0.24.4 <0.28.0'
|
||||
barback: '^0.15.2+2'
|
||||
code_transformers: '0.2.9+4'
|
||||
dart_style: '>=0.1.8 <0.3.0'
|
||||
glob: '^1.0.0'
|
||||
html: '^0.12.0'
|
||||
@ -19,11 +18,13 @@ dependencies:
|
||||
logging: '>=0.9.0 <0.12.0'
|
||||
observe: '^0.13.1'
|
||||
protobuf: '^0.5.0'
|
||||
quiver: '^0.21.4'
|
||||
source_span: '^1.0.0'
|
||||
stack_trace: '^1.1.1'
|
||||
dev_dependencies:
|
||||
code_transformers: '>=0.2.9+4 <0.4.0'
|
||||
guinness: '^0.1.18'
|
||||
quiver: '^0.21.4'
|
||||
test: '^0.12.6'
|
||||
transformers:
|
||||
- angular2
|
||||
- $dart2js:
|
||||
|
@ -20,18 +20,12 @@ export {OnActivate, OnDeactivate, OnReuse, CanDeactivate, CanReuse} from './src/
|
||||
export {CanActivate} from './src/router/lifecycle_annotations';
|
||||
export {Instruction, ComponentInstruction} from './src/router/instruction';
|
||||
export {OpaqueToken} from 'angular2/core';
|
||||
export {ROUTER_PROVIDERS_COMMON} from 'angular2/src/router/router_providers_common';
|
||||
export {ROUTER_PROVIDERS, ROUTER_BINDINGS} from 'angular2/src/router/router_providers';
|
||||
|
||||
import {PlatformLocation} from './src/router/platform_location';
|
||||
import {LocationStrategy} from './src/router/location_strategy';
|
||||
import {PathLocationStrategy} from './src/router/path_location_strategy';
|
||||
import {Router, RootRouter} from './src/router/router';
|
||||
import {RouterOutlet} from './src/router/router_outlet';
|
||||
import {RouterLink} from './src/router/router_link';
|
||||
import {RouteRegistry, ROUTER_PRIMARY_COMPONENT} from './src/router/route_registry';
|
||||
import {Location} from './src/router/location';
|
||||
import {ApplicationRef, provide, OpaqueToken, Provider} from 'angular2/core';
|
||||
import {CONST_EXPR} from './src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
|
||||
/**
|
||||
* A list of directives. To use the router directives like {@link RouterOutlet} and
|
||||
@ -56,63 +50,3 @@ import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
* ```
|
||||
*/
|
||||
export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]);
|
||||
|
||||
/**
|
||||
* A list of {@link Provider}s. To use the router, you must add this to your application.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
|
||||
*
|
||||
* ```
|
||||
* import {Component} from 'angular2/core';
|
||||
* import {
|
||||
* ROUTER_DIRECTIVES,
|
||||
* ROUTER_PROVIDERS,
|
||||
* RouteConfig
|
||||
* } from 'angular2/router';
|
||||
*
|
||||
* @Component({directives: [ROUTER_DIRECTIVES]})
|
||||
* @RouteConfig([
|
||||
* {...},
|
||||
* ])
|
||||
* class AppCmp {
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* bootstrap(AppCmp, [ROUTER_PROVIDERS]);
|
||||
* ```
|
||||
*/
|
||||
export const ROUTER_PROVIDERS: any[] = CONST_EXPR([
|
||||
RouteRegistry,
|
||||
CONST_EXPR(new Provider(LocationStrategy, {useClass: PathLocationStrategy})),
|
||||
PlatformLocation,
|
||||
Location,
|
||||
CONST_EXPR(new Provider(
|
||||
Router,
|
||||
{
|
||||
useFactory: routerFactory,
|
||||
deps: CONST_EXPR([RouteRegistry, Location, ROUTER_PRIMARY_COMPONENT, ApplicationRef])
|
||||
})),
|
||||
CONST_EXPR(new Provider(
|
||||
ROUTER_PRIMARY_COMPONENT,
|
||||
{useFactory: routerPrimaryComponentFactory, deps: CONST_EXPR([ApplicationRef])}))
|
||||
]);
|
||||
|
||||
/**
|
||||
* Use {@link ROUTER_PROVIDERS} instead.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const ROUTER_BINDINGS = ROUTER_PROVIDERS;
|
||||
|
||||
function routerFactory(registry, location, primaryComponent, appRef) {
|
||||
var rootRouter = new RootRouter(registry, location, primaryComponent);
|
||||
appRef.registerDisposeListener(() => rootRouter.dispose());
|
||||
return rootRouter;
|
||||
}
|
||||
|
||||
function routerPrimaryComponentFactory(app) {
|
||||
if (app.componentTypes.length == 0) {
|
||||
throw new BaseException("Bootstrap at least one component before injecting Router.");
|
||||
}
|
||||
return app.componentTypes[0];
|
||||
}
|
||||
|
@ -169,10 +169,10 @@ export class NgClass implements DoCheck, OnDestroy {
|
||||
if (className.indexOf(' ') > -1) {
|
||||
var classes = className.split(/\s+/g);
|
||||
for (var i = 0, len = classes.length; i < len; i++) {
|
||||
this._renderer.setElementClass(this._ngEl, classes[i], enabled);
|
||||
this._renderer.setElementClass(this._ngEl.nativeElement, classes[i], enabled);
|
||||
}
|
||||
} else {
|
||||
this._renderer.setElementClass(this._ngEl, className, enabled);
|
||||
this._renderer.setElementClass(this._ngEl.nativeElement, className, enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
IterableDiffers,
|
||||
ViewContainerRef,
|
||||
TemplateRef,
|
||||
ViewRef
|
||||
EmbeddedViewRef,
|
||||
TrackByFn
|
||||
} from 'angular2/core';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
|
||||
@ -59,10 +60,11 @@ import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
* See a [live demo](http://plnkr.co/edit/KVuXxDp0qinGDyo307QW?p=preview) for a more detailed
|
||||
* example.
|
||||
*/
|
||||
@Directive({selector: '[ngFor][ngForOf]', inputs: ['ngForOf', 'ngForTemplate']})
|
||||
@Directive({selector: '[ngFor][ngForOf]', inputs: ['ngForTrackBy', 'ngForOf', 'ngForTemplate']})
|
||||
export class NgFor implements DoCheck {
|
||||
/** @internal */
|
||||
_ngForOf: any;
|
||||
_ngForTrackBy: TrackByFn;
|
||||
private _differ: IterableDiffer;
|
||||
|
||||
constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef,
|
||||
@ -71,7 +73,7 @@ export class NgFor implements DoCheck {
|
||||
set ngForOf(value: any) {
|
||||
this._ngForOf = value;
|
||||
if (isBlank(this._differ) && isPresent(value)) {
|
||||
this._differ = this._iterableDiffers.find(value).create(this._cdr);
|
||||
this._differ = this._iterableDiffers.find(value).create(this._cdr, this._ngForTrackBy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +83,8 @@ export class NgFor implements DoCheck {
|
||||
}
|
||||
}
|
||||
|
||||
set ngForTrackBy(value: TrackByFn) { this._ngForTrackBy = value; }
|
||||
|
||||
ngDoCheck() {
|
||||
if (isPresent(this._differ)) {
|
||||
var changes = this._differ.diff(this._ngForOf);
|
||||
@ -110,8 +114,14 @@ export class NgFor implements DoCheck {
|
||||
}
|
||||
|
||||
for (var i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
|
||||
this._viewContainer.get(i).setLocal('last', i === ilen - 1);
|
||||
var viewRef = <EmbeddedViewRef>this._viewContainer.get(i);
|
||||
viewRef.setLocal('last', i === ilen - 1);
|
||||
}
|
||||
|
||||
changes.forEachIdentityChange((record) => {
|
||||
var viewRef = <EmbeddedViewRef>this._viewContainer.get(record.currentIndex);
|
||||
viewRef.setLocal('\$implicit', record.item);
|
||||
});
|
||||
}
|
||||
|
||||
private _perViewChange(view, record) {
|
||||
@ -153,7 +163,7 @@ export class NgFor implements DoCheck {
|
||||
}
|
||||
|
||||
class RecordViewTuple {
|
||||
view: ViewRef;
|
||||
view: EmbeddedViewRef;
|
||||
record: any;
|
||||
constructor(record, view) {
|
||||
this.record = record;
|
||||
|
@ -92,6 +92,6 @@ export class NgStyle implements DoCheck {
|
||||
}
|
||||
|
||||
private _setStyle(name: string, val: string): void {
|
||||
this._renderer.setElementStyle(this._ngEl, name, val);
|
||||
this._renderer.setElementStyle(this._ngEl.nativeElement, name, val);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ import {ListWrapper, Map} from 'angular2/src/facade/collection';
|
||||
|
||||
const _WHEN_DEFAULT = CONST_EXPR(new Object());
|
||||
|
||||
class SwitchView {
|
||||
/** @internal */
|
||||
export class SwitchView {
|
||||
constructor(private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef) {}
|
||||
|
||||
create(): void { this._viewContainerRef.createEmbeddedView(this._templateRef); }
|
||||
|
@ -21,7 +21,7 @@ class ObservableListDiff extends DefaultIterableDiffer {
|
||||
}
|
||||
}
|
||||
|
||||
dynamic diff(ObservableList collection) {
|
||||
DefaultIterableDiffer diff(ObservableList collection) {
|
||||
if (collection is! ObservableList) {
|
||||
throw "Cannot change the type of a collection";
|
||||
}
|
||||
@ -57,7 +57,7 @@ class ObservableListDiff extends DefaultIterableDiffer {
|
||||
class ObservableListDiffFactory implements IterableDifferFactory {
|
||||
const ObservableListDiffFactory();
|
||||
bool supports(obj) => obj is ObservableList;
|
||||
IterableDiffer create(ChangeDetectorRef cdRef) {
|
||||
IterableDiffer create(ChangeDetectorRef cdRef, [Function trackByFn]) {
|
||||
return new ObservableListDiff(cdRef);
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ export {
|
||||
NgSelectOption,
|
||||
SelectControlValueAccessor
|
||||
} from './forms/directives/select_control_value_accessor';
|
||||
export {FORM_DIRECTIVES} from './forms/directives';
|
||||
export {FORM_DIRECTIVES, RadioButtonState} from './forms/directives';
|
||||
export {NG_VALIDATORS, NG_ASYNC_VALIDATORS, Validators} from './forms/validators';
|
||||
export {
|
||||
RequiredValidator,
|
||||
@ -39,4 +39,25 @@ export {
|
||||
MaxLengthValidator,
|
||||
Validator
|
||||
} from './forms/directives/validators';
|
||||
export {FormBuilder, FORM_PROVIDERS, FORM_BINDINGS} from './forms/form_builder';
|
||||
export {FormBuilder} from './forms/form_builder';
|
||||
import {FormBuilder} from './forms/form_builder';
|
||||
import {RadioControlRegistry} from './forms/directives/radio_control_value_accessor';
|
||||
import {Type, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
|
||||
/**
|
||||
* Shorthand set of providers used for building Angular forms.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* bootstrap(MyApp, [FORM_PROVIDERS]);
|
||||
* ```
|
||||
*/
|
||||
export const FORM_PROVIDERS: Type[] = CONST_EXPR([FormBuilder, RadioControlRegistry]);
|
||||
|
||||
/**
|
||||
* See {@link FORM_PROVIDERS} instead.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const FORM_BINDINGS = FORM_PROVIDERS;
|
||||
|
@ -8,6 +8,7 @@ import {NgForm} from './directives/ng_form';
|
||||
import {DefaultValueAccessor} from './directives/default_value_accessor';
|
||||
import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
|
||||
import {NumberValueAccessor} from './directives/number_value_accessor';
|
||||
import {RadioControlValueAccessor} from './directives/radio_control_value_accessor';
|
||||
import {NgControlStatus} from './directives/ng_control_status';
|
||||
import {
|
||||
SelectControlValueAccessor,
|
||||
@ -23,6 +24,10 @@ export {NgFormModel} from './directives/ng_form_model';
|
||||
export {NgForm} from './directives/ng_form';
|
||||
export {DefaultValueAccessor} from './directives/default_value_accessor';
|
||||
export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
|
||||
export {
|
||||
RadioControlValueAccessor,
|
||||
RadioButtonState
|
||||
} from './directives/radio_control_value_accessor';
|
||||
export {NumberValueAccessor} from './directives/number_value_accessor';
|
||||
export {NgControlStatus} from './directives/ng_control_status';
|
||||
export {
|
||||
@ -63,6 +68,7 @@ export const FORM_DIRECTIVES: Type[] = CONST_EXPR([
|
||||
NumberValueAccessor,
|
||||
CheckboxControlValueAccessor,
|
||||
SelectControlValueAccessor,
|
||||
RadioControlValueAccessor,
|
||||
NgControlStatus,
|
||||
|
||||
RequiredValidator,
|
||||
|
@ -18,7 +18,7 @@ const CHECKBOX_VALUE_ACCESSOR = CONST_EXPR(new Provider(
|
||||
selector:
|
||||
'input[type=checkbox][ngControl],input[type=checkbox][ngFormControl],input[type=checkbox][ngModel]',
|
||||
host: {'(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()'},
|
||||
bindings: [CHECKBOX_VALUE_ACCESSOR]
|
||||
providers: [CHECKBOX_VALUE_ACCESSOR]
|
||||
})
|
||||
export class CheckboxControlValueAccessor implements ControlValueAccessor {
|
||||
onChange = (_) => {};
|
||||
@ -27,7 +27,7 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor {
|
||||
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
|
||||
|
||||
writeValue(value: any): void {
|
||||
this._renderer.setElementProperty(this._elementRef, 'checked', value);
|
||||
this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', value);
|
||||
}
|
||||
registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; }
|
||||
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
|
||||
|
@ -31,7 +31,7 @@ export class DefaultValueAccessor implements ControlValueAccessor {
|
||||
|
||||
writeValue(value: any): void {
|
||||
var normalizedValue = isBlank(value) ? '' : value;
|
||||
this._renderer.setElementProperty(this._elementRef, 'value', normalizedValue);
|
||||
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', normalizedValue);
|
||||
}
|
||||
|
||||
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
|
||||
|
@ -31,7 +31,7 @@ export class NumberValueAccessor implements ControlValueAccessor {
|
||||
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
|
||||
|
||||
writeValue(value: number): void {
|
||||
this._renderer.setElementProperty(this._elementRef, 'value', value);
|
||||
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', value);
|
||||
}
|
||||
|
||||
registerOnChange(fn: (_: number) => void): void {
|
||||
|
@ -0,0 +1,126 @@
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
Renderer,
|
||||
Self,
|
||||
forwardRef,
|
||||
Provider,
|
||||
Attribute,
|
||||
Input,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
Injector,
|
||||
Injectable
|
||||
} from 'angular2/core';
|
||||
import {
|
||||
NG_VALUE_ACCESSOR,
|
||||
ControlValueAccessor
|
||||
} from 'angular2/src/common/forms/directives/control_value_accessor';
|
||||
import {NgControl} from 'angular2/src/common/forms/directives/ng_control';
|
||||
import {CONST_EXPR, looseIdentical, isPresent} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
const RADIO_VALUE_ACCESSOR = CONST_EXPR(new Provider(
|
||||
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => RadioControlValueAccessor), multi: true}));
|
||||
|
||||
|
||||
/**
|
||||
* Internal class used by Angular to uncheck radio buttons with the matching name.
|
||||
*/
|
||||
@Injectable()
|
||||
export class RadioControlRegistry {
|
||||
private _accessors: any[] = [];
|
||||
|
||||
add(control: NgControl, accessor: RadioControlValueAccessor) {
|
||||
this._accessors.push([control, accessor]);
|
||||
}
|
||||
|
||||
remove(accessor: RadioControlValueAccessor) {
|
||||
var indexToRemove = -1;
|
||||
for (var i = 0; i < this._accessors.length; ++i) {
|
||||
if (this._accessors[i][1] === accessor) {
|
||||
indexToRemove = i;
|
||||
}
|
||||
}
|
||||
ListWrapper.removeAt(this._accessors, indexToRemove);
|
||||
}
|
||||
|
||||
select(accessor: RadioControlValueAccessor) {
|
||||
this._accessors.forEach((c) => {
|
||||
if (c[0].control.root === accessor._control.control.root && c[1] !== accessor) {
|
||||
c[1].fireUncheck();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The value provided by the forms API for radio buttons.
|
||||
*/
|
||||
export class RadioButtonState {
|
||||
constructor(public checked: boolean, public value: string) {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The accessor for writing a radio control value and listening to changes that is used by the
|
||||
* {@link NgModel}, {@link NgFormControl}, and {@link NgControlName} directives.
|
||||
*
|
||||
* ### Example
|
||||
* ```
|
||||
* @Component({
|
||||
* template: `
|
||||
* <input type="radio" name="food" [(ngModel)]="foodChicken">
|
||||
* <input type="radio" name="food" [(ngModel)]="foodFish">
|
||||
* `
|
||||
* })
|
||||
* class FoodCmp {
|
||||
* foodChicken = new RadioButtonState(true, "chicken");
|
||||
* foodFish = new RadioButtonState(false, "fish");
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@Directive({
|
||||
selector:
|
||||
'input[type=radio][ngControl],input[type=radio][ngFormControl],input[type=radio][ngModel]',
|
||||
host: {'(change)': 'onChange()', '(blur)': 'onTouched()'},
|
||||
providers: [RADIO_VALUE_ACCESSOR]
|
||||
})
|
||||
export class RadioControlValueAccessor implements ControlValueAccessor,
|
||||
OnDestroy, OnInit {
|
||||
_state: RadioButtonState;
|
||||
_control: NgControl;
|
||||
@Input() name: string;
|
||||
_fn: Function;
|
||||
onChange = () => {};
|
||||
onTouched = () => {};
|
||||
|
||||
constructor(private _renderer: Renderer, private _elementRef: ElementRef,
|
||||
private _registry: RadioControlRegistry, private _injector: Injector) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._control = this._injector.get(NgControl);
|
||||
this._registry.add(this._control, this);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void { this._registry.remove(this); }
|
||||
|
||||
writeValue(value: any): void {
|
||||
this._state = value;
|
||||
if (isPresent(value) && value.checked) {
|
||||
this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', true);
|
||||
}
|
||||
}
|
||||
|
||||
registerOnChange(fn: (_: any) => {}): void {
|
||||
this._fn = fn;
|
||||
this.onChange = () => {
|
||||
fn(new RadioButtonState(true, this._state.value));
|
||||
this._registry.select(this);
|
||||
};
|
||||
}
|
||||
|
||||
fireUncheck(): void { this._fn(new RadioButtonState(false, this._state.value)); }
|
||||
|
||||
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
|
||||
}
|
@ -36,11 +36,7 @@ export class NgSelectOption {
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'select[ngControl],select[ngFormControl],select[ngModel]',
|
||||
host: {
|
||||
'(change)': 'onChange($event.target.value)',
|
||||
'(input)': 'onChange($event.target.value)',
|
||||
'(blur)': 'onTouched()'
|
||||
},
|
||||
host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
|
||||
bindings: [SELECT_VALUE_ACCESSOR]
|
||||
})
|
||||
export class SelectControlValueAccessor implements ControlValueAccessor {
|
||||
@ -55,7 +51,7 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
|
||||
|
||||
writeValue(value: any): void {
|
||||
this.value = value;
|
||||
this._renderer.setElementProperty(this._elementRef, 'value', value);
|
||||
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', value);
|
||||
}
|
||||
|
||||
registerOnChange(fn: () => any): void { this.onChange = fn; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {isBlank, isPresent, looseIdentical} from 'angular2/src/facade/lang';
|
||||
import {isBlank, isPresent, looseIdentical, hasConstructor} from 'angular2/src/facade/lang';
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
|
||||
import {ControlContainer} from './control_container';
|
||||
@ -13,6 +13,7 @@ import {DefaultValueAccessor} from './default_value_accessor';
|
||||
import {NumberValueAccessor} from './number_value_accessor';
|
||||
import {CheckboxControlValueAccessor} from './checkbox_value_accessor';
|
||||
import {SelectControlValueAccessor} from './select_control_value_accessor';
|
||||
import {RadioControlValueAccessor} from './radio_control_value_accessor';
|
||||
import {normalizeValidator} from './normalize_validator';
|
||||
|
||||
|
||||
@ -80,13 +81,14 @@ export function selectValueAccessor(dir: NgControl,
|
||||
var defaultAccessor;
|
||||
var builtinAccessor;
|
||||
var customAccessor;
|
||||
|
||||
valueAccessors.forEach(v => {
|
||||
if (v instanceof DefaultValueAccessor) {
|
||||
if (hasConstructor(v, DefaultValueAccessor)) {
|
||||
defaultAccessor = v;
|
||||
|
||||
} else if (v instanceof CheckboxControlValueAccessor || v instanceof NumberValueAccessor ||
|
||||
v instanceof SelectControlValueAccessor) {
|
||||
} else if (hasConstructor(v, CheckboxControlValueAccessor) ||
|
||||
hasConstructor(v, NumberValueAccessor) ||
|
||||
hasConstructor(v, SelectControlValueAccessor) ||
|
||||
hasConstructor(v, RadioControlValueAccessor)) {
|
||||
if (isPresent(builtinAccessor))
|
||||
_throwError(dir, "More than one built-in value accessor matches");
|
||||
builtinAccessor = v;
|
||||
|
@ -106,21 +106,3 @@ export class FormBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand set of providers used for building Angular forms.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* bootstrap(MyApp, [FORM_PROVIDERS]);
|
||||
* ```
|
||||
*/
|
||||
export const FORM_PROVIDERS: Type[] = CONST_EXPR([FormBuilder]);
|
||||
|
||||
/**
|
||||
* See {@link FORM_PROVIDERS} instead.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
export const FORM_BINDINGS = FORM_PROVIDERS;
|
||||
|
@ -14,7 +14,7 @@ export const VALID = "VALID";
|
||||
export const INVALID = "INVALID";
|
||||
|
||||
/**
|
||||
* Indicates that a Control is pending, i.e. that async validation is occuring and
|
||||
* Indicates that a Control is pending, i.e. that async validation is occurring and
|
||||
* errors are not yet available for the input value.
|
||||
*/
|
||||
export const PENDING = "PENDING";
|
||||
@ -208,6 +208,16 @@ export abstract class AbstractControl {
|
||||
return isPresent(this.getError(errorCode, path));
|
||||
}
|
||||
|
||||
get root(): AbstractControl {
|
||||
let x: AbstractControl = this;
|
||||
|
||||
while (isPresent(x._parent)) {
|
||||
x = x._parent;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_updateControlsErrors(): void {
|
||||
this._status = this._calculateStatus();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {isBlank, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {isBlank, isPresent, CONST_EXPR, isString} from 'angular2/src/facade/lang';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/promise';
|
||||
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
@ -44,7 +44,9 @@ export class Validators {
|
||||
* Validator that requires controls to have a non-empty value.
|
||||
*/
|
||||
static required(control: modelModule.Control): {[key: string]: boolean} {
|
||||
return isBlank(control.value) || control.value == "" ? {"required": true} : null;
|
||||
return isBlank(control.value) || (isString(control.value) && control.value == "") ?
|
||||
{"required": true} :
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {isBlank, isPresent, isPromise, CONST} from 'angular2/src/facade/lang';
|
||||
import {Promise, ObservableWrapper, Observable, EventEmitter} from 'angular2/src/facade/async';
|
||||
import {ObservableWrapper, Observable, EventEmitter} from 'angular2/src/facade/async';
|
||||
import {
|
||||
Pipe,
|
||||
Injectable,
|
||||
@ -33,7 +33,7 @@ class PromiseStrategy {
|
||||
|
||||
var _promiseStrategy = new PromiseStrategy();
|
||||
var _observableStrategy = new ObservableStrategy();
|
||||
|
||||
var __unused: Promise<any>; // avoid unused import when Promise union types are erased
|
||||
|
||||
/**
|
||||
* The `async` pipe subscribes to an Observable or Promise and returns the latest value it has
|
||||
@ -81,6 +81,7 @@ export class AsyncPipe implements PipeTransform, OnDestroy {
|
||||
if (isPresent(obj)) {
|
||||
this._subscribe(obj);
|
||||
}
|
||||
this._latestReturnedValue = this._latestValue;
|
||||
return this._latestValue;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||
|
||||
@ -43,7 +43,7 @@ export function createChangeDetectorDefinitions(
|
||||
|
||||
class ProtoViewVisitor implements TemplateAstVisitor {
|
||||
viewIndex: number;
|
||||
boundTextCount: number = 0;
|
||||
nodeCount: number = 0;
|
||||
boundElementCount: number = 0;
|
||||
variableNames: string[] = [];
|
||||
bindingRecords: BindingRecord[] = [];
|
||||
@ -57,6 +57,7 @@ class ProtoViewVisitor implements TemplateAstVisitor {
|
||||
}
|
||||
|
||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
|
||||
this.nodeCount++;
|
||||
this.boundElementCount++;
|
||||
templateVisitAll(this, ast.outputs);
|
||||
for (var i = 0; i < ast.directives.length; i++) {
|
||||
@ -73,6 +74,7 @@ class ProtoViewVisitor implements TemplateAstVisitor {
|
||||
}
|
||||
|
||||
visitElement(ast: ElementAst, context: any): any {
|
||||
this.nodeCount++;
|
||||
if (ast.isBound()) {
|
||||
this.boundElementCount++;
|
||||
}
|
||||
@ -132,14 +134,20 @@ class ProtoViewVisitor implements TemplateAstVisitor {
|
||||
}
|
||||
visitAttr(ast: AttrAst, context: any): any { return null; }
|
||||
visitBoundText(ast: BoundTextAst, context: any): any {
|
||||
var boundTextIndex = this.boundTextCount++;
|
||||
this.bindingRecords.push(BindingRecord.createForTextNode(ast.value, boundTextIndex));
|
||||
var nodeIndex = this.nodeCount++;
|
||||
this.bindingRecords.push(BindingRecord.createForTextNode(ast.value, nodeIndex));
|
||||
return null;
|
||||
}
|
||||
visitText(ast: TextAst, context: any): any {
|
||||
this.nodeCount++;
|
||||
return null;
|
||||
}
|
||||
visitText(ast: TextAst, context: any): any { return null; }
|
||||
visitDirective(ast: DirectiveAst, directiveIndexAsNumber: number): any {
|
||||
var directiveIndex = new DirectiveIndex(this.boundElementCount - 1, directiveIndexAsNumber);
|
||||
var directiveMetadata = ast.directive;
|
||||
var outputsArray = [];
|
||||
StringMapWrapper.forEach(ast.directive.outputs, (eventName, dirProperty) => outputsArray.push(
|
||||
[dirProperty, eventName]));
|
||||
var directiveRecord = new DirectiveRecord({
|
||||
directiveIndex: directiveIndex,
|
||||
callAfterContentInit:
|
||||
@ -153,7 +161,9 @@ class ProtoViewVisitor implements TemplateAstVisitor {
|
||||
callOnChanges: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1,
|
||||
callDoCheck: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.DoCheck) !== -1,
|
||||
callOnInit: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnInit) !== -1,
|
||||
changeDetection: directiveMetadata.changeDetection
|
||||
callOnDestroy: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1,
|
||||
changeDetection: directiveMetadata.changeDetection,
|
||||
outputs: outputsArray
|
||||
});
|
||||
this.directiveRecords.push(directiveRecord);
|
||||
|
||||
|
@ -3,6 +3,9 @@ import {SourceExpressions, moduleRef} from './source_module';
|
||||
import {
|
||||
ChangeDetectorJITGenerator
|
||||
} from 'angular2/src/core/change_detection/change_detection_jit_generator';
|
||||
import {AbstractChangeDetector} from 'angular2/src/core/change_detection/abstract_change_detector';
|
||||
import {ChangeDetectionUtil} from 'angular2/src/core/change_detection/change_detection_util';
|
||||
import {ChangeDetectorState} from 'angular2/src/core/change_detection/constants';
|
||||
|
||||
import {createChangeDetectorDefinitions} from './change_definition_factory';
|
||||
import {IS_DART, isJsObject, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
@ -23,6 +26,12 @@ const ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
|
||||
const UTIL = "ChangeDetectionUtil";
|
||||
const CHANGE_DETECTOR_STATE = "ChangeDetectorState";
|
||||
|
||||
export const CHANGE_DETECTION_JIT_IMPORTS = CONST_EXPR({
|
||||
'AbstractChangeDetector': AbstractChangeDetector,
|
||||
'ChangeDetectionUtil': ChangeDetectionUtil,
|
||||
'ChangeDetectorState': ChangeDetectorState
|
||||
});
|
||||
|
||||
var ABSTRACT_CHANGE_DETECTOR_MODULE = moduleRef(
|
||||
`package:angular2/src/core/change_detection/abstract_change_detector${MODULE_SUFFIX}`);
|
||||
var UTIL_MODULE =
|
||||
@ -45,14 +54,8 @@ export class ChangeDetectionCompiler {
|
||||
}
|
||||
|
||||
private _createChangeDetectorFactory(definition: ChangeDetectorDefinition): Function {
|
||||
if (IS_DART || !this._genConfig.useJit) {
|
||||
var proto = new DynamicProtoChangeDetector(definition);
|
||||
return (dispatcher) => proto.instantiate(dispatcher);
|
||||
} else {
|
||||
return new ChangeDetectorJITGenerator(definition, UTIL, ABSTRACT_CHANGE_DETECTOR,
|
||||
CHANGE_DETECTOR_STATE)
|
||||
.generate();
|
||||
}
|
||||
return () => proto.instantiate();
|
||||
}
|
||||
|
||||
compileComponentCodeGen(componentType: CompileTypeMetadata, strategy: ChangeDetectionStrategy,
|
||||
@ -81,7 +84,7 @@ export class ChangeDetectionCompiler {
|
||||
definition, `${UTIL_MODULE}${UTIL}`,
|
||||
`${ABSTRACT_CHANGE_DETECTOR_MODULE}${ABSTRACT_CHANGE_DETECTOR}`,
|
||||
`${CONSTANTS_MODULE}${CHANGE_DETECTOR_STATE}`);
|
||||
factories.push(`function(dispatcher) { return new ${codegen.typeName}(dispatcher); }`);
|
||||
factories.push(`function() { return new ${codegen.typeName}(); }`);
|
||||
sourcePart = codegen.generateSource();
|
||||
}
|
||||
index++;
|
||||
|
@ -1,375 +0,0 @@
|
||||
import {isPresent, isBlank, Type, isString, StringWrapper, IS_DART} from 'angular2/src/facade/lang';
|
||||
import {SetWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
TemplateCmd,
|
||||
TextCmd,
|
||||
NgContentCmd,
|
||||
BeginElementCmd,
|
||||
EndElementCmd,
|
||||
BeginComponentCmd,
|
||||
EndComponentCmd,
|
||||
EmbeddedTemplateCmd,
|
||||
CompiledComponentTemplate
|
||||
} from 'angular2/src/core/linker/template_commands';
|
||||
import {
|
||||
TemplateAst,
|
||||
TemplateAstVisitor,
|
||||
NgContentAst,
|
||||
EmbeddedTemplateAst,
|
||||
ElementAst,
|
||||
VariableAst,
|
||||
BoundEventAst,
|
||||
BoundElementPropertyAst,
|
||||
AttrAst,
|
||||
BoundTextAst,
|
||||
TextAst,
|
||||
DirectiveAst,
|
||||
BoundDirectivePropertyAst,
|
||||
templateVisitAll
|
||||
} from './template_ast';
|
||||
import {CompileTypeMetadata, CompileDirectiveMetadata} from './directive_metadata';
|
||||
import {SourceExpressions, SourceExpression, moduleRef} from './source_module';
|
||||
|
||||
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
|
||||
import {
|
||||
escapeSingleQuoteString,
|
||||
codeGenConstConstructorCall,
|
||||
codeGenValueFn,
|
||||
MODULE_SUFFIX
|
||||
} from './util';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
|
||||
export var TEMPLATE_COMMANDS_MODULE_REF =
|
||||
moduleRef(`package:angular2/src/core/linker/template_commands${MODULE_SUFFIX}`);
|
||||
|
||||
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
||||
const CLASS_ATTR = 'class';
|
||||
const STYLE_ATTR = 'style';
|
||||
|
||||
@Injectable()
|
||||
export class CommandCompiler {
|
||||
compileComponentRuntime(component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
changeDetectorFactories: Function[],
|
||||
componentTemplateFactory: Function): TemplateCmd[] {
|
||||
var visitor = new CommandBuilderVisitor(
|
||||
new RuntimeCommandFactory(component, componentTemplateFactory, changeDetectorFactories), 0);
|
||||
templateVisitAll(visitor, template);
|
||||
return visitor.result;
|
||||
}
|
||||
|
||||
compileComponentCodeGen(component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
changeDetectorFactoryExpressions: string[],
|
||||
componentTemplateFactory: Function): SourceExpression {
|
||||
var visitor =
|
||||
new CommandBuilderVisitor(new CodegenCommandFactory(component, componentTemplateFactory,
|
||||
changeDetectorFactoryExpressions),
|
||||
0);
|
||||
templateVisitAll(visitor, template);
|
||||
return new SourceExpression([], codeGenArray(visitor.result));
|
||||
}
|
||||
}
|
||||
|
||||
interface CommandFactory<R> {
|
||||
createText(value: string, isBound: boolean, ngContentIndex: number): R;
|
||||
createNgContent(index: number, ngContentIndex: number): R;
|
||||
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isBound: boolean, ngContentIndex: number): R;
|
||||
createEndElement(): R;
|
||||
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
encapsulation: ViewEncapsulation, ngContentIndex: number): R;
|
||||
createEndComponent(): R;
|
||||
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isMerged: boolean, ngContentIndex: number, children: R[]): R;
|
||||
}
|
||||
|
||||
class RuntimeCommandFactory implements CommandFactory<TemplateCmd> {
|
||||
constructor(private component: CompileDirectiveMetadata,
|
||||
private componentTemplateFactory: Function,
|
||||
private changeDetectorFactories: Function[]) {}
|
||||
private _mapDirectives(directives: CompileDirectiveMetadata[]): Type[] {
|
||||
return directives.map(directive => directive.type.runtime);
|
||||
}
|
||||
|
||||
createText(value: string, isBound: boolean, ngContentIndex: number): TemplateCmd {
|
||||
return new TextCmd(value, isBound, ngContentIndex);
|
||||
}
|
||||
createNgContent(index: number, ngContentIndex: number): TemplateCmd {
|
||||
return new NgContentCmd(index, ngContentIndex);
|
||||
}
|
||||
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isBound: boolean, ngContentIndex: number): TemplateCmd {
|
||||
return new BeginElementCmd(name, attrNameAndValues, eventTargetAndNames, variableNameAndValues,
|
||||
this._mapDirectives(directives), isBound, ngContentIndex);
|
||||
}
|
||||
createEndElement(): TemplateCmd { return new EndElementCmd(); }
|
||||
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
encapsulation: ViewEncapsulation, ngContentIndex: number): TemplateCmd {
|
||||
var nestedTemplateAccessor = this.componentTemplateFactory(directives[0]);
|
||||
return new BeginComponentCmd(name, attrNameAndValues, eventTargetAndNames,
|
||||
variableNameAndValues, this._mapDirectives(directives),
|
||||
encapsulation, ngContentIndex, nestedTemplateAccessor);
|
||||
}
|
||||
createEndComponent(): TemplateCmd { return new EndComponentCmd(); }
|
||||
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isMerged: boolean, ngContentIndex: number,
|
||||
children: TemplateCmd[]): TemplateCmd {
|
||||
return new EmbeddedTemplateCmd(attrNameAndValues, variableNameAndValues,
|
||||
this._mapDirectives(directives), isMerged, ngContentIndex,
|
||||
this.changeDetectorFactories[embeddedTemplateIndex], children);
|
||||
}
|
||||
}
|
||||
|
||||
class CodegenCommandFactory implements CommandFactory<Expression> {
|
||||
constructor(private component: CompileDirectiveMetadata,
|
||||
private componentTemplateFactory: Function,
|
||||
private changeDetectorFactoryExpressions: string[]) {}
|
||||
|
||||
createText(value: string, isBound: boolean, ngContentIndex: number): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'TextCmd')}(${escapeSingleQuoteString(value)}, ${isBound}, ${ngContentIndex})`);
|
||||
}
|
||||
createNgContent(index: number, ngContentIndex: number): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'NgContentCmd')}(${index}, ${ngContentIndex})`);
|
||||
}
|
||||
createBeginElement(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isBound: boolean, ngContentIndex: number): Expression {
|
||||
var attrsExpression = codeGenArray(attrNameAndValues);
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'BeginElementCmd')}(${escapeSingleQuoteString(name)}, ${attrsExpression}, ` +
|
||||
`${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${isBound}, ${ngContentIndex})`);
|
||||
}
|
||||
createEndElement(): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EndElementCmd')}()`);
|
||||
}
|
||||
createBeginComponent(name: string, attrNameAndValues: string[], eventTargetAndNames: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
encapsulation: ViewEncapsulation, ngContentIndex: number): Expression {
|
||||
var attrsExpression = codeGenArray(attrNameAndValues);
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'BeginComponentCmd')}(${escapeSingleQuoteString(name)}, ${attrsExpression}, ` +
|
||||
`${codeGenArray(eventTargetAndNames)}, ${codeGenArray(variableNameAndValues)}, ${codeGenDirectivesArray(directives)}, ${codeGenViewEncapsulation(encapsulation)}, ${ngContentIndex}, ${this.componentTemplateFactory(directives[0])})`);
|
||||
}
|
||||
createEndComponent(): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EndComponentCmd')}()`);
|
||||
}
|
||||
createEmbeddedTemplate(embeddedTemplateIndex: number, attrNameAndValues: string[],
|
||||
variableNameAndValues: string[], directives: CompileDirectiveMetadata[],
|
||||
isMerged: boolean, ngContentIndex: number,
|
||||
children: Expression[]): Expression {
|
||||
return new Expression(
|
||||
`${codeGenConstConstructorCall(TEMPLATE_COMMANDS_MODULE_REF+'EmbeddedTemplateCmd')}(${codeGenArray(attrNameAndValues)}, ${codeGenArray(variableNameAndValues)}, ` +
|
||||
`${codeGenDirectivesArray(directives)}, ${isMerged}, ${ngContentIndex}, ${this.changeDetectorFactoryExpressions[embeddedTemplateIndex]}, ${codeGenArray(children)})`);
|
||||
}
|
||||
}
|
||||
|
||||
function visitAndReturnContext(visitor: TemplateAstVisitor, asts: TemplateAst[],
|
||||
context: any): any {
|
||||
templateVisitAll(visitor, asts, context);
|
||||
return context;
|
||||
}
|
||||
|
||||
class CommandBuilderVisitor<R> implements TemplateAstVisitor {
|
||||
result: R[] = [];
|
||||
transitiveNgContentCount: number = 0;
|
||||
constructor(public commandFactory: CommandFactory<R>, public embeddedTemplateIndex: number) {}
|
||||
|
||||
private _readAttrNameAndValues(directives: CompileDirectiveMetadata[],
|
||||
attrAsts: TemplateAst[]): string[] {
|
||||
var attrs = keyValueArrayToMap(visitAndReturnContext(this, attrAsts, []));
|
||||
directives.forEach(directiveMeta => {
|
||||
StringMapWrapper.forEach(directiveMeta.hostAttributes, (value, name) => {
|
||||
var prevValue = attrs[name];
|
||||
attrs[name] = isPresent(prevValue) ? mergeAttributeValue(name, prevValue, value) : value;
|
||||
});
|
||||
});
|
||||
return mapToKeyValueArray(attrs);
|
||||
}
|
||||
|
||||
visitNgContent(ast: NgContentAst, context: any): any {
|
||||
this.transitiveNgContentCount++;
|
||||
this.result.push(this.commandFactory.createNgContent(ast.index, ast.ngContentIndex));
|
||||
return null;
|
||||
}
|
||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
|
||||
this.embeddedTemplateIndex++;
|
||||
var childVisitor = new CommandBuilderVisitor(this.commandFactory, this.embeddedTemplateIndex);
|
||||
templateVisitAll(childVisitor, ast.children);
|
||||
var isMerged = childVisitor.transitiveNgContentCount > 0;
|
||||
var variableNameAndValues = [];
|
||||
ast.vars.forEach((varAst) => {
|
||||
variableNameAndValues.push(varAst.name);
|
||||
variableNameAndValues.push(varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR);
|
||||
});
|
||||
var directives = [];
|
||||
ListWrapper.forEachWithIndex(ast.directives, (directiveAst: DirectiveAst, index: number) => {
|
||||
directiveAst.visit(this, new DirectiveContext(index, [], [], directives));
|
||||
});
|
||||
this.result.push(this.commandFactory.createEmbeddedTemplate(
|
||||
this.embeddedTemplateIndex, this._readAttrNameAndValues(directives, ast.attrs),
|
||||
variableNameAndValues, directives, isMerged, ast.ngContentIndex, childVisitor.result));
|
||||
this.transitiveNgContentCount += childVisitor.transitiveNgContentCount;
|
||||
this.embeddedTemplateIndex = childVisitor.embeddedTemplateIndex;
|
||||
return null;
|
||||
}
|
||||
visitElement(ast: ElementAst, context: any): any {
|
||||
var component = ast.getComponent();
|
||||
var eventTargetAndNames = visitAndReturnContext(this, ast.outputs, []);
|
||||
var variableNameAndValues = [];
|
||||
if (isBlank(component)) {
|
||||
ast.exportAsVars.forEach((varAst) => {
|
||||
variableNameAndValues.push(varAst.name);
|
||||
variableNameAndValues.push(null);
|
||||
});
|
||||
}
|
||||
var directives = [];
|
||||
ListWrapper.forEachWithIndex(ast.directives, (directiveAst: DirectiveAst, index: number) => {
|
||||
directiveAst.visit(this, new DirectiveContext(index, eventTargetAndNames,
|
||||
variableNameAndValues, directives));
|
||||
});
|
||||
eventTargetAndNames = removeKeyValueArrayDuplicates(eventTargetAndNames);
|
||||
|
||||
var attrNameAndValues = this._readAttrNameAndValues(directives, ast.attrs);
|
||||
if (isPresent(component)) {
|
||||
this.result.push(this.commandFactory.createBeginComponent(
|
||||
ast.name, attrNameAndValues, eventTargetAndNames, variableNameAndValues, directives,
|
||||
component.template.encapsulation, ast.ngContentIndex));
|
||||
templateVisitAll(this, ast.children);
|
||||
this.result.push(this.commandFactory.createEndComponent());
|
||||
} else {
|
||||
this.result.push(this.commandFactory.createBeginElement(
|
||||
ast.name, attrNameAndValues, eventTargetAndNames, variableNameAndValues, directives,
|
||||
ast.isBound(), ast.ngContentIndex));
|
||||
templateVisitAll(this, ast.children);
|
||||
this.result.push(this.commandFactory.createEndElement());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
||||
visitAttr(ast: AttrAst, attrNameAndValues: string[]): any {
|
||||
attrNameAndValues.push(ast.name);
|
||||
attrNameAndValues.push(ast.value);
|
||||
return null;
|
||||
}
|
||||
visitBoundText(ast: BoundTextAst, context: any): any {
|
||||
this.result.push(this.commandFactory.createText(null, true, ast.ngContentIndex));
|
||||
return null;
|
||||
}
|
||||
visitText(ast: TextAst, context: any): any {
|
||||
this.result.push(this.commandFactory.createText(ast.value, false, ast.ngContentIndex));
|
||||
return null;
|
||||
}
|
||||
visitDirective(ast: DirectiveAst, ctx: DirectiveContext): any {
|
||||
ctx.targetDirectives.push(ast.directive);
|
||||
templateVisitAll(this, ast.hostEvents, ctx.eventTargetAndNames);
|
||||
ast.exportAsVars.forEach(varAst => {
|
||||
ctx.targetVariableNameAndValues.push(varAst.name);
|
||||
ctx.targetVariableNameAndValues.push(ctx.index);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
visitEvent(ast: BoundEventAst, eventTargetAndNames: string[]): any {
|
||||
eventTargetAndNames.push(ast.target);
|
||||
eventTargetAndNames.push(ast.name);
|
||||
return null;
|
||||
}
|
||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
||||
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
|
||||
}
|
||||
|
||||
function removeKeyValueArrayDuplicates(keyValueArray: string[]): string[] {
|
||||
var knownPairs = new Set();
|
||||
var resultKeyValueArray = [];
|
||||
for (var i = 0; i < keyValueArray.length; i += 2) {
|
||||
var key = keyValueArray[i];
|
||||
var value = keyValueArray[i + 1];
|
||||
var pairId = `${key}:${value}`;
|
||||
if (!SetWrapper.has(knownPairs, pairId)) {
|
||||
resultKeyValueArray.push(key);
|
||||
resultKeyValueArray.push(value);
|
||||
knownPairs.add(pairId);
|
||||
}
|
||||
}
|
||||
return resultKeyValueArray;
|
||||
}
|
||||
|
||||
function keyValueArrayToMap(keyValueArr: string[]): {[key: string]: string} {
|
||||
var data: {[key: string]: string} = {};
|
||||
for (var i = 0; i < keyValueArr.length; i += 2) {
|
||||
data[keyValueArr[i]] = keyValueArr[i + 1];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function mapToKeyValueArray(data: {[key: string]: string}): string[] {
|
||||
var entryArray = [];
|
||||
StringMapWrapper.forEach(data, (value, name) => { entryArray.push([name, value]); });
|
||||
// We need to sort to get a defined output order
|
||||
// for tests and for caching generated artifacts...
|
||||
ListWrapper.sort(entryArray, (entry1, entry2) => StringWrapper.compare(entry1[0], entry2[0]));
|
||||
var keyValueArray = [];
|
||||
entryArray.forEach((entry) => {
|
||||
keyValueArray.push(entry[0]);
|
||||
keyValueArray.push(entry[1]);
|
||||
});
|
||||
return keyValueArray;
|
||||
}
|
||||
|
||||
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
|
||||
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
|
||||
return `${attrValue1} ${attrValue2}`;
|
||||
} else {
|
||||
return attrValue2;
|
||||
}
|
||||
}
|
||||
|
||||
class DirectiveContext {
|
||||
constructor(public index: number, public eventTargetAndNames: string[],
|
||||
public targetVariableNameAndValues: any[],
|
||||
public targetDirectives: CompileDirectiveMetadata[]) {}
|
||||
}
|
||||
|
||||
class Expression {
|
||||
constructor(public value: string) {}
|
||||
}
|
||||
|
||||
function escapeValue(value: any): string {
|
||||
if (value instanceof Expression) {
|
||||
return value.value;
|
||||
} else if (isString(value)) {
|
||||
return escapeSingleQuoteString(value);
|
||||
} else if (isBlank(value)) {
|
||||
return 'null';
|
||||
} else {
|
||||
return `${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
function codeGenArray(data: any[]): string {
|
||||
var base = `[${data.map(escapeValue).join(',')}]`;
|
||||
return IS_DART ? `const ${base}` : base;
|
||||
}
|
||||
|
||||
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
|
||||
var expressions = directives.map(
|
||||
directiveType => `${moduleRef(directiveType.type.moduleUrl)}${directiveType.type.name}`);
|
||||
var base = `[${expressions.join(',')}]`;
|
||||
return IS_DART ? `const ${base}` : base;
|
||||
}
|
||||
|
||||
function codeGenViewEncapsulation(value: ViewEncapsulation): string {
|
||||
if (IS_DART) {
|
||||
return `${TEMPLATE_COMMANDS_MODULE_REF}${value}`;
|
||||
} else {
|
||||
return `${value}`;
|
||||
}
|
||||
}
|
@ -17,7 +17,8 @@ import {TemplateNormalizer} from 'angular2/src/compiler/template_normalizer';
|
||||
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
|
||||
import {ChangeDetectionCompiler} from 'angular2/src/compiler/change_detector_compiler';
|
||||
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
|
||||
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
|
||||
import {ViewCompiler} from 'angular2/src/compiler/view_compiler';
|
||||
import {ProtoViewCompiler} from 'angular2/src/compiler/proto_view_compiler';
|
||||
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
|
||||
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {Compiler} from 'angular2/src/core/linker/compiler';
|
||||
@ -44,7 +45,8 @@ export const COMPILER_PROVIDERS: Array<Type | Provider | any[]> = CONST_EXPR([
|
||||
RuntimeMetadataResolver,
|
||||
DEFAULT_PACKAGE_URL_PROVIDER,
|
||||
StyleCompiler,
|
||||
CommandCompiler,
|
||||
ProtoViewCompiler,
|
||||
ViewCompiler,
|
||||
ChangeDetectionCompiler,
|
||||
new Provider(ChangeDetectorGenConfig, {useFactory: _createChangeDetectorGenConfig, deps: []}),
|
||||
TemplateCompiler,
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
RegExpWrapper,
|
||||
StringWrapper
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {unimplemented} from 'angular2/src/facade/exceptions';
|
||||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
@ -21,6 +22,16 @@ import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/linker/i
|
||||
// group 2: "event" from "(event)"
|
||||
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
|
||||
|
||||
export abstract class CompileMetadataWithType {
|
||||
static fromJson(data: {[key: string]: any}): CompileMetadataWithType {
|
||||
return _COMPILE_METADATA_FROM_JSON[data['class']](data);
|
||||
}
|
||||
|
||||
abstract toJson(): {[key: string]: any};
|
||||
|
||||
get type(): CompileTypeMetadata { return unimplemented(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata regarding compilation of a type.
|
||||
*/
|
||||
@ -107,7 +118,7 @@ export class CompileTemplateMetadata {
|
||||
/**
|
||||
* Metadata regarding compilation of a directive.
|
||||
*/
|
||||
export class CompileDirectiveMetadata {
|
||||
export class CompileDirectiveMetadata implements CompileMetadataWithType {
|
||||
static create({type, isComponent, dynamicLoadable, selector, exportAs, changeDetection, inputs,
|
||||
outputs, host, lifecycleHooks, template}: {
|
||||
type?: CompileTypeMetadata,
|
||||
@ -241,6 +252,7 @@ export class CompileDirectiveMetadata {
|
||||
|
||||
toJson(): {[key: string]: any} {
|
||||
return {
|
||||
'class': 'Directive',
|
||||
'isComponent': this.isComponent,
|
||||
'dynamicLoadable': this.dynamicLoadable,
|
||||
'selector': this.selector,
|
||||
@ -284,3 +296,38 @@ export function createHostComponentMeta(componentType: CompileTypeMetadata,
|
||||
selector: '*'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export class CompilePipeMetadata implements CompileMetadataWithType {
|
||||
type: CompileTypeMetadata;
|
||||
name: string;
|
||||
pure: boolean;
|
||||
constructor({type, name,
|
||||
pure}: {type?: CompileTypeMetadata, name?: string, pure?: boolean} = {}) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.pure = normalizeBool(pure);
|
||||
}
|
||||
|
||||
static fromJson(data: {[key: string]: any}): CompilePipeMetadata {
|
||||
return new CompilePipeMetadata({
|
||||
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
|
||||
name: data['name'],
|
||||
pure: data['pure']
|
||||
});
|
||||
}
|
||||
|
||||
toJson(): {[key: string]: any} {
|
||||
return {
|
||||
'class': 'Pipe',
|
||||
'type': isPresent(this.type) ? this.type.toJson() : null,
|
||||
'name': this.name,
|
||||
'pure': this.pure
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var _COMPILE_METADATA_FROM_JSON = {
|
||||
'Directive': CompileDirectiveMetadata.fromJson,
|
||||
'Pipe': CompilePipeMetadata.fromJson
|
||||
};
|
||||
|
@ -73,10 +73,13 @@ const $LT = 60;
|
||||
const $EQ = 61;
|
||||
const $GT = 62;
|
||||
const $QUESTION = 63;
|
||||
const $A = 65;
|
||||
const $Z = 90;
|
||||
const $LBRACKET = 91;
|
||||
const $RBRACKET = 93;
|
||||
const $A = 65;
|
||||
const $F = 70;
|
||||
const $X = 88;
|
||||
const $Z = 90;
|
||||
|
||||
const $a = 97;
|
||||
const $f = 102;
|
||||
const $z = 122;
|
||||
@ -102,7 +105,6 @@ class ControlFlowError {
|
||||
// See http://www.w3.org/TR/html51/syntax.html#writing
|
||||
class _HtmlTokenizer {
|
||||
private input: string;
|
||||
private inputLowercase: string;
|
||||
private length: number;
|
||||
// Note: this is always lowercase!
|
||||
private peek: number = -1;
|
||||
@ -117,7 +119,6 @@ class _HtmlTokenizer {
|
||||
|
||||
constructor(private file: ParseSourceFile) {
|
||||
this.input = file.content;
|
||||
this.inputLowercase = file.content.toLowerCase();
|
||||
this.length = file.content.length;
|
||||
this._advance();
|
||||
}
|
||||
@ -133,16 +134,16 @@ class _HtmlTokenizer {
|
||||
while (this.peek !== $EOF) {
|
||||
var start = this._getLocation();
|
||||
try {
|
||||
if (this._attemptChar($LT)) {
|
||||
if (this._attemptChar($BANG)) {
|
||||
if (this._attemptChar($LBRACKET)) {
|
||||
if (this._attemptCharCode($LT)) {
|
||||
if (this._attemptCharCode($BANG)) {
|
||||
if (this._attemptCharCode($LBRACKET)) {
|
||||
this._consumeCdata(start);
|
||||
} else if (this._attemptChar($MINUS)) {
|
||||
} else if (this._attemptCharCode($MINUS)) {
|
||||
this._consumeComment(start);
|
||||
} else {
|
||||
this._consumeDocType(start);
|
||||
}
|
||||
} else if (this._attemptChar($SLASH)) {
|
||||
} else if (this._attemptCharCode($SLASH)) {
|
||||
this._consumeTagClose(start);
|
||||
} else {
|
||||
this._consumeTagOpen(start);
|
||||
@ -205,11 +206,10 @@ class _HtmlTokenizer {
|
||||
this.column++;
|
||||
}
|
||||
this.index++;
|
||||
this.peek = this.index >= this.length ? $EOF : StringWrapper.charCodeAt(this.inputLowercase,
|
||||
this.index);
|
||||
this.peek = this.index >= this.length ? $EOF : StringWrapper.charCodeAt(this.input, this.index);
|
||||
}
|
||||
|
||||
private _attemptChar(charCode: number): boolean {
|
||||
private _attemptCharCode(charCode: number): boolean {
|
||||
if (this.peek === charCode) {
|
||||
this._advance();
|
||||
return true;
|
||||
@ -217,38 +217,55 @@ class _HtmlTokenizer {
|
||||
return false;
|
||||
}
|
||||
|
||||
private _requireChar(charCode: number) {
|
||||
private _attemptCharCodeCaseInsensitive(charCode: number): boolean {
|
||||
if (compareCharCodeCaseInsensitive(this.peek, charCode)) {
|
||||
this._advance();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private _requireCharCode(charCode: number) {
|
||||
var location = this._getLocation();
|
||||
if (!this._attemptChar(charCode)) {
|
||||
if (!this._attemptCharCode(charCode)) {
|
||||
throw this._createError(unexpectedCharacterErrorMsg(this.peek), location);
|
||||
}
|
||||
}
|
||||
|
||||
private _attemptChars(chars: string): boolean {
|
||||
private _attemptStr(chars: string): boolean {
|
||||
for (var i = 0; i < chars.length; i++) {
|
||||
if (!this._attemptChar(StringWrapper.charCodeAt(chars, i))) {
|
||||
if (!this._attemptCharCode(StringWrapper.charCodeAt(chars, i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private _requireChars(chars: string) {
|
||||
private _attemptStrCaseInsensitive(chars: string): boolean {
|
||||
for (var i = 0; i < chars.length; i++) {
|
||||
if (!this._attemptCharCodeCaseInsensitive(StringWrapper.charCodeAt(chars, i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private _requireStr(chars: string) {
|
||||
var location = this._getLocation();
|
||||
if (!this._attemptChars(chars)) {
|
||||
if (!this._attemptStr(chars)) {
|
||||
throw this._createError(unexpectedCharacterErrorMsg(this.peek), location);
|
||||
}
|
||||
}
|
||||
|
||||
private _attemptUntilFn(predicate: Function) {
|
||||
private _attemptCharCodeUntilFn(predicate: Function) {
|
||||
while (!predicate(this.peek)) {
|
||||
this._advance();
|
||||
}
|
||||
}
|
||||
|
||||
private _requireUntilFn(predicate: Function, len: number) {
|
||||
private _requireCharCodeUntilFn(predicate: Function, len: number) {
|
||||
var start = this._getLocation();
|
||||
this._attemptUntilFn(predicate);
|
||||
this._attemptCharCodeUntilFn(predicate);
|
||||
if (this.index - start.offset < len) {
|
||||
throw this._createError(unexpectedCharacterErrorMsg(this.peek), start);
|
||||
}
|
||||
@ -273,10 +290,10 @@ class _HtmlTokenizer {
|
||||
private _decodeEntity(): string {
|
||||
var start = this._getLocation();
|
||||
this._advance();
|
||||
if (this._attemptChar($HASH)) {
|
||||
let isHex = this._attemptChar($x);
|
||||
if (this._attemptCharCode($HASH)) {
|
||||
let isHex = this._attemptCharCode($x) || this._attemptCharCode($X);
|
||||
let numberStart = this._getLocation().offset;
|
||||
this._attemptUntilFn(isDigitEntityEnd);
|
||||
this._attemptCharCodeUntilFn(isDigitEntityEnd);
|
||||
if (this.peek != $SEMICOLON) {
|
||||
throw this._createError(unexpectedCharacterErrorMsg(this.peek), this._getLocation());
|
||||
}
|
||||
@ -291,7 +308,7 @@ class _HtmlTokenizer {
|
||||
}
|
||||
} else {
|
||||
let startPosition = this._savePosition();
|
||||
this._attemptUntilFn(isNamedEntityEnd);
|
||||
this._attemptCharCodeUntilFn(isNamedEntityEnd);
|
||||
if (this.peek != $SEMICOLON) {
|
||||
this._restorePosition(startPosition);
|
||||
return '&';
|
||||
@ -315,7 +332,7 @@ class _HtmlTokenizer {
|
||||
var parts = [];
|
||||
while (true) {
|
||||
tagCloseStart = this._getLocation();
|
||||
if (this._attemptChar(firstCharOfEnd) && attemptEndRest()) {
|
||||
if (this._attemptCharCode(firstCharOfEnd) && attemptEndRest()) {
|
||||
break;
|
||||
}
|
||||
if (this.index > tagCloseStart.offset) {
|
||||
@ -330,18 +347,18 @@ class _HtmlTokenizer {
|
||||
|
||||
private _consumeComment(start: ParseLocation) {
|
||||
this._beginToken(HtmlTokenType.COMMENT_START, start);
|
||||
this._requireChar($MINUS);
|
||||
this._requireCharCode($MINUS);
|
||||
this._endToken([]);
|
||||
var textToken = this._consumeRawText(false, $MINUS, () => this._attemptChars('->'));
|
||||
var textToken = this._consumeRawText(false, $MINUS, () => this._attemptStr('->'));
|
||||
this._beginToken(HtmlTokenType.COMMENT_END, textToken.sourceSpan.end);
|
||||
this._endToken([]);
|
||||
}
|
||||
|
||||
private _consumeCdata(start: ParseLocation) {
|
||||
this._beginToken(HtmlTokenType.CDATA_START, start);
|
||||
this._requireChars('cdata[');
|
||||
this._requireStr('CDATA[');
|
||||
this._endToken([]);
|
||||
var textToken = this._consumeRawText(false, $RBRACKET, () => this._attemptChars(']>'));
|
||||
var textToken = this._consumeRawText(false, $RBRACKET, () => this._attemptStr(']>'));
|
||||
this._beginToken(HtmlTokenType.CDATA_END, textToken.sourceSpan.end);
|
||||
this._endToken([]);
|
||||
}
|
||||
@ -367,7 +384,7 @@ class _HtmlTokenizer {
|
||||
} else {
|
||||
nameStart = nameOrPrefixStart;
|
||||
}
|
||||
this._requireUntilFn(isNameEnd, this.index === nameStart ? 1 : 0);
|
||||
this._requireCharCodeUntilFn(isNameEnd, this.index === nameStart ? 1 : 0);
|
||||
var name = this.input.substring(nameStart, this.index);
|
||||
return [prefix, name];
|
||||
}
|
||||
@ -381,16 +398,16 @@ class _HtmlTokenizer {
|
||||
}
|
||||
var nameStart = this.index;
|
||||
this._consumeTagOpenStart(start);
|
||||
lowercaseTagName = this.inputLowercase.substring(nameStart, this.index);
|
||||
this._attemptUntilFn(isNotWhitespace);
|
||||
lowercaseTagName = this.input.substring(nameStart, this.index).toLowerCase();
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
while (this.peek !== $SLASH && this.peek !== $GT) {
|
||||
this._consumeAttributeName();
|
||||
this._attemptUntilFn(isNotWhitespace);
|
||||
if (this._attemptChar($EQ)) {
|
||||
this._attemptUntilFn(isNotWhitespace);
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
if (this._attemptCharCode($EQ)) {
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
this._consumeAttributeValue();
|
||||
}
|
||||
this._attemptUntilFn(isNotWhitespace);
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
}
|
||||
this._consumeTagOpenEnd();
|
||||
} catch (e) {
|
||||
@ -416,11 +433,11 @@ class _HtmlTokenizer {
|
||||
|
||||
private _consumeRawTextWithTagClose(lowercaseTagName: string, decodeEntities: boolean) {
|
||||
var textToken = this._consumeRawText(decodeEntities, $LT, () => {
|
||||
if (!this._attemptChar($SLASH)) return false;
|
||||
this._attemptUntilFn(isNotWhitespace);
|
||||
if (!this._attemptChars(lowercaseTagName)) return false;
|
||||
this._attemptUntilFn(isNotWhitespace);
|
||||
if (!this._attemptChar($GT)) return false;
|
||||
if (!this._attemptCharCode($SLASH)) return false;
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
if (!this._attemptStrCaseInsensitive(lowercaseTagName)) return false;
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
if (!this._attemptCharCode($GT)) return false;
|
||||
return true;
|
||||
});
|
||||
this._beginToken(HtmlTokenType.TAG_CLOSE, textToken.sourceSpan.end);
|
||||
@ -453,27 +470,27 @@ class _HtmlTokenizer {
|
||||
this._advance();
|
||||
} else {
|
||||
var valueStart = this.index;
|
||||
this._requireUntilFn(isNameEnd, 1);
|
||||
this._requireCharCodeUntilFn(isNameEnd, 1);
|
||||
value = this.input.substring(valueStart, this.index);
|
||||
}
|
||||
this._endToken([this._processCarriageReturns(value)]);
|
||||
}
|
||||
|
||||
private _consumeTagOpenEnd() {
|
||||
var tokenType =
|
||||
this._attemptChar($SLASH) ? HtmlTokenType.TAG_OPEN_END_VOID : HtmlTokenType.TAG_OPEN_END;
|
||||
var tokenType = this._attemptCharCode($SLASH) ? HtmlTokenType.TAG_OPEN_END_VOID :
|
||||
HtmlTokenType.TAG_OPEN_END;
|
||||
this._beginToken(tokenType);
|
||||
this._requireChar($GT);
|
||||
this._requireCharCode($GT);
|
||||
this._endToken([]);
|
||||
}
|
||||
|
||||
private _consumeTagClose(start: ParseLocation) {
|
||||
this._beginToken(HtmlTokenType.TAG_CLOSE, start);
|
||||
this._attemptUntilFn(isNotWhitespace);
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
var prefixAndName;
|
||||
prefixAndName = this._consumePrefixAndName();
|
||||
this._attemptUntilFn(isNotWhitespace);
|
||||
this._requireChar($GT);
|
||||
this._attemptCharCodeUntilFn(isNotWhitespace);
|
||||
this._requireCharCode($GT);
|
||||
this._endToken(prefixAndName);
|
||||
}
|
||||
|
||||
@ -534,11 +551,19 @@ function isTextEnd(code: number): boolean {
|
||||
}
|
||||
|
||||
function isAsciiLetter(code: number): boolean {
|
||||
return code >= $a && code <= $z;
|
||||
return code >= $a && code <= $z || code >= $A && code <= $Z;
|
||||
}
|
||||
|
||||
function isAsciiHexDigit(code: number): boolean {
|
||||
return code >= $a && code <= $f || code >= $0 && code <= $9;
|
||||
return code >= $a && code <= $f || code >= $A && code <= $F || code >= $0 && code <= $9;
|
||||
}
|
||||
|
||||
function compareCharCodeCaseInsensitive(code1: number, code2: number): boolean {
|
||||
return toUpperCaseCharCode(code1) == toUpperCaseCharCode(code2);
|
||||
}
|
||||
|
||||
function toUpperCaseCharCode(code: number): number {
|
||||
return code >= $a && code <= $z ? code - $a + $A : code;
|
||||
}
|
||||
|
||||
function mergeTextTokens(srcTokens: HtmlToken[]): HtmlToken[] {
|
||||
|
397
modules/angular2/src/compiler/proto_view_compiler.ts
Normal file
397
modules/angular2/src/compiler/proto_view_compiler.ts
Normal file
@ -0,0 +1,397 @@
|
||||
import {
|
||||
isPresent,
|
||||
isBlank,
|
||||
Type,
|
||||
isString,
|
||||
StringWrapper,
|
||||
IS_DART,
|
||||
CONST_EXPR
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {
|
||||
SetWrapper,
|
||||
StringMapWrapper,
|
||||
ListWrapper,
|
||||
MapWrapper
|
||||
} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
TemplateAst,
|
||||
TemplateAstVisitor,
|
||||
NgContentAst,
|
||||
EmbeddedTemplateAst,
|
||||
ElementAst,
|
||||
VariableAst,
|
||||
BoundEventAst,
|
||||
BoundElementPropertyAst,
|
||||
AttrAst,
|
||||
BoundTextAst,
|
||||
TextAst,
|
||||
DirectiveAst,
|
||||
BoundDirectivePropertyAst,
|
||||
templateVisitAll
|
||||
} from './template_ast';
|
||||
import {
|
||||
CompileTypeMetadata,
|
||||
CompileDirectiveMetadata,
|
||||
CompilePipeMetadata
|
||||
} from './directive_metadata';
|
||||
import {SourceExpressions, SourceExpression, moduleRef} from './source_module';
|
||||
import {AppProtoView, AppView} from 'angular2/src/core/linker/view';
|
||||
import {ViewType} from 'angular2/src/core/linker/view_type';
|
||||
import {AppProtoElement, AppElement} from 'angular2/src/core/linker/element';
|
||||
import {ResolvedMetadataCache} from 'angular2/src/core/linker/resolved_metadata_cache';
|
||||
import {
|
||||
escapeSingleQuoteString,
|
||||
codeGenConstConstructorCall,
|
||||
codeGenValueFn,
|
||||
codeGenFnHeader,
|
||||
MODULE_SUFFIX,
|
||||
codeGenStringMap,
|
||||
Expression,
|
||||
Statement
|
||||
} from './util';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
|
||||
export const PROTO_VIEW_JIT_IMPORTS = CONST_EXPR(
|
||||
{'AppProtoView': AppProtoView, 'AppProtoElement': AppProtoElement, 'ViewType': ViewType});
|
||||
|
||||
// TODO: have a single file that reexports everything needed for
|
||||
// codegen explicitly
|
||||
// - helps understanding what codegen works against
|
||||
// - less imports in codegen code
|
||||
export var APP_VIEW_MODULE_REF = moduleRef('package:angular2/src/core/linker/view' + MODULE_SUFFIX);
|
||||
export var VIEW_TYPE_MODULE_REF =
|
||||
moduleRef('package:angular2/src/core/linker/view_type' + MODULE_SUFFIX);
|
||||
export var APP_EL_MODULE_REF =
|
||||
moduleRef('package:angular2/src/core/linker/element' + MODULE_SUFFIX);
|
||||
export var METADATA_MODULE_REF =
|
||||
moduleRef('package:angular2/src/core/metadata/view' + MODULE_SUFFIX);
|
||||
|
||||
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
||||
const CLASS_ATTR = 'class';
|
||||
const STYLE_ATTR = 'style';
|
||||
|
||||
@Injectable()
|
||||
export class ProtoViewCompiler {
|
||||
constructor() {}
|
||||
|
||||
compileProtoViewRuntime(metadataCache: ResolvedMetadataCache, component: CompileDirectiveMetadata,
|
||||
template: TemplateAst[], pipes: CompilePipeMetadata[]):
|
||||
CompileProtoViews<AppProtoView, AppProtoElement, any> {
|
||||
var protoViewFactory = new RuntimeProtoViewFactory(metadataCache, component, pipes);
|
||||
var allProtoViews = [];
|
||||
protoViewFactory.createCompileProtoView(template, [], [], allProtoViews);
|
||||
return new CompileProtoViews<AppProtoView, AppProtoElement, any>([], allProtoViews);
|
||||
}
|
||||
|
||||
compileProtoViewCodeGen(resolvedMetadataCacheExpr: Expression,
|
||||
component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
pipes: CompilePipeMetadata[]):
|
||||
CompileProtoViews<Expression, Expression, string> {
|
||||
var protoViewFactory = new CodeGenProtoViewFactory(resolvedMetadataCacheExpr, component, pipes);
|
||||
var allProtoViews = [];
|
||||
var allStatements = [];
|
||||
protoViewFactory.createCompileProtoView(template, [], allStatements, allProtoViews);
|
||||
return new CompileProtoViews<Expression, Expression, string>(
|
||||
allStatements.map(stmt => stmt.statement), allProtoViews);
|
||||
}
|
||||
}
|
||||
|
||||
export class CompileProtoViews<APP_PROTO_VIEW, APP_PROTO_EL, STATEMENT> {
|
||||
constructor(public declarations: STATEMENT[],
|
||||
public protoViews: CompileProtoView<APP_PROTO_VIEW, APP_PROTO_EL>[]) {}
|
||||
}
|
||||
|
||||
|
||||
export class CompileProtoView<APP_PROTO_VIEW, APP_PROTO_EL> {
|
||||
constructor(public embeddedTemplateIndex: number,
|
||||
public protoElements: CompileProtoElement<APP_PROTO_EL>[],
|
||||
public protoView: APP_PROTO_VIEW) {}
|
||||
}
|
||||
|
||||
export class CompileProtoElement<APP_PROTO_EL> {
|
||||
constructor(public boundElementIndex, public attrNameAndValues: string[][],
|
||||
public variableNameAndValues: string[][], public renderEvents: BoundEventAst[],
|
||||
public directives: CompileDirectiveMetadata[], public embeddedTemplateIndex: number,
|
||||
public appProtoEl: APP_PROTO_EL) {}
|
||||
}
|
||||
|
||||
function visitAndReturnContext(visitor: TemplateAstVisitor, asts: TemplateAst[],
|
||||
context: any): any {
|
||||
templateVisitAll(visitor, asts, context);
|
||||
return context;
|
||||
}
|
||||
|
||||
abstract class ProtoViewFactory<APP_PROTO_VIEW, APP_PROTO_EL, STATEMENT> {
|
||||
constructor(public component: CompileDirectiveMetadata) {}
|
||||
|
||||
abstract createAppProtoView(embeddedTemplateIndex: number, viewType: ViewType,
|
||||
templateVariableBindings: string[][],
|
||||
targetStatements: STATEMENT[]): APP_PROTO_VIEW;
|
||||
|
||||
abstract createAppProtoElement(boundElementIndex: number, attrNameAndValues: string[][],
|
||||
variableNameAndValues: string[][],
|
||||
directives: CompileDirectiveMetadata[],
|
||||
targetStatements: STATEMENT[]): APP_PROTO_EL;
|
||||
|
||||
createCompileProtoView(template: TemplateAst[], templateVariableBindings: string[][],
|
||||
targetStatements: STATEMENT[],
|
||||
targetProtoViews: CompileProtoView<APP_PROTO_VIEW, APP_PROTO_EL>[]):
|
||||
CompileProtoView<APP_PROTO_VIEW, APP_PROTO_EL> {
|
||||
var embeddedTemplateIndex = targetProtoViews.length;
|
||||
// Note: targetProtoViews needs to be in depth first order.
|
||||
// So we "reserve" a space here that we fill after the recursion is done
|
||||
targetProtoViews.push(null);
|
||||
var builder = new ProtoViewBuilderVisitor<APP_PROTO_VIEW, APP_PROTO_EL, any>(
|
||||
this, targetStatements, targetProtoViews);
|
||||
templateVisitAll(builder, template);
|
||||
var viewType = getViewType(this.component, embeddedTemplateIndex);
|
||||
var appProtoView = this.createAppProtoView(embeddedTemplateIndex, viewType,
|
||||
templateVariableBindings, targetStatements);
|
||||
var cpv = new CompileProtoView<APP_PROTO_VIEW, APP_PROTO_EL>(
|
||||
embeddedTemplateIndex, builder.protoElements, appProtoView);
|
||||
targetProtoViews[embeddedTemplateIndex] = cpv;
|
||||
return cpv;
|
||||
}
|
||||
}
|
||||
|
||||
class CodeGenProtoViewFactory extends ProtoViewFactory<Expression, Expression, Statement> {
|
||||
private _nextVarId: number = 0;
|
||||
|
||||
constructor(public resolvedMetadataCacheExpr: Expression, component: CompileDirectiveMetadata,
|
||||
public pipes: CompilePipeMetadata[]) {
|
||||
super(component);
|
||||
}
|
||||
|
||||
private _nextProtoViewVar(embeddedTemplateIndex: number): string {
|
||||
return `appProtoView${this._nextVarId++}_${this.component.type.name}${embeddedTemplateIndex}`;
|
||||
}
|
||||
|
||||
createAppProtoView(embeddedTemplateIndex: number, viewType: ViewType,
|
||||
templateVariableBindings: string[][],
|
||||
targetStatements: Statement[]): Expression {
|
||||
var protoViewVarName = this._nextProtoViewVar(embeddedTemplateIndex);
|
||||
var viewTypeExpr = codeGenViewType(viewType);
|
||||
var pipesExpr = embeddedTemplateIndex === 0 ?
|
||||
codeGenTypesArray(this.pipes.map(pipeMeta => pipeMeta.type)) :
|
||||
null;
|
||||
var statement =
|
||||
`var ${protoViewVarName} = ${APP_VIEW_MODULE_REF}AppProtoView.create(${this.resolvedMetadataCacheExpr.expression}, ${viewTypeExpr}, ${pipesExpr}, ${codeGenStringMap(templateVariableBindings)});`;
|
||||
targetStatements.push(new Statement(statement));
|
||||
return new Expression(protoViewVarName);
|
||||
}
|
||||
|
||||
createAppProtoElement(boundElementIndex: number, attrNameAndValues: string[][],
|
||||
variableNameAndValues: string[][], directives: CompileDirectiveMetadata[],
|
||||
targetStatements: Statement[]): Expression {
|
||||
var varName = `appProtoEl${this._nextVarId++}_${this.component.type.name}`;
|
||||
var value = `${APP_EL_MODULE_REF}AppProtoElement.create(
|
||||
${this.resolvedMetadataCacheExpr.expression},
|
||||
${boundElementIndex},
|
||||
${codeGenStringMap(attrNameAndValues)},
|
||||
${codeGenDirectivesArray(directives)},
|
||||
${codeGenStringMap(variableNameAndValues)}
|
||||
)`;
|
||||
var statement = `var ${varName} = ${value};`;
|
||||
targetStatements.push(new Statement(statement));
|
||||
return new Expression(varName);
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeProtoViewFactory extends ProtoViewFactory<AppProtoView, AppProtoElement, any> {
|
||||
constructor(public metadataCache: ResolvedMetadataCache, component: CompileDirectiveMetadata,
|
||||
public pipes: CompilePipeMetadata[]) {
|
||||
super(component);
|
||||
}
|
||||
|
||||
createAppProtoView(embeddedTemplateIndex: number, viewType: ViewType,
|
||||
templateVariableBindings: string[][], targetStatements: any[]): AppProtoView {
|
||||
var pipes =
|
||||
embeddedTemplateIndex === 0 ? this.pipes.map(pipeMeta => pipeMeta.type.runtime) : [];
|
||||
var templateVars = keyValueArrayToStringMap(templateVariableBindings);
|
||||
return AppProtoView.create(this.metadataCache, viewType, pipes, templateVars);
|
||||
}
|
||||
|
||||
createAppProtoElement(boundElementIndex: number, attrNameAndValues: string[][],
|
||||
variableNameAndValues: string[][], directives: CompileDirectiveMetadata[],
|
||||
targetStatements: any[]): AppProtoElement {
|
||||
var attrs = keyValueArrayToStringMap(attrNameAndValues);
|
||||
return AppProtoElement.create(this.metadataCache, boundElementIndex, attrs,
|
||||
directives.map(dirMeta => dirMeta.type.runtime),
|
||||
keyValueArrayToStringMap(variableNameAndValues));
|
||||
}
|
||||
}
|
||||
|
||||
class ProtoViewBuilderVisitor<APP_PROTO_VIEW, APP_PROTO_EL, STATEMENT> implements
|
||||
TemplateAstVisitor {
|
||||
protoElements: CompileProtoElement<APP_PROTO_EL>[] = [];
|
||||
boundElementCount: number = 0;
|
||||
|
||||
constructor(public factory: ProtoViewFactory<APP_PROTO_VIEW, APP_PROTO_EL, STATEMENT>,
|
||||
public allStatements: STATEMENT[],
|
||||
public allProtoViews: CompileProtoView<APP_PROTO_VIEW, APP_PROTO_EL>[]) {}
|
||||
|
||||
private _readAttrNameAndValues(directives: CompileDirectiveMetadata[],
|
||||
attrAsts: TemplateAst[]): string[][] {
|
||||
var attrs = visitAndReturnContext(this, attrAsts, {});
|
||||
directives.forEach(directiveMeta => {
|
||||
StringMapWrapper.forEach(directiveMeta.hostAttributes, (value, name) => {
|
||||
var prevValue = attrs[name];
|
||||
attrs[name] = isPresent(prevValue) ? mergeAttributeValue(name, prevValue, value) : value;
|
||||
});
|
||||
});
|
||||
return mapToKeyValueArray(attrs);
|
||||
}
|
||||
|
||||
visitBoundText(ast: BoundTextAst, context: any): any { return null; }
|
||||
visitText(ast: TextAst, context: any): any { return null; }
|
||||
|
||||
visitNgContent(ast: NgContentAst, context: any): any { return null; }
|
||||
|
||||
visitElement(ast: ElementAst, context: any): any {
|
||||
var boundElementIndex = null;
|
||||
if (ast.isBound()) {
|
||||
boundElementIndex = this.boundElementCount++;
|
||||
}
|
||||
var component = ast.getComponent();
|
||||
|
||||
var variableNameAndValues: string[][] = [];
|
||||
if (isBlank(component)) {
|
||||
ast.exportAsVars.forEach((varAst) => { variableNameAndValues.push([varAst.name, null]); });
|
||||
}
|
||||
var directives = [];
|
||||
var renderEvents: Map<string, BoundEventAst> =
|
||||
visitAndReturnContext(this, ast.outputs, new Map<string, BoundEventAst>());
|
||||
ListWrapper.forEachWithIndex(ast.directives, (directiveAst: DirectiveAst, index: number) => {
|
||||
directiveAst.visit(this, new DirectiveContext(index, boundElementIndex, renderEvents,
|
||||
variableNameAndValues, directives));
|
||||
});
|
||||
var renderEventArray = [];
|
||||
renderEvents.forEach((eventAst, _) => renderEventArray.push(eventAst));
|
||||
|
||||
var attrNameAndValues = this._readAttrNameAndValues(directives, ast.attrs);
|
||||
this._addProtoElement(ast.isBound(), boundElementIndex, attrNameAndValues,
|
||||
variableNameAndValues, renderEventArray, directives, null);
|
||||
templateVisitAll(this, ast.children);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
|
||||
var boundElementIndex = this.boundElementCount++;
|
||||
var directives: CompileDirectiveMetadata[] = [];
|
||||
ListWrapper.forEachWithIndex(ast.directives, (directiveAst: DirectiveAst, index: number) => {
|
||||
directiveAst.visit(
|
||||
this, new DirectiveContext(index, boundElementIndex, new Map<string, BoundEventAst>(), [],
|
||||
directives));
|
||||
});
|
||||
|
||||
var attrNameAndValues = this._readAttrNameAndValues(directives, ast.attrs);
|
||||
var templateVariableBindings = ast.vars.map(
|
||||
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
|
||||
var nestedProtoView = this.factory.createCompileProtoView(
|
||||
ast.children, templateVariableBindings, this.allStatements, this.allProtoViews);
|
||||
this._addProtoElement(true, boundElementIndex, attrNameAndValues, [], [], directives,
|
||||
nestedProtoView.embeddedTemplateIndex);
|
||||
return null;
|
||||
}
|
||||
|
||||
private _addProtoElement(isBound: boolean, boundElementIndex, attrNameAndValues: string[][],
|
||||
variableNameAndValues: string[][], renderEvents: BoundEventAst[],
|
||||
directives: CompileDirectiveMetadata[], embeddedTemplateIndex: number) {
|
||||
var appProtoEl = null;
|
||||
if (isBound) {
|
||||
appProtoEl =
|
||||
this.factory.createAppProtoElement(boundElementIndex, attrNameAndValues,
|
||||
variableNameAndValues, directives, this.allStatements);
|
||||
}
|
||||
var compileProtoEl = new CompileProtoElement<APP_PROTO_EL>(
|
||||
boundElementIndex, attrNameAndValues, variableNameAndValues, renderEvents, directives,
|
||||
embeddedTemplateIndex, appProtoEl);
|
||||
this.protoElements.push(compileProtoEl);
|
||||
}
|
||||
|
||||
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
||||
visitAttr(ast: AttrAst, attrNameAndValues: {[key: string]: string}): any {
|
||||
attrNameAndValues[ast.name] = ast.value;
|
||||
return null;
|
||||
}
|
||||
visitDirective(ast: DirectiveAst, ctx: DirectiveContext): any {
|
||||
ctx.targetDirectives.push(ast.directive);
|
||||
templateVisitAll(this, ast.hostEvents, ctx.hostEventTargetAndNames);
|
||||
ast.exportAsVars.forEach(
|
||||
varAst => { ctx.targetVariableNameAndValues.push([varAst.name, ctx.index]); });
|
||||
return null;
|
||||
}
|
||||
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
|
||||
eventTargetAndNames.set(ast.fullName, ast);
|
||||
return null;
|
||||
}
|
||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
||||
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
|
||||
}
|
||||
|
||||
function mapToKeyValueArray(data: {[key: string]: string}): string[][] {
|
||||
var entryArray = [];
|
||||
StringMapWrapper.forEach(data, (value, name) => { entryArray.push([name, value]); });
|
||||
// We need to sort to get a defined output order
|
||||
// for tests and for caching generated artifacts...
|
||||
ListWrapper.sort(entryArray, (entry1, entry2) => StringWrapper.compare(entry1[0], entry2[0]));
|
||||
var keyValueArray = [];
|
||||
entryArray.forEach((entry) => { keyValueArray.push([entry[0], entry[1]]); });
|
||||
return keyValueArray;
|
||||
}
|
||||
|
||||
function mergeAttributeValue(attrName: string, attrValue1: string, attrValue2: string): string {
|
||||
if (attrName == CLASS_ATTR || attrName == STYLE_ATTR) {
|
||||
return `${attrValue1} ${attrValue2}`;
|
||||
} else {
|
||||
return attrValue2;
|
||||
}
|
||||
}
|
||||
|
||||
class DirectiveContext {
|
||||
constructor(public index: number, public boundElementIndex: number,
|
||||
public hostEventTargetAndNames: Map<string, BoundEventAst>,
|
||||
public targetVariableNameAndValues: any[][],
|
||||
public targetDirectives: CompileDirectiveMetadata[]) {}
|
||||
}
|
||||
|
||||
function keyValueArrayToStringMap(keyValueArray: any[][]): {[key: string]: any} {
|
||||
var stringMap: {[key: string]: string} = {};
|
||||
for (var i = 0; i < keyValueArray.length; i++) {
|
||||
var entry = keyValueArray[i];
|
||||
stringMap[entry[0]] = entry[1];
|
||||
}
|
||||
return stringMap;
|
||||
}
|
||||
|
||||
function codeGenDirectivesArray(directives: CompileDirectiveMetadata[]): string {
|
||||
var expressions = directives.map(directiveType => typeRef(directiveType.type));
|
||||
return `[${expressions.join(',')}]`;
|
||||
}
|
||||
|
||||
function codeGenTypesArray(types: CompileTypeMetadata[]): string {
|
||||
var expressions = types.map(typeRef);
|
||||
return `[${expressions.join(',')}]`;
|
||||
}
|
||||
|
||||
function codeGenViewType(value: ViewType): string {
|
||||
if (IS_DART) {
|
||||
return `${VIEW_TYPE_MODULE_REF}${value}`;
|
||||
} else {
|
||||
return `${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
function typeRef(type: CompileTypeMetadata): string {
|
||||
return `${moduleRef(type.moduleUrl)}${type.name}`;
|
||||
}
|
||||
|
||||
function getViewType(component: CompileDirectiveMetadata, embeddedTemplateIndex: number): ViewType {
|
||||
if (embeddedTemplateIndex > 0) {
|
||||
return ViewType.EMBEDDED;
|
||||
} else if (component.type.isHost) {
|
||||
return ViewType.HOST;
|
||||
} else {
|
||||
return ViewType.COMPONENT;
|
||||
}
|
||||
}
|
@ -1,23 +1,22 @@
|
||||
import {Compiler, Compiler_, internalCreateProtoView} from 'angular2/src/core/linker/compiler';
|
||||
import {ProtoViewRef} from 'angular2/src/core/linker/view_ref';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/linker/proto_view_factory';
|
||||
import {Compiler, Compiler_} from 'angular2/src/core/linker/compiler';
|
||||
import {HostViewFactoryRef, HostViewFactoryRef_} from 'angular2/src/core/linker/view_ref';
|
||||
import {TemplateCompiler} from './template_compiler';
|
||||
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
export abstract class RuntimeCompiler extends Compiler {}
|
||||
export abstract class RuntimeCompiler extends Compiler {
|
||||
abstract compileInHost(componentType: Type): Promise<HostViewFactoryRef>;
|
||||
abstract clearCache();
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class RuntimeCompiler_ extends Compiler_ implements RuntimeCompiler {
|
||||
constructor(_protoViewFactory: ProtoViewFactory, private _templateCompiler: TemplateCompiler) {
|
||||
super(_protoViewFactory);
|
||||
}
|
||||
constructor(private _templateCompiler: TemplateCompiler) { super(); }
|
||||
|
||||
compileInHost(componentType: Type): Promise<ProtoViewRef> {
|
||||
compileInHost(componentType: Type): Promise<HostViewFactoryRef_> {
|
||||
return this._templateCompiler.compileHostComponentRuntime(componentType)
|
||||
.then(compiledHostTemplate => internalCreateProtoView(this, compiledHostTemplate));
|
||||
.then(hostViewFactory => new HostViewFactoryRef_(hostViewFactory));
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
|
@ -11,25 +11,29 @@ import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import * as cpl from './directive_metadata';
|
||||
import * as md from 'angular2/src/core/metadata/directives';
|
||||
import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver';
|
||||
import {PipeResolver} from 'angular2/src/core/linker/pipe_resolver';
|
||||
import {ViewResolver} from 'angular2/src/core/linker/view_resolver';
|
||||
import {ViewMetadata} from 'angular2/src/core/metadata/view';
|
||||
import {hasLifecycleHook} from 'angular2/src/core/linker/directive_lifecycle_reflector';
|
||||
import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/linker/interfaces';
|
||||
import {reflector} from 'angular2/src/core/reflection/reflection';
|
||||
import {Injectable, Inject, Optional} from 'angular2/src/core/di';
|
||||
import {PLATFORM_DIRECTIVES} from 'angular2/src/core/platform_directives_and_pipes';
|
||||
import {PLATFORM_DIRECTIVES, PLATFORM_PIPES} from 'angular2/src/core/platform_directives_and_pipes';
|
||||
import {MODULE_SUFFIX} from './util';
|
||||
import {getUrlScheme} from 'angular2/src/compiler/url_resolver';
|
||||
|
||||
@Injectable()
|
||||
export class RuntimeMetadataResolver {
|
||||
private _cache = new Map<Type, cpl.CompileDirectiveMetadata>();
|
||||
private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>();
|
||||
private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
|
||||
|
||||
constructor(private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
|
||||
@Optional() @Inject(PLATFORM_DIRECTIVES) private _platformDirectives: Type[]) {}
|
||||
constructor(private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver,
|
||||
private _viewResolver: ViewResolver,
|
||||
@Optional() @Inject(PLATFORM_DIRECTIVES) private _platformDirectives: Type[],
|
||||
@Optional() @Inject(PLATFORM_PIPES) private _platformPipes: Type[]) {}
|
||||
|
||||
getMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
|
||||
var meta = this._cache.get(directiveType);
|
||||
getDirectiveMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
|
||||
var meta = this._directiveCache.get(directiveType);
|
||||
if (isBlank(meta)) {
|
||||
var dirMeta = this._directiveResolver.resolve(directiveType);
|
||||
var moduleUrl = null;
|
||||
@ -63,7 +67,23 @@ export class RuntimeMetadataResolver {
|
||||
host: dirMeta.host,
|
||||
lifecycleHooks: LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(hook, directiveType))
|
||||
});
|
||||
this._cache.set(directiveType, meta);
|
||||
this._directiveCache.set(directiveType, meta);
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
getPipeMetadata(pipeType: Type): cpl.CompilePipeMetadata {
|
||||
var meta = this._pipeCache.get(pipeType);
|
||||
if (isBlank(meta)) {
|
||||
var pipeMeta = this._pipeResolver.resolve(pipeType);
|
||||
var moduleUrl = reflector.importUri(pipeType);
|
||||
meta = new cpl.CompilePipeMetadata({
|
||||
type: new cpl.CompileTypeMetadata(
|
||||
{name: stringify(pipeType), moduleUrl: moduleUrl, runtime: pipeType}),
|
||||
name: pipeMeta.name,
|
||||
pure: pipeMeta.pure
|
||||
});
|
||||
this._pipeCache.set(pipeType, meta);
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
@ -72,13 +92,25 @@ export class RuntimeMetadataResolver {
|
||||
var view = this._viewResolver.resolve(component);
|
||||
var directives = flattenDirectives(view, this._platformDirectives);
|
||||
for (var i = 0; i < directives.length; i++) {
|
||||
if (!isValidDirective(directives[i])) {
|
||||
if (!isValidType(directives[i])) {
|
||||
throw new BaseException(
|
||||
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
|
||||
}
|
||||
}
|
||||
|
||||
return directives.map(type => this.getMetadata(type));
|
||||
return directives.map(type => this.getDirectiveMetadata(type));
|
||||
}
|
||||
|
||||
getViewPipesMetadata(component: Type): cpl.CompilePipeMetadata[] {
|
||||
var view = this._viewResolver.resolve(component);
|
||||
var pipes = flattenPipes(view, this._platformPipes);
|
||||
for (var i = 0; i < pipes.length; i++) {
|
||||
if (!isValidType(pipes[i])) {
|
||||
throw new BaseException(
|
||||
`Unexpected piped value '${stringify(pipes[i])}' on the View of component '${stringify(component)}'`);
|
||||
}
|
||||
}
|
||||
return pipes.map(type => this.getPipeMetadata(type));
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,6 +125,17 @@ function flattenDirectives(view: ViewMetadata, platformDirectives: any[]): Type[
|
||||
return directives;
|
||||
}
|
||||
|
||||
function flattenPipes(view: ViewMetadata, platformPipes: any[]): Type[] {
|
||||
let pipes = [];
|
||||
if (isPresent(platformPipes)) {
|
||||
flattenArray(platformPipes, pipes);
|
||||
}
|
||||
if (isPresent(view.pipes)) {
|
||||
flattenArray(view.pipes, pipes);
|
||||
}
|
||||
return pipes;
|
||||
}
|
||||
|
||||
function flattenArray(tree: any[], out: Array<Type | any[]>): void {
|
||||
for (var i = 0; i < tree.length; i++) {
|
||||
var item = resolveForwardRef(tree[i]);
|
||||
@ -104,7 +147,7 @@ function flattenArray(tree: any[], out: Array<Type | any[]>): void {
|
||||
}
|
||||
}
|
||||
|
||||
function isValidDirective(value: Type): boolean {
|
||||
function isValidType(value: Type): boolean {
|
||||
return isPresent(value) && (value instanceof Type);
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ import {
|
||||
}
|
||||
|
||||
* encapsultion: Styles defined within ShadowDOM, apply only to
|
||||
dom inside the ShadowDOM. Polymer uses one of two techniques to imlement
|
||||
dom inside the ShadowDOM. Polymer uses one of two techniques to implement
|
||||
this feature.
|
||||
|
||||
By default, rules are prefixed with the host element tag name
|
||||
|
@ -10,6 +10,10 @@ export function moduleRef(moduleUrl): string {
|
||||
* Represents generated source code with module references. Internal to the Angular compiler.
|
||||
*/
|
||||
export class SourceModule {
|
||||
static getSourceWithoutImports(sourceWithModuleRefs: string): string {
|
||||
return StringWrapper.replaceAllMapped(sourceWithModuleRefs, MODULE_REGEXP, (match) => '');
|
||||
}
|
||||
|
||||
constructor(public moduleUrl: string, public sourceWithModuleRefs: string) {}
|
||||
|
||||
getSourceWithImports(): SourceWithImports {
|
||||
|
@ -3,7 +3,7 @@ import {SourceModule, SourceExpression, moduleRef} from './source_module';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
|
||||
import {XHR} from 'angular2/src/compiler/xhr';
|
||||
import {IS_DART, StringWrapper, isBlank} from 'angular2/src/facade/lang';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {ShadowCss} from 'angular2/src/compiler/shadow_css';
|
||||
import {UrlResolver} from 'angular2/src/compiler/url_resolver';
|
||||
import {extractStyleUrls} from './style_url_resolver';
|
||||
@ -14,7 +14,10 @@ import {
|
||||
MODULE_SUFFIX
|
||||
} from './util';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
import {COMPONENT_VARIABLE, HOST_ATTR, CONTENT_ATTR} from 'angular2/src/core/render/view_factory';
|
||||
|
||||
const COMPONENT_VARIABLE = '%COMP%';
|
||||
const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
|
||||
const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
|
||||
|
||||
@Injectable()
|
||||
export class StyleCompiler {
|
||||
|
@ -1,37 +1,74 @@
|
||||
import {IS_DART, Type, Json, isBlank, stringify} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {ListWrapper, SetWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {
|
||||
CompiledComponentTemplate,
|
||||
TemplateCmd,
|
||||
CompiledHostTemplate,
|
||||
BeginComponentCmd
|
||||
} from 'angular2/src/core/linker/template_commands';
|
||||
IS_DART,
|
||||
Type,
|
||||
Json,
|
||||
isBlank,
|
||||
isPresent,
|
||||
stringify,
|
||||
evalExpression
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {
|
||||
ListWrapper,
|
||||
SetWrapper,
|
||||
MapWrapper,
|
||||
StringMapWrapper
|
||||
} from 'angular2/src/facade/collection';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {
|
||||
createHostComponentMeta,
|
||||
CompileDirectiveMetadata,
|
||||
CompileTypeMetadata,
|
||||
CompileTemplateMetadata
|
||||
CompileTemplateMetadata,
|
||||
CompilePipeMetadata,
|
||||
CompileMetadataWithType
|
||||
} from './directive_metadata';
|
||||
import {TemplateAst} from './template_ast';
|
||||
import {
|
||||
TemplateAst,
|
||||
TemplateAstVisitor,
|
||||
NgContentAst,
|
||||
EmbeddedTemplateAst,
|
||||
ElementAst,
|
||||
VariableAst,
|
||||
BoundEventAst,
|
||||
BoundElementPropertyAst,
|
||||
AttrAst,
|
||||
BoundTextAst,
|
||||
TextAst,
|
||||
DirectiveAst,
|
||||
BoundDirectivePropertyAst,
|
||||
templateVisitAll
|
||||
} from './template_ast';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
import {SourceModule, moduleRef} from './source_module';
|
||||
import {ChangeDetectionCompiler} from './change_detector_compiler';
|
||||
import {SourceModule, moduleRef, SourceExpression} from './source_module';
|
||||
import {ChangeDetectionCompiler, CHANGE_DETECTION_JIT_IMPORTS} from './change_detector_compiler';
|
||||
import {StyleCompiler} from './style_compiler';
|
||||
import {CommandCompiler} from './command_compiler';
|
||||
import {TemplateParser} from './template_parser';
|
||||
import {ViewCompiler, VIEW_JIT_IMPORTS} from './view_compiler';
|
||||
import {
|
||||
ProtoViewCompiler,
|
||||
APP_VIEW_MODULE_REF,
|
||||
CompileProtoView,
|
||||
PROTO_VIEW_JIT_IMPORTS
|
||||
} from './proto_view_compiler';
|
||||
import {TemplateParser, PipeCollector} from './template_parser';
|
||||
import {TemplateNormalizer} from './template_normalizer';
|
||||
import {RuntimeMetadataResolver} from './runtime_metadata';
|
||||
import {HostViewFactory} from 'angular2/src/core/linker/view';
|
||||
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {ResolvedMetadataCache} from 'angular2/src/core/linker/resolved_metadata_cache';
|
||||
|
||||
import {TEMPLATE_COMMANDS_MODULE_REF} from './command_compiler';
|
||||
import {
|
||||
codeGenExportVariable,
|
||||
escapeSingleQuoteString,
|
||||
codeGenValueFn,
|
||||
MODULE_SUFFIX
|
||||
MODULE_SUFFIX,
|
||||
addAll,
|
||||
Expression
|
||||
} from './util';
|
||||
|
||||
export var METADATA_CACHE_MODULE_REF =
|
||||
moduleRef('package:angular2/src/core/linker/resolved_metadata_cache' + MODULE_SUFFIX);
|
||||
|
||||
/**
|
||||
* An internal module of the Angular compiler that begins with component types,
|
||||
* extracts templates, and eventually produces a compiled version of the component
|
||||
@ -40,15 +77,16 @@ import {
|
||||
@Injectable()
|
||||
export class TemplateCompiler {
|
||||
private _hostCacheKeys = new Map<Type, any>();
|
||||
private _compiledTemplateCache = new Map<any, CompiledComponentTemplate>();
|
||||
private _compiledTemplateDone = new Map<any, Promise<CompiledComponentTemplate>>();
|
||||
private _nextTemplateId: number = 0;
|
||||
private _compiledTemplateCache = new Map<any, CompiledTemplate>();
|
||||
private _compiledTemplateDone = new Map<any, Promise<CompiledTemplate>>();
|
||||
|
||||
constructor(private _runtimeMetadataResolver: RuntimeMetadataResolver,
|
||||
private _templateNormalizer: TemplateNormalizer,
|
||||
private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler,
|
||||
private _commandCompiler: CommandCompiler,
|
||||
private _cdCompiler: ChangeDetectionCompiler) {}
|
||||
private _cdCompiler: ChangeDetectionCompiler,
|
||||
private _protoViewCompiler: ProtoViewCompiler, private _viewCompiler: ViewCompiler,
|
||||
private _resolvedMetadataCache: ResolvedMetadataCache,
|
||||
private _genConfig: ChangeDetectorGenConfig) {}
|
||||
|
||||
normalizeDirectiveMetadata(directive: CompileDirectiveMetadata):
|
||||
Promise<CompileDirectiveMetadata> {
|
||||
@ -75,99 +113,29 @@ export class TemplateCompiler {
|
||||
}));
|
||||
}
|
||||
|
||||
compileHostComponentRuntime(type: Type): Promise<CompiledHostTemplate> {
|
||||
compileHostComponentRuntime(type: Type): Promise<HostViewFactory> {
|
||||
var compMeta: CompileDirectiveMetadata =
|
||||
this._runtimeMetadataResolver.getDirectiveMetadata(type);
|
||||
var hostCacheKey = this._hostCacheKeys.get(type);
|
||||
if (isBlank(hostCacheKey)) {
|
||||
hostCacheKey = new Object();
|
||||
this._hostCacheKeys.set(type, hostCacheKey);
|
||||
var compMeta: CompileDirectiveMetadata = this._runtimeMetadataResolver.getMetadata(type);
|
||||
assertComponent(compMeta);
|
||||
var hostMeta: CompileDirectiveMetadata =
|
||||
createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||
|
||||
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], new Set());
|
||||
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], [], []);
|
||||
}
|
||||
return this._compiledTemplateDone.get(hostCacheKey)
|
||||
.then(compiledTemplate => new CompiledHostTemplate(compiledTemplate));
|
||||
.then((compiledTemplate: CompiledTemplate) =>
|
||||
new HostViewFactory(compMeta.selector, compiledTemplate.viewFactory));
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
this._hostCacheKeys.clear();
|
||||
this._styleCompiler.clearCache();
|
||||
this._compiledTemplateCache.clear();
|
||||
this._compiledTemplateDone.clear();
|
||||
}
|
||||
|
||||
private _compileComponentRuntime(
|
||||
cacheKey: any, compMeta: CompileDirectiveMetadata, viewDirectives: CompileDirectiveMetadata[],
|
||||
compilingComponentCacheKeys: Set<any>): CompiledComponentTemplate {
|
||||
let uniqViewDirectives = removeDuplicates(viewDirectives);
|
||||
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
|
||||
var done = this._compiledTemplateDone.get(cacheKey);
|
||||
if (isBlank(compiledTemplate)) {
|
||||
var styles = [];
|
||||
var changeDetectorFactory;
|
||||
var commands = [];
|
||||
var templateId = `${stringify(compMeta.type.runtime)}Template${this._nextTemplateId++}`;
|
||||
compiledTemplate = new CompiledComponentTemplate(
|
||||
templateId, (dispatcher) => changeDetectorFactory(dispatcher), commands, styles);
|
||||
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
|
||||
compilingComponentCacheKeys.add(cacheKey);
|
||||
done = PromiseWrapper
|
||||
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
|
||||
uniqViewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
|
||||
.then((stylesAndNormalizedViewDirMetas: any[]) => {
|
||||
var childPromises = [];
|
||||
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
|
||||
var parsedTemplate = this._templateParser.parse(
|
||||
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
|
||||
|
||||
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
|
||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||
changeDetectorFactory = changeDetectorFactories[0];
|
||||
var tmpStyles: string[] = stylesAndNormalizedViewDirMetas[0];
|
||||
tmpStyles.forEach(style => styles.push(style));
|
||||
var tmpCommands: TemplateCmd[] = this._compileCommandsRuntime(
|
||||
compMeta, parsedTemplate, changeDetectorFactories,
|
||||
compilingComponentCacheKeys, childPromises);
|
||||
tmpCommands.forEach(cmd => commands.push(cmd));
|
||||
return PromiseWrapper.all(childPromises);
|
||||
})
|
||||
.then((_) => {
|
||||
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
|
||||
return compiledTemplate;
|
||||
});
|
||||
this._compiledTemplateDone.set(cacheKey, done);
|
||||
}
|
||||
return compiledTemplate;
|
||||
}
|
||||
|
||||
private _compileCommandsRuntime(compMeta: CompileDirectiveMetadata, parsedTemplate: TemplateAst[],
|
||||
changeDetectorFactories: Function[],
|
||||
compilingComponentCacheKeys: Set<Type>,
|
||||
childPromises: Promise<any>[]): TemplateCmd[] {
|
||||
var cmds: TemplateCmd[] = this._commandCompiler.compileComponentRuntime(
|
||||
compMeta, parsedTemplate, changeDetectorFactories,
|
||||
(childComponentDir: CompileDirectiveMetadata) => {
|
||||
var childCacheKey = childComponentDir.type.runtime;
|
||||
var childViewDirectives: CompileDirectiveMetadata[] =
|
||||
this._runtimeMetadataResolver.getViewDirectivesMetadata(
|
||||
childComponentDir.type.runtime);
|
||||
var childIsRecursive = SetWrapper.has(compilingComponentCacheKeys, childCacheKey);
|
||||
var childTemplate = this._compileComponentRuntime(
|
||||
childCacheKey, childComponentDir, childViewDirectives, compilingComponentCacheKeys);
|
||||
if (!childIsRecursive) {
|
||||
// Only wait for a child if it is not a cycle
|
||||
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
|
||||
}
|
||||
return () => childTemplate;
|
||||
});
|
||||
cmds.forEach(cmd => {
|
||||
if (cmd instanceof BeginComponentCmd) {
|
||||
cmd.templateGetter();
|
||||
}
|
||||
});
|
||||
return cmds;
|
||||
this._hostCacheKeys.clear();
|
||||
}
|
||||
|
||||
compileTemplatesCodeGen(components: NormalizedComponentWithViewDirectives[]): SourceModule {
|
||||
@ -175,37 +143,21 @@ export class TemplateCompiler {
|
||||
throw new BaseException('No components given');
|
||||
}
|
||||
var declarations = [];
|
||||
var templateArguments = [];
|
||||
var componentMetas: CompileDirectiveMetadata[] = [];
|
||||
components.forEach(componentWithDirs => {
|
||||
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
||||
assertComponent(compMeta);
|
||||
componentMetas.push(compMeta);
|
||||
|
||||
this._processTemplateCodeGen(compMeta, componentWithDirs.directives, declarations,
|
||||
templateArguments);
|
||||
this._compileComponentCodeGen(compMeta, componentWithDirs.directives, componentWithDirs.pipes,
|
||||
declarations);
|
||||
if (compMeta.dynamicLoadable) {
|
||||
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||
componentMetas.push(hostMeta);
|
||||
this._processTemplateCodeGen(hostMeta, [compMeta], declarations, templateArguments);
|
||||
}
|
||||
});
|
||||
ListWrapper.forEachWithIndex(componentMetas, (compMeta: CompileDirectiveMetadata,
|
||||
index: number) => {
|
||||
var templateId = `${compMeta.type.moduleUrl}|${compMeta.type.name}`;
|
||||
var viewFactoryExpression =
|
||||
this._compileComponentCodeGen(hostMeta, [compMeta], [], declarations);
|
||||
var constructionKeyword = IS_DART ? 'const' : 'new';
|
||||
var compiledTemplateExpr =
|
||||
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledComponentTemplate('${templateId}',${(<any[]>templateArguments[index]).join(',')})`;
|
||||
var variableValueExpr;
|
||||
if (compMeta.type.isHost) {
|
||||
variableValueExpr =
|
||||
`${constructionKeyword} ${TEMPLATE_COMMANDS_MODULE_REF}CompiledHostTemplate(${compiledTemplateExpr})`;
|
||||
} else {
|
||||
variableValueExpr = compiledTemplateExpr;
|
||||
`${constructionKeyword} ${APP_VIEW_MODULE_REF}HostViewFactory('${compMeta.selector}',${viewFactoryExpression})`;
|
||||
var varName = codeGenHostViewFactoryName(compMeta.type);
|
||||
declarations.push(`${codeGenExportVariable(varName)}${compiledTemplateExpr};`);
|
||||
}
|
||||
var varName = templateVariableName(compMeta.type);
|
||||
declarations.push(`${codeGenExportVariable(varName)}${variableValueExpr};`);
|
||||
declarations.push(`${codeGenValueFn([], varName, templateGetterName(compMeta.type))};`);
|
||||
});
|
||||
var moduleUrl = components[0].component.type.moduleUrl;
|
||||
return new SourceModule(`${templateModuleUrl(moduleUrl)}`, declarations.join('\n'));
|
||||
@ -215,31 +167,150 @@ export class TemplateCompiler {
|
||||
return this._styleCompiler.compileStylesheetCodeGen(stylesheetUrl, cssText);
|
||||
}
|
||||
|
||||
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata,
|
||||
|
||||
|
||||
private _compileComponentRuntime(cacheKey: any, compMeta: CompileDirectiveMetadata,
|
||||
viewDirectives: CompileDirectiveMetadata[],
|
||||
pipes: CompilePipeMetadata[],
|
||||
compilingComponentsPath: any[]): CompiledTemplate {
|
||||
let uniqViewDirectives = <CompileDirectiveMetadata[]>removeDuplicates(viewDirectives);
|
||||
let uniqViewPipes = <CompilePipeMetadata[]>removeDuplicates(pipes);
|
||||
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
|
||||
var done = this._compiledTemplateDone.get(cacheKey);
|
||||
if (isBlank(compiledTemplate)) {
|
||||
compiledTemplate = new CompiledTemplate();
|
||||
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
|
||||
done = PromiseWrapper
|
||||
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
|
||||
uniqViewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
|
||||
.then((stylesAndNormalizedViewDirMetas: any[]) => {
|
||||
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
|
||||
var styles = stylesAndNormalizedViewDirMetas[0];
|
||||
var parsedTemplate = this._templateParser.parse(
|
||||
compMeta.template.template, normalizedViewDirMetas, uniqViewPipes,
|
||||
compMeta.type.name);
|
||||
|
||||
var childPromises = [];
|
||||
var usedDirectives = DirectiveCollector.findUsedDirectives(parsedTemplate);
|
||||
usedDirectives.components.forEach(
|
||||
component => this._compileNestedComponentRuntime(
|
||||
component, compilingComponentsPath, childPromises));
|
||||
return PromiseWrapper.all(childPromises)
|
||||
.then((_) => {
|
||||
var filteredPipes = filterPipes(parsedTemplate, uniqViewPipes);
|
||||
compiledTemplate.init(this._createViewFactoryRuntime(
|
||||
compMeta, parsedTemplate, usedDirectives.directives, styles,
|
||||
filteredPipes));
|
||||
return compiledTemplate;
|
||||
});
|
||||
});
|
||||
this._compiledTemplateDone.set(cacheKey, done);
|
||||
}
|
||||
return compiledTemplate;
|
||||
}
|
||||
|
||||
private _compileNestedComponentRuntime(childComponentDir: CompileDirectiveMetadata,
|
||||
parentCompilingComponentsPath: any[],
|
||||
childPromises: Promise<any>[]) {
|
||||
var compilingComponentsPath = ListWrapper.clone(parentCompilingComponentsPath);
|
||||
|
||||
var childCacheKey = childComponentDir.type.runtime;
|
||||
var childViewDirectives: CompileDirectiveMetadata[] =
|
||||
this._runtimeMetadataResolver.getViewDirectivesMetadata(childComponentDir.type.runtime);
|
||||
var childViewPipes: CompilePipeMetadata[] =
|
||||
this._runtimeMetadataResolver.getViewPipesMetadata(childComponentDir.type.runtime);
|
||||
var childIsRecursive = ListWrapper.contains(compilingComponentsPath, childCacheKey);
|
||||
compilingComponentsPath.push(childCacheKey);
|
||||
this._compileComponentRuntime(childCacheKey, childComponentDir, childViewDirectives,
|
||||
childViewPipes, compilingComponentsPath);
|
||||
if (!childIsRecursive) {
|
||||
// Only wait for a child if it is not a cycle
|
||||
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
|
||||
}
|
||||
}
|
||||
|
||||
private _createViewFactoryRuntime(compMeta: CompileDirectiveMetadata,
|
||||
parsedTemplate: TemplateAst[],
|
||||
directives: CompileDirectiveMetadata[], styles: string[],
|
||||
pipes: CompilePipeMetadata[]): Function {
|
||||
if (IS_DART || !this._genConfig.useJit) {
|
||||
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
|
||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||
var protoViews = this._protoViewCompiler.compileProtoViewRuntime(
|
||||
this._resolvedMetadataCache, compMeta, parsedTemplate, pipes);
|
||||
return this._viewCompiler.compileComponentRuntime(
|
||||
compMeta, parsedTemplate, styles, protoViews.protoViews, changeDetectorFactories,
|
||||
(compMeta) => this._getNestedComponentViewFactory(compMeta));
|
||||
} else {
|
||||
var declarations = [];
|
||||
var viewFactoryExpr = this._createViewFactoryCodeGen('resolvedMetadataCache', compMeta,
|
||||
new SourceExpression([], 'styles'),
|
||||
parsedTemplate, pipes, declarations);
|
||||
var vars: {[key: string]: any} =
|
||||
{'exports': {}, 'styles': styles, 'resolvedMetadataCache': this._resolvedMetadataCache};
|
||||
directives.forEach(dirMeta => {
|
||||
vars[dirMeta.type.name] = dirMeta.type.runtime;
|
||||
if (dirMeta.isComponent && dirMeta.type.runtime !== compMeta.type.runtime) {
|
||||
vars[`viewFactory_${dirMeta.type.name}0`] = this._getNestedComponentViewFactory(dirMeta);
|
||||
}
|
||||
});
|
||||
pipes.forEach(pipeMeta => vars[pipeMeta.type.name] = pipeMeta.type.runtime);
|
||||
var declarationsWithoutImports =
|
||||
SourceModule.getSourceWithoutImports(declarations.join('\n'));
|
||||
return evalExpression(
|
||||
`viewFactory_${compMeta.type.name}`, viewFactoryExpr, declarationsWithoutImports,
|
||||
mergeStringMaps(
|
||||
[vars, CHANGE_DETECTION_JIT_IMPORTS, PROTO_VIEW_JIT_IMPORTS, VIEW_JIT_IMPORTS]));
|
||||
}
|
||||
}
|
||||
|
||||
private _getNestedComponentViewFactory(compMeta: CompileDirectiveMetadata): Function {
|
||||
return this._compiledTemplateCache.get(compMeta.type.runtime).viewFactory;
|
||||
}
|
||||
|
||||
private _compileComponentCodeGen(compMeta: CompileDirectiveMetadata,
|
||||
directives: CompileDirectiveMetadata[],
|
||||
targetDeclarations: string[], targetTemplateArguments: any[][]) {
|
||||
let uniqueDirectives = removeDuplicates(directives);
|
||||
pipes: CompilePipeMetadata[],
|
||||
targetDeclarations: string[]): string {
|
||||
let uniqueDirectives = <CompileDirectiveMetadata[]>removeDuplicates(directives);
|
||||
let uniqPipes = <CompilePipeMetadata[]>removeDuplicates(pipes);
|
||||
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.template);
|
||||
var parsedTemplate = this._templateParser.parse(compMeta.template.template, uniqueDirectives,
|
||||
compMeta.type.name);
|
||||
uniqPipes, compMeta.type.name);
|
||||
var filteredPipes = filterPipes(parsedTemplate, uniqPipes);
|
||||
return this._createViewFactoryCodeGen(
|
||||
`${METADATA_CACHE_MODULE_REF}CODEGEN_RESOLVED_METADATA_CACHE`, compMeta, styleExpr,
|
||||
parsedTemplate, filteredPipes, targetDeclarations);
|
||||
}
|
||||
|
||||
private _createViewFactoryCodeGen(resolvedMetadataCacheExpr: string,
|
||||
compMeta: CompileDirectiveMetadata, styleExpr: SourceExpression,
|
||||
parsedTemplate: TemplateAst[], pipes: CompilePipeMetadata[],
|
||||
targetDeclarations: string[]): string {
|
||||
var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen(
|
||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||
var commandsExpr = this._commandCompiler.compileComponentCodeGen(
|
||||
compMeta, parsedTemplate, changeDetectorsExprs.expressions,
|
||||
codeGenComponentTemplateFactory);
|
||||
var protoViewExprs = this._protoViewCompiler.compileProtoViewCodeGen(
|
||||
new Expression(resolvedMetadataCacheExpr), compMeta, parsedTemplate, pipes);
|
||||
var viewFactoryExpr = this._viewCompiler.compileComponentCodeGen(
|
||||
compMeta, parsedTemplate, styleExpr, protoViewExprs.protoViews, changeDetectorsExprs,
|
||||
codeGenComponentViewFactoryName);
|
||||
|
||||
addAll(styleExpr.declarations, targetDeclarations);
|
||||
addAll(changeDetectorsExprs.declarations, targetDeclarations);
|
||||
addAll(commandsExpr.declarations, targetDeclarations);
|
||||
addAll(protoViewExprs.declarations, targetDeclarations);
|
||||
addAll(viewFactoryExpr.declarations, targetDeclarations);
|
||||
|
||||
targetTemplateArguments.push(
|
||||
[changeDetectorsExprs.expressions[0], commandsExpr.expression, styleExpr.expression]);
|
||||
return viewFactoryExpr.expression;
|
||||
}
|
||||
}
|
||||
|
||||
export class NormalizedComponentWithViewDirectives {
|
||||
constructor(public component: CompileDirectiveMetadata,
|
||||
public directives: CompileDirectiveMetadata[]) {}
|
||||
public directives: CompileDirectiveMetadata[], public pipes: CompilePipeMetadata[]) {}
|
||||
}
|
||||
|
||||
class CompiledTemplate {
|
||||
viewFactory: Function = null;
|
||||
init(viewFactory: Function) { this.viewFactory = viewFactory; }
|
||||
}
|
||||
|
||||
function assertComponent(meta: CompileDirectiveMetadata) {
|
||||
@ -248,30 +319,28 @@ function assertComponent(meta: CompileDirectiveMetadata) {
|
||||
}
|
||||
}
|
||||
|
||||
function templateVariableName(type: CompileTypeMetadata): string {
|
||||
return `${type.name}Template`;
|
||||
}
|
||||
|
||||
function templateGetterName(type: CompileTypeMetadata): string {
|
||||
return `${templateVariableName(type)}Getter`;
|
||||
}
|
||||
|
||||
function templateModuleUrl(moduleUrl: string): string {
|
||||
var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length);
|
||||
return `${urlWithoutSuffix}.template${MODULE_SUFFIX}`;
|
||||
}
|
||||
|
||||
function addAll(source: any[], target: any[]) {
|
||||
for (var i = 0; i < source.length; i++) {
|
||||
target.push(source[i]);
|
||||
}
|
||||
|
||||
function codeGenHostViewFactoryName(type: CompileTypeMetadata): string {
|
||||
return `hostViewFactory_${type.name}`;
|
||||
}
|
||||
|
||||
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
|
||||
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateGetterName(nestedCompType.type)}`;
|
||||
function codeGenComponentViewFactoryName(nestedCompType: CompileDirectiveMetadata): string {
|
||||
return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}viewFactory_${nestedCompType.type.name}0`;
|
||||
}
|
||||
|
||||
function removeDuplicates(items: CompileDirectiveMetadata[]): CompileDirectiveMetadata[] {
|
||||
function mergeStringMaps(maps: Array<{[key: string]: any}>): {[key: string]: any} {
|
||||
var result = {};
|
||||
maps.forEach(
|
||||
(map) => { StringMapWrapper.forEach(map, (value, key) => { result[key] = value; }); });
|
||||
return result;
|
||||
}
|
||||
|
||||
function removeDuplicates(items: CompileMetadataWithType[]): CompileMetadataWithType[] {
|
||||
let res = [];
|
||||
items.forEach(item => {
|
||||
let hasMatch =
|
||||
@ -284,3 +353,100 @@ function removeDuplicates(items: CompileDirectiveMetadata[]): CompileDirectiveMe
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
class DirectiveCollector implements TemplateAstVisitor {
|
||||
static findUsedDirectives(parsedTemplate: TemplateAst[]): DirectiveCollector {
|
||||
var collector = new DirectiveCollector();
|
||||
templateVisitAll(collector, parsedTemplate);
|
||||
return collector;
|
||||
}
|
||||
|
||||
directives: CompileDirectiveMetadata[] = [];
|
||||
components: CompileDirectiveMetadata[] = [];
|
||||
|
||||
visitBoundText(ast: BoundTextAst, context: any): any { return null; }
|
||||
visitText(ast: TextAst, context: any): any { return null; }
|
||||
|
||||
visitNgContent(ast: NgContentAst, context: any): any { return null; }
|
||||
|
||||
visitElement(ast: ElementAst, context: any): any {
|
||||
templateVisitAll(this, ast.directives);
|
||||
templateVisitAll(this, ast.children);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
|
||||
templateVisitAll(this, ast.directives);
|
||||
templateVisitAll(this, ast.children);
|
||||
return null;
|
||||
}
|
||||
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
||||
visitAttr(ast: AttrAst, attrNameAndValues: {[key: string]: string}): any { return null; }
|
||||
visitDirective(ast: DirectiveAst, ctx: any): any {
|
||||
if (ast.directive.isComponent) {
|
||||
this.components.push(ast.directive);
|
||||
}
|
||||
this.directives.push(ast.directive);
|
||||
return null;
|
||||
}
|
||||
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
|
||||
return null;
|
||||
}
|
||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
||||
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
|
||||
}
|
||||
|
||||
|
||||
function filterPipes(template: TemplateAst[],
|
||||
allPipes: CompilePipeMetadata[]): CompilePipeMetadata[] {
|
||||
var visitor = new PipeVisitor();
|
||||
templateVisitAll(visitor, template);
|
||||
return allPipes.filter((pipeMeta) => SetWrapper.has(visitor.collector.pipes, pipeMeta.name));
|
||||
}
|
||||
|
||||
class PipeVisitor implements TemplateAstVisitor {
|
||||
collector: PipeCollector = new PipeCollector();
|
||||
|
||||
visitBoundText(ast: BoundTextAst, context: any): any {
|
||||
ast.value.visit(this.collector);
|
||||
return null;
|
||||
}
|
||||
visitText(ast: TextAst, context: any): any { return null; }
|
||||
|
||||
visitNgContent(ast: NgContentAst, context: any): any { return null; }
|
||||
|
||||
visitElement(ast: ElementAst, context: any): any {
|
||||
templateVisitAll(this, ast.inputs);
|
||||
templateVisitAll(this, ast.outputs);
|
||||
templateVisitAll(this, ast.directives);
|
||||
templateVisitAll(this, ast.children);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
|
||||
templateVisitAll(this, ast.outputs);
|
||||
templateVisitAll(this, ast.directives);
|
||||
templateVisitAll(this, ast.children);
|
||||
return null;
|
||||
}
|
||||
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
||||
visitAttr(ast: AttrAst, attrNameAndValues: {[key: string]: string}): any { return null; }
|
||||
visitDirective(ast: DirectiveAst, ctx: any): any {
|
||||
templateVisitAll(this, ast.inputs);
|
||||
templateVisitAll(this, ast.hostEvents);
|
||||
templateVisitAll(this, ast.hostProperties);
|
||||
return null;
|
||||
}
|
||||
visitEvent(ast: BoundEventAst, eventTargetAndNames: Map<string, BoundEventAst>): any {
|
||||
ast.handler.visit(this.collector);
|
||||
return null;
|
||||
}
|
||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any {
|
||||
ast.value.visit(this.collector);
|
||||
return null;
|
||||
}
|
||||
visitElementProperty(ast: BoundElementPropertyAst, context: any): any {
|
||||
ast.value.visit(this.collector);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
} from './directive_metadata';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
import {XHR} from 'angular2/src/compiler/xhr';
|
||||
import {UrlResolver} from 'angular2/src/compiler/url_resolver';
|
||||
@ -112,6 +112,10 @@ class TemplatePreparseVisitor implements HtmlAstVisitor {
|
||||
case PreparsedElementType.STYLESHEET:
|
||||
this.styleUrls.push(preparsedElement.hrefAttr);
|
||||
break;
|
||||
default:
|
||||
// DDC reports this as error. See:
|
||||
// https://github.com/dart-lang/dev_compiler/issues/428
|
||||
break;
|
||||
}
|
||||
if (preparsedElement.nonBindable) {
|
||||
this.ngNonBindableStackCount++;
|
||||
|
@ -5,10 +5,11 @@ import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {Parser, AST, ASTWithSource} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {TemplateBinding} from 'angular2/src/core/change_detection/parser/ast';
|
||||
import {CompileDirectiveMetadata} from './directive_metadata';
|
||||
import {CompileDirectiveMetadata, CompilePipeMetadata} from './directive_metadata';
|
||||
import {HtmlParser} from './html_parser';
|
||||
import {splitNsName} from './html_tags';
|
||||
import {ParseSourceSpan, ParseError, ParseLocation} from './parse_util';
|
||||
import {RecursiveAstVisitor, BindingPipe} from 'angular2/src/core/change_detection/parser/ast';
|
||||
|
||||
|
||||
import {
|
||||
@ -51,8 +52,8 @@ import {splitAtColon} from './util';
|
||||
// Group 3 = "on-"
|
||||
// Group 4 = "bindon-"
|
||||
// Group 5 = the identifier after "bind-", "var-/#", or "on-"
|
||||
// Group 6 = idenitifer inside [()]
|
||||
// Group 7 = idenitifer inside []
|
||||
// Group 6 = identifier inside [()]
|
||||
// Group 7 = identifier inside []
|
||||
// Group 8 = identifier inside ()
|
||||
var BIND_NAME_REGEXP =
|
||||
/^(?:(?:(?:(bind-)|(var-|#)|(on-)|(bindon-))(.+))|\[\(([^\)]+)\)\]|\[([^\]]+)\]|\(([^\)]+)\))$/g;
|
||||
@ -88,9 +89,10 @@ export class TemplateParser {
|
||||
private _htmlParser: HtmlParser,
|
||||
@Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {}
|
||||
|
||||
parse(template: string, directives: CompileDirectiveMetadata[],
|
||||
parse(template: string, directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
|
||||
templateUrl: string): TemplateAst[] {
|
||||
var parseVisitor = new TemplateParseVisitor(directives, this._exprParser, this._schemaRegistry);
|
||||
var parseVisitor =
|
||||
new TemplateParseVisitor(directives, pipes, this._exprParser, this._schemaRegistry);
|
||||
var htmlAstWithErrors = this._htmlParser.parse(template, templateUrl);
|
||||
var result = htmlVisitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_COMPONENT);
|
||||
var errors: ParseError[] = htmlAstWithErrors.errors.concat(parseVisitor.errors);
|
||||
@ -111,9 +113,10 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
errors: TemplateParseError[] = [];
|
||||
directivesIndex = new Map<CompileDirectiveMetadata, number>();
|
||||
ngContentCount: number = 0;
|
||||
pipesByName: Map<string, CompilePipeMetadata>;
|
||||
|
||||
constructor(directives: CompileDirectiveMetadata[], private _exprParser: Parser,
|
||||
private _schemaRegistry: ElementSchemaRegistry) {
|
||||
constructor(directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
|
||||
private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry) {
|
||||
this.selectorMatcher = new SelectorMatcher();
|
||||
ListWrapper.forEachWithIndex(directives,
|
||||
(directive: CompileDirectiveMetadata, index: number) => {
|
||||
@ -121,6 +124,8 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
this.selectorMatcher.addSelectables(selector, directive);
|
||||
this.directivesIndex.set(directive, index);
|
||||
});
|
||||
this.pipesByName = new Map<string, CompilePipeMetadata>();
|
||||
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
|
||||
}
|
||||
|
||||
private _reportError(message: string, sourceSpan: ParseSourceSpan) {
|
||||
@ -130,7 +135,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
private _parseInterpolation(value: string, sourceSpan: ParseSourceSpan): ASTWithSource {
|
||||
var sourceInfo = sourceSpan.start.toString();
|
||||
try {
|
||||
return this._exprParser.parseInterpolation(value, sourceInfo);
|
||||
var ast = this._exprParser.parseInterpolation(value, sourceInfo);
|
||||
this._checkPipes(ast, sourceSpan);
|
||||
return ast;
|
||||
} catch (e) {
|
||||
this._reportError(`${e}`, sourceSpan);
|
||||
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
||||
@ -140,7 +147,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
private _parseAction(value: string, sourceSpan: ParseSourceSpan): ASTWithSource {
|
||||
var sourceInfo = sourceSpan.start.toString();
|
||||
try {
|
||||
return this._exprParser.parseAction(value, sourceInfo);
|
||||
var ast = this._exprParser.parseAction(value, sourceInfo);
|
||||
this._checkPipes(ast, sourceSpan);
|
||||
return ast;
|
||||
} catch (e) {
|
||||
this._reportError(`${e}`, sourceSpan);
|
||||
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
||||
@ -150,7 +159,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
private _parseBinding(value: string, sourceSpan: ParseSourceSpan): ASTWithSource {
|
||||
var sourceInfo = sourceSpan.start.toString();
|
||||
try {
|
||||
return this._exprParser.parseBinding(value, sourceInfo);
|
||||
var ast = this._exprParser.parseBinding(value, sourceInfo);
|
||||
this._checkPipes(ast, sourceSpan);
|
||||
return ast;
|
||||
} catch (e) {
|
||||
this._reportError(`${e}`, sourceSpan);
|
||||
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
|
||||
@ -160,13 +171,31 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
private _parseTemplateBindings(value: string, sourceSpan: ParseSourceSpan): TemplateBinding[] {
|
||||
var sourceInfo = sourceSpan.start.toString();
|
||||
try {
|
||||
return this._exprParser.parseTemplateBindings(value, sourceInfo);
|
||||
var bindings = this._exprParser.parseTemplateBindings(value, sourceInfo);
|
||||
bindings.forEach((binding) => {
|
||||
if (isPresent(binding.expression)) {
|
||||
this._checkPipes(binding.expression, sourceSpan);
|
||||
}
|
||||
});
|
||||
return bindings;
|
||||
} catch (e) {
|
||||
this._reportError(`${e}`, sourceSpan);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private _checkPipes(ast: ASTWithSource, sourceSpan: ParseSourceSpan) {
|
||||
if (isPresent(ast)) {
|
||||
var collector = new PipeCollector();
|
||||
ast.visit(collector);
|
||||
collector.pipes.forEach((pipeName) => {
|
||||
if (!this.pipesByName.has(pipeName)) {
|
||||
this._reportError(`The pipe '${pipeName}' could not be found`, sourceSpan);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
visitText(ast: HtmlTextAst, component: Component): any {
|
||||
var ngContentIndex = component.findNgContentIndex(TEXT_CSS_SELECTOR);
|
||||
var expr = this._parseInterpolation(ast.value, ast.sourceSpan);
|
||||
@ -210,13 +239,13 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
var attrs = [];
|
||||
|
||||
element.attrs.forEach(attr => {
|
||||
matchableAttrs.push([attr.name, attr.value]);
|
||||
var hasBinding = this._parseAttr(attr, matchableAttrs, elementOrDirectiveProps, events, vars);
|
||||
var hasTemplateBinding = this._parseInlineTemplateBinding(
|
||||
attr, templateMatchableAttrs, templateElementOrDirectiveProps, templateVars);
|
||||
if (!hasBinding && !hasTemplateBinding) {
|
||||
// don't include the bindings as attributes as well in the AST
|
||||
attrs.push(this.visitAttr(attr, null));
|
||||
matchableAttrs.push([attr.name, attr.value]);
|
||||
}
|
||||
if (hasTemplateBinding) {
|
||||
hasInlineTemplates = true;
|
||||
@ -404,8 +433,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
var parts = splitAtColon(name, [null, name]);
|
||||
var target = parts[0];
|
||||
var eventName = parts[1];
|
||||
targetEvents.push(new BoundEventAst(eventName, target,
|
||||
this._parseAction(expression, sourceSpan), sourceSpan));
|
||||
var ast = this._parseAction(expression, sourceSpan);
|
||||
targetMatchableAttrs.push([name, ast.source]);
|
||||
targetEvents.push(new BoundEventAst(eventName, target, ast, sourceSpan));
|
||||
// Don't detect directives for event names for now,
|
||||
// so don't add the event name to the matchableAttrs
|
||||
}
|
||||
@ -714,3 +744,14 @@ function createElementCssSelector(elementName: string, matchableAttrs: string[][
|
||||
|
||||
var EMPTY_COMPONENT = new Component(new SelectorMatcher(), null);
|
||||
var NON_BINDABLE_VISITOR = new NonBindableVisitor();
|
||||
|
||||
|
||||
export class PipeCollector extends RecursiveAstVisitor {
|
||||
pipes: Set<string> = new Set<string>();
|
||||
visitPipe(ast: BindingPipe): any {
|
||||
this.pipes.add(ast.name);
|
||||
ast.exp.visit(this);
|
||||
this.visitAll(ast.args);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
import {IS_DART, StringWrapper, isBlank} from 'angular2/src/facade/lang';
|
||||
import {
|
||||
IS_DART,
|
||||
StringWrapper,
|
||||
isBlank,
|
||||
isPresent,
|
||||
isString,
|
||||
isArray
|
||||
} from 'angular2/src/facade/lang';
|
||||
|
||||
var CAMEL_CASE_REGEXP = /([A-Z])/g;
|
||||
var DASH_CASE_REGEXP = /-([a-z])/g;
|
||||
@ -7,6 +14,8 @@ var DOUBLE_QUOTE_ESCAPE_STRING_RE = /"|\\|\n|\r|\$/g;
|
||||
|
||||
export var MODULE_SUFFIX = IS_DART ? '.dart' : '.js';
|
||||
|
||||
export var CONST_VAR = IS_DART ? 'const' : 'var';
|
||||
|
||||
export function camelCaseToDashCase(input: string): string {
|
||||
return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP,
|
||||
(m) => { return '-' + m[1].toLowerCase(); });
|
||||
@ -63,17 +72,24 @@ export function codeGenConstConstructorCall(name: string): string {
|
||||
|
||||
export function codeGenValueFn(params: string[], value: string, fnName: string = ''): string {
|
||||
if (IS_DART) {
|
||||
return `${fnName}(${params.join(',')}) => ${value}`;
|
||||
return `${codeGenFnHeader(params, fnName)} => ${value}`;
|
||||
} else {
|
||||
return `function ${fnName}(${params.join(',')}) { return ${value}; }`;
|
||||
return `${codeGenFnHeader(params, fnName)} { return ${value}; }`;
|
||||
}
|
||||
}
|
||||
|
||||
export function codeGenFnHeader(params: string[], fnName: string = ''): string {
|
||||
if (IS_DART) {
|
||||
return `${fnName}(${params.join(',')})`;
|
||||
} else {
|
||||
return `function ${fnName}(${params.join(',')})`;
|
||||
}
|
||||
}
|
||||
export function codeGenToString(expr: string): string {
|
||||
if (IS_DART) {
|
||||
return `'\${${expr}}'`;
|
||||
} else {
|
||||
// JS automatically convets to string...
|
||||
// JS automatically converts to string...
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
@ -86,3 +102,77 @@ export function splitAtColon(input: string, defaultValues: string[]): string[] {
|
||||
return defaultValues;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class Statement {
|
||||
constructor(public statement: string) {}
|
||||
}
|
||||
|
||||
export class Expression {
|
||||
constructor(public expression: string, public isArray = false) {}
|
||||
}
|
||||
|
||||
export function escapeValue(value: any): string {
|
||||
if (value instanceof Expression) {
|
||||
return value.expression;
|
||||
} else if (isString(value)) {
|
||||
return escapeSingleQuoteString(value);
|
||||
} else if (isBlank(value)) {
|
||||
return 'null';
|
||||
} else {
|
||||
return `${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function codeGenArray(data: any[]): string {
|
||||
return `[${data.map(escapeValue).join(',')}]`;
|
||||
}
|
||||
|
||||
export function codeGenFlatArray(values: any[]): string {
|
||||
var result = '([';
|
||||
var isFirstArrayEntry = true;
|
||||
var concatFn = IS_DART ? '.addAll' : 'concat';
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
var value = values[i];
|
||||
if (value instanceof Expression && (<Expression>value).isArray) {
|
||||
result += `]).${concatFn}(${value.expression}).${concatFn}([`;
|
||||
isFirstArrayEntry = true;
|
||||
} else {
|
||||
if (!isFirstArrayEntry) {
|
||||
result += ',';
|
||||
}
|
||||
isFirstArrayEntry = false;
|
||||
result += escapeValue(value);
|
||||
}
|
||||
}
|
||||
result += '])';
|
||||
return result;
|
||||
}
|
||||
|
||||
export function codeGenStringMap(keyValueArray: any[][]): string {
|
||||
return `{${keyValueArray.map(codeGenKeyValue).join(',')}}`;
|
||||
}
|
||||
|
||||
function codeGenKeyValue(keyValue: any[]): string {
|
||||
return `${escapeValue(keyValue[0])}:${escapeValue(keyValue[1])}`;
|
||||
}
|
||||
|
||||
export function addAll(source: any[], target: any[]) {
|
||||
for (var i = 0; i < source.length; i++) {
|
||||
target.push(source[i]);
|
||||
}
|
||||
}
|
||||
|
||||
export function flattenArray(source: any[], target: any[]): any[] {
|
||||
if (isPresent(source)) {
|
||||
for (var i = 0; i < source.length; i++) {
|
||||
var item = source[i];
|
||||
if (isArray(item)) {
|
||||
flattenArray(item, target);
|
||||
} else {
|
||||
target.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
606
modules/angular2/src/compiler/view_compiler.ts
Normal file
606
modules/angular2/src/compiler/view_compiler.ts
Normal file
@ -0,0 +1,606 @@
|
||||
import {
|
||||
isPresent,
|
||||
isBlank,
|
||||
Type,
|
||||
isString,
|
||||
StringWrapper,
|
||||
IS_DART,
|
||||
CONST_EXPR
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {SetWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
TemplateAst,
|
||||
TemplateAstVisitor,
|
||||
NgContentAst,
|
||||
EmbeddedTemplateAst,
|
||||
ElementAst,
|
||||
VariableAst,
|
||||
BoundEventAst,
|
||||
BoundElementPropertyAst,
|
||||
AttrAst,
|
||||
BoundTextAst,
|
||||
TextAst,
|
||||
DirectiveAst,
|
||||
BoundDirectivePropertyAst,
|
||||
templateVisitAll
|
||||
} from './template_ast';
|
||||
import {CompileTypeMetadata, CompileDirectiveMetadata} from './directive_metadata';
|
||||
import {SourceExpressions, SourceExpression, moduleRef} from './source_module';
|
||||
import {
|
||||
AppProtoView,
|
||||
AppView,
|
||||
flattenNestedViewRenderNodes,
|
||||
checkSlotCount
|
||||
} from 'angular2/src/core/linker/view';
|
||||
import {ViewType} from 'angular2/src/core/linker/view_type';
|
||||
import {AppViewManager_} from 'angular2/src/core/linker/view_manager';
|
||||
import {AppProtoElement, AppElement} from 'angular2/src/core/linker/element';
|
||||
import {Renderer, ParentRenderer} from 'angular2/src/core/render/api';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
|
||||
import {
|
||||
escapeSingleQuoteString,
|
||||
codeGenConstConstructorCall,
|
||||
codeGenValueFn,
|
||||
codeGenFnHeader,
|
||||
MODULE_SUFFIX,
|
||||
Statement,
|
||||
escapeValue,
|
||||
codeGenArray,
|
||||
codeGenFlatArray,
|
||||
Expression,
|
||||
flattenArray,
|
||||
CONST_VAR
|
||||
} from './util';
|
||||
import {ResolvedProvider, Injectable, Injector} from 'angular2/src/core/di';
|
||||
|
||||
import {
|
||||
APP_VIEW_MODULE_REF,
|
||||
APP_EL_MODULE_REF,
|
||||
METADATA_MODULE_REF,
|
||||
CompileProtoView,
|
||||
CompileProtoElement
|
||||
} from './proto_view_compiler';
|
||||
|
||||
export const VIEW_JIT_IMPORTS = CONST_EXPR({
|
||||
'AppView': AppView,
|
||||
'AppElement': AppElement,
|
||||
'flattenNestedViewRenderNodes': flattenNestedViewRenderNodes,
|
||||
'checkSlotCount': checkSlotCount
|
||||
});
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class ViewCompiler {
|
||||
constructor() {}
|
||||
|
||||
compileComponentRuntime(component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
styles: Array<string | any[]>,
|
||||
protoViews: CompileProtoView<AppProtoView, AppProtoElement>[],
|
||||
changeDetectorFactories: Function[],
|
||||
componentViewFactory: Function): Function {
|
||||
var viewFactory = new RuntimeViewFactory(component, styles, protoViews, changeDetectorFactories,
|
||||
componentViewFactory);
|
||||
return viewFactory.createViewFactory(template, 0, []);
|
||||
}
|
||||
|
||||
compileComponentCodeGen(component: CompileDirectiveMetadata, template: TemplateAst[],
|
||||
styles: SourceExpression,
|
||||
protoViews: CompileProtoView<Expression, Expression>[],
|
||||
changeDetectorFactoryExpressions: SourceExpressions,
|
||||
componentViewFactory: Function): SourceExpression {
|
||||
var viewFactory = new CodeGenViewFactory(
|
||||
component, styles, protoViews, changeDetectorFactoryExpressions, componentViewFactory);
|
||||
var targetStatements: Statement[] = [];
|
||||
var viewFactoryExpression = viewFactory.createViewFactory(template, 0, targetStatements);
|
||||
return new SourceExpression(targetStatements.map(stmt => stmt.statement),
|
||||
viewFactoryExpression.expression);
|
||||
}
|
||||
}
|
||||
|
||||
interface ViewFactory<EXPRESSION, STATEMENT> {
|
||||
createText(renderer: EXPRESSION, parent: EXPRESSION, text: string,
|
||||
targetStatements: STATEMENT[]): EXPRESSION;
|
||||
|
||||
createElement(renderer: EXPRESSION, parent: EXPRESSION, name: string, rootSelector: EXPRESSION,
|
||||
targetStatements: STATEMENT[]): EXPRESSION;
|
||||
|
||||
createTemplateAnchor(renderer: EXPRESSION, parent: EXPRESSION,
|
||||
targetStatements: STATEMENT[]): EXPRESSION;
|
||||
|
||||
createGlobalEventListener(renderer: EXPRESSION, view: EXPRESSION, boundElementIndex: number,
|
||||
eventAst: BoundEventAst, targetStatements: STATEMENT[]): EXPRESSION;
|
||||
|
||||
createElementEventListener(renderer: EXPRESSION, view: EXPRESSION, boundElementIndex: number,
|
||||
renderNode: EXPRESSION, eventAst: BoundEventAst,
|
||||
targetStatements: STATEMENT[]): EXPRESSION;
|
||||
|
||||
setElementAttribute(renderer: EXPRESSION, renderNode: EXPRESSION, attrName: string,
|
||||
attrValue: string, targetStatements: STATEMENT[]);
|
||||
|
||||
createAppElement(appProtoEl: EXPRESSION, view: EXPRESSION, renderNode: EXPRESSION,
|
||||
parentAppEl: EXPRESSION, embeddedViewFactory: EXPRESSION,
|
||||
targetStatements: STATEMENT[]): EXPRESSION;
|
||||
|
||||
createAndSetComponentView(renderer: EXPRESSION, viewManager: EXPRESSION, view: EXPRESSION,
|
||||
appEl: EXPRESSION, component: CompileDirectiveMetadata,
|
||||
contentNodesByNgContentIndex: EXPRESSION[][],
|
||||
targetStatements: STATEMENT[]);
|
||||
|
||||
getProjectedNodes(projectableNodes: EXPRESSION, ngContentIndex: number): EXPRESSION;
|
||||
|
||||
appendProjectedNodes(renderer: EXPRESSION, parent: EXPRESSION, nodes: EXPRESSION,
|
||||
targetStatements: STATEMENT[]);
|
||||
|
||||
createViewFactory(asts: TemplateAst[], embeddedTemplateIndex: number,
|
||||
targetStatements: STATEMENT[]): EXPRESSION;
|
||||
}
|
||||
|
||||
class CodeGenViewFactory implements ViewFactory<Expression, Statement> {
|
||||
private _nextVarId: number = 0;
|
||||
constructor(public component: CompileDirectiveMetadata, public styles: SourceExpression,
|
||||
public protoViews: CompileProtoView<Expression, Expression>[],
|
||||
public changeDetectorExpressions: SourceExpressions,
|
||||
public componentViewFactory: Function) {}
|
||||
|
||||
private _nextVar(prefix: string): string {
|
||||
return `${prefix}${this._nextVarId++}_${this.component.type.name}`;
|
||||
}
|
||||
|
||||
private _nextRenderVar(): string { return this._nextVar('render'); }
|
||||
|
||||
private _nextAppVar(): string { return this._nextVar('app'); }
|
||||
|
||||
private _nextDisposableVar(): string {
|
||||
return `disposable${this._nextVarId++}_${this.component.type.name}`;
|
||||
}
|
||||
|
||||
createText(renderer: Expression, parent: Expression, text: string,
|
||||
targetStatements: Statement[]): Expression {
|
||||
var varName = this._nextRenderVar();
|
||||
var statement =
|
||||
`var ${varName} = ${renderer.expression}.createText(${isPresent(parent) ? parent.expression : null}, ${escapeSingleQuoteString(text)});`;
|
||||
targetStatements.push(new Statement(statement));
|
||||
return new Expression(varName);
|
||||
}
|
||||
|
||||
createElement(renderer: Expression, parentRenderNode: Expression, name: string,
|
||||
rootSelector: Expression, targetStatements: Statement[]): Expression {
|
||||
var varName = this._nextRenderVar();
|
||||
var valueExpr;
|
||||
if (isPresent(rootSelector)) {
|
||||
valueExpr = `${rootSelector.expression} == null ?
|
||||
${renderer.expression}.createElement(${isPresent(parentRenderNode) ? parentRenderNode.expression : null}, ${escapeSingleQuoteString(name)}) :
|
||||
${renderer.expression}.selectRootElement(${rootSelector.expression});`;
|
||||
} else {
|
||||
valueExpr =
|
||||
`${renderer.expression}.createElement(${isPresent(parentRenderNode) ? parentRenderNode.expression : null}, ${escapeSingleQuoteString(name)})`;
|
||||
}
|
||||
var statement = `var ${varName} = ${valueExpr};`;
|
||||
targetStatements.push(new Statement(statement));
|
||||
return new Expression(varName);
|
||||
}
|
||||
|
||||
createTemplateAnchor(renderer: Expression, parentRenderNode: Expression,
|
||||
targetStatements: Statement[]): Expression {
|
||||
var varName = this._nextRenderVar();
|
||||
var valueExpr =
|
||||
`${renderer.expression}.createTemplateAnchor(${isPresent(parentRenderNode) ? parentRenderNode.expression : null});`;
|
||||
targetStatements.push(new Statement(`var ${varName} = ${valueExpr}`));
|
||||
return new Expression(varName);
|
||||
}
|
||||
|
||||
createGlobalEventListener(renderer: Expression, appView: Expression, boundElementIndex: number,
|
||||
eventAst: BoundEventAst, targetStatements: Statement[]): Expression {
|
||||
var disposableVar = this._nextDisposableVar();
|
||||
var eventHandlerExpr = codeGenEventHandler(appView, boundElementIndex, eventAst.fullName);
|
||||
targetStatements.push(new Statement(
|
||||
`var ${disposableVar} = ${renderer.expression}.listenGlobal(${escapeValue(eventAst.target)}, ${escapeValue(eventAst.name)}, ${eventHandlerExpr});`));
|
||||
return new Expression(disposableVar);
|
||||
}
|
||||
|
||||
createElementEventListener(renderer: Expression, appView: Expression, boundElementIndex: number,
|
||||
renderNode: Expression, eventAst: BoundEventAst,
|
||||
targetStatements: Statement[]) {
|
||||
var disposableVar = this._nextDisposableVar();
|
||||
var eventHandlerExpr = codeGenEventHandler(appView, boundElementIndex, eventAst.fullName);
|
||||
targetStatements.push(new Statement(
|
||||
`var ${disposableVar} = ${renderer.expression}.listen(${renderNode.expression}, ${escapeValue(eventAst.name)}, ${eventHandlerExpr});`));
|
||||
return new Expression(disposableVar);
|
||||
}
|
||||
|
||||
setElementAttribute(renderer: Expression, renderNode: Expression, attrName: string,
|
||||
attrValue: string, targetStatements: Statement[]) {
|
||||
targetStatements.push(new Statement(
|
||||
`${renderer.expression}.setElementAttribute(${renderNode.expression}, ${escapeSingleQuoteString(attrName)}, ${escapeSingleQuoteString(attrValue)});`));
|
||||
}
|
||||
|
||||
createAppElement(appProtoEl: Expression, appView: Expression, renderNode: Expression,
|
||||
parentAppEl: Expression, embeddedViewFactory: Expression,
|
||||
targetStatements: Statement[]): Expression {
|
||||
var appVar = this._nextAppVar();
|
||||
var varValue =
|
||||
`new ${APP_EL_MODULE_REF}AppElement(${appProtoEl.expression}, ${appView.expression},
|
||||
${isPresent(parentAppEl) ? parentAppEl.expression : null}, ${renderNode.expression}, ${isPresent(embeddedViewFactory) ? embeddedViewFactory.expression : null})`;
|
||||
targetStatements.push(new Statement(`var ${appVar} = ${varValue};`));
|
||||
return new Expression(appVar);
|
||||
}
|
||||
|
||||
createAndSetComponentView(renderer: Expression, viewManager: Expression, view: Expression,
|
||||
appEl: Expression, component: CompileDirectiveMetadata,
|
||||
contentNodesByNgContentIndex: Expression[][],
|
||||
targetStatements: Statement[]) {
|
||||
var codeGenContentNodes;
|
||||
if (this.component.type.isHost) {
|
||||
codeGenContentNodes = `${view.expression}.projectableNodes`;
|
||||
} else {
|
||||
codeGenContentNodes =
|
||||
`[${contentNodesByNgContentIndex.map( nodes => codeGenFlatArray(nodes) ).join(',')}]`;
|
||||
}
|
||||
targetStatements.push(new Statement(
|
||||
`${this.componentViewFactory(component)}(${renderer.expression}, ${viewManager.expression}, ${appEl.expression}, ${codeGenContentNodes}, null, null, null);`));
|
||||
}
|
||||
|
||||
getProjectedNodes(projectableNodes: Expression, ngContentIndex: number): Expression {
|
||||
return new Expression(`${projectableNodes.expression}[${ngContentIndex}]`, true);
|
||||
}
|
||||
|
||||
appendProjectedNodes(renderer: Expression, parent: Expression, nodes: Expression,
|
||||
targetStatements: Statement[]) {
|
||||
targetStatements.push(new Statement(
|
||||
`${renderer.expression}.projectNodes(${parent.expression}, ${APP_VIEW_MODULE_REF}flattenNestedViewRenderNodes(${nodes.expression}));`));
|
||||
}
|
||||
|
||||
createViewFactory(asts: TemplateAst[], embeddedTemplateIndex: number,
|
||||
targetStatements: Statement[]): Expression {
|
||||
var compileProtoView = this.protoViews[embeddedTemplateIndex];
|
||||
var isHostView = this.component.type.isHost;
|
||||
var isComponentView = embeddedTemplateIndex === 0 && !isHostView;
|
||||
var visitor = new ViewBuilderVisitor<Expression, Statement>(
|
||||
new Expression('renderer'), new Expression('viewManager'),
|
||||
new Expression('projectableNodes'), isHostView ? new Expression('rootSelector') : null,
|
||||
new Expression('view'), compileProtoView, targetStatements, this);
|
||||
|
||||
templateVisitAll(
|
||||
visitor, asts,
|
||||
new ParentElement(isComponentView ? new Expression('parentRenderNode') : null, null, null));
|
||||
|
||||
var appProtoView = compileProtoView.protoView.expression;
|
||||
var viewFactoryName = codeGenViewFactoryName(this.component, embeddedTemplateIndex);
|
||||
var changeDetectorFactory = this.changeDetectorExpressions.expressions[embeddedTemplateIndex];
|
||||
var factoryArgs = [
|
||||
'parentRenderer',
|
||||
'viewManager',
|
||||
'containerEl',
|
||||
'projectableNodes',
|
||||
'rootSelector',
|
||||
'dynamicallyCreatedProviders',
|
||||
'rootInjector'
|
||||
];
|
||||
var initRendererStmts = [];
|
||||
var rendererExpr = `parentRenderer`;
|
||||
if (embeddedTemplateIndex === 0) {
|
||||
var renderCompTypeVar = this._nextVar('renderType');
|
||||
targetStatements.push(new Statement(`var ${renderCompTypeVar} = null;`));
|
||||
var stylesVar = this._nextVar('styles');
|
||||
targetStatements.push(
|
||||
new Statement(`${CONST_VAR} ${stylesVar} = ${this.styles.expression};`));
|
||||
var encapsulation = this.component.template.encapsulation;
|
||||
initRendererStmts.push(`if (${renderCompTypeVar} == null) {
|
||||
${renderCompTypeVar} = viewManager.createRenderComponentType(${codeGenViewEncapsulation(encapsulation)}, ${stylesVar});
|
||||
}`);
|
||||
rendererExpr = `parentRenderer.renderComponent(${renderCompTypeVar})`;
|
||||
}
|
||||
var statement = `
|
||||
${codeGenFnHeader(factoryArgs, viewFactoryName)}{
|
||||
${initRendererStmts.join('\n')}
|
||||
var renderer = ${rendererExpr};
|
||||
var view = new ${APP_VIEW_MODULE_REF}AppView(
|
||||
${appProtoView}, renderer, viewManager,
|
||||
projectableNodes,
|
||||
containerEl,
|
||||
dynamicallyCreatedProviders, rootInjector,
|
||||
${changeDetectorFactory}()
|
||||
);
|
||||
${APP_VIEW_MODULE_REF}checkSlotCount(${escapeValue(this.component.type.name)}, ${this.component.template.ngContentSelectors.length}, projectableNodes);
|
||||
${isComponentView ? 'var parentRenderNode = renderer.createViewRoot(view.containerAppElement.nativeElement);' : ''}
|
||||
${visitor.renderStmts.map(stmt => stmt.statement).join('\n')}
|
||||
${visitor.appStmts.map(stmt => stmt.statement).join('\n')}
|
||||
|
||||
view.init(${codeGenFlatArray(visitor.rootNodesOrAppElements)}, ${codeGenArray(visitor.renderNodes)}, ${codeGenArray(visitor.appDisposables)},
|
||||
${codeGenArray(visitor.appElements)});
|
||||
return view;
|
||||
}`;
|
||||
targetStatements.push(new Statement(statement));
|
||||
return new Expression(viewFactoryName);
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeViewFactory implements ViewFactory<any, any> {
|
||||
constructor(public component: CompileDirectiveMetadata, public styles: Array<string | any[]>,
|
||||
public protoViews: CompileProtoView<AppProtoView, AppProtoElement>[],
|
||||
public changeDetectorFactories: Function[], public componentViewFactory: Function) {}
|
||||
|
||||
createText(renderer: Renderer, parent: any, text: string, targetStatements: any[]): any {
|
||||
return renderer.createText(parent, text);
|
||||
}
|
||||
|
||||
createElement(renderer: Renderer, parent: any, name: string, rootSelector: string,
|
||||
targetStatements: any[]): any {
|
||||
var el;
|
||||
if (isPresent(rootSelector)) {
|
||||
el = renderer.selectRootElement(rootSelector);
|
||||
} else {
|
||||
el = renderer.createElement(parent, name);
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
createTemplateAnchor(renderer: Renderer, parent: any, targetStatements: any[]): any {
|
||||
return renderer.createTemplateAnchor(parent);
|
||||
}
|
||||
|
||||
createGlobalEventListener(renderer: Renderer, appView: AppView, boundElementIndex: number,
|
||||
eventAst: BoundEventAst, targetStatements: any[]): any {
|
||||
return renderer.listenGlobal(
|
||||
eventAst.target, eventAst.name,
|
||||
(event) => appView.triggerEventHandlers(eventAst.fullName, event, boundElementIndex));
|
||||
}
|
||||
|
||||
createElementEventListener(renderer: Renderer, appView: AppView, boundElementIndex: number,
|
||||
renderNode: any, eventAst: BoundEventAst,
|
||||
targetStatements: any[]): any {
|
||||
return renderer.listen(
|
||||
renderNode, eventAst.name,
|
||||
(event) => appView.triggerEventHandlers(eventAst.fullName, event, boundElementIndex));
|
||||
}
|
||||
|
||||
setElementAttribute(renderer: Renderer, renderNode: any, attrName: string, attrValue: string,
|
||||
targetStatements: any[]) {
|
||||
renderer.setElementAttribute(renderNode, attrName, attrValue);
|
||||
}
|
||||
|
||||
createAppElement(appProtoEl: AppProtoElement, appView: AppView, renderNode: any,
|
||||
parentAppEl: AppElement, embeddedViewFactory: Function,
|
||||
targetStatements: any[]): any {
|
||||
return new AppElement(appProtoEl, appView, parentAppEl, renderNode, embeddedViewFactory);
|
||||
}
|
||||
|
||||
createAndSetComponentView(renderer: Renderer, viewManager: AppViewManager_, appView: AppView,
|
||||
appEl: AppElement, component: CompileDirectiveMetadata,
|
||||
contentNodesByNgContentIndex: Array<Array<any | any[]>>,
|
||||
targetStatements: any[]) {
|
||||
var flattenedContentNodes;
|
||||
if (this.component.type.isHost) {
|
||||
flattenedContentNodes = appView.projectableNodes;
|
||||
} else {
|
||||
flattenedContentNodes = ListWrapper.createFixedSize(contentNodesByNgContentIndex.length);
|
||||
for (var i = 0; i < contentNodesByNgContentIndex.length; i++) {
|
||||
flattenedContentNodes[i] = flattenArray(contentNodesByNgContentIndex[i], []);
|
||||
}
|
||||
}
|
||||
this.componentViewFactory(component)(renderer, viewManager, appEl, flattenedContentNodes);
|
||||
}
|
||||
|
||||
getProjectedNodes(projectableNodes: any[][], ngContentIndex: number): any[] {
|
||||
return projectableNodes[ngContentIndex];
|
||||
}
|
||||
|
||||
appendProjectedNodes(renderer: Renderer, parent: any, nodes: any[], targetStatements: any[]) {
|
||||
renderer.projectNodes(parent, flattenNestedViewRenderNodes(nodes));
|
||||
}
|
||||
|
||||
createViewFactory(asts: TemplateAst[], embeddedTemplateIndex: number,
|
||||
targetStatements: any[]): Function {
|
||||
var compileProtoView = this.protoViews[embeddedTemplateIndex];
|
||||
var isComponentView = compileProtoView.protoView.type === ViewType.COMPONENT;
|
||||
var renderComponentType = null;
|
||||
return (parentRenderer: ParentRenderer, viewManager: AppViewManager_, containerEl: AppElement,
|
||||
projectableNodes: any[][], rootSelector: string = null,
|
||||
dynamicallyCreatedProviders: ResolvedProvider[] = null,
|
||||
rootInjector: Injector = null) => {
|
||||
checkSlotCount(this.component.type.name, this.component.template.ngContentSelectors.length,
|
||||
projectableNodes);
|
||||
var renderer;
|
||||
if (embeddedTemplateIndex === 0) {
|
||||
if (isBlank(renderComponentType)) {
|
||||
renderComponentType = viewManager.createRenderComponentType(
|
||||
this.component.template.encapsulation, this.styles);
|
||||
}
|
||||
renderer = parentRenderer.renderComponent(renderComponentType);
|
||||
} else {
|
||||
renderer = <Renderer>parentRenderer;
|
||||
}
|
||||
var changeDetector = this.changeDetectorFactories[embeddedTemplateIndex]();
|
||||
var view =
|
||||
new AppView(compileProtoView.protoView, renderer, viewManager, projectableNodes,
|
||||
containerEl, dynamicallyCreatedProviders, rootInjector, changeDetector);
|
||||
var visitor = new ViewBuilderVisitor<any, any>(
|
||||
renderer, viewManager, projectableNodes, rootSelector, view, compileProtoView, [], this);
|
||||
var parentRenderNode =
|
||||
isComponentView ? renderer.createViewRoot(containerEl.nativeElement) : null;
|
||||
templateVisitAll(visitor, asts, new ParentElement(parentRenderNode, null, null));
|
||||
view.init(flattenArray(visitor.rootNodesOrAppElements, []), visitor.renderNodes,
|
||||
visitor.appDisposables, visitor.appElements);
|
||||
return view;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ParentElement<EXPRESSION> {
|
||||
public contentNodesByNgContentIndex: Array<EXPRESSION>[];
|
||||
|
||||
constructor(public renderNode: EXPRESSION, public appEl: EXPRESSION,
|
||||
public component: CompileDirectiveMetadata) {
|
||||
if (isPresent(component)) {
|
||||
this.contentNodesByNgContentIndex =
|
||||
ListWrapper.createFixedSize(component.template.ngContentSelectors.length);
|
||||
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
|
||||
this.contentNodesByNgContentIndex[i] = [];
|
||||
}
|
||||
} else {
|
||||
this.contentNodesByNgContentIndex = null;
|
||||
}
|
||||
}
|
||||
|
||||
addContentNode(ngContentIndex: number, nodeExpr: EXPRESSION) {
|
||||
this.contentNodesByNgContentIndex[ngContentIndex].push(nodeExpr);
|
||||
}
|
||||
}
|
||||
|
||||
class ViewBuilderVisitor<EXPRESSION, STATEMENT> implements TemplateAstVisitor {
|
||||
renderStmts: Array<STATEMENT> = [];
|
||||
renderNodes: EXPRESSION[] = [];
|
||||
appStmts: Array<STATEMENT> = [];
|
||||
appElements: EXPRESSION[] = [];
|
||||
appDisposables: EXPRESSION[] = [];
|
||||
|
||||
rootNodesOrAppElements: EXPRESSION[] = [];
|
||||
|
||||
elementCount: number = 0;
|
||||
|
||||
constructor(public renderer: EXPRESSION, public viewManager: EXPRESSION,
|
||||
public projectableNodes: EXPRESSION, public rootSelector: EXPRESSION,
|
||||
public view: EXPRESSION, public protoView: CompileProtoView<EXPRESSION, EXPRESSION>,
|
||||
public targetStatements: STATEMENT[],
|
||||
public factory: ViewFactory<EXPRESSION, STATEMENT>) {}
|
||||
|
||||
private _addRenderNode(renderNode: EXPRESSION, appEl: EXPRESSION, ngContentIndex: number,
|
||||
parent: ParentElement<EXPRESSION>) {
|
||||
this.renderNodes.push(renderNode);
|
||||
if (isPresent(parent.component)) {
|
||||
if (isPresent(ngContentIndex)) {
|
||||
parent.addContentNode(ngContentIndex, isPresent(appEl) ? appEl : renderNode);
|
||||
}
|
||||
} else if (isBlank(parent.renderNode)) {
|
||||
this.rootNodesOrAppElements.push(isPresent(appEl) ? appEl : renderNode);
|
||||
}
|
||||
}
|
||||
|
||||
private _getParentRenderNode(ngContentIndex: number,
|
||||
parent: ParentElement<EXPRESSION>): EXPRESSION {
|
||||
return isPresent(parent.component) &&
|
||||
parent.component.template.encapsulation !== ViewEncapsulation.Native ?
|
||||
null :
|
||||
parent.renderNode;
|
||||
}
|
||||
|
||||
visitBoundText(ast: BoundTextAst, parent: ParentElement<EXPRESSION>): any {
|
||||
return this._visitText('', ast.ngContentIndex, parent);
|
||||
}
|
||||
visitText(ast: TextAst, parent: ParentElement<EXPRESSION>): any {
|
||||
return this._visitText(ast.value, ast.ngContentIndex, parent);
|
||||
}
|
||||
private _visitText(value: string, ngContentIndex: number, parent: ParentElement<EXPRESSION>) {
|
||||
var renderNode = this.factory.createText(
|
||||
this.renderer, this._getParentRenderNode(ngContentIndex, parent), value, this.renderStmts);
|
||||
this._addRenderNode(renderNode, null, ngContentIndex, parent);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitNgContent(ast: NgContentAst, parent: ParentElement<EXPRESSION>): any {
|
||||
var nodesExpression = this.factory.getProjectedNodes(this.projectableNodes, ast.index);
|
||||
if (isPresent(parent.component)) {
|
||||
if (isPresent(ast.ngContentIndex)) {
|
||||
parent.addContentNode(ast.ngContentIndex, nodesExpression);
|
||||
}
|
||||
} else {
|
||||
if (isPresent(parent.renderNode)) {
|
||||
this.factory.appendProjectedNodes(this.renderer, parent.renderNode, nodesExpression,
|
||||
this.renderStmts);
|
||||
} else {
|
||||
this.rootNodesOrAppElements.push(nodesExpression);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
visitElement(ast: ElementAst, parent: ParentElement<EXPRESSION>): any {
|
||||
var renderNode = this.factory.createElement(
|
||||
this.renderer, this._getParentRenderNode(ast.ngContentIndex, parent), ast.name,
|
||||
this.rootSelector, this.renderStmts);
|
||||
|
||||
var component = ast.getComponent();
|
||||
var elementIndex = this.elementCount++;
|
||||
var protoEl = this.protoView.protoElements[elementIndex];
|
||||
|
||||
protoEl.renderEvents.forEach((eventAst) => {
|
||||
var disposable;
|
||||
if (isPresent(eventAst.target)) {
|
||||
disposable = this.factory.createGlobalEventListener(
|
||||
this.renderer, this.view, protoEl.boundElementIndex, eventAst, this.renderStmts);
|
||||
} else {
|
||||
disposable = this.factory.createElementEventListener(this.renderer, this.view,
|
||||
protoEl.boundElementIndex, renderNode,
|
||||
eventAst, this.renderStmts);
|
||||
}
|
||||
this.appDisposables.push(disposable);
|
||||
});
|
||||
for (var i = 0; i < protoEl.attrNameAndValues.length; i++) {
|
||||
var attrName = protoEl.attrNameAndValues[i][0];
|
||||
var attrValue = protoEl.attrNameAndValues[i][1];
|
||||
this.factory.setElementAttribute(this.renderer, renderNode, attrName, attrValue,
|
||||
this.renderStmts);
|
||||
}
|
||||
var appEl = null;
|
||||
if (isPresent(protoEl.appProtoEl)) {
|
||||
appEl = this.factory.createAppElement(protoEl.appProtoEl, this.view, renderNode, parent.appEl,
|
||||
null, this.appStmts);
|
||||
this.appElements.push(appEl);
|
||||
}
|
||||
this._addRenderNode(renderNode, appEl, ast.ngContentIndex, parent);
|
||||
|
||||
var newParent = new ParentElement<EXPRESSION>(
|
||||
renderNode, isPresent(appEl) ? appEl : parent.appEl, component);
|
||||
templateVisitAll(this, ast.children, newParent);
|
||||
if (isPresent(appEl) && isPresent(component)) {
|
||||
this.factory.createAndSetComponentView(this.renderer, this.viewManager, this.view, appEl,
|
||||
component, newParent.contentNodesByNgContentIndex,
|
||||
this.appStmts);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, parent: ParentElement<EXPRESSION>): any {
|
||||
var renderNode = this.factory.createTemplateAnchor(
|
||||
this.renderer, this._getParentRenderNode(ast.ngContentIndex, parent), this.renderStmts);
|
||||
|
||||
var elementIndex = this.elementCount++;
|
||||
var protoEl = this.protoView.protoElements[elementIndex];
|
||||
var embeddedViewFactory = this.factory.createViewFactory(
|
||||
ast.children, protoEl.embeddedTemplateIndex, this.targetStatements);
|
||||
|
||||
var appEl = this.factory.createAppElement(protoEl.appProtoEl, this.view, renderNode,
|
||||
parent.appEl, embeddedViewFactory, this.appStmts);
|
||||
this._addRenderNode(renderNode, appEl, ast.ngContentIndex, parent);
|
||||
this.appElements.push(appEl);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitVariable(ast: VariableAst, ctx: any): any { return null; }
|
||||
visitAttr(ast: AttrAst, ctx: any): any { return null; }
|
||||
visitDirective(ast: DirectiveAst, ctx: any): any { return null; }
|
||||
visitEvent(ast: BoundEventAst, ctx: any): any { return null; }
|
||||
visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; }
|
||||
visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; }
|
||||
}
|
||||
|
||||
|
||||
function codeGenEventHandler(view: Expression, boundElementIndex: number,
|
||||
eventName: string): string {
|
||||
return codeGenValueFn(
|
||||
['event'],
|
||||
`${view.expression}.triggerEventHandlers(${escapeValue(eventName)}, event, ${boundElementIndex})`);
|
||||
}
|
||||
|
||||
function codeGenViewFactoryName(component: CompileDirectiveMetadata,
|
||||
embeddedTemplateIndex: number): string {
|
||||
return `viewFactory_${component.type.name}${embeddedTemplateIndex}`;
|
||||
}
|
||||
|
||||
function codeGenViewEncapsulation(value: ViewEncapsulation): string {
|
||||
if (IS_DART) {
|
||||
return `${METADATA_MODULE_REF}${value}`;
|
||||
} else {
|
||||
return `${value}`;
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
|
||||
// TODO: vsavkin rename it into TemplateLoader
|
||||
/**
|
||||
* An interface for retrieving documents by URL that the compiler uses
|
||||
|
@ -2,10 +2,10 @@ import {XHR} from 'angular2/src/compiler/xhr';
|
||||
import {ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {isBlank, isPresent, normalizeBlank} from 'angular2/src/facade/lang';
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
import {PromiseCompleter, PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {PromiseCompleter, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
/**
|
||||
* A mock implemenation of {@link XHR} that allows outgoing requests to be mocked
|
||||
* A mock implementation of {@link XHR} that allows outgoing requests to be mocked
|
||||
* and responded to within a single test, without going to the network.
|
||||
*/
|
||||
export class MockXHR extends XHR {
|
||||
|
@ -11,13 +11,10 @@ import {
|
||||
KeyValueDiffers,
|
||||
defaultKeyValueDiffers
|
||||
} from './change_detection/change_detection';
|
||||
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from './linker/view_pool';
|
||||
import {ResolvedMetadataCache} from 'angular2/src/core/linker/resolved_metadata_cache';
|
||||
import {AppViewManager} from './linker/view_manager';
|
||||
import {AppViewManager_} from "./linker/view_manager";
|
||||
import {AppViewManagerUtils} from './linker/view_manager_utils';
|
||||
import {ViewResolver} from './linker/view_resolver';
|
||||
import {AppViewListener} from './linker/view_listener';
|
||||
import {ProtoViewFactory} from './linker/proto_view_factory';
|
||||
import {DirectiveResolver} from './linker/directive_resolver';
|
||||
import {PipeResolver} from './linker/pipe_resolver';
|
||||
import {Compiler} from './linker/compiler';
|
||||
@ -32,12 +29,8 @@ import {DynamicComponentLoader_} from "./linker/dynamic_component_loader";
|
||||
export const APPLICATION_COMMON_PROVIDERS: Array<Type | Provider | any[]> = CONST_EXPR([
|
||||
new Provider(Compiler, {useClass: Compiler_}),
|
||||
APP_ID_RANDOM_PROVIDER,
|
||||
AppViewPool,
|
||||
new Provider(APP_VIEW_POOL_CAPACITY, {useValue: 10000}),
|
||||
ResolvedMetadataCache,
|
||||
new Provider(AppViewManager, {useClass: AppViewManager_}),
|
||||
AppViewManagerUtils,
|
||||
AppViewListener,
|
||||
ProtoViewFactory,
|
||||
ViewResolver,
|
||||
new Provider(IterableDiffers, {useValue: defaultIterableDiffers}),
|
||||
new Provider(KeyValueDiffers, {useValue: defaultKeyValueDiffers}),
|
||||
|
@ -15,12 +15,7 @@ import {
|
||||
PLATFORM_INITIALIZER,
|
||||
APP_INITIALIZER
|
||||
} from './application_tokens';
|
||||
import {
|
||||
Promise,
|
||||
PromiseWrapper,
|
||||
PromiseCompleter,
|
||||
ObservableWrapper
|
||||
} from 'angular2/src/facade/async';
|
||||
import {PromiseWrapper, PromiseCompleter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability';
|
||||
import {
|
||||
@ -33,11 +28,11 @@ import {
|
||||
ExceptionHandler,
|
||||
unimplemented
|
||||
} from 'angular2/src/facade/exceptions';
|
||||
import {internalView} from 'angular2/src/core/linker/view_ref';
|
||||
import {Console} from 'angular2/src/core/console';
|
||||
import {wtfLeave, wtfCreateScope, WtfScopeFn} from './profile/profile';
|
||||
import {ChangeDetectorRef} from 'angular2/src/core/change_detection/change_detector_ref';
|
||||
import {lockMode} from 'angular2/src/facade/lang';
|
||||
import {ElementRef_} from 'angular2/src/core/linker/element_ref';
|
||||
|
||||
/**
|
||||
* Construct providers specific to an individual root component.
|
||||
@ -56,10 +51,10 @@ function _componentProviders(appComponentType: Type): Array<Type | Provider | an
|
||||
() => { appRef._unloadComponent(ref); })
|
||||
.then((componentRef) => {
|
||||
ref = componentRef;
|
||||
if (isPresent(componentRef.location.nativeElement)) {
|
||||
var testability = injector.getOptional(Testability);
|
||||
if (isPresent(testability)) {
|
||||
injector.get(TestabilityRegistry)
|
||||
.registerApplication(componentRef.location.nativeElement,
|
||||
injector.get(Testability));
|
||||
.registerApplication(componentRef.location.nativeElement, testability);
|
||||
}
|
||||
return componentRef;
|
||||
});
|
||||
@ -217,25 +212,36 @@ export class PlatformRef_ extends PlatformRef {
|
||||
|
||||
application(providers: Array<Type | Provider | any[]>): ApplicationRef {
|
||||
var app = this._initApp(createNgZone(), providers);
|
||||
return app;
|
||||
if (PromiseWrapper.isPromise(app)) {
|
||||
throw new BaseException(
|
||||
"Cannot use asyncronous app initializers with application. Use asyncApplication instead.");
|
||||
}
|
||||
return <ApplicationRef>app;
|
||||
}
|
||||
|
||||
asyncApplication(bindingFn: (zone: NgZone) => Promise<Array<Type | Provider | any[]>>,
|
||||
additionalProviders?: Array<Type | Provider | any[]>): Promise<ApplicationRef> {
|
||||
var zone = createNgZone();
|
||||
var completer = PromiseWrapper.completer();
|
||||
if (bindingFn === null) {
|
||||
completer.resolve(this._initApp(zone, additionalProviders));
|
||||
} else {
|
||||
zone.run(() => {
|
||||
PromiseWrapper.then(bindingFn(zone), (providers: Array<Type | Provider | any[]>) => {
|
||||
if (isPresent(additionalProviders)) {
|
||||
providers = ListWrapper.concat(providers, additionalProviders);
|
||||
}
|
||||
completer.resolve(this._initApp(zone, providers));
|
||||
let promise = this._initApp(zone, providers);
|
||||
completer.resolve(promise);
|
||||
});
|
||||
});
|
||||
}
|
||||
return completer.promise;
|
||||
}
|
||||
|
||||
private _initApp(zone: NgZone, providers: Array<Type | Provider | any[]>): ApplicationRef {
|
||||
private _initApp(zone: NgZone,
|
||||
providers: Array<Type | Provider | any[]>): Promise<ApplicationRef>|
|
||||
ApplicationRef {
|
||||
var injector: Injector;
|
||||
var app: ApplicationRef;
|
||||
zone.run(() => {
|
||||
@ -259,9 +265,13 @@ export class PlatformRef_ extends PlatformRef {
|
||||
});
|
||||
app = new ApplicationRef_(this, zone, injector);
|
||||
this._applications.push(app);
|
||||
_runAppInitializers(injector);
|
||||
var promise = _runAppInitializers(injector);
|
||||
if (promise !== null) {
|
||||
return PromiseWrapper.then(promise, (_) => app);
|
||||
} else {
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
ListWrapper.clone(this._applications).forEach((app) => app.dispose());
|
||||
@ -273,9 +283,22 @@ export class PlatformRef_ extends PlatformRef {
|
||||
_applicationDisposed(app: ApplicationRef): void { ListWrapper.remove(this._applications, app); }
|
||||
}
|
||||
|
||||
function _runAppInitializers(injector: Injector): void {
|
||||
function _runAppInitializers(injector: Injector): Promise<any> {
|
||||
let inits: Function[] = injector.getOptional(APP_INITIALIZER);
|
||||
if (isPresent(inits)) inits.forEach(init => init());
|
||||
let promises: Promise<any>[] = [];
|
||||
if (isPresent(inits)) {
|
||||
inits.forEach(init => {
|
||||
var retVal = init();
|
||||
if (PromiseWrapper.isPromise(retVal)) {
|
||||
promises.push(retVal);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (promises.length > 0) {
|
||||
return PromiseWrapper.all(promises);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -428,18 +451,17 @@ export class ApplicationRef_ extends ApplicationRef {
|
||||
});
|
||||
return completer.promise.then(_ => {
|
||||
let c = this._injector.get(Console);
|
||||
let modeDescription =
|
||||
assertionsEnabled() ?
|
||||
"in the development mode. Call enableProdMode() to enable the production mode." :
|
||||
"in the production mode. Call enableDevMode() to enable the development mode.";
|
||||
c.log(`Angular 2 is running ${modeDescription}`);
|
||||
if (assertionsEnabled()) {
|
||||
c.log(
|
||||
"Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode.");
|
||||
}
|
||||
return _;
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_loadComponent(ref): void {
|
||||
var appChangeDetector = internalView(ref.hostView).changeDetector;
|
||||
var appChangeDetector = (<ElementRef_>ref.location).internalElement.parentView.changeDetector;
|
||||
this._changeDetectorRefs.push(appChangeDetector.ref);
|
||||
this.tick();
|
||||
this._rootComponents.push(ref);
|
||||
@ -451,7 +473,8 @@ export class ApplicationRef_ extends ApplicationRef {
|
||||
if (!ListWrapper.contains(this._rootComponents, ref)) {
|
||||
return;
|
||||
}
|
||||
this.unregisterChangeDetector(internalView(ref.hostView).changeDetector.ref);
|
||||
this.unregisterChangeDetector(
|
||||
(<ElementRef_>ref.location).internalElement.parentView.changeDetector.ref);
|
||||
ListWrapper.remove(this._rootComponents, ref);
|
||||
}
|
||||
|
||||
@ -484,5 +507,5 @@ export class ApplicationRef_ extends ApplicationRef {
|
||||
this._platform._applicationDisposed(this);
|
||||
}
|
||||
|
||||
get componentTypes(): any[] { return this._rootComponentTypes; }
|
||||
get componentTypes(): Type[] { return this._rootComponentTypes; }
|
||||
}
|
||||
|
@ -20,5 +20,6 @@ export {
|
||||
IterableDifferFactory,
|
||||
KeyValueDiffers,
|
||||
KeyValueDiffer,
|
||||
KeyValueDifferFactory
|
||||
KeyValueDifferFactory,
|
||||
TrackByFn
|
||||
} from './change_detection/change_detection';
|
||||
|
@ -8,14 +8,16 @@ import {Pipes} from './pipes';
|
||||
import {
|
||||
ChangeDetectionError,
|
||||
ExpressionChangedAfterItHasBeenCheckedException,
|
||||
DehydratedException
|
||||
DehydratedException,
|
||||
EventEvaluationErrorContext,
|
||||
EventEvaluationError
|
||||
} from './exceptions';
|
||||
import {BindingTarget} from './binding_record';
|
||||
import {Locals} from './parser/locals';
|
||||
import {ChangeDetectionStrategy, ChangeDetectorState} from './constants';
|
||||
import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
|
||||
import {isObservable} from './observable_facade';
|
||||
|
||||
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
|
||||
|
||||
@ -38,14 +40,18 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
mode: ChangeDetectionStrategy = null;
|
||||
pipes: Pipes = null;
|
||||
propertyBindingIndex: number;
|
||||
outputSubscriptions: any[];
|
||||
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
subscriptions: any[];
|
||||
streams: any[];
|
||||
|
||||
constructor(public id: string, public dispatcher: ChangeDispatcher,
|
||||
public numberOfPropertyProtoRecords: number, public bindingTargets: BindingTarget[],
|
||||
public directiveIndices: DirectiveIndex[], public strategy: ChangeDetectionStrategy) {
|
||||
dispatcher: ChangeDispatcher;
|
||||
|
||||
|
||||
constructor(public id: string, public numberOfPropertyProtoRecords: number,
|
||||
public bindingTargets: BindingTarget[], public directiveIndices: DirectiveIndex[],
|
||||
public strategy: ChangeDetectionStrategy) {
|
||||
this.ref = new ChangeDetectorRef_(this);
|
||||
}
|
||||
|
||||
@ -65,10 +71,24 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
|
||||
remove(): void { this.parent.removeContentChild(this); }
|
||||
|
||||
handleEvent(eventName: string, elIndex: number, locals: Locals): boolean {
|
||||
var res = this.handleEventInternal(eventName, elIndex, locals);
|
||||
handleEvent(eventName: string, elIndex: number, event: any): boolean {
|
||||
if (!this.hydrated()) {
|
||||
this.throwDehydratedError(`${this.id} -> ${eventName}`);
|
||||
}
|
||||
try {
|
||||
var locals = new Map<string, any>();
|
||||
locals.set('$event', event);
|
||||
var res = !this.handleEventInternal(eventName, elIndex, new Locals(this.locals, locals));
|
||||
this.markPathToRootAsCheckOnce();
|
||||
return res;
|
||||
} catch (e) {
|
||||
var c = this.dispatcher.getDebugContext(null, elIndex, null);
|
||||
var context = isPresent(c) ?
|
||||
new EventEvaluationErrorContext(c.element, c.componentElement, c.context,
|
||||
c.locals, c.injector) :
|
||||
null;
|
||||
throw new EventEvaluationError(eventName, e, e.stack, context);
|
||||
}
|
||||
}
|
||||
|
||||
handleEventInternal(eventName: string, elIndex: number, locals: Locals): boolean { return false; }
|
||||
@ -110,7 +130,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
// facilitate error reporting.
|
||||
detectChangesInRecords(throwOnChange: boolean): void {
|
||||
if (!this.hydrated()) {
|
||||
this.throwDehydratedError();
|
||||
this.throwDehydratedError(this.id);
|
||||
}
|
||||
try {
|
||||
this.detectChangesInRecordsInternal(throwOnChange);
|
||||
@ -133,7 +153,8 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
|
||||
// This method is not intended to be overridden. Subclasses should instead provide an
|
||||
// implementation of `hydrateDirectives`.
|
||||
hydrate(context: T, locals: Locals, directives: any, pipes: Pipes): void {
|
||||
hydrate(context: T, locals: Locals, dispatcher: ChangeDispatcher, pipes: Pipes): void {
|
||||
this.dispatcher = dispatcher;
|
||||
this.mode = ChangeDetectionUtil.changeDetectionMode(this.strategy);
|
||||
this.context = context;
|
||||
|
||||
@ -143,12 +164,12 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
|
||||
this.locals = locals;
|
||||
this.pipes = pipes;
|
||||
this.hydrateDirectives(directives);
|
||||
this.hydrateDirectives(dispatcher);
|
||||
this.state = ChangeDetectorState.NeverChecked;
|
||||
}
|
||||
|
||||
// Subclasses should override this method to hydrate any directives.
|
||||
hydrateDirectives(directives: any): void {}
|
||||
hydrateDirectives(dispatcher: ChangeDispatcher): void {}
|
||||
|
||||
// This method is not intended to be overridden. Subclasses should instead provide an
|
||||
// implementation of `dehydrateDirectives`.
|
||||
@ -160,6 +181,9 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
this._unsubsribeFromObservables();
|
||||
}
|
||||
|
||||
this._unsubscribeFromOutputs();
|
||||
|
||||
this.dispatcher = null;
|
||||
this.context = null;
|
||||
this.locals = null;
|
||||
this.pipes = null;
|
||||
@ -171,6 +195,19 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
|
||||
hydrated(): boolean { return isPresent(this.context); }
|
||||
|
||||
destroyRecursive(): void {
|
||||
this.dispatcher.notifyOnDestroy();
|
||||
this.dehydrate();
|
||||
var children = this.contentChildren;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
children[i].destroyRecursive();
|
||||
}
|
||||
children = this.viewChildren;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
children[i].destroyRecursive();
|
||||
}
|
||||
}
|
||||
|
||||
afterContentLifecycleCallbacks(): void {
|
||||
this.dispatcher.notifyAfterContentChecked();
|
||||
this.afterContentLifecycleCallbacksInternal();
|
||||
@ -224,6 +261,15 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
}
|
||||
}
|
||||
|
||||
private _unsubscribeFromOutputs(): void {
|
||||
if (isPresent(this.outputSubscriptions)) {
|
||||
for (var i = 0; i < this.outputSubscriptions.length; ++i) {
|
||||
ObservableWrapper.dispose(this.outputSubscriptions[i]);
|
||||
this.outputSubscriptions[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is an experimental feature. Works only in Dart.
|
||||
observeValue(value: any, index: number): any {
|
||||
if (isObservable(value)) {
|
||||
@ -298,7 +344,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
private _throwError(exception: any, stack: any): void {
|
||||
var error;
|
||||
try {
|
||||
var c = this.dispatcher.getDebugContext(this._currentBinding().elementIndex, null);
|
||||
var c = this.dispatcher.getDebugContext(null, this._currentBinding().elementIndex, null);
|
||||
var context = isPresent(c) ? new _Context(c.element, c.componentElement, c.context, c.locals,
|
||||
c.injector, this._currentBinding().debug) :
|
||||
null;
|
||||
@ -316,7 +362,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
|
||||
oldValue, newValue, null);
|
||||
}
|
||||
|
||||
throwDehydratedError(): void { throw new DehydratedException(); }
|
||||
throwDehydratedError(detail: string): void { throw new DehydratedException(detail); }
|
||||
|
||||
private _currentBinding(): BindingTarget {
|
||||
return this.bindingTargets[this.propertyBindingIndex];
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {IterableDiffers, IterableDifferFactory} from './differs/iterable_differs';
|
||||
import {IterableDiffers, IterableDifferFactory, TrackByFn} from './differs/iterable_differs';
|
||||
import {DefaultIterableDifferFactory} from './differs/default_iterable_differ';
|
||||
import {KeyValueDiffers, KeyValueDifferFactory} from './differs/keyvalue_differs';
|
||||
import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ';
|
||||
@ -37,7 +37,12 @@ export {BindingRecord, BindingTarget} from './binding_record';
|
||||
export {DirectiveIndex, DirectiveRecord} from './directive_record';
|
||||
export {DynamicChangeDetector} from './dynamic_change_detector';
|
||||
export {ChangeDetectorRef} from './change_detector_ref';
|
||||
export {IterableDiffers, IterableDiffer, IterableDifferFactory} from './differs/iterable_differs';
|
||||
export {
|
||||
IterableDiffers,
|
||||
IterableDiffer,
|
||||
IterableDifferFactory,
|
||||
TrackByFn
|
||||
} from './differs/iterable_differs';
|
||||
export {KeyValueDiffers, KeyValueDiffer, KeyValueDifferFactory} from './differs/keyvalue_differs';
|
||||
export {PipeTransform} from './pipe_transform';
|
||||
export {WrappedValue, SimpleChange} from './change_detection_util';
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user