Compare commits
143 Commits
Author | SHA1 | Date | |
---|---|---|---|
530b824faa | |||
e22d3a605c | |||
c6645e7a04 | |||
f0396f1e54 | |||
adb1d62967 | |||
cfe83939a4 | |||
973607fe9d | |||
664f7fa477 | |||
b155ae116b | |||
ce51ea93a1 | |||
d38e08812e | |||
aa9ba7f9fe | |||
102d06b974 | |||
11ec80a053 | |||
75eecdc351 | |||
965eecc587 | |||
c4fb696189 | |||
72df747dd6 | |||
579bed1a7a | |||
b59fb23f4a | |||
2aa460b30e | |||
e0022ae9cd | |||
f2e923edd8 | |||
c2f5ed545c | |||
5d75df8fb1 | |||
ed2b71799c | |||
fad99cca0e | |||
3f5ead3845 | |||
a89e709515 | |||
6a7689d4ea | |||
696ba01a4e | |||
81d64d6bec | |||
7410941a7c | |||
d159ad8b88 | |||
250c8da768 | |||
778e6e759f | |||
35a0721217 | |||
ba045e88d7 | |||
67806a7b25 | |||
9778a23be8 | |||
87e06d765e | |||
56f3e18c1c | |||
637515e71b | |||
27ecd077d4 | |||
4db1be0292 | |||
a0dbef9ea4 | |||
3aaf43f73c | |||
d952ae24dd | |||
da9e57b3d5 | |||
44d4f82dae | |||
bde2b4425c | |||
2a3de802a0 | |||
71f9eaa743 | |||
a62c186d15 | |||
c8bf281174 | |||
de6c6445af | |||
54238822e6 | |||
8b3fbb5bf4 | |||
2f61d3c320 | |||
5894f6ee1c | |||
6d9fcd62de | |||
0cbccc06dd | |||
ed670a36fb | |||
8e44577df3 | |||
6921c20ea1 | |||
52970c09e1 | |||
eecdf3414e | |||
21f766968d | |||
4b68fdce6f | |||
c12ea3a1f0 | |||
d7dbdc5c36 | |||
0112a903f9 | |||
66bbc84127 | |||
554129d6fe | |||
e32a0cabfe | |||
c828e5627b | |||
1626e74c59 | |||
a15a2b46d1 | |||
379ed75593 | |||
0f619896b3 | |||
7060655806 | |||
b5fc3eb9de | |||
451bdb9a75 | |||
983ccc02ad | |||
00f99b3c4c | |||
ba4ea82f68 | |||
982eb7bba8 | |||
3606c55410 | |||
2c65027391 | |||
4ee92f14a6 | |||
c9b65914d3 | |||
02352bcd9e | |||
0d55600fd8 | |||
af4eb00c91 | |||
d3e7ebb3b4 | |||
420f5c4275 | |||
b773a4ab98 | |||
55f15c54d9 | |||
4556532c26 | |||
54e75766ad | |||
d3333f04ba | |||
75f8522b8d | |||
a771ee5d90 | |||
a4cbe3542a | |||
cc9419d1ca | |||
d5393c7f91 | |||
71dd92bbb8 | |||
977978edb5 | |||
eb70966065 | |||
cf4bea587d | |||
8e9cd57951 | |||
f23896f519 | |||
0e59d18fc2 | |||
54c8a321a9 | |||
9005a6f3cd | |||
3c6a5063f7 | |||
b49d54e606 | |||
55fd82e587 | |||
7f3d0bbf97 | |||
3db02d244a | |||
50b605686e | |||
64d4aafbc7 | |||
a931a419fa | |||
6a97b5b722 | |||
aad1126446 | |||
7b463df52b | |||
a2432c9f10 | |||
e500484ccc | |||
a0dcb0b828 | |||
c4b71920d1 | |||
650f5fb5c7 | |||
c32e83334b | |||
7bdd9aecbd | |||
5ede67c345 | |||
31b671ab54 | |||
3804d20b6d | |||
0a5a87887e | |||
c46afce0f5 | |||
76c781fd37 | |||
51eb3d418e | |||
48c18985cc | |||
167cbed266 | |||
70e8802540 |
@ -1,25 +0,0 @@
|
||||
# These options are enabled when running on CI
|
||||
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
|
||||
# Don't be spammy in the logs
|
||||
build --noshow_progress
|
||||
|
||||
# Don't run manual tests
|
||||
test --test_tag_filters=-manual
|
||||
|
||||
# Enable experimental CircleCI bazel remote cache proxy
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
build --experimental_remote_spawn_cache --remote_rest_cache=http://localhost:7643
|
||||
|
||||
# Prevent unstable environment variables from tainting cache keys
|
||||
build --experimental_strict_action_env
|
||||
|
||||
# Workaround https://github.com/bazelbuild/bazel/issues/3645
|
||||
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
|
||||
# Limit Bazel to consuming resources that fit in CircleCI "medium" class which is the default:
|
||||
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
|
||||
build --local_resources=3072,2.0,1.0
|
||||
|
||||
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
|
||||
test --flaky_test_attempts=2
|
@ -15,13 +15,6 @@
|
||||
var_1: &docker_image angular/ngcontainer:0.1.0
|
||||
var_2: &cache_key angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-0.1.0
|
||||
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
var_3: &setup-bazel-remote-cache
|
||||
run:
|
||||
name: Start up bazel remote cache proxy
|
||||
command: ~/bazel-remote-proxy -backend circleci://
|
||||
background: true
|
||||
|
||||
# Settings common to each job
|
||||
anchor_1: &job_defaults
|
||||
working_directory: ~/ng
|
||||
@ -41,16 +34,14 @@ jobs:
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
- run: .circleci/setup_cache.sh
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- *setup-bazel-remote-cache
|
||||
|
||||
- run: 'yarn buildifier -mode=check ||
|
||||
(echo -e "\nBUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
|
||||
- run: 'yarn skylint ||
|
||||
# Check BUILD.bazel formatting before we have a node_modules directory
|
||||
# Then we don't need any exclude pattern to avoid checking those files
|
||||
- run: 'buildifier -mode=check $(find . -type f \( -name BUILD.bazel -or -name BUILD \)) ||
|
||||
(echo "BUILD files not formatted. Please run ''yarn buildifier''" ; exit 1)'
|
||||
# Run the skylark linter to check our Bazel rules
|
||||
- run: 'find . -type f -name "*.bzl" |
|
||||
xargs java -jar /usr/local/bin/Skylint_deploy.jar ||
|
||||
(echo -e "\n.bzl files have lint errors. Please run ''yarn skylint''"; exit 1)'
|
||||
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
|
||||
@ -63,11 +54,6 @@ jobs:
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
- run: .circleci/setup_cache.sh
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- *setup-bazel-remote-cache
|
||||
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
|
||||
@ -76,16 +62,7 @@ jobs:
|
||||
# Use bazel query so that we explicitly ask for all buildable targets to be built as well
|
||||
# This avoids waiting for a build command to finish before running the first test
|
||||
# See https://github.com/bazelbuild/bazel/issues/4257
|
||||
- run: bazel query --output=label '//modules/... union //packages/... union //tools/...' | xargs bazel test
|
||||
|
||||
# CircleCI will allow us to go back and view/download these artifacts from past builds.
|
||||
# Also we can use a service like https://buildsize.org/ to automatically track binary size of these artifacts.
|
||||
- store_artifacts:
|
||||
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js
|
||||
destination: packages/core/test/bundling/hello_world/bundle.min.js
|
||||
- store_artifacts:
|
||||
path: dist/bin/packages/core/test/bundling/hello_world/bundle.min.js.brotli
|
||||
destination: packages/core/test/bundling/hello_world/bundle.min.js.brotli
|
||||
- run: bazel query --output=label '//modules/... union //packages/... union //tools/...' | xargs bazel test --config=ci
|
||||
|
||||
- save_cache:
|
||||
key: *cache_key
|
||||
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Install bazel remote cache proxy
|
||||
# This is temporary until the feature is no longer experimental on CircleCI.
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
|
||||
set -u -e
|
||||
|
||||
readonly DOWNLOAD_URL="https://5-116431813-gh.circle-artifacts.com/0/pkg/bazel-remote-proxy-$(uname -s)_$(uname -m)"
|
||||
|
||||
curl --fail -o ~/bazel-remote-proxy "$DOWNLOAD_URL"
|
||||
chmod +x ~/bazel-remote-proxy
|
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -25,7 +25,7 @@ ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
|
||||
## Minimal reproduction of the problem with instructions
|
||||
<!--
|
||||
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
|
||||
https://stackblitz.com or similar (you can use this template as a starting point: https://stackblitz.com/fork/angular-gitter).
|
||||
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).
|
||||
-->
|
||||
|
||||
## What is the motivation / use case for changing the behavior?
|
||||
|
18
.github/angular-robot.yml
vendored
18
.github/angular-robot.yml
vendored
@ -50,15 +50,13 @@ merge:
|
||||
noConflict: true
|
||||
# list of labels that a PR needs to have, checked with a regexp (e.g. "PR target:" will work for the label "PR target: master")
|
||||
requiredLabels:
|
||||
- "PR target: *"
|
||||
- "PR target:"
|
||||
- "cla: yes"
|
||||
|
||||
# list of labels that a PR shouldn't have, checked after the required labels with a regexp
|
||||
forbiddenLabels:
|
||||
- "PR target: TBD"
|
||||
- "PR action: cleanup"
|
||||
- "PR action: review"
|
||||
- "PR state: blocked"
|
||||
- "cla: no"
|
||||
|
||||
# list of PR statuses that need to be successful
|
||||
@ -86,15 +84,9 @@ triage:
|
||||
triagedLabels:
|
||||
-
|
||||
- "type: bug"
|
||||
- "severity*"
|
||||
- "freq*"
|
||||
- "comp: *"
|
||||
- "severity"
|
||||
- "freq"
|
||||
- "comp:"
|
||||
-
|
||||
- "type: feature"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: refactor"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: RFC / Discussion / question"
|
||||
- "comp: *"
|
||||
- "comp:"
|
||||
|
@ -207,12 +207,6 @@ groups:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/forms/*"
|
||||
- "aio/content/guide/forms.md"
|
||||
- "aio/content/guide/form-validation.md"
|
||||
- "aio/content/guide/reactive-forms.md"
|
||||
- "aio/content/examples/forms/*"
|
||||
- "aio/content/examples/form-validation/*"
|
||||
- "aio/content/examples/reactive-forms/*"
|
||||
users:
|
||||
- kara #primary
|
||||
- tinayuangao #secondary
|
||||
|
@ -56,6 +56,7 @@ env:
|
||||
- CI_MODE=aio
|
||||
- CI_MODE=aio_e2e AIO_SHARD=0
|
||||
- CI_MODE=aio_e2e AIO_SHARD=1
|
||||
- CI_MODE=bazel
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
@ -32,7 +32,6 @@ filegroup(
|
||||
"reflect-metadata",
|
||||
"source-map-support",
|
||||
"minimist",
|
||||
"tslib",
|
||||
] for ext in [
|
||||
"*.js",
|
||||
"*.json",
|
||||
|
150
CHANGELOG.md
150
CHANGELOG.md
@ -1,86 +1,3 @@
|
||||
<a name="6.0.0-beta.4"></a>
|
||||
# [6.0.0-beta.4](https://github.com/angular/angular/compare/6.0.0-beta.3...6.0.0-beta.4) (2018-02-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** allow TS to read ambient typings ([#21876](https://github.com/angular/angular/issues/21876)) ([b081dfe](https://github.com/angular/angular/commit/b081dfe)), closes [#21872](https://github.com/angular/angular/issues/21872)
|
||||
* **bazel:** improve error message for missing assets ([#22096](https://github.com/angular/angular/issues/22096)) ([dcf64a0](https://github.com/angular/angular/commit/dcf64a0)), closes [#22095](https://github.com/angular/angular/issues/22095)
|
||||
* **common:** add locale currency values ([#21783](https://github.com/angular/angular/issues/21783)) ([420cc7a](https://github.com/angular/angular/commit/420cc7a)), closes [#20385](https://github.com/angular/angular/issues/20385)
|
||||
* **common:** round currencies based on decimal digits in `CurrencyPipe` ([#21783](https://github.com/angular/angular/issues/21783)) ([44154e7](https://github.com/angular/angular/commit/44154e7)), closes [#10189](https://github.com/angular/angular/issues/10189)
|
||||
* **common:** weaken AsyncPipe transform signature ([#22169](https://github.com/angular/angular/issues/22169)) ([be59c3a](https://github.com/angular/angular/commit/be59c3a))
|
||||
* **compiler:** make unary plus operator consistent to JavaScript ([#22154](https://github.com/angular/angular/issues/22154)) ([72f8abd](https://github.com/angular/angular/commit/72f8abd)), closes [#22089](https://github.com/angular/angular/issues/22089)
|
||||
* **core:** add stacktrace in log when error during cleanup component in TestBed ([#22162](https://github.com/angular/angular/issues/22162)) ([16d1700](https://github.com/angular/angular/commit/16d1700))
|
||||
* **core:** ensure initial value of QueryList length ([#21980](https://github.com/angular/angular/issues/21980)) ([#21982](https://github.com/angular/angular/issues/21982)) ([e56de10](https://github.com/angular/angular/commit/e56de10)), closes [#21980](https://github.com/angular/angular/issues/21980)
|
||||
* **core:** use appropriate inert document strategy for Firefox & Safari ([#17019](https://github.com/angular/angular/issues/17019)) ([a751649](https://github.com/angular/angular/commit/a751649))
|
||||
* **forms:** make Validators.email support optional controls ([#20869](https://github.com/angular/angular/issues/20869)) ([140e7c0](https://github.com/angular/angular/commit/140e7c0))
|
||||
* **forms:** prevent event emission on enable/disable when emitEvent is false ([#12366](https://github.com/angular/angular/issues/12366)) ([#21018](https://github.com/angular/angular/issues/21018)) ([0bcfae7](https://github.com/angular/angular/commit/0bcfae7))
|
||||
* **forms:** set state before emitting a value from ngModelChange ([#21514](https://github.com/angular/angular/issues/21514)) ([9744a1c](https://github.com/angular/angular/commit/9744a1c)), closes [#21513](https://github.com/angular/angular/issues/21513)
|
||||
* **language-service:** correct instructions to install the language service ([#22000](https://github.com/angular/angular/issues/22000)) ([b37cee3](https://github.com/angular/angular/commit/b37cee3))
|
||||
* **platform-browser:** add @Injectable where it was missing ([#22005](https://github.com/angular/angular/issues/22005)) ([0a1a397](https://github.com/angular/angular/commit/0a1a397))
|
||||
* **platform-browser:** support 0/false/null values in transfer_state ([#22179](https://github.com/angular/angular/issues/22179)) ([6435ecd](https://github.com/angular/angular/commit/6435ecd))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **bazel:** allow explicit specification of factories ([#22003](https://github.com/angular/angular/issues/22003)) ([e442881](https://github.com/angular/angular/commit/e442881))
|
||||
* **compiler:** mark @NgModules in provider lists for identification at runtime ([#22005](https://github.com/angular/angular/issues/22005)) ([2d5e7d1](https://github.com/angular/angular/commit/2d5e7d1))
|
||||
* **forms:** multiple validators for array method ([#20766](https://github.com/angular/angular/issues/20766)) ([941e88f](https://github.com/angular/angular/commit/941e88f)), closes [#20665](https://github.com/angular/angular/issues/20665)
|
||||
* change @Injectable() to support tree-shakeable tokens ([#22005](https://github.com/angular/angular/issues/22005)) ([235a235](https://github.com/angular/angular/commit/235a235))
|
||||
|
||||
|
||||
|
||||
<a name="5.2.5"></a>
|
||||
## [5.2.5](https://github.com/angular/angular/compare/5.2.4...5.2.5) (2018-02-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **aio:** update Firebase redirects and SW routes ([#21763](https://github.com/angular/angular/pull/21763)) ([#22104](https://github.com/angular/angular/pull/22104)) ([15ff7ba](https://github.com/angular/angular/commit/15ff7ba)), closes [#21377](https://github.com/angular/angular/issues/21377)
|
||||
* **bazel:** allow TS to read ambient typings ([#21876](https://github.com/angular/angular/issues/21876)) ([d57fd0b](https://github.com/angular/angular/commit/d57fd0b)), closes [#21872](https://github.com/angular/angular/issues/21872)
|
||||
* **bazel:** improve error message for missing assets ([#22096](https://github.com/angular/angular/issues/22096)) ([c5ec8d9](https://github.com/angular/angular/commit/c5ec8d9)), closes [#22095](https://github.com/angular/angular/issues/22095)
|
||||
* **common:** weaken AsyncPipe transform signature ([#22169](https://github.com/angular/angular/issues/22169)) ([c6bdc83](https://github.com/angular/angular/commit/c6bdc83))
|
||||
* **compiler:** make unary plus operator consistent to JavaScript ([#22154](https://github.com/angular/angular/issues/22154)) ([1b8ea10](https://github.com/angular/angular/commit/1b8ea10)), closes [#22089](https://github.com/angular/angular/issues/22089)
|
||||
* **core:** add stacktrace in log when error during cleanup component in TestBed ([#22162](https://github.com/angular/angular/issues/22162)) ([c4f841f](https://github.com/angular/angular/commit/c4f841f))
|
||||
* **core:** ensure initial value of QueryList length ([#21980](https://github.com/angular/angular/issues/21980)) ([#21982](https://github.com/angular/angular/issues/21982)) ([47b73fd](https://github.com/angular/angular/commit/47b73fd)), closes [#21980](https://github.com/angular/angular/issues/21980)
|
||||
* **core:** use appropriate inert document strategy for Firefox & Safari ([#17019](https://github.com/angular/angular/issues/17019)) ([47b71d9](https://github.com/angular/angular/commit/47b71d9))
|
||||
* **forms:** prevent event emission on enable/disable when emitEvent is false ([#12366](https://github.com/angular/angular/issues/12366)) ([#21018](https://github.com/angular/angular/issues/21018)) ([56b9591](https://github.com/angular/angular/commit/56b9591))
|
||||
* **language-service:** correct instructions to install the language service ([#22000](https://github.com/angular/angular/issues/22000)) ([0b23573](https://github.com/angular/angular/commit/0b23573))
|
||||
* **platform-browser:** support 0/false/null values in transfer_state ([#22179](https://github.com/angular/angular/issues/22179)) ([da6ab91](https://github.com/angular/angular/commit/da6ab91))
|
||||
|
||||
|
||||
|
||||
<a name="6.0.0-beta.3"></a>
|
||||
# [6.0.0-beta.3](https://github.com/angular/angular/compare/6.0.0-beta.2...6.0.0-beta.3) (2018-02-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** don't convert null to a string when flushing a mock request ([#21417](https://github.com/angular/angular/issues/21417)) ([8b14488](https://github.com/angular/angular/commit/8b14488)), closes [#20744](https://github.com/angular/angular/issues/20744)
|
||||
* **core:** fix [#20582](https://github.com/angular/angular/issues/20582), don't need to wrap zone in location change listener ([#20640](https://github.com/angular/angular/issues/20640)) ([f791e9f](https://github.com/angular/angular/commit/f791e9f))
|
||||
* **core:** fix proper propagation of subscriptions in EventEmitter ([#22016](https://github.com/angular/angular/issues/22016)) ([e81606c](https://github.com/angular/angular/commit/e81606c)), closes [#21999](https://github.com/angular/angular/issues/21999)
|
||||
* **core:** should check Zone existance when scheduleMicroTask ([#20656](https://github.com/angular/angular/issues/20656)) ([3a86940](https://github.com/angular/angular/commit/3a86940))
|
||||
* **forms:** publish missing types ([#19941](https://github.com/angular/angular/issues/19941)) ([2707012](https://github.com/angular/angular/commit/2707012))
|
||||
* **ivy:** generate correct interpolations ([#21946](https://github.com/angular/angular/issues/21946)) ([3cc1d76](https://github.com/angular/angular/commit/3cc1d76))
|
||||
* **ivy:** generate lifecycle pattern ([#21865](https://github.com/angular/angular/issues/21865)) ([f816666](https://github.com/angular/angular/commit/f816666))
|
||||
* **ivy:** improve `bindV` perf and memory usage ([#21881](https://github.com/angular/angular/issues/21881)) ([0846784](https://github.com/angular/angular/commit/0846784))
|
||||
* **ivy:** remove unnecessary parameter of NgOnChangesFeature ([#21879](https://github.com/angular/angular/issues/21879)) ([65cf1ad](https://github.com/angular/angular/commit/65cf1ad))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler-cli:** reflect static methods added to classes in metadata ([#21926](https://github.com/angular/angular/issues/21926)) ([eb8ddd2](https://github.com/angular/angular/commit/eb8ddd2))
|
||||
* **ivy:** add canonical example of a pipe. ([#21834](https://github.com/angular/angular/issues/21834)) ([743d8bc](https://github.com/angular/angular/commit/743d8bc))
|
||||
* **ivy:** add support for attributes on ng-content nodes ([#21935](https://github.com/angular/angular/issues/21935)) ([1aa2947](https://github.com/angular/angular/commit/1aa2947))
|
||||
* **ivy:** memoize array literals in render3 ([#21973](https://github.com/angular/angular/issues/21973)) ([4d62be6](https://github.com/angular/angular/commit/4d62be6))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **ivy:** improve Uglify configuration in hello world integration test ([#21985](https://github.com/angular/angular/issues/21985)) ([7e51e52](https://github.com/angular/angular/commit/7e51e52))
|
||||
|
||||
|
||||
|
||||
<a name="5.2.4"></a>
|
||||
## [5.2.4](https://github.com/angular/angular/compare/5.2.3...5.2.4) (2018-02-07)
|
||||
|
||||
@ -94,17 +11,6 @@
|
||||
|
||||
|
||||
|
||||
<a name="6.0.0-beta.2"></a>
|
||||
# [6.0.0-beta.2](https://github.com/angular/angular/compare/6.0.0-beta.1...6.0.0-beta.2) (2018-01-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **router:** add navigationSource and restoredState to NavigationStart event ([#21728](https://github.com/angular/angular/issues/21728)) ([c40ae7f](https://github.com/angular/angular/commit/c40ae7f))
|
||||
* **service-worker:** add helper script which will uninstall SW ([#21863](https://github.com/angular/angular/issues/21863)) ([b10540a](https://github.com/angular/angular/commit/b10540a))
|
||||
|
||||
|
||||
|
||||
<a name="5.2.3"></a>
|
||||
## [5.2.3](https://github.com/angular/angular/compare/5.2.2...5.2.3) (2018-01-31)
|
||||
|
||||
@ -122,32 +28,6 @@
|
||||
|
||||
|
||||
|
||||
<a name="6.0.0-beta.1"></a>
|
||||
# [6.0.0-beta.1](https://github.com/angular/angular/compare/6.0.0-beta.0...6.0.0-beta.1) (2018-01-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** A null value should remove the style on IE ([#21679](https://github.com/angular/angular/issues/21679)) ([7d49443](https://github.com/angular/angular/commit/7d49443)), closes [#21064](https://github.com/angular/angular/issues/21064)
|
||||
* avoid triggering a cli bug ([#21611](https://github.com/angular/angular/issues/21611)) ([0eabd07](https://github.com/angular/angular/commit/0eabd07))
|
||||
* **common:** don't remove special characters when extracting CLDR data ([#21626](https://github.com/angular/angular/issues/21626)) ([135a282](https://github.com/angular/angular/commit/135a282))
|
||||
* **common:** extract plural function from i18n locale data files for TS 2.6 ([#21626](https://github.com/angular/angular/issues/21626)) ([97b18b2](https://github.com/angular/angular/commit/97b18b2)), closes [#21608](https://github.com/angular/angular/issues/21608)
|
||||
* **common:** fallback to last defined value for named date and time formats ([#21299](https://github.com/angular/angular/issues/21299)) ([879756d](https://github.com/angular/angular/commit/879756d)), closes [#21282](https://github.com/angular/angular/issues/21282)
|
||||
* **compiler:** add support for marker tags in xliff serializers ([#21250](https://github.com/angular/angular/issues/21250)) ([f74130c](https://github.com/angular/angular/commit/f74130c)), closes [#21078](https://github.com/angular/angular/issues/21078)
|
||||
* **compiler:** Don't strip `/*# sourceURL ... */` ([#16088](https://github.com/angular/angular/issues/16088)) ([5f681f9](https://github.com/angular/angular/commit/5f681f9))
|
||||
* **compiler:** fix ICU select messages to use male/female/other ([#21713](https://github.com/angular/angular/issues/21713)) ([cb5090c](https://github.com/angular/angular/commit/cb5090c))
|
||||
* **compiler-cli:** do not fold errors past calls in the collector ([#21708](https://github.com/angular/angular/issues/21708)) ([dd86790](https://github.com/angular/angular/commit/dd86790))
|
||||
* **compiler-cli:** do not lower expressions in non-modules ([#21649](https://github.com/angular/angular/issues/21649)) ([7f93aad](https://github.com/angular/angular/commit/7f93aad))
|
||||
* **router:** don't use ParamsInheritanceStrategy in declarations ([#21574](https://github.com/angular/angular/issues/21574)) ([925e654](https://github.com/angular/angular/commit/925e654)), closes [#21456](https://github.com/angular/angular/issues/21456)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compiler:** implement "enableIvy" compiler option ([#21427](https://github.com/angular/angular/issues/21427)) ([64d16de](https://github.com/angular/angular/commit/64d16de))
|
||||
* **core:** optional generic type for ElementRef ([#20765](https://github.com/angular/angular/issues/20765)) ([d3d9aac](https://github.com/angular/angular/commit/d3d9aac)), closes [#13139](https://github.com/angular/angular/issues/13139)
|
||||
|
||||
|
||||
|
||||
<a name="5.2.2"></a>
|
||||
## [5.2.2](https://github.com/angular/angular/compare/5.2.1...5.2.2) (2018-01-25)
|
||||
|
||||
@ -167,36 +47,6 @@
|
||||
|
||||
|
||||
|
||||
<a name="6.0.0-beta.0"></a>
|
||||
# [6.0.0-beta.0](https://github.com/angular/angular/compare/5.2.0...6.0.0-beta.0) (2018-01-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **animations:** fix increment/decrement aliases example ([#18323](https://github.com/angular/angular/issues/18323)) ([d2aa8ac](https://github.com/angular/angular/commit/d2aa8ac))
|
||||
* **benchpress:** should still support selenium_webdriver < 3.6.0 ([#21477](https://github.com/angular/angular/issues/21477)) ([9b84a32](https://github.com/angular/angular/commit/9b84a32))
|
||||
* **common:** set correct timezone for ISO8601 dates in Safari ([#21506](https://github.com/angular/angular/issues/21506)) ([05208b8](https://github.com/angular/angular/commit/05208b8)), closes [#21491](https://github.com/angular/angular/issues/21491)
|
||||
* **compiler:** cache external reference resolution ([#21359](https://github.com/angular/angular/issues/21359)) ([e3e2fc0](https://github.com/angular/angular/commit/e3e2fc0))
|
||||
* **compiler:** make `.ngsummary.json` files idempotent ([#21448](https://github.com/angular/angular/issues/21448)) ([e64b1e9](https://github.com/angular/angular/commit/e64b1e9))
|
||||
* **core:** fix chained http call ([#20924](https://github.com/angular/angular/issues/20924)) ([7e3f9a4](https://github.com/angular/angular/commit/7e3f9a4)), closes [#20921](https://github.com/angular/angular/issues/20921)
|
||||
* **ivy:** Add workaround for AJD in google3 ([#21488](https://github.com/angular/angular/issues/21488)) ([6af3672](https://github.com/angular/angular/commit/6af3672))
|
||||
* **language-service:** Clear caches when program changes ([#21337](https://github.com/angular/angular/issues/21337)) ([43e1520](https://github.com/angular/angular/commit/43e1520)), closes [#19405](https://github.com/angular/angular/issues/19405)
|
||||
* **service-worker:** properly handle invalid hashes in all scenarios ([#21288](https://github.com/angular/angular/issues/21288)) ([3951098](https://github.com/angular/angular/commit/3951098))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **bazel:** allow ng_module rules to control whether type checking is enabled ([#21460](https://github.com/angular/angular/issues/21460)) ([cffa0fe](https://github.com/angular/angular/commit/cffa0fe))
|
||||
* **core:** add binding name to content changed error ([#20352](https://github.com/angular/angular/issues/20352)) ([d3bf54b](https://github.com/angular/angular/commit/d3bf54b))
|
||||
* **forms:** handle string with and without line boundary on pattern validator ([#19256](https://github.com/angular/angular/issues/19256)) ([54bf179](https://github.com/angular/angular/commit/54bf179))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* **ivy:** add missing dom element in render3_function tree benchmark ([#21476](https://github.com/angular/angular/issues/21476)) ([9b5a485](https://github.com/angular/angular/commit/9b5a485))
|
||||
|
||||
|
||||
|
||||
<a name="5.2.1"></a>
|
||||
## [5.2.1](https://github.com/angular/angular/compare/5.2.0...5.2.1) (2018-01-17)
|
||||
|
||||
|
@ -51,7 +51,7 @@ and help you to craft the change so that it is successfully accepted into the pr
|
||||
|
||||
Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
|
||||
|
||||
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs, we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions like:
|
||||
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using http://plnkr.co. Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:
|
||||
|
||||
- version of Angular used
|
||||
- 3rd-party libraries and their versions
|
||||
@ -61,7 +61,7 @@ A minimal reproduce scenario using http://plnkr.co/ allows us to quickly confirm
|
||||
|
||||
We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
|
||||
|
||||
Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that doesn't have enough info to be reproduced.
|
||||
Unfortunately we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
|
||||
|
||||
You can file new issues by filling out our [new issue form](https://github.com/angular/angular/issues/new).
|
||||
|
||||
@ -173,12 +173,12 @@ The **header** is mandatory and the **scope** of the header is optional.
|
||||
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
|
||||
to read on GitHub as well as in various git tools.
|
||||
|
||||
The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
|
||||
Footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
|
||||
|
||||
Samples: (even more [samples](https://github.com/angular/angular/commits/master))
|
||||
|
||||
```
|
||||
docs(changelog): update changelog to beta.5
|
||||
docs(changelog): update change log to beta.5
|
||||
```
|
||||
```
|
||||
fix(release): need to depend on latest rxjs and zone.js
|
||||
@ -203,7 +203,7 @@ Must be one of the following:
|
||||
* **test**: Adding missing tests or correcting existing tests
|
||||
|
||||
### Scope
|
||||
The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages.
|
||||
The scope should be the name of the npm package affected (as perceived by person reading changelog generated from commit messages.
|
||||
|
||||
The following is the list of supported scopes:
|
||||
|
||||
@ -232,10 +232,10 @@ There are currently a few exceptions to the "use package name" rule:
|
||||
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
|
||||
|
||||
### Subject
|
||||
The subject contains a succinct description of the change:
|
||||
The subject contains succinct description of the change:
|
||||
|
||||
* use the imperative, present tense: "change" not "changed" nor "changes"
|
||||
* don't capitalize the first letter
|
||||
* don't capitalize first letter
|
||||
* no dot (.) at the end
|
||||
|
||||
### Body
|
||||
@ -266,7 +266,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
|
||||
* https://help.github.com/articles/setting-your-commit-email-address-in-git/
|
||||
* https://stackoverflow.com/questions/37245303/what-does-usera-committed-with-userb-13-days-ago-on-github-mean
|
||||
* https://help.github.com/articles/about-commit-email-addresses/
|
||||
* https://help.github.com/articles/blocking-command-line-pushes-that-expose-your-personal-email-address/
|
||||
* https://help.github.com/articles/blocking-command-line-pushes-that-expose-your-personal-email-address/
|
||||
|
||||
Note that if you have more than one Git identity, it is important to verify that you are logged in with the same ID with which you signed the CLA, before you commit changes. If not, your PR will fail the CLA check.
|
||||
|
||||
|
40
WORKSPACE
40
WORKSPACE
@ -1,14 +1,11 @@
|
||||
workspace(name = "angular")
|
||||
|
||||
# Using a pre-release snapshot to pick up a commit that makes all nodejs_binary
|
||||
# programs produce source-mapped stack traces.
|
||||
RULES_NODEJS_VERSION = "926349cea4cd360afcd5647ccdd09d2d2fb471aa"
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
http_archive(
|
||||
git_repository(
|
||||
name = "build_bazel_rules_nodejs",
|
||||
url = "https://github.com/bazelbuild/rules_nodejs/archive/%s.zip" % RULES_NODEJS_VERSION,
|
||||
strip_prefix = "rules_nodejs-%s" % RULES_NODEJS_VERSION,
|
||||
sha256 = "5ba3c8c209078c2e3f0c6aa4abd01a1a561f92a5bfda04e25604af5f4734d69d",
|
||||
remote = "https://github.com/bazelbuild/rules_nodejs.git",
|
||||
commit = "230d39a391226f51c03448f91eb61370e2e58c42",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories")
|
||||
@ -16,13 +13,10 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_reposi
|
||||
check_bazel_version("0.9.0")
|
||||
node_repositories(package_json = ["//:package.json"])
|
||||
|
||||
RULES_TYPESCRIPT_VERSION = "0.10.1"
|
||||
|
||||
http_archive(
|
||||
git_repository(
|
||||
name = "build_bazel_rules_typescript",
|
||||
url = "https://github.com/bazelbuild/rules_typescript/archive/%s.zip" % RULES_TYPESCRIPT_VERSION,
|
||||
strip_prefix = "rules_typescript-%s" % RULES_TYPESCRIPT_VERSION,
|
||||
sha256 = "a2c81776a4a492ff9f878f9705639f5647bef345f7f3e1da09c9eeb8dec80485",
|
||||
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
||||
commit = "eb3244363e1cb265c84e723b347926f28c29aa35"
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
|
||||
@ -62,23 +56,3 @@ http_archive(
|
||||
strip_prefix = "bazel-9755c72b48866ed034bd28aa033e9abd27431b1e",
|
||||
sha256 = "5b8443fc3481b5fcd9e7f348e1dd93c1397f78b223623c39eb56494c55f41962",
|
||||
)
|
||||
|
||||
# We have a source dependency on the Devkit repository, because it's built with
|
||||
# Bazel.
|
||||
# This allows us to edit sources and have the effect appear immediately without
|
||||
# re-packaging or "npm link"ing.
|
||||
# Even better, things like aspects will visit the entire graph including
|
||||
# ts_library rules in the devkit repository.
|
||||
http_archive(
|
||||
name = "angular_devkit",
|
||||
url = "https://github.com/angular/devkit/archive/v0.3.1.zip",
|
||||
strip_prefix = "devkit-0.3.1",
|
||||
sha256 = "31d4b597fe9336650acf13df053c1c84dcbe9c29c6a833bcac3819cd3fd8cad3",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "org_brotli",
|
||||
url = "https://github.com/google/brotli/archive/v1.0.2.zip",
|
||||
strip_prefix = "brotli-1.0.2",
|
||||
sha256 = "b43d5d6bc40f2fa6c785b738d86c6bbe022732fe25196ebbe43b9653a025920d",
|
||||
)
|
||||
|
@ -39,7 +39,7 @@
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "tests/e2e/protractor.conf.js"
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
@ -50,12 +50,12 @@
|
||||
"project": "src/tsconfig.spec.json"
|
||||
},
|
||||
{
|
||||
"project": "tests/e2e/tsconfig.e2e.json"
|
||||
"project": "e2e/tsconfig.e2e.json"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "src/karma.conf.js"
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
|
@ -15,7 +15,6 @@ describe('Form Validation Tests', function () {
|
||||
});
|
||||
|
||||
tests('Template-Driven Form');
|
||||
bobTests();
|
||||
});
|
||||
|
||||
describe('Reactive form', () => {
|
||||
|
@ -20,7 +20,7 @@ export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
|
||||
// #enddocregion directive-providers
|
||||
})
|
||||
export class ForbiddenValidatorDirective implements Validator {
|
||||
@Input('appForbiddenName') forbiddenName: string;
|
||||
@Input() forbiddenName: string;
|
||||
|
||||
validate(control: AbstractControl): {[key: string]: any} {
|
||||
return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- #docregion name-with-error-msg -->
|
||||
<!-- #docregion name-input -->
|
||||
<input id="name" name="name" class="form-control"
|
||||
required minlength="4" appForbiddenName="bob"
|
||||
required minlength="4" forbiddenName="bob"
|
||||
[(ngModel)]="hero.name" #name="ngModel" >
|
||||
<!-- #enddocregion name-input -->
|
||||
|
||||
|
@ -21,14 +21,7 @@ import { MessagesComponent } from './messages/messages.component';
|
||||
FormsModule
|
||||
],
|
||||
// #docregion providers
|
||||
// #docregion providers-heroservice
|
||||
providers: [
|
||||
HeroService,
|
||||
// #enddocregion providers-heroservice
|
||||
MessageService
|
||||
// #docregion providers-heroservice
|
||||
],
|
||||
// #enddocregion providers-heroservice
|
||||
providers: [ HeroService, MessageService ],
|
||||
// #enddocregion providers
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
|
@ -3,6 +3,6 @@
|
||||
<h2>Messages</h2>
|
||||
<button class="clear"
|
||||
(click)="messageService.clear()">clear</button>
|
||||
<div *ngFor="let message of messageService.messages"> {{message}} </div>
|
||||
<div *ngFor='let message of messageService.messages'> {{message}} </div>
|
||||
|
||||
</div>
|
||||
|
@ -190,29 +190,6 @@ describe('Tutorial part 6', () => {
|
||||
const maxId = heroesBefore[heroesBefore.length - 1].id;
|
||||
expect(heroesAfter[numHeroes]).toEqual({id: maxId + 1, name: newHeroName});
|
||||
});
|
||||
|
||||
it('displays correctly styled buttons', async () => {
|
||||
element.all(by.buttonText('x')).then(buttons => {
|
||||
for (const button of buttons) {
|
||||
// Inherited styles from styles.css
|
||||
expect(button.getCssValue('font-family')).toBe('Arial');
|
||||
expect(button.getCssValue('border')).toContain('none');
|
||||
expect(button.getCssValue('padding')).toBe('5px 10px');
|
||||
expect(button.getCssValue('border-radius')).toBe('4px');
|
||||
// Styles defined in heroes.component.css
|
||||
expect(button.getCssValue('left')).toBe('194px');
|
||||
expect(button.getCssValue('top')).toBe('-32px');
|
||||
}
|
||||
});
|
||||
|
||||
const addButton = element(by.buttonText('add'));
|
||||
// Inherited styles from styles.css
|
||||
expect(addButton.getCssValue('font-family')).toBe('Arial');
|
||||
expect(addButton.getCssValue('border')).toContain('none');
|
||||
expect(addButton.getCssValue('padding')).toBe('5px 10px');
|
||||
expect(addButton.getCssValue('border-radius')).toBe('4px');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Progressive hero search', () => {
|
||||
|
@ -51,7 +51,7 @@
|
||||
}
|
||||
|
||||
/* #docregion additions */
|
||||
button {
|
||||
.button {
|
||||
background-color: #eee;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
|
@ -92,7 +92,7 @@ You can control your app compilation by providing template compiler options in t
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"fullTemplateTypeCheck": true,
|
||||
"preserveWhitespaces": true,
|
||||
"preserveWhiteSpaces": false,
|
||||
...
|
||||
}
|
||||
}
|
||||
@ -234,7 +234,9 @@ done manually.
|
||||
### *preserveWhitespaces*
|
||||
|
||||
This option tells the compiler whether to remove blank text nodes from compiled templates.
|
||||
As of v6, this option is `false` by default, which results in smaller emitted template factory modules.
|
||||
This option is `true` by default.
|
||||
|
||||
*Note*: It is recommended to set this explicitly to `false` as it emits smaller template factory modules and might be set to `false` by default in the future.
|
||||
|
||||
### *allowEmptyCodegenFiles*
|
||||
|
||||
@ -243,16 +245,6 @@ Tells the compiler to generate all the possible generated files even if they are
|
||||
how `bazel` rules track file dependencies. It is not recommended to use this option outside of the `bazel`
|
||||
rules.
|
||||
|
||||
### *enableIvy*
|
||||
|
||||
Tells the compiler to generate definitions using the Render3 style code generation. This option defaults to `false`.
|
||||
|
||||
Not all features are supported with this option enabled. It is only supported
|
||||
for experimentation and testing of Render3 style code generation.
|
||||
|
||||
*Note*: Is it not recommended to use this option as it is not yet feature complete with the Render2 code generation.
|
||||
|
||||
|
||||
## Angular Metadata and AOT
|
||||
|
||||
The Angular **AOT compiler** extracts and interprets **metadata** about the parts of the application that Angular is supposed to manage.
|
||||
|
@ -1,175 +0,0 @@
|
||||
<div class="breadcrumb">
|
||||
<a href="#">API<a> / <a href="#">@core<a>
|
||||
</div>
|
||||
<header class="api-header">
|
||||
<h1><label class="api-status-label experimental">experimental</label><label class="api-type-label class">class</label>Class Name</h1>
|
||||
</header>
|
||||
<div class="page-actions">
|
||||
<a href="#"><label class="raised page-label"><i class="material-icons">mode_edit</i>suggest edits</label></a>
|
||||
<a href="#"><label class="raised page-label"><i class="material-icons">code</i>view source</label></a>
|
||||
</div>
|
||||
<p>Class description goes here. This is a short and to the point one or two sentence description that easily introduces the reader to the class.</p>
|
||||
<div class="api-body">
|
||||
<section>
|
||||
<h2>Overview</h2>
|
||||
<code-example language="ts" hidecopy="true" ng-version="5.2.0"><aio-code class="simple-code" ng-reflect-ng-class="[object Object]" ng-reflect-code="
|
||||
class <a href="api/core/Compi" ng-reflect-hide-copy="true" ng-reflect-language="ts" ng-reflect-linenums="" ng-reflect-path="" ng-reflect-region="" ng-reflect-title=""><pre class="prettyprint lang-ts">
|
||||
<code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/core/Compiler" class="code-anchor"><span class="typ">Compiler</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||
</span><a class="code-anchor" href="api/core/Compiler#compileModuleSync"><span class="pln">compileModuleSync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">NgModuleFactory</span><span class="pun"><</span><span class="pln">T</span><span class="pun">></span></a><span class="pln">
|
||||
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAsync"><span class="pln">compileModuleAsync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun"><</span><span class="typ">NgModuleFactory</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>></span></a><span class="pln">
|
||||
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsSync"><span class="pln">compileModuleAndAllComponentsSync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">ModuleWithComponentFactories</span><span class="pun"><</span><span class="pln">T</span><span class="pun">></span></a><span class="pln">
|
||||
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsAsync"><span class="pln">compileModuleAndAllComponentsAsync</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun"><</span><span class="typ">ModuleWithComponentFactories</span><span class="pun"><</span><span class="pln">T</span><span class="pun">>></span></a><span class="pln">
|
||||
</span><a class="code-anchor" href="api/core/Compiler#clearCache"><span class="pln">clearCache</span><span class="pun">():</span><span class="pln"> </span><span class="kwd">void</span></a><span class="pln">
|
||||
</span><a class="code-anchor" href="api/core/Compiler#clearCacheFor"><span class="pln">clearCacheFor</span><span class="pun">(</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun"><</span><span class="pln">any</span><span class="pun">>)</span></a><span class="pln">
|
||||
</span><span class="pun">}</span></code>
|
||||
</pre></aio-code></code-example>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Description</h2>
|
||||
<p>The longer class description goes here which can include multiple paragraphs.</p>
|
||||
</p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
||||
<h3>Subclasses</h3>
|
||||
<ul>
|
||||
<li><a href="#">Subclass1</a></li>
|
||||
<li><a href="#">Subclass2</a></li>
|
||||
<li><a href="#">Subclass3</a></li>
|
||||
</ul>
|
||||
<h3>See Also</h3>
|
||||
<ul>
|
||||
<li><a href="#">Link1</a></li>
|
||||
<li><a href="#">Link2</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Constructor</h2>
|
||||
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
||||
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
||||
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
||||
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
||||
</pre></aio-code></code-example>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Properties</h2>
|
||||
<table class="is-full-width list-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code><strong>Property1</strong></code>
|
||||
</td>
|
||||
<td><label class="property-type-label type">Type</label></td>
|
||||
<td>Description goes here</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code><strong>Property2</strong></code>
|
||||
</td>
|
||||
<td>Type</td>
|
||||
<td>Description goes here</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code><strong>Property3</strong></code>
|
||||
</td>
|
||||
<td>Type</td>
|
||||
<td>Description goes here</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section class="api-method">
|
||||
<h2>Methods</h2>
|
||||
<table class="is-full-width item-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Method1Name( )</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p>Description goes here</p>
|
||||
<br>
|
||||
<p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="is-full-width api-method item-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Method2Name( )</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<p>Description goes here</p>
|
||||
<hr>
|
||||
<h5>Declaration</h5>
|
||||
<code-example language="ts" hidecopy="true" ng-version="5.2.0">
|
||||
<aio-code class="simple-code"><pre class="prettyprint lang-ts">
|
||||
<code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/animations/AnimationBuilder" class="code-anchor"><span class="typ">AnimationBuilder</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln"></span><a class="code-anchor" href="api/animations/AnimationBuilder#build"><span class="pln">build</span><span class="pun">(</span><span class="pln">animation</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pun">[]):</span><span class="pln"> </span><span class="typ">AnimationFactory</span></a><span class="pln"></span><span class="pun">}</span></code></pre>
|
||||
</aio-code>
|
||||
</code-example>
|
||||
<h6>Parameters</h6>
|
||||
<h6>Returns</h6>
|
||||
<p>Returns information and results goes here.</p>
|
||||
<h6>Errors</h6>
|
||||
<p>Error information goes here</p>
|
||||
<hr>
|
||||
<p>Further details provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.</p><hr>
|
||||
<h6>Overloads</h6>
|
||||
<table class="is-full-width">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
||||
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
||||
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
||||
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
||||
</pre></aio-code></code-example>
|
||||
</td>
|
||||
<td>Description goes here</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
||||
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
||||
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
||||
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
||||
</pre></aio-code></code-example>
|
||||
</td>
|
||||
<td>Description goes here</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr>
|
||||
<h5>Example: Descriptive Title of Method Example</h5>
|
||||
<p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Example: Descriptive Title of Combined Example Goes Here</h2>
|
||||
<p>Intro description text about what the example is and how it can be used.</p>
|
||||
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
|
||||
<aio-code class="simple-code"><pre class="prettyprint lang-">
|
||||
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
|
||||
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
|
||||
</span><span class="pun">}[],</span><span class="pln"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
|
||||
</pre></aio-code></code-example>
|
||||
<p>Further explanation provided as needed. Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball.</p>
|
||||
</section>
|
||||
</div>
|
@ -120,13 +120,11 @@ The documentation for the version prior to v.2.2.0 has been removed.
|
||||
|
||||
## ES6 described in "TypeScript to JavaScript" (2016-11-14)
|
||||
|
||||
The updated TypeScript to JavaScript guide explains how to write apps in ES6/7
|
||||
The updated TypeScript to JavaScript guide (removed August 2017, PR #18694)
|
||||
explains how to write apps in ES6/7
|
||||
by translating the common idioms in the TypeScript documentation examples
|
||||
(and elsewhere on the web) to ES6/7 and ES5.
|
||||
|
||||
This was [removed in August 2017](https://github.com/angular/angular/pull/18694) but can still be
|
||||
viewed in the [v2 documentation](https://v2.angular.io/docs/ts/latest/cookbook/ts-to-js.html).
|
||||
|
||||
## Sync with Angular v.2.1.1 (2016-10-21)
|
||||
|
||||
Docs and code samples updated and tested with Angular v.2.1.1.
|
||||
|
@ -140,11 +140,6 @@ is available to <code>declarations</code> of this module.</p>
|
||||
<td><p>Binds the presence of CSS classes on the element to the truthiness of the associated map values. The right-hand expression should return {class-name: true/false} map.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><div <b>[ngStyle]</b>="{'property': 'value'}"></code><br><code><div <b>[ngStyle]</b>="dynamicStyles()"></code></td>
|
||||
<td><p>Allows you to assign styles to an HTML element using CSS. You can use CSS directly, as in the first example, or you can call a method from the component.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<table class="is-full-width is-fixed-layout">
|
||||
|
@ -97,7 +97,7 @@ In fact, many libraries declare and export components you'll never use.
|
||||
For example, a material design library will export all components because it doesn’t know which ones you will use. However, it is unlikely that you will use them all.
|
||||
For the ones you don't reference, the tree shaker drops these components from the final code package.
|
||||
|
||||
If a component isn't an _entry component_ and isn't found in a template,
|
||||
If a component isn't an _entry component_ or isn't found in a template,
|
||||
the tree shaker will throw it away. So, it's best to add only the components that are truly entry components to help keep your app
|
||||
as trim as possible.
|
||||
|
||||
|
@ -98,7 +98,7 @@ When the CLI generated the `CustomerDashboardComponent` for the feature module,
|
||||
</code-example>
|
||||
|
||||
|
||||
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardModule`:
|
||||
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the declarations array, add an exports array containing `CustomerDashboardModule`:
|
||||
|
||||
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
|
||||
</code-example>
|
||||
|
@ -171,7 +171,7 @@ comes together:
|
||||
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive" title="shared/forbidden-name.directive.ts (directive)">
|
||||
</code-example>
|
||||
|
||||
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example:
|
||||
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `forbiddenName`, to any input element to activate it. For example:
|
||||
|
||||
<code-example path="form-validation/src/app/template/hero-form-template.component.html" region="name-input" title="template/hero-form-template.component.html (forbidden-name-input)" linenums="false">
|
||||
|
||||
|
@ -512,6 +512,10 @@ You rarely access Angular feature modules directly. You usually import them from
|
||||
|
||||
## NgModule
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
|
||||
|
||||
Helps you organize an application into cohesive blocks of functionality.
|
||||
An NgModule identifies the components, directives, and pipes that the application uses along with the list of external NgModules that the application needs, such as `FormsModule`.
|
||||
|
||||
@ -522,7 +526,7 @@ For details and examples, see [NgModules](guide/ngmodules) and the
|
||||
related files in that section.
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{@a O}
|
||||
|
||||
@ -627,10 +631,13 @@ For more information, see the [Routing & Navigation](guide/router) page.
|
||||
|
||||
## Router module
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
||||
A separate [NgModule](guide/glossary#ngmodule) that provides the necessary service providers and directives for navigating through application views.
|
||||
|
||||
For more information, see the [Routing & Navigation](guide/router) page.
|
||||
|
||||
</div>
|
||||
|
||||
## Routing component
|
||||
|
||||
|
@ -358,7 +358,7 @@ subscribes without a callback.
|
||||
The bare `.subscribe()` _seems_ pointless.
|
||||
|
||||
In fact, it is essential.
|
||||
Merely calling `HeroService.deleteHero()` **does not initiate the DELETE request.**
|
||||
Merely calling `HeroService.addHero()` **does not initiate the DELETE request.**
|
||||
|
||||
<code-example
|
||||
path="http/src/app/heroes/heroes.component.ts"
|
||||
|
@ -57,7 +57,7 @@ You can also use the VS Quick Open (⌘+P) to search for the extension. When you
|
||||
enter the following command:
|
||||
|
||||
```sh
|
||||
ext install Angular.ng-template
|
||||
ext install ng-template
|
||||
```
|
||||
|
||||
Then click the install button to install the Angular Language Service.
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Lifecycle Hooks
|
||||
|
||||
<img src="generated/images/guide/lifecycle-hooks/hooks-in-sequence.png" alt="Us" class="left">
|
||||
|
||||
A component has a lifecycle managed by Angular.
|
||||
|
||||
Angular creates it, renders it, creates and renders its children,
|
||||
@ -8,7 +10,7 @@ checks it when its data-bound properties change, and destroys it before removing
|
||||
Angular offers **lifecycle hooks**
|
||||
that provide visibility into these key life moments and the ability to act when they occur.
|
||||
|
||||
A directive has the same set of lifecycle hooks.
|
||||
A directive has the same set of lifecycle hooks, minus the hooks that are specific to component content and views.
|
||||
|
||||
{@a hooks-overview}
|
||||
|
||||
@ -25,7 +27,7 @@ that Angular calls shortly after creating the component:
|
||||
|
||||
<code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" title="peek-a-boo.component.ts (excerpt)" linenums="false"></code-example>
|
||||
|
||||
No directive or component will implement all of the lifecycle hooks.
|
||||
No directive or component will implement all of the lifecycle hooks and some of the hooks only make sense for components.
|
||||
Angular only calls a directive/component hook method *if it is defined*.
|
||||
|
||||
{@a hooks-purpose-timing}
|
||||
@ -86,10 +88,12 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Respond after Angular projects external content into the component's view / the view that a directive is in.
|
||||
Respond after Angular projects external content into the component's view.
|
||||
|
||||
Called _once_ after the first `ngDoCheck()`.
|
||||
|
||||
_A component-only hook_.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr style='vertical-align:top'>
|
||||
@ -98,10 +102,12 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Respond after Angular checks the content projected into the directive/component.
|
||||
Respond after Angular checks the content projected into the component.
|
||||
|
||||
Called after the `ngAfterContentInit()` and every subsequent `ngDoCheck()`.
|
||||
|
||||
_A component-only hook_.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr style='vertical-align:top'>
|
||||
@ -110,10 +116,12 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Respond after Angular initializes the component's views and child views / the view that a directive is in.
|
||||
Respond after Angular initializes the component's views and child views.
|
||||
|
||||
Called _once_ after the first `ngAfterContentChecked()`.
|
||||
|
||||
_A component-only hook_.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr style='vertical-align:top'>
|
||||
@ -122,10 +130,12 @@ calls the lifecycle hook methods in the following sequence at specific moments:
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Respond after Angular checks the component's views and child views / the view that a directive is in.
|
||||
Respond after Angular checks the component's views and child views.
|
||||
|
||||
Called after the `ngAfterViewInit` and every subsequent `ngAfterContentChecked()`.
|
||||
|
||||
_A component-only hook_.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr style='vertical-align:top'>
|
||||
|
@ -27,7 +27,7 @@ JavaScript modules help you namespace, preventing accidental global variables.
|
||||
## NgModules
|
||||
|
||||
<!-- KW-- perMisko: let's discuss. This does not answer the question why it is different. Also, last sentence is confusing.-->
|
||||
NgModules are classes decorated with `@NgModule`. The `@NgModule` decorator’s `imports` array tells Angular what other NgModules the current module needs. The modules in the `imports` array are different than JavaScript modules because they are NgModules rather than regular JavaScript modules. Classes with an `@NgModule` decorator are by convention kept in their own files, but what makes them an `NgModule` isn’t being in their own file, like JavaScript modules; it’s the presence of `@NgModule` and its metadata.
|
||||
NgModules are classes decorated with `@NgModule`. The `@NgModule` decorator’s `imports` array tells Angular what other NgModules the current module needs. The modules in the imports array are different than JavaScript modules because they are NgModules rather than regular JavaScript modules. Classes with an `@NgModule` decorator are by convention kept in their own files, but what makes them an `NgModule` isn’t being in their own file, like JavaScript modules; it’s the presence of `@NgModule` and its metadata.
|
||||
|
||||
The `AppModule` generated from the Angular CLI demonstrates both kinds of modules in action:
|
||||
|
||||
@ -53,7 +53,7 @@ export class AppModule { }
|
||||
```
|
||||
|
||||
|
||||
The NgModule classes differ from JavaScript module in the following key ways:
|
||||
The NgModule classes differ from JavaScript module classes in the following key ways:
|
||||
|
||||
* An NgModule bounds [declarable classes](guide/ngmodule-faq#q-declarable) only.
|
||||
Declarables are the only classes that matter to the [Angular compiler](guide/ngmodule-faq#q-angular-compiler).
|
||||
|
@ -45,7 +45,7 @@ NgModule metadata does the following:
|
||||
* Declares which components, directives, and pipes belong to the module.
|
||||
* Makes some of those components, directives, and pipes public so that other module's component templates can use them.
|
||||
* Imports other modules with the components, directives, and pipes that components in the current module need.
|
||||
* Provides services that the other application components can use.
|
||||
* Provides services at the other application components can use.
|
||||
|
||||
Every Angular app has at least one module, the root module.
|
||||
You [bootstrap](guide/bootstrapping) that module to launch the application.
|
||||
|
@ -496,7 +496,7 @@ Remember that impure pipes are called every few milliseconds.
|
||||
If you're not careful, this pipe will punish the server with requests.
|
||||
|
||||
In the following code, the pipe only calls the server when the request URL changes and it caches the server response.
|
||||
The code uses the [Angular http](guide/http) client to retrieve data:
|
||||
The code uses the [Angular http](guide/http) client to retrieve data</span>:
|
||||
|
||||
|
||||
<code-example path="pipes/src/app/fetch-json.pipe.ts" title="src/app/fetch-json.pipe.ts">
|
||||
|
@ -10,7 +10,7 @@ see the <live-example></live-example>.
|
||||
<hr>
|
||||
|
||||
## Create a service
|
||||
You can provide services to your app by using the `providers` array in an NgModule.
|
||||
You can provide services to your app by using the providers array in an NgModule.
|
||||
Consider the default app generated by the CLI. In order to add a user service to it,
|
||||
you can generate one by entering the following command in the terminal window:
|
||||
|
||||
@ -20,7 +20,7 @@ ng generate service User
|
||||
|
||||
This creates a service called `UserService`. You now need to make the service available in your
|
||||
app's injector. Update `app.module.ts` by importing it with your other import statements at the top
|
||||
of the file and adding it to the `providers` array:
|
||||
of the file and adding it to the providers array:
|
||||
|
||||
<code-example path="providers/src/app/app.module.ts" title="src/app/app.module.ts" linenums="false">
|
||||
</code-example>
|
||||
@ -28,7 +28,7 @@ of the file and adding it to the `providers` array:
|
||||
|
||||
## Provider scope
|
||||
|
||||
When you add a service provider to the `providers` array of the root module, it’s available throughout the app. Additionally, when you import a module that has providers, those providers are also available to all the classes in the app as long they have the lookup token. For example, if you import the `HttpClientModule` into your `AppModule`, its providers are then available to the entire app and you can make HTTP requests from anywhere in your app.
|
||||
When you add a service provider to the providers array of the root module, it’s available throughout the app. Additionally, when you import a module that has providers, those providers are also available to all the classes in the app as long they have the lookup token. For example, if you import the `HttpClientModule` into your `AppModule`, its providers are then available to the entire app and you can make HTTP requests from anywhere in your app.
|
||||
|
||||
|
||||
## Limiting provider scope by lazy loading modules
|
||||
|
@ -418,7 +418,7 @@ To see the form model, add the following line after the
|
||||
closing `form` tag in the `hero-detail.component.html`:
|
||||
|
||||
|
||||
<code-example path="reactive-forms/src/app/hero-detail/hero-detail-2.component.html" region="form-value-json" title="src/app/hero-detail/hero-detail.component.html" linenums="false">
|
||||
<code-example path="reactive-forms/src/app/hero-detail/hero-detail-3.component.html" region="form-value-json" title="src/app/hero-detail/hero-detail.component.html" linenums="false">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
@ -290,42 +290,20 @@ out of date. Right click the Cache Storage title and refresh the caches.
|
||||
Stopping and starting the service worker in the Service Worker
|
||||
pane triggers a check for updates.
|
||||
|
||||
## Service Worker Safety
|
||||
## Fail-safe
|
||||
|
||||
Like any complex system, bugs or broken configurations can cause
|
||||
the Angular service worker to act in unforeseen ways. While its
|
||||
design attempts to minimize the impact of such problems, the
|
||||
Angular service worker contains several failsafe mechanisms in case
|
||||
Angular service worker contains a failsafe mechanism in case
|
||||
an administrator ever needs to deactivate the service worker quickly.
|
||||
|
||||
## Fail-safe
|
||||
|
||||
To deactivate the service worker, remove or rename the
|
||||
`ngsw-config.json` file. When the service worker's request
|
||||
for `ngsw.json` returns a `404`, then the service worker
|
||||
removes all of its caches and de-registers itself,
|
||||
essentially self-destructing.
|
||||
|
||||
### Safety Worker
|
||||
|
||||
Also included in the `@angular/service-worker` NPM package is a small
|
||||
script `safety-worker.js`, which when loaded will unregister itself
|
||||
from the browser. This script can be used as a last resort to get rid
|
||||
of unwanted service workers already installed on client pages.
|
||||
|
||||
It's important to note that you cannot register this worker directly,
|
||||
as old clients with cached state may not see a new `index.html` which
|
||||
installs the different worker script. Instead, you must serve the
|
||||
contents of `safety-worker.js` at the URL of the Service Worker script
|
||||
you are trying to unregister, and must continue to do so until you are
|
||||
certain all users have successfully unregistered the old worker. For
|
||||
most sites, this means that you should serve the safety worker at the
|
||||
old Service Worker URL forever.
|
||||
|
||||
This script can be used both to deactivate `@angular/service-worker`
|
||||
as well as any other Service Workers which might have been served in
|
||||
the past on your site.
|
||||
|
||||
## More on Angular service workers
|
||||
|
||||
You may also be interested in the following:
|
||||
|
BIN
aio/content/images/guide/lifecycle-hooks/hooks-in-sequence.png
Normal file
BIN
aio/content/images/guide/lifecycle-hooks/hooks-in-sequence.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
Before Width: | Height: | Size: 9.5 KiB |
@ -1,9 +0,0 @@
|
||||
[
|
||||
{
|
||||
"startDate": "2018-02-14",
|
||||
"endDate": "2018-04-22",
|
||||
"message": "Join us for ng-conf<br/>Apr 18th-20th, 2018",
|
||||
"imageUrl": "generated/images/marketing/home/ng-conf.png",
|
||||
"linkUrl": "http://ng-conf.org/"
|
||||
}
|
||||
]
|
@ -20,7 +20,7 @@
|
||||
|
||||
<div class="feature">
|
||||
<div class="feature-title">Native</div>
|
||||
<p class="text-body">Build native mobile apps with strategies from Cordova, Ionic, or NativeScript.</p>
|
||||
<p class="text-body">Build native mobile apps with strategies from Ionic Framework, NativeScript, and React Native.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature">
|
||||
|
@ -29,7 +29,14 @@
|
||||
|
||||
<div class="home-rows">
|
||||
|
||||
<aio-announcement-bar></aio-announcement-bar>
|
||||
<!-- Announcement Bar -->
|
||||
<div class="homepage-container">
|
||||
<div class="announcement-bar">
|
||||
<img src="generated/images/marketing/home/ng-atl.png">
|
||||
<p>Join us in Atlanta for ngATL<br>Jan 30 - Feb 2, 2018</p>
|
||||
<a class="button" href="http://ng-atl.org/">Learn More</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Group 1 -->
|
||||
<div layout="row" layout-xs="column" class="home-row homepage-container">
|
||||
|
@ -241,19 +241,6 @@
|
||||
"rev": true,
|
||||
"title": "NinjaCodeGen - Angular CRUD Generator",
|
||||
"url": "https://ninjaCodeGen.com"
|
||||
},
|
||||
"angular-playground": {
|
||||
"desc": "UI development environment for building, testing, and documenting Angular applications.",
|
||||
"rev": true,
|
||||
"title": "Angular Playground",
|
||||
"url": "http://www.angularplayground.it/"
|
||||
},
|
||||
"nx": {
|
||||
"desc": "Nx (Nrwl Extensions for Angular) is an open source toolkit built on top of Angular CLI to help enterprise teams develop Angular at scale.",
|
||||
"rev": true,
|
||||
"title": "Nx",
|
||||
"logo": "https://nrwl.io/assets/nx-logo.png",
|
||||
"url": "https://nrwl.io/nx"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -451,13 +438,6 @@
|
||||
"rev": true,
|
||||
"title": "Essential Angular",
|
||||
"url": "https://gumroad.com/l/essential_angular"
|
||||
},
|
||||
"angular-buch": {
|
||||
"desc": "The first German book about Angular. It gives you a detailed practical overview of the key concepts of the platform. In each chapter a sample application is built upon with a new Angular topic. All sources are available on GitHub.",
|
||||
"logo": "https://angular-buch.com/assets/img/brand.svg",
|
||||
"rev": true,
|
||||
"title": "Angular-Buch (German)",
|
||||
"url": "https://angular-buch.com/"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -502,13 +482,6 @@
|
||||
"title": "CodeSchool: Accelerating Through Angular",
|
||||
"url": "https://www.codeschool.com/courses/accelerating-through-angular-2"
|
||||
},
|
||||
"angular-playbook": {
|
||||
"desc": "Learn advanced Angular best practices for enterprise teams, created by Nrwl.io.",
|
||||
"logo": "https://nrwl.io/assets/logo_footer_2x.png",
|
||||
"rev": true,
|
||||
"title": "Angular Enterprise Playbook",
|
||||
"url": "https://angularplaybook.com"
|
||||
},
|
||||
"a2b": {
|
||||
"desc": "Hundreds of Angular courses for all skill levels",
|
||||
"logo": "",
|
||||
@ -679,13 +652,6 @@
|
||||
"rev": true,
|
||||
"title": "We Are One Sàrl",
|
||||
"url": "https://weareone.ch/courses/angular/"
|
||||
},
|
||||
"angular-schule": {
|
||||
"desc": "Angular onsite training and public workshops in Germany from the authors of the German Angular book. We also regularly post articles and videos on our blog (in English and German language).",
|
||||
"logo": "https://angular.schule/assets/img/brand.svg",
|
||||
"rev": true,
|
||||
"title": "Angular.Schule (German)",
|
||||
"url": "https://angular.schule/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,7 @@
|
||||
},
|
||||
|
||||
{
|
||||
"url": "tutorial",
|
||||
"title": "Tutorial",
|
||||
"tooltip": "The Tour of Heroes tutorial takes you through the steps of creating an Angular application in TypeScript.",
|
||||
"children": [
|
||||
@ -121,6 +122,7 @@
|
||||
},
|
||||
|
||||
{
|
||||
"url": "guide/architecture",
|
||||
"title": "Fundamentals",
|
||||
"tooltip": "The fundamentals of Angular",
|
||||
"children": [
|
||||
@ -168,11 +170,6 @@
|
||||
"title": "Attribute Directives",
|
||||
"tooltip": "Attribute directives attach behavior to elements."
|
||||
},
|
||||
{
|
||||
"url": "guide/structural-directives",
|
||||
"title": "Structural Directives",
|
||||
"tooltip": "Structural directives manipulate the layout of the page."
|
||||
},
|
||||
{
|
||||
"url": "guide/pipes",
|
||||
"title": "Pipes",
|
||||
|
@ -29,7 +29,7 @@ and annotate the component class with `@Component`.
|
||||
|
||||
The CLI generated three metadata properties:
|
||||
|
||||
1. `selector`— the component's CSS element selector
|
||||
1. `selector`— the components CSS element selector
|
||||
1. `templateUrl`— the location of the component's template file.
|
||||
1. `styleUrls`— the location of the component's private CSS styles.
|
||||
|
||||
|
@ -96,7 +96,7 @@ Bind the `HeroesComponent.selectedHero` to the element's `hero` property like th
|
||||
`[hero]="selectedHero"` is an Angular [property binding](guide/template-syntax#property-binding).
|
||||
|
||||
It's a _one way_ data binding from
|
||||
the `selectedHero` property of the `HeroesComponent` to the `hero` property of the target element, which maps to the `hero` property of the `HeroDetailComponent`.
|
||||
the `selectedHero` property of the `HeroComponent` to the `hero` property of the target element, which maps to the `hero` property of the `HeroDetailComponent`.
|
||||
|
||||
Now when the user clicks a hero in the list, the `selectedHero` changes.
|
||||
When the `selectedHero` changes, the _property binding_ updates `hero`
|
||||
|
@ -97,7 +97,7 @@ Since you did not, you'll have to provide it yourself.
|
||||
|
||||
Open the `AppModule` class, import the `HeroService`, and add it to the `@NgModule.providers` array.
|
||||
|
||||
<code-example path="toh-pt4/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-heroservice">
|
||||
<code-example path="toh-pt4/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers">
|
||||
</code-example>
|
||||
|
||||
The `providers` array tells Angular to create a single, shared instance of `HeroService`
|
||||
@ -105,12 +105,6 @@ and inject into any class that asks for it.
|
||||
|
||||
The `HeroService` is now ready to plug into the `HeroesComponent`.
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
This is a interim code sample that will allow you to provide and use the `HeroService`. At this point, the code will differ from the `HeroService` in the ["final code review"](#final-code-review).
|
||||
|
||||
</div>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
Learn more about _providers_ in the [Providers](guide/providers) guide.
|
||||
@ -429,10 +423,6 @@ Here are the code files discussed on this page and your app should look like thi
|
||||
path="toh-pt4/src/app/messages/messages.component.css">
|
||||
</code-pane>
|
||||
|
||||
<code-pane title="src/app/app.module.ts"
|
||||
path="toh-pt4/src/app/app.module.ts">
|
||||
</code-pane>
|
||||
|
||||
<code-pane title="src/app/app.component.html"
|
||||
path="toh-pt4/src/app/app.component.html">
|
||||
</code-pane>
|
||||
|
@ -24,7 +24,7 @@ export class ApiPage extends SitePage {
|
||||
//
|
||||
// and we want to be able to pull out the code elements from only the first level
|
||||
// if `onlyDirect` is set to `true`.
|
||||
const selector = `.inline-sidebar .descendants.${docType} ${onlyDirect ? '>' : ''} ul > li > code`;
|
||||
const selector = `.descendants.${docType} ${onlyDirect ? '>' : ''} li > :not(ul) code`;
|
||||
return element.all(by.css(selector)).map<string>(item => item && item.getText());
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { browser, by, element, ElementFinder } from 'protractor';
|
||||
import { browser, by, element } from 'protractor';
|
||||
import { SitePage } from './app.po';
|
||||
|
||||
describe('site App', function() {
|
||||
@ -11,7 +11,7 @@ describe('site App', function() {
|
||||
|
||||
it('should show features text after clicking "Features"', () => {
|
||||
page.navigateTo('');
|
||||
page.click(page.getTopMenuLink('features'));
|
||||
page.getTopMenuLink('features').click();
|
||||
expect(page.getDocViewerText()).toMatch(/Progressive web apps/i);
|
||||
});
|
||||
|
||||
@ -19,74 +19,28 @@ describe('site App', function() {
|
||||
page.navigateTo('');
|
||||
expect(browser.getTitle()).toBe('Angular');
|
||||
|
||||
page.click(page.getTopMenuLink('features'));
|
||||
page.getTopMenuLink('features').click();
|
||||
expect(browser.getTitle()).toBe('Angular - FEATURES & BENEFITS');
|
||||
|
||||
page.click(page.homeLink);
|
||||
page.homeLink.click();
|
||||
expect(browser.getTitle()).toBe('Angular');
|
||||
});
|
||||
|
||||
it('should not navigate when clicking on nav-item headings (sub-menu toggles)', () => {
|
||||
// Show the sidenav.
|
||||
page.navigateTo('docs');
|
||||
expect(page.locationPath()).toBe('/docs');
|
||||
|
||||
// Get the top-level nav-item headings (sub-menu toggles).
|
||||
const navItemHeadings = page.getNavItemHeadings(page.sidenav, 1);
|
||||
|
||||
// Test all headings (and sub-headings).
|
||||
expect(navItemHeadings.count()).toBeGreaterThan(0);
|
||||
navItemHeadings.each(heading => testNavItemHeading(heading!, 1));
|
||||
|
||||
// Helpers
|
||||
function expectToBeCollapsed(element: ElementFinder) {
|
||||
expect(element.getAttribute('class')).toMatch(/\bcollapsed\b/);
|
||||
expect(element.getAttribute('class')).not.toMatch(/\bexpanded\b/);
|
||||
}
|
||||
|
||||
function expectToBeExpanded(element: ElementFinder) {
|
||||
expect(element.getAttribute('class')).not.toMatch(/\bcollapsed\b/);
|
||||
expect(element.getAttribute('class')).toMatch(/\bexpanded\b/);
|
||||
}
|
||||
|
||||
function testNavItemHeading(heading: ElementFinder, level: number) {
|
||||
const children = page.getNavItemHeadingChildren(heading, level);
|
||||
|
||||
// Headings are initially collapsed.
|
||||
expectToBeCollapsed(children);
|
||||
|
||||
// Ensure heading does not cause navigation when expanding.
|
||||
page.click(heading);
|
||||
expectToBeExpanded(children);
|
||||
expect(page.locationPath()).toBe('/docs');
|
||||
|
||||
// Recursively test child-headings (while this heading is expanded).
|
||||
const nextLevel = level + 1;
|
||||
const childNavItemHeadings = page.getNavItemHeadings(children, nextLevel);
|
||||
childNavItemHeadings.each(childHeading => testNavItemHeading(childHeading!, nextLevel));
|
||||
|
||||
// Ensure heading does not cause navigation when collapsing.
|
||||
page.click(heading);
|
||||
expectToBeCollapsed(children);
|
||||
expect(page.locationPath()).toBe('/docs');
|
||||
}
|
||||
});
|
||||
|
||||
it('should show the tutorial index page at `/tutorial` after jitterbugging through features', () => {
|
||||
// check that we can navigate directly to the tutorial page
|
||||
page.navigateTo('tutorial');
|
||||
expect(page.getDocViewerText()).toMatch(/Tutorial: Tour of Heroes/i);
|
||||
|
||||
// navigate to a different page
|
||||
page.click(page.getTopMenuLink('features'));
|
||||
page.getTopMenuLink('features').click();
|
||||
expect(page.getDocViewerText()).toMatch(/Progressive web apps/i);
|
||||
|
||||
// Show the menu
|
||||
page.click(page.docsMenuLink);
|
||||
page.docsMenuLink.click();
|
||||
|
||||
// Tutorial folder should still be expanded because this test runs in wide mode
|
||||
// Navigate to the tutorial introduction via a link in the sidenav
|
||||
page.click(page.getNavItem(/introduction/i));
|
||||
page.getNavItem(/introduction/i).click();
|
||||
expect(page.getDocViewerText()).toMatch(/Tutorial: Tour of Heroes/i);
|
||||
});
|
||||
|
||||
@ -103,7 +57,8 @@ describe('site App', function() {
|
||||
page.scrollToBottom();
|
||||
expect(page.getScrollTop()).toBeGreaterThan(0);
|
||||
|
||||
page.click(page.getNavItem(/api/i));
|
||||
page.getNavItem(/api/i).click();
|
||||
browser.waitForAngular();
|
||||
expect(page.locationPath()).toBe('/api');
|
||||
expect(page.getScrollTop()).toBe(0);
|
||||
});
|
||||
@ -114,7 +69,8 @@ describe('site App', function() {
|
||||
page.scrollToBottom();
|
||||
expect(page.getScrollTop()).toBeGreaterThan(0);
|
||||
|
||||
page.click(page.getNavItem(/security/i));
|
||||
page.getNavItem(/security/i).click();
|
||||
browser.waitForAngular();
|
||||
expect(page.locationPath()).toBe('/guide/security');
|
||||
expect(page.getScrollTop()).toBe(0);
|
||||
});
|
||||
@ -146,7 +102,7 @@ describe('site App', function() {
|
||||
it('should call ga with new URL on navigation', done => {
|
||||
let path: string;
|
||||
page.navigateTo('');
|
||||
page.click(page.getTopMenuLink('features'));
|
||||
page.getTopMenuLink('features').click();
|
||||
page.locationPath()
|
||||
.then(p => path = p)
|
||||
.then(() => page.ga())
|
||||
@ -169,7 +125,7 @@ describe('site App', function() {
|
||||
expect(element(by.css('meta[name="googlebot"][content="noindex"]')).isPresent()).toBeTruthy();
|
||||
expect(element(by.css('meta[name="robots"][content="noindex"]')).isPresent()).toBeTruthy();
|
||||
|
||||
page.click(page.getTopMenuLink('features'));
|
||||
page.getTopMenuLink('features').click();
|
||||
expect(element(by.css('meta[name="googlebot"]')).isPresent()).toBeFalsy();
|
||||
expect(element(by.css('meta[name="robots"]')).isPresent()).toBeFalsy();
|
||||
});
|
@ -7,7 +7,6 @@ export class SitePage {
|
||||
links = element.all(by.css('md-toolbar a'));
|
||||
homeLink = element(by.css('a.home'));
|
||||
docsMenuLink = element(by.cssContainingText('aio-top-menu a', 'Docs'));
|
||||
sidenav = element(by.css('mat-sidenav'));
|
||||
docViewer = element(by.css('aio-doc-viewer'));
|
||||
codeExample = element.all(by.css('aio-doc-viewer pre > code'));
|
||||
ghLink = this.docViewer
|
||||
@ -25,17 +24,7 @@ export class SitePage {
|
||||
.filter(element => element.getText().then(text => pattern.test(text)))
|
||||
.first();
|
||||
}
|
||||
getNavItemHeadings(parent: ElementFinder, level: number) {
|
||||
const targetSelector = `aio-nav-item .vertical-menu-item.heading.level-${level}`;
|
||||
return parent.all(by.css(targetSelector));
|
||||
}
|
||||
getNavItemHeadingChildren(heading: ElementFinder, level: number) {
|
||||
const targetSelector = `.heading-children.level-${level}`;
|
||||
const script = `return arguments[0].parentNode.querySelector('${targetSelector}');`;
|
||||
return element(() => browser.executeScript(script, heading));
|
||||
}
|
||||
getTopMenuLink(path) { return element(by.css(`aio-top-menu a[href="${path}"]`)); }
|
||||
|
||||
ga() { return browser.executeScript('return window["ga"].q') as promise.Promise<any[][]>; }
|
||||
locationPath() { return browser.executeScript('return document.location.pathname') as promise.Promise<string>; }
|
||||
|
||||
@ -64,10 +53,6 @@ export class SitePage {
|
||||
return browser.executeScript('window.scrollTo(0, document.body.scrollHeight)');
|
||||
}
|
||||
|
||||
click(element: ElementFinder) {
|
||||
return element.click().then(() => browser.waitForAngular());
|
||||
}
|
||||
|
||||
enterSearch(query: string) {
|
||||
const input = element(by.css('.search-container input[type=search]'));
|
||||
input.clear();
|
@ -12,98 +12,50 @@
|
||||
// make sure the routing RegExp in `ngsw-manifest.json` is updated accordingly.
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// A random bad indexed page that used `api/api`
|
||||
{"type": 301, "source": "/api/api/:rest*", "destination": "/api/:rest*"},
|
||||
// cli-quickstart.html, glossary.html, quickstart.html, server-communication.html, style-guide.html
|
||||
{"type": 301, "source": "/docs/ts/latest/cli-quickstart.html", "destination": "/guide/quickstart"},
|
||||
{"type": 301, "source": "/docs/ts/latest/glossary.html", "destination": "/guide/glossary"},
|
||||
{"type": 301, "source": "/docs/ts/latest/quickstart.html", "destination": "/guide/quickstart"},
|
||||
{"type": 301, "source": "/docs/ts/latest/guide/server-communication.html", "destination": "/guide/http"},
|
||||
{"type": 301, "source": "/docs/ts/latest/guide/style-guide.html", "destination": "/guide/styleguide"},
|
||||
|
||||
// Guide renames
|
||||
{"type": 301, "source": "/docs/*/latest/cli-quickstart.html", "destination": "/guide/quickstart"},
|
||||
{"type": 301, "source": "/docs/*/latest/glossary.html", "destination": "/guide/glossary"},
|
||||
{"type": 301, "source": "/docs/*/latest/quickstart.html", "destination": "/guide/quickstart"},
|
||||
{"type": 301, "source": "/docs/*/latest/guide/server-communication.html", "destination": "/guide/http"},
|
||||
{"type": 301, "source": "/docs/*/latest/guide/style-guide.html", "destination": "/guide/styleguide"},
|
||||
// guide/cli-quickstart, styleguide
|
||||
{"type": 301, "source": "/guide/cli-quickstart", "destination": "/guide/quickstart"},
|
||||
{"type": 301, "source": "/styleguide", "destination": "/guide/styleguide"},
|
||||
|
||||
// cookbook/a1-a2-quick-reference.html, cookbook/component-communication.html, cookbook/dependency-injection.html
|
||||
{"type": 301, "source": "/docs/ts/latest/cookbook/a1-a2-quick-reference.html", "destination": "/guide/ajs-quick-reference"},
|
||||
{"type": 301, "source": "/docs/ts/latest/cookbook/component-communication.html", "destination": "/guide/component-interaction"},
|
||||
{"type": 301, "source": "/docs/ts/latest/cookbook/dependency-injection.html", "destination": "/guide/dependency-injection-in-action"},
|
||||
|
||||
// cookbook, cookbook/, cookbook/index.html
|
||||
{"type": 301, "source": "/docs/ts/latest/cookbook", "destination": "/docs"},
|
||||
{"type": 301, "source": "/docs/ts/latest/cookbook/", "destination": "/docs"},
|
||||
{"type": 301, "source": "/docs/ts/latest/cookbook/index.html", "destination": "/docs"},
|
||||
|
||||
// cookbook/*.html
|
||||
{"type": 301, "source": "/docs/ts/latest/cookbook/:cookbook.html", "destination": "/guide/:cookbook"},
|
||||
|
||||
// docs/ts/latest/api/<package>/index/*-<type>.html (+ special case for `NgFor` which has been renamed)
|
||||
{"type": 301, "source": "/docs/ts/latest/api/common/index/NgFor-directive.html", "destination": "/api/common/NgForOf"},
|
||||
{"type": 301, "source": "/docs/ts/latest/api/:package/index/:api-*.html", "destination": "/api/:package/:api"},
|
||||
|
||||
// docs/ts/latest
|
||||
{"type": 301, "source": "/docs/ts/latest", "destination": "/docs"},
|
||||
|
||||
// guide/*, tutorial/*, **/*
|
||||
{"type": 301, "source": "/docs/ts/latest/:any*", "destination": "/:any*"},
|
||||
|
||||
// aot-compiler.md and metadata.md combined into aot-compiler.md - issue #19510
|
||||
{"type": 301, "source": "/guide/metadata", "destination": "/guide/aot-compiler"},
|
||||
|
||||
// ngmodule.md renamed to ngmodules.md
|
||||
{"type": 301, "source": "/guide/ngmodule", "destination": "/guide/ngmodules"},
|
||||
|
||||
// service-worker-getstart.md, service-worker-comm.md, service-worker-configref.md
|
||||
{"type": 301, "source": "/guide/service-worker-getstart", "destination": "/guide/service-worker-getting-started"},
|
||||
{"type": 301, "source": "/guide/service-worker-comm", "destination": "/guide/service-worker-communications"},
|
||||
{"type": 301, "source": "/guide/service-worker-configref", "destination": "/guide/service-worker-config"},
|
||||
|
||||
// some top level guide pages on old site were moved below the guide folder
|
||||
{"type": 301, "source": "/styleguide", "destination": "/guide/styleguide"},
|
||||
{"type": 301, "source": "/docs/styleguide", "destination": "/guide/styleguide"},
|
||||
|
||||
// news is now blog
|
||||
{"type": 301, "source": "/news*", "destination": "https://blog.angular.io/"},
|
||||
|
||||
// cookbook guides were moved (and sometime renamed or removed)
|
||||
{"type": 301, "source": "/docs/*/latest/cookbook", "destination": "/docs"},
|
||||
{"type": 301, "source": "/docs/*/latest/cookbook/", "destination": "/docs"},
|
||||
{"type": 301, "source": "/docs/*/latest/cookbook/index.html", "destination": "/docs"},
|
||||
{"type": 301, "source": "/**/cookbook/ts-to-js*", "destination": "https://github.com/angular/angular/blob/master/aio/content/guide/change-log.md#es6--described-in-typescript-to-javascript-2016-11-14"},
|
||||
{"type": 301, "source": "/docs/*/latest/cookbook/a1-a2-quick-reference.html", "destination": "/guide/ajs-quick-reference"},
|
||||
{"type": 301, "source": "/docs/*/latest/cookbook/component-communication.html", "destination": "/guide/component-interaction"},
|
||||
{"type": 301, "source": "/docs/*/latest/cookbook/dependency-injection.html", "destination": "/guide/dependency-injection-in-action"},
|
||||
{"type": 301, "source": "/docs/*/latest/cookbook/:cookbook.html", "destination": "/guide/:cookbook"},
|
||||
|
||||
// Forms related code was moved from the `common` to `forms` package (and NgFor was renamed to NgForOf)
|
||||
{"type": 301, "source": "/**/NgFor-*", "destination": "/api/common/NgForOf"},
|
||||
{"type": 301, "source": "/**/api/common/index/MaxLengthValidator-*", "destination": "/api/forms/MaxLengthValidator"},
|
||||
{"type": 301, "source": "/**/api/common/ControlGroup*", "destination": "/api/forms/FormGroup"},
|
||||
{"type": 301, "source": "/**/api/common/Control*", "destination": "/api/forms/FormControl"},
|
||||
{"type": 301, "source": "/**/api/common/SelectControlValueAccessor-*", "destination": "/api/forms/SelectControlValueAccessor"},
|
||||
{"type": 301, "source": "/**/api/common/NgModel", "destination": "/api/forms/NgModel"},
|
||||
|
||||
// Animations moves, renames and removals
|
||||
{"type": 301, "source": "/api/animate/:rest*", "destination": "/api/animations/:rest*"},
|
||||
// AnimationStateDeclarationMetadata was removed
|
||||
{"type": 301, "source": "/**/AnimationStateDeclarationMetadata*", "destination": "/api/animations"},
|
||||
// `AnimationDriver` was moved to the `animations/browser` package
|
||||
{"type": 301, "source": "/api/platform-browser/AnimationDriver", "destination": "/api/animations/browser/AnimationDriver"},
|
||||
|
||||
// The `testing` package was renamed to `core/testing`
|
||||
{"type": 301, "source": "/api/testing/:api-*", "destination": "/api/core/testing/:api"},
|
||||
|
||||
// CORE_DIRECTIVES & PLATFORM_PIPES were removed and are now in the CommonModule
|
||||
{"type": 301, "source": "/**/CORE_DIRECTIVES*", "destination": "/api/common/CommonModule"},
|
||||
{"type": 301, "source": "/**/PLATFORM_PIPES*", "destination": "/api/common/CommonModule"},
|
||||
|
||||
// DirectiveMetadata is now covered by the Directive decorator
|
||||
{"type": 301, "source": "/**/DirectiveMetadata-*", "destination": "/api/core/Directive"},
|
||||
|
||||
// OptionalMetadata is now covered by the Optional decorator
|
||||
{"type": 301, "source": "/**/OptionalMetadata-*", "destination": "/api/core/Optional"},
|
||||
|
||||
// HTTP_PROVIDERS was removed and is now provided in HttpModule
|
||||
{"type": 301, "source": "/**/HTTP_PROVIDERS*", "destination": "/api/http/HttpModule"},
|
||||
|
||||
// URLs that use the old scheme of adding the type to the end (e.g. `SomeClass-class`)
|
||||
{"type": 301, "source": "/api/:package/:api-*", "destination": "/api/:package/:api"},
|
||||
{"type": 301, "source": "/api/:package/testing/index/:api-*", "destination": "/api/:package/testing/:api"},
|
||||
{"type": 301, "source": "/api/:package/testing/:api-*", "destination": "/api/:package/testing/:api"},
|
||||
{"type": 301, "source": "/api/upgrade/:package/index/:api-*", "destination": "/api/upgrade/:package/:api"},
|
||||
{"type": 301, "source": "/api/upgrade/:package/:api-*", "destination": "/api/upgrade/:package/:api"},
|
||||
|
||||
// URLs that use the old scheme before we moved the docs to the angular/angular repo
|
||||
{"type": 301, "source": "/docs/*/latest", "destination": "/docs"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/", "destination": "/api"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/:package", "destination": "/api/:package"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/testing/:api-*", "destination": "/api/core/testing/:api"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/:package/:api-*", "destination": "/api/:package/:api"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/:package/index/:api-*", "destination": "/api/:package/:api"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/:package/testing", "destination": "/api/:package/testing"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/:package/testing/index/:api-*", "destination": "/api/:package/testing/:api"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/platform-browser/animations/index/:api-*", "destination": "/api/platform-browser/animations/:api"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/upgrade/:package/:api-*", "destination": "/api/upgrade/:package/:api"},
|
||||
{"type": 301, "source": "/docs/*/latest/api/upgrade/:package/index/:api-*", "destination": "/api/upgrade/:package/:api"},
|
||||
{"type": 301, "source": "/docs/*/latest/glossary", "destination": "/guide/glossary"},
|
||||
{"type": 301, "source": "/docs/*/latest/guide/", "destination": "/docs"},
|
||||
{"type": 301, "source": "/docs/*/latest/guide/lifecycle-hooks", "destination": "/guide/lifecycle-hooks"},
|
||||
{"type": 301, "source": "/docs/*/latest/:rest*", "destination": "/:rest*"},
|
||||
{"type": 301, "source": "/docs/latest/:rest*", "destination": "/:rest*"},
|
||||
{"type": 301, "source": "/docs/styleguide*", "destination": "/guide/styleguide"},
|
||||
{"type": 301, "source": "/guide/metadata", "destination": "/guide/aot-compiler"},
|
||||
{"type": 301, "source": "/guide/ngmodule", "destination": "/guide/ngmodules"},
|
||||
{"type": 301, "source": "/guide/learning-angular*", "destination": "/guide/quickstart"},
|
||||
{"type": 301, "source": "/testing", "destination": "/guide/testing"},
|
||||
{"type": 301, "source": "/testing/**", "destination": "/guide/testing"}
|
||||
{"type": 301, "source": "/guide/service-worker-configref", "destination": "/guide/service-worker-config"}
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
|
@ -19,7 +19,7 @@
|
||||
"routing": {
|
||||
"index": "/index.html",
|
||||
"routes": {
|
||||
"^(?!/styleguide|/docs/.|(?:/guide/(?:cli-quickstart|metadata|ngmodule|service-worker-(?:getstart|comm|configref)|learning-angular)|/news)(?:\\.html|/)?$|/testing|/api/(?:.+/[^/]+-|platform-browser/AnimationDriver|testing|api/|(?:common/(?:NgModel|Control|MaxLengthValidator))|(?:[^/]+/)?(?:NgFor(?:$|-)|AnimationStateDeclarationMetadata|CORE_DIRECTIVES|PLATFORM_PIPES|DirectiveMetadata|HTTP_PROVIDERS))|.*/stackblitz(?:\\.html)?$|.*\\.[^\/.]+$)": {
|
||||
"^(?!/docs/.|(?:/guide/(?:cli-quickstart|metadata|ngmodule|service-worker-(?:getstart|comm|configref)|learning-angular)|/news/?)$|/testing|/api/(?:common/NgModel|platform-browser/AnimationDriver|testing|api)).*/(?!e?stackblitz|(?:NgFor|MaxLengthValidator)-|Control(?:Group)?|AnimationStateDeclarationMetadata|CORE_DIRECTIVES|PLATFORM_PIPES|DirectiveMetadata|HTTP_PROVIDERS)[^/.]*$": {
|
||||
"match": "regex"
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
"build": "yarn ~~build",
|
||||
"prebuild-local": "yarn setup-local",
|
||||
"build-local": "yarn ~~build",
|
||||
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
|
||||
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint",
|
||||
"test": "yarn check-env && ng test",
|
||||
"pree2e": "yarn check-env && yarn ~~update-webdriver",
|
||||
"e2e": "ng e2e --no-webdriver-update",
|
||||
@ -44,10 +44,7 @@
|
||||
"docs-watch": "node tools/transforms/authors-package/watchr.js",
|
||||
"docs-lint": "eslint --ignore-path=\"tools/transforms/.eslintignore\" tools/transforms",
|
||||
"docs-test": "node tools/transforms/test.js",
|
||||
"deployment-config-test": "jasmine-ts tests/deployment/**/*.spec.ts",
|
||||
"firebase-utils-test": "jasmine-ts tools/firebase-test-utils/*.spec.ts",
|
||||
"tools-lint": "tslint -c \"tools/tslint.json\" \"tools/firebase-test-utils/**/*.ts\"",
|
||||
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js && yarn firebase-utils-test",
|
||||
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js",
|
||||
"preserve-and-sync": "yarn docs",
|
||||
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch --watch-only\" \"yarn start\"",
|
||||
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
|
||||
@ -101,13 +98,12 @@
|
||||
"archiver": "^1.3.0",
|
||||
"canonical-path": "^0.0.2",
|
||||
"chalk": "^2.1.0",
|
||||
"cjson": "^0.5.0",
|
||||
"codelyzer": "~2.0.0",
|
||||
"concurrently": "^3.4.0",
|
||||
"cross-spawn": "^5.1.0",
|
||||
"css-selector-parser": "^1.3.0",
|
||||
"dgeni": "^0.4.7",
|
||||
"dgeni-packages": "0.24.1",
|
||||
"dgeni-packages": "^0.24.0",
|
||||
"entities": "^1.1.1",
|
||||
"eslint": "^3.19.0",
|
||||
"eslint-plugin-jasmine": "^2.2.0",
|
||||
@ -122,7 +118,6 @@
|
||||
"image-size": "^0.5.1",
|
||||
"jasmine-core": "^2.8.0",
|
||||
"jasmine-spec-reporter": "^4.1.0",
|
||||
"jasmine-ts": "^0.2.1",
|
||||
"jsdom": "^9.12.0",
|
||||
"karma": "^1.7.0",
|
||||
"karma-chrome-launcher": "^2.1.1",
|
||||
@ -152,7 +147,6 @@
|
||||
"unist-util-visit-parents": "^1.1.1",
|
||||
"vrsource-tslint-rules": "^4.0.1",
|
||||
"watchr": "^3.0.1",
|
||||
"xregexp": "^4.0.0",
|
||||
"yargs": "^7.0.2"
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./*.e2e-spec.ts'
|
||||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
@ -26,7 +26,7 @@ exports.config = {
|
||||
},
|
||||
beforeLaunch: function() {
|
||||
require('ts-node').register({
|
||||
project: 'tests/e2e/tsconfig.e2e.json'
|
||||
project: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
},
|
||||
onPrepare() {
|
@ -4,7 +4,7 @@
|
||||
<mat-progress-bar mode="indeterminate" color="warn"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<mat-toolbar color="primary" class="app-toolbar no-print" [class.transitioning]="isTransitioning">
|
||||
<mat-toolbar color="primary" class="app-toolbar" [class.transitioning]="isTransitioning">
|
||||
<mat-toolbar-row class="notification-container">
|
||||
<aio-notification
|
||||
icon="insert_comment"
|
||||
@ -18,7 +18,7 @@
|
||||
</aio-notification>
|
||||
</mat-toolbar-row>
|
||||
<mat-toolbar-row>
|
||||
<button mat-button class="hamburger" [class.starting]="isStarting" (click)="sidenav.toggle()" title="Docs menu">
|
||||
<button mat-button class="hamburger" (click)="sidenav.toggle()" title="Docs menu">
|
||||
<mat-icon svgIcon="menu"></mat-icon>
|
||||
</button>
|
||||
<a class="nav-link home" href="/" [ngSwitch]="isSideBySide">
|
||||
@ -29,7 +29,6 @@
|
||||
<aio-search-box class="search-container" #searchBox (onSearch)="doSearch($event)" (onFocus)="doSearch($event)"></aio-search-box>
|
||||
</mat-toolbar-row>
|
||||
</mat-toolbar>
|
||||
|
||||
<aio-search-results #searchResultsView *ngIf="showSearchResults" [searchResults]="searchResults | async" (resultSelected)="hideSearchResults()"></aio-search-results>
|
||||
|
||||
<mat-sidenav-container class="sidenav-container" [class.starting]="isStarting" [class.has-floating-toc]="hasFloatingToc" role="main">
|
||||
@ -57,11 +56,11 @@
|
||||
|
||||
</mat-sidenav-container>
|
||||
|
||||
<div *ngIf="hasFloatingToc" class="toc-container no-print" [style.max-height.px]="tocMaxHeight" (mousewheel)="restrainScrolling($event)">
|
||||
<div *ngIf="hasFloatingToc" class="toc-container" [style.max-height.px]="tocMaxHeight" (mousewheel)="restrainScrolling($event)">
|
||||
<aio-toc></aio-toc>
|
||||
</div>
|
||||
|
||||
<footer class="no-print">
|
||||
<footer>
|
||||
<aio-footer [nodes]="footerNodes" [versionInfo]="versionInfo" ></aio-footer>
|
||||
</footer>
|
||||
|
||||
|
@ -8,12 +8,9 @@ import { By } from '@angular/platform-browser';
|
||||
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { of } from 'rxjs/observable/of';
|
||||
import { timer } from 'rxjs/observable/timer';
|
||||
import 'rxjs/add/operator/mapTo';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppModule } from './app.module';
|
||||
import { DocumentService } from 'app/documents/document.service';
|
||||
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
|
||||
import { Deployment } from 'app/shared/deployment.service';
|
||||
import { EmbedComponentsService } from 'app/embed-components/embed-components.service';
|
||||
@ -34,30 +31,18 @@ import { TocItem, TocService } from 'app/shared/toc.service';
|
||||
|
||||
const sideBySideBreakPoint = 992;
|
||||
const hideToCBreakPoint = 800;
|
||||
const startedDelay = 100;
|
||||
|
||||
describe('AppComponent', () => {
|
||||
let component: AppComponent;
|
||||
let fixture: ComponentFixture<AppComponent>;
|
||||
|
||||
let documentService: DocumentService;
|
||||
let docViewer: HTMLElement;
|
||||
let docViewerComponent: DocViewerComponent;
|
||||
let hamburger: HTMLButtonElement;
|
||||
let locationService: MockLocationService;
|
||||
let sidenav: MatSidenav;
|
||||
let tocService: TocService;
|
||||
|
||||
async function awaitDocRendered() {
|
||||
const newDocPromise = new Promise(resolve => documentService.currentDocument.subscribe(resolve));
|
||||
const docRenderedPromise = new Promise(resolve => docViewerComponent.docRendered.subscribe(resolve));
|
||||
|
||||
await newDocPromise; // Wait for the new document to be fetched.
|
||||
fixture.detectChanges(); // Propagate document change to the view (i.e to `DocViewer`).
|
||||
await docRenderedPromise; // Wait for the `docRendered` event.
|
||||
};
|
||||
|
||||
function initializeTest(waitForDoc = true) {
|
||||
const initializeTest = () => {
|
||||
fixture = TestBed.createComponent(AppComponent);
|
||||
component = fixture.componentInstance;
|
||||
|
||||
@ -65,27 +50,21 @@ describe('AppComponent', () => {
|
||||
component.onResize(sideBySideBreakPoint + 1); // wide by default
|
||||
|
||||
const de = fixture.debugElement;
|
||||
const docViewerDe = de.query(By.css('aio-doc-viewer'));
|
||||
|
||||
documentService = de.injector.get(DocumentService) as DocumentService;
|
||||
docViewer = docViewerDe.nativeElement;
|
||||
docViewerComponent = docViewerDe.componentInstance;
|
||||
docViewer = de.query(By.css('aio-doc-viewer')).nativeElement;
|
||||
hamburger = de.query(By.css('.hamburger')).nativeElement;
|
||||
locationService = de.injector.get(LocationService) as any;
|
||||
locationService = de.injector.get(LocationService) as any as MockLocationService;
|
||||
sidenav = de.query(By.directive(MatSidenav)).componentInstance;
|
||||
tocService = de.injector.get(TocService);
|
||||
|
||||
return waitForDoc && awaitDocRendered();
|
||||
};
|
||||
|
||||
|
||||
describe('with proper DocViewer', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
DocViewerComponent.animationsEnabled = false;
|
||||
|
||||
createTestingModule('a/b');
|
||||
await initializeTest();
|
||||
initializeTest();
|
||||
});
|
||||
|
||||
afterEach(() => DocViewerComponent.animationsEnabled = true);
|
||||
@ -377,43 +356,43 @@ describe('AppComponent', () => {
|
||||
let selectElement: DebugElement;
|
||||
let selectComponent: SelectComponent;
|
||||
|
||||
async function setupSelectorForTesting(mode?: string) {
|
||||
function setupSelectorForTesting(mode?: string) {
|
||||
createTestingModule('a/b', mode);
|
||||
await initializeTest();
|
||||
initializeTest();
|
||||
component.onResize(sideBySideBreakPoint + 1); // side-by-side
|
||||
selectElement = fixture.debugElement.query(By.directive(SelectComponent));
|
||||
selectComponent = selectElement.componentInstance;
|
||||
}
|
||||
|
||||
it('should select the version that matches the deploy mode', async () => {
|
||||
await setupSelectorForTesting();
|
||||
it('should select the version that matches the deploy mode', () => {
|
||||
setupSelectorForTesting();
|
||||
expect(selectComponent.selected.title).toContain('stable');
|
||||
await setupSelectorForTesting('next');
|
||||
setupSelectorForTesting('next');
|
||||
expect(selectComponent.selected.title).toContain('next');
|
||||
await setupSelectorForTesting('archive');
|
||||
setupSelectorForTesting('archive');
|
||||
expect(selectComponent.selected.title).toContain('v4');
|
||||
});
|
||||
|
||||
it('should add the current raw version string to the selected version', async () => {
|
||||
await setupSelectorForTesting();
|
||||
it('should add the current raw version string to the selected version', () => {
|
||||
setupSelectorForTesting();
|
||||
expect(selectComponent.selected.title).toContain(`(v${component.versionInfo.raw})`);
|
||||
await setupSelectorForTesting('next');
|
||||
setupSelectorForTesting('next');
|
||||
expect(selectComponent.selected.title).toContain(`(v${component.versionInfo.raw})`);
|
||||
await setupSelectorForTesting('archive');
|
||||
setupSelectorForTesting('archive');
|
||||
expect(selectComponent.selected.title).toContain(`(v${component.versionInfo.raw})`);
|
||||
});
|
||||
|
||||
// Older docs versions have an href
|
||||
it('should navigate when change to a version with a url', async () => {
|
||||
await setupSelectorForTesting();
|
||||
it('should navigate when change to a version with a url', () => {
|
||||
setupSelectorForTesting();
|
||||
const versionWithUrlIndex = component.docVersions.findIndex(v => !!v.url);
|
||||
const versionWithUrl = component.docVersions[versionWithUrlIndex];
|
||||
selectElement.triggerEventHandler('change', { option: versionWithUrl, index: versionWithUrlIndex});
|
||||
expect(locationService.go).toHaveBeenCalledWith(versionWithUrl.url);
|
||||
});
|
||||
|
||||
it('should not navigate when change to a version without a url', async () => {
|
||||
await setupSelectorForTesting();
|
||||
it('should not navigate when change to a version without a url', () => {
|
||||
setupSelectorForTesting();
|
||||
const versionWithoutUrlIndex = component.docVersions.length;
|
||||
const versionWithoutUrl = component.docVersions[versionWithoutUrlIndex] = { title: 'foo' };
|
||||
selectElement.triggerEventHandler('change', { option: versionWithoutUrl, index: versionWithoutUrlIndex });
|
||||
@ -422,39 +401,37 @@ describe('AppComponent', () => {
|
||||
});
|
||||
|
||||
describe('currentDocument', () => {
|
||||
const navigateTo = async (path: string) => {
|
||||
locationService.go(path);
|
||||
await awaitDocRendered();
|
||||
};
|
||||
|
||||
it('should display a guide page (guide/pipes)', async () => {
|
||||
await navigateTo('guide/pipes');
|
||||
it('should display a guide page (guide/pipes)', () => {
|
||||
locationService.go('guide/pipes');
|
||||
fixture.detectChanges();
|
||||
expect(docViewer.textContent).toMatch(/Pipes/i);
|
||||
});
|
||||
|
||||
it('should display the api page', async () => {
|
||||
await navigateTo('api');
|
||||
it('should display the api page', () => {
|
||||
locationService.go('api');
|
||||
fixture.detectChanges();
|
||||
expect(docViewer.textContent).toMatch(/API/i);
|
||||
});
|
||||
|
||||
it('should display a marketing page', async () => {
|
||||
await navigateTo('features');
|
||||
it('should display a marketing page', () => {
|
||||
locationService.go('features');
|
||||
fixture.detectChanges();
|
||||
expect(docViewer.textContent).toMatch(/Features/i);
|
||||
});
|
||||
|
||||
it('should update the document title', async () => {
|
||||
it('should update the document title', () => {
|
||||
const titleService = TestBed.get(Title);
|
||||
spyOn(titleService, 'setTitle');
|
||||
|
||||
await navigateTo('guide/pipes');
|
||||
locationService.go('guide/pipes');
|
||||
fixture.detectChanges();
|
||||
expect(titleService.setTitle).toHaveBeenCalledWith('Angular - Pipes');
|
||||
});
|
||||
|
||||
it('should update the document title, with a default value if the document has no title', async () => {
|
||||
it('should update the document title, with a default value if the document has no title', () => {
|
||||
const titleService = TestBed.get(Title);
|
||||
spyOn(titleService, 'setTitle');
|
||||
|
||||
await navigateTo('no-title');
|
||||
locationService.go('no-title');
|
||||
fixture.detectChanges();
|
||||
expect(titleService.setTitle).toHaveBeenCalledWith('Angular');
|
||||
});
|
||||
});
|
||||
@ -532,9 +509,7 @@ describe('AppComponent', () => {
|
||||
expect(scrollToTopSpy).not.toHaveBeenCalled();
|
||||
|
||||
locationService.go('guide/pipes');
|
||||
tick(1); // triggers the HTTP response for the document
|
||||
fixture.detectChanges(); // triggers the event that calls `onDocInserted`
|
||||
|
||||
expect(scrollToTopSpy).toHaveBeenCalled();
|
||||
expect(scrollSpy).not.toHaveBeenCalled();
|
||||
|
||||
@ -683,16 +658,18 @@ describe('AppComponent', () => {
|
||||
});
|
||||
|
||||
describe('deployment banner', () => {
|
||||
it('should show a message if the deployment mode is "archive"', async () => {
|
||||
it('should show a message if the deployment mode is "archive"', () => {
|
||||
createTestingModule('a/b', 'archive');
|
||||
await initializeTest();
|
||||
initializeTest();
|
||||
fixture.detectChanges();
|
||||
const banner: HTMLElement = fixture.debugElement.query(By.css('aio-mode-banner')).nativeElement;
|
||||
expect(banner.textContent).toContain('archived documentation for Angular v4');
|
||||
});
|
||||
|
||||
it('should show no message if the deployment mode is not "archive"', async () => {
|
||||
it('should show no message if the deployment mode is not "archive"', () => {
|
||||
createTestingModule('a/b', 'stable');
|
||||
await initializeTest();
|
||||
initializeTest();
|
||||
fixture.detectChanges();
|
||||
const banner: HTMLElement = fixture.debugElement.query(By.css('aio-mode-banner')).nativeElement;
|
||||
expect(banner.textContent!.trim()).toEqual('');
|
||||
});
|
||||
@ -701,6 +678,7 @@ describe('AppComponent', () => {
|
||||
describe('search', () => {
|
||||
describe('initialization', () => {
|
||||
it('should initialize the search worker', inject([SearchService], (searchService: SearchService) => {
|
||||
fixture.detectChanges(); // triggers ngOnInit
|
||||
expect(searchService.initWorker).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
@ -793,103 +771,103 @@ describe('AppComponent', () => {
|
||||
describe('archive redirection', () => {
|
||||
it('should redirect to `docs` if deployment mode is `archive` and not at a docs page', () => {
|
||||
createTestingModule('', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
||||
|
||||
createTestingModule('resources', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).toHaveBeenCalledWith('docs');
|
||||
|
||||
createTestingModule('guide/aot-compiler', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('tutorial', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('tutorial/toh-pt1', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('docs', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('api', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('api/core/getPlatform', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not redirect if deployment mode is `next`', () => {
|
||||
createTestingModule('', 'next');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('resources', 'next');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('guide/aot-compiler', 'next');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('tutorial', 'next');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('tutorial/toh-pt1', 'next');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('docs', 'next');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('api', 'next');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('api/core/getPlatform', 'next');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not redirect to `docs` if deployment mode is `stable`', () => {
|
||||
createTestingModule('', 'stable');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('resources', 'stable');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('guide/aot-compiler', 'stable');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('tutorial', 'stable');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('tutorial/toh-pt1', 'stable');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('docs', 'stable');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('api', 'stable');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
|
||||
createTestingModule('api/core/getPlatform', 'stable');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@ -911,68 +889,27 @@ describe('AppComponent', () => {
|
||||
});
|
||||
|
||||
describe('initial rendering', () => {
|
||||
beforeEach(jasmine.clock().install);
|
||||
afterEach(jasmine.clock().uninstall);
|
||||
|
||||
it('should initially disable Angular animations until a document is rendered', () => {
|
||||
initializeTest(false);
|
||||
jasmine.clock().tick(1); // triggers the HTTP response for the document
|
||||
|
||||
expect(component.isStarting).toBe(true);
|
||||
expect(fixture.debugElement.properties['@.disabled']).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docInserted');
|
||||
jasmine.clock().tick(startedDelay);
|
||||
fixture.detectChanges();
|
||||
expect(component.isStarting).toBe(true);
|
||||
expect(fixture.debugElement.properties['@.disabled']).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docRendered');
|
||||
jasmine.clock().tick(startedDelay);
|
||||
fixture.detectChanges();
|
||||
expect(component.isStarting).toBe(false);
|
||||
expect(fixture.debugElement.properties['@.disabled']).toBe(false);
|
||||
});
|
||||
|
||||
it('should initially add the starting class until a document is rendered', () => {
|
||||
initializeTest(false);
|
||||
jasmine.clock().tick(1); // triggers the HTTP response for the document
|
||||
const sidenavContainer = fixture.debugElement.query(By.css('mat-sidenav-container')).nativeElement;
|
||||
const getSidenavContainer = () => fixture.debugElement.query(By.css('mat-sidenav-container'));
|
||||
|
||||
initializeTest();
|
||||
|
||||
expect(component.isStarting).toBe(true);
|
||||
expect(hamburger.classList.contains('starting')).toBe(true);
|
||||
expect(sidenavContainer.classList.contains('starting')).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docInserted');
|
||||
jasmine.clock().tick(startedDelay);
|
||||
fixture.detectChanges();
|
||||
expect(component.isStarting).toBe(true);
|
||||
expect(hamburger.classList.contains('starting')).toBe(true);
|
||||
expect(sidenavContainer.classList.contains('starting')).toBe(true);
|
||||
expect(getSidenavContainer().classes['starting']).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docRendered');
|
||||
jasmine.clock().tick(startedDelay);
|
||||
fixture.detectChanges();
|
||||
expect(component.isStarting).toBe(false);
|
||||
expect(hamburger.classList.contains('starting')).toBe(false);
|
||||
expect(sidenavContainer.classList.contains('starting')).toBe(false);
|
||||
expect(getSidenavContainer().classes['starting']).toBe(false);
|
||||
});
|
||||
|
||||
it('should initially disable animations on the DocViewer for the first rendering', () => {
|
||||
initializeTest(false);
|
||||
jasmine.clock().tick(1); // triggers the HTTP response for the document
|
||||
initializeTest();
|
||||
|
||||
expect(component.isStarting).toBe(true);
|
||||
expect(docViewer.classList.contains('no-animations')).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docInserted');
|
||||
jasmine.clock().tick(startedDelay);
|
||||
fixture.detectChanges();
|
||||
expect(component.isStarting).toBe(true);
|
||||
expect(docViewer.classList.contains('no-animations')).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docRendered');
|
||||
jasmine.clock().tick(startedDelay);
|
||||
fixture.detectChanges();
|
||||
expect(component.isStarting).toBe(false);
|
||||
expect(docViewer.classList.contains('no-animations')).toBe(false);
|
||||
@ -984,63 +921,50 @@ describe('AppComponent', () => {
|
||||
afterEach(jasmine.clock().uninstall);
|
||||
|
||||
it('should set the transitioning class on `.app-toolbar` while a document is being rendered', () => {
|
||||
initializeTest(false);
|
||||
jasmine.clock().tick(1); // triggers the HTTP response for the document
|
||||
const toolbar = fixture.debugElement.query(By.css('.app-toolbar'));
|
||||
const getToolbar = () => fixture.debugElement.query(By.css('.app-toolbar'));
|
||||
|
||||
initializeTest();
|
||||
|
||||
// Initially, `isTransitoning` is true.
|
||||
expect(component.isTransitioning).toBe(true);
|
||||
expect(toolbar.classes['transitioning']).toBe(true);
|
||||
expect(getToolbar().classes['transitioning']).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docRendered');
|
||||
fixture.detectChanges();
|
||||
expect(component.isTransitioning).toBe(false);
|
||||
expect(toolbar.classes['transitioning']).toBe(false);
|
||||
expect(getToolbar().classes['transitioning']).toBe(false);
|
||||
|
||||
// While a document is being rendered, `isTransitoning` is set to true.
|
||||
triggerDocViewerEvent('docReady');
|
||||
fixture.detectChanges();
|
||||
expect(component.isTransitioning).toBe(true);
|
||||
expect(toolbar.classes['transitioning']).toBe(true);
|
||||
expect(getToolbar().classes['transitioning']).toBe(true);
|
||||
|
||||
triggerDocViewerEvent('docRendered');
|
||||
fixture.detectChanges();
|
||||
expect(component.isTransitioning).toBe(false);
|
||||
expect(toolbar.classes['transitioning']).toBe(false);
|
||||
expect(getToolbar().classes['transitioning']).toBe(false);
|
||||
});
|
||||
|
||||
it('should update the sidenav state as soon as a new document is inserted (but not before)', () => {
|
||||
initializeTest(false);
|
||||
jasmine.clock().tick(1); // triggers the HTTP response for the document
|
||||
jasmine.clock().tick(0); // calls `updateSideNav()` for initial rendering
|
||||
it('should update the sidenav state as soon as a new document is inserted', () => {
|
||||
initializeTest();
|
||||
const updateSideNavSpy = spyOn(component, 'updateSideNav');
|
||||
|
||||
triggerDocViewerEvent('docReady');
|
||||
jasmine.clock().tick(0);
|
||||
expect(updateSideNavSpy).not.toHaveBeenCalled();
|
||||
|
||||
triggerDocViewerEvent('docInserted');
|
||||
jasmine.clock().tick(0);
|
||||
expect(updateSideNavSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
updateSideNavSpy.calls.reset();
|
||||
|
||||
triggerDocViewerEvent('docReady');
|
||||
jasmine.clock().tick(0);
|
||||
expect(updateSideNavSpy).not.toHaveBeenCalled();
|
||||
|
||||
triggerDocViewerEvent('docInserted');
|
||||
jasmine.clock().tick(0);
|
||||
expect(updateSideNavSpy).toHaveBeenCalledTimes(1);
|
||||
expect(updateSideNavSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('pageId', () => {
|
||||
const navigateTo = (path: string) => {
|
||||
locationService.go(path);
|
||||
jasmine.clock().tick(1); // triggers the HTTP response for the document
|
||||
triggerDocViewerEvent('docInserted');
|
||||
jasmine.clock().tick(0); // triggers `updateHostClasses()`
|
||||
jasmine.clock().tick(0);
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
@ -1048,7 +972,7 @@ describe('AppComponent', () => {
|
||||
afterEach(jasmine.clock().uninstall);
|
||||
|
||||
it('should set the id of the doc viewer container based on the current doc', () => {
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
const container = fixture.debugElement.query(By.css('section.sidenav-content'));
|
||||
|
||||
navigateTo('guide/pipes');
|
||||
@ -1065,7 +989,7 @@ describe('AppComponent', () => {
|
||||
});
|
||||
|
||||
it('should not be affected by changes to the query', () => {
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
const container = fixture.debugElement.query(By.css('section.sidenav-content'));
|
||||
|
||||
navigateTo('guide/pipes');
|
||||
@ -1078,9 +1002,8 @@ describe('AppComponent', () => {
|
||||
|
||||
describe('hostClasses', () => {
|
||||
const triggerUpdateHostClasses = () => {
|
||||
jasmine.clock().tick(1); // triggers the HTTP response for document
|
||||
triggerDocViewerEvent('docInserted');
|
||||
jasmine.clock().tick(0); // triggers `updateHostClasses()`
|
||||
jasmine.clock().tick(0);
|
||||
fixture.detectChanges();
|
||||
};
|
||||
const navigateTo = (path: string) => {
|
||||
@ -1092,7 +1015,7 @@ describe('AppComponent', () => {
|
||||
afterEach(jasmine.clock().uninstall);
|
||||
|
||||
it('should set the css classes of the host container based on the current doc and navigation view', () => {
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
|
||||
navigateTo('guide/pipes');
|
||||
checkHostClass('page', 'guide-pipes');
|
||||
@ -1111,7 +1034,7 @@ describe('AppComponent', () => {
|
||||
});
|
||||
|
||||
it('should set the css class of the host container based on the open/closed state of the side nav', async () => {
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
|
||||
navigateTo('guide/pipes');
|
||||
checkHostClass('sidenav', 'open');
|
||||
@ -1136,7 +1059,7 @@ describe('AppComponent', () => {
|
||||
|
||||
it('should set the css class of the host container based on the initial deployment mode', () => {
|
||||
createTestingModule('a/b', 'archive');
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
|
||||
triggerUpdateHostClasses();
|
||||
checkHostClass('mode', 'archive');
|
||||
@ -1156,13 +1079,13 @@ describe('AppComponent', () => {
|
||||
const HIDE_DELAY = 500;
|
||||
const getProgressBar = () => fixture.debugElement.query(By.directive(MatProgressBar));
|
||||
const initializeAndCompleteNavigation = () => {
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
triggerDocViewerEvent('docReady');
|
||||
tick(HIDE_DELAY);
|
||||
};
|
||||
|
||||
it('should initially be hidden', () => {
|
||||
initializeTest(false);
|
||||
initializeTest();
|
||||
expect(getProgressBar()).toBeFalsy();
|
||||
});
|
||||
|
||||
@ -1377,8 +1300,6 @@ class TestHttpClient {
|
||||
const contents = `${h1}<h2 id="#somewhere">Some heading</h2>`;
|
||||
data = { id, contents };
|
||||
}
|
||||
|
||||
// Preserve async nature of `HttpClient`.
|
||||
return timer(1).mapTo(data);
|
||||
return of(data);
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export class AppComponent implements OnInit {
|
||||
|
||||
currentDocument: DocumentContents;
|
||||
currentDocVersion: NavigationNode;
|
||||
currentNodes: CurrentNodes = {};
|
||||
currentNodes: CurrentNodes;
|
||||
currentPath: string;
|
||||
docVersions: NavigationNode[];
|
||||
dtOn = false;
|
||||
@ -57,11 +57,9 @@ export class AppComponent implements OnInit {
|
||||
@HostBinding('class')
|
||||
hostClasses = '';
|
||||
|
||||
// Disable all Angular animations for the initial render.
|
||||
@HostBinding('@.disabled')
|
||||
isFetching = false;
|
||||
isStarting = true;
|
||||
isTransitioning = true;
|
||||
isFetching = false;
|
||||
isSideBySide = false;
|
||||
private isFetchingTimeout: any;
|
||||
private isSideNavDoc = false;
|
||||
@ -120,6 +118,12 @@ export class AppComponent implements OnInit {
|
||||
/* No need to unsubscribe because this root component never dies */
|
||||
|
||||
this.documentService.currentDocument.subscribe(doc => this.currentDocument = doc);
|
||||
// Generally, we want to delay updating the host classes for the new document, until after the
|
||||
// leaving document has been removed (to avoid having the styles for the new document applied
|
||||
// prematurely).
|
||||
// On the first document, though, (when we know there is no previous document), we want to
|
||||
// ensure the styles are applied as soon as possible to avoid flicker.
|
||||
this.documentService.currentDocument.first().subscribe(doc => this.updateHostClassesForDoc(doc));
|
||||
|
||||
this.locationService.currentPath.subscribe(path => {
|
||||
// Redirect to docs if we are in archive mode and are not hitting a docs page
|
||||
@ -171,22 +175,11 @@ export class AppComponent implements OnInit {
|
||||
this.topMenuNarrowNodes = views['TopBarNarrow'] || this.topMenuNodes;
|
||||
});
|
||||
|
||||
this.navigationService.versionInfo.subscribe(vi => this.versionInfo = vi);
|
||||
this.navigationService.versionInfo.subscribe( vi => this.versionInfo = vi );
|
||||
|
||||
const hasNonEmptyToc = this.tocService.tocList.map(tocList => tocList.length > 0);
|
||||
combineLatest(hasNonEmptyToc, this.showFloatingToc)
|
||||
.subscribe(([hasToc, showFloatingToc]) => this.hasFloatingToc = hasToc && showFloatingToc);
|
||||
|
||||
// Generally, we want to delay updating the shell (e.g. host classes, sidenav state) for the new
|
||||
// document, until after the leaving document has been removed (to avoid having the styles for
|
||||
// the new document applied prematurely).
|
||||
// For the first document, though, (when we know there is no previous document), we want to
|
||||
// ensure the styles are applied as soon as possible to avoid flicker.
|
||||
combineLatest(
|
||||
this.documentService.currentDocument, // ...needed to determine host classes
|
||||
this.navigationService.currentNodes) // ...needed to determine `sidenav` state
|
||||
.first()
|
||||
.subscribe(() => this.updateShell());
|
||||
}
|
||||
|
||||
// Scroll to the anchor in the hash fragment or top of doc.
|
||||
@ -212,11 +205,14 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
onDocInserted() {
|
||||
// Update the shell (host classes, sidenav state) to match the new document.
|
||||
// This may be called as a result of actions initiated by view updates.
|
||||
// In order to avoid errors (e.g. `ExpressionChangedAfterItHasBeenChecked`), updating the view
|
||||
// (e.g. sidenav, host classes) needs to happen asynchronously.
|
||||
setTimeout(() => this.updateShell());
|
||||
// TODO: Find a better way to avoid `ExpressionChangedAfterItHasBeenChecked` error.
|
||||
setTimeout(() => {
|
||||
// Update the SideNav state (if necessary).
|
||||
this.updateSideNav();
|
||||
|
||||
// Update the host classes to match the new document.
|
||||
this.updateHostClassesForDoc(this.currentDocument);
|
||||
});
|
||||
|
||||
// Scroll 500ms after the new document has been inserted into the doc-viewer.
|
||||
// The delay is to allow time for async layout to complete.
|
||||
@ -224,14 +220,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
onDocRendered() {
|
||||
if (this.isStarting) {
|
||||
// In order to ensure that the initial sidenav-content left margin
|
||||
// adjustment happens without animation, we need to ensure that
|
||||
// `isStarting` remains `true` until the margin change is triggered.
|
||||
// (Apparently, this happens with a slight delay.)
|
||||
setTimeout(() => this.isStarting = false, 100);
|
||||
}
|
||||
|
||||
this.isStarting = false;
|
||||
this.isTransitioning = false;
|
||||
}
|
||||
|
||||
@ -252,7 +241,7 @@ export class AppComponent implements OnInit {
|
||||
// items in the top-bar, ensure the sidenav is closed.
|
||||
// (This condition can only be met when the resize event changes the value of `isSideBySide`
|
||||
// from `false` to `true` while on a non-sidenav doc.)
|
||||
this.sidenav.toggle(false);
|
||||
this.sideNavToggle(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,6 +272,10 @@ export class AppComponent implements OnInit {
|
||||
return true;
|
||||
}
|
||||
|
||||
sideNavToggle(value?: boolean) {
|
||||
this.sidenav.toggle(value);
|
||||
}
|
||||
|
||||
setPageId(id: string) {
|
||||
// Special case the home page
|
||||
this.pageId = (id === 'index') ? 'home' : id.replace('/', '-');
|
||||
@ -307,7 +300,7 @@ export class AppComponent implements OnInit {
|
||||
const sideNavOpen = `sidenav-${this.sidenav.opened ? 'open' : 'closed'}`;
|
||||
const pageClass = `page-${this.pageId}`;
|
||||
const folderClass = `folder-${this.folderId}`;
|
||||
const viewClasses = Object.keys(this.currentNodes).map(view => `view-${view}`).join(' ');
|
||||
const viewClasses = Object.keys(this.currentNodes || {}).map(view => `view-${view}`).join(' ');
|
||||
const notificationClass = `aio-notification-${this.notification.showNotification}`;
|
||||
const notificationAnimatingClass = this.notificationAnimating ? 'aio-notification-animating' : '';
|
||||
|
||||
@ -322,13 +315,9 @@ export class AppComponent implements OnInit {
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
updateShell() {
|
||||
// Update the SideNav state (if necessary).
|
||||
this.updateSideNav();
|
||||
|
||||
// Update the host classes.
|
||||
this.setPageId(this.currentDocument.id);
|
||||
this.setFolderId(this.currentDocument.id);
|
||||
updateHostClassesForDoc(doc: DocumentContents) {
|
||||
this.setPageId(doc.id);
|
||||
this.setFolderId(doc.id);
|
||||
this.updateHostClasses();
|
||||
}
|
||||
|
||||
@ -344,7 +333,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
// May be open or closed when wide; always closed when narrow.
|
||||
this.sidenav.toggle(this.isSideBySide && openSideNav);
|
||||
this.sideNavToggle(this.isSideBySide && openSideNav);
|
||||
}
|
||||
|
||||
// Dynamically change height of table of contents container
|
||||
|
@ -23,16 +23,14 @@ describe('AppModule', () => {
|
||||
});
|
||||
|
||||
it('should provide a list of eagerly-loaded embedded components', () => {
|
||||
const eagerSelector = Object.keys(componentsMap).find(selector => Array.isArray(componentsMap[selector]))!;
|
||||
const selectorCount = eagerSelector.split(',').length;
|
||||
|
||||
const eagerConfig = Object.keys(componentsMap).filter(selector => Array.isArray(componentsMap[selector]));
|
||||
expect(eagerConfig.length).toBeGreaterThan(0);
|
||||
|
||||
const eagerSelectors = eagerConfig.reduce<string[]>((selectors, config) => selectors.concat(config.split(',')), []);
|
||||
expect(eagerSelectors.length).toBeGreaterThan(0);
|
||||
expect(eagerSelector).not.toBeNull();
|
||||
expect(selectorCount).toBe(componentsMap[eagerSelector].length);
|
||||
|
||||
// For example...
|
||||
expect(eagerSelectors).toContain('aio-toc');
|
||||
expect(eagerSelectors).toContain('aio-announcement-bar');
|
||||
expect(eagerSelector).toContain('aio-toc');
|
||||
});
|
||||
|
||||
it('should provide a list of lazy-loaded embedded components', () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { ErrorHandler, NgModule } from '@angular/core';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
@ -14,7 +14,6 @@ import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { ROUTES } from '@angular/router';
|
||||
|
||||
|
||||
import { AnnouncementBarComponent } from 'app/embedded/announcement-bar/announcement-bar.component';
|
||||
import { AppComponent } from 'app/app.component';
|
||||
import { EMBEDDED_COMPONENTS, EmbeddedComponentsMap } from 'app/embed-components/embed-components.service';
|
||||
import { CustomIconRegistry, SVG_ICONS } from 'app/shared/custom-icon-registry';
|
||||
@ -32,7 +31,6 @@ import { TopMenuComponent } from 'app/layout/top-menu/top-menu.component';
|
||||
import { FooterComponent } from 'app/layout/footer/footer.component';
|
||||
import { NavMenuComponent } from 'app/layout/nav-menu/nav-menu.component';
|
||||
import { NavItemComponent } from 'app/layout/nav-item/nav-item.component';
|
||||
import { ReportingErrorHandler } from 'app/shared/reporting-error-handler';
|
||||
import { ScrollService } from 'app/shared/scroll.service';
|
||||
import { ScrollSpyService } from 'app/shared/scroll-spy.service';
|
||||
import { SearchBoxComponent } from 'app/search/search-box/search-box.component';
|
||||
@ -111,7 +109,6 @@ export const svgIconProviders = [
|
||||
SharedModule
|
||||
],
|
||||
declarations: [
|
||||
AnnouncementBarComponent,
|
||||
AppComponent,
|
||||
DocViewerComponent,
|
||||
DtComponent,
|
||||
@ -127,7 +124,6 @@ export const svgIconProviders = [
|
||||
providers: [
|
||||
Deployment,
|
||||
DocumentService,
|
||||
{ provide: ErrorHandler, useClass: ReportingErrorHandler },
|
||||
GaService,
|
||||
Logger,
|
||||
Location,
|
||||
@ -147,7 +143,6 @@ export const svgIconProviders = [
|
||||
provide: EMBEDDED_COMPONENTS,
|
||||
useValue: {
|
||||
/* tslint:disable: max-line-length */
|
||||
'aio-announcement-bar': [AnnouncementBarComponent],
|
||||
'aio-toc': [TocComponent],
|
||||
'aio-api-list, aio-contributor-list, aio-file-not-found-search, aio-resource-list, code-example, code-tabs, current-location, live-example': embeddedModulePath,
|
||||
/* tslint:enable: max-line-length */
|
||||
@ -161,7 +156,7 @@ export const svgIconProviders = [
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
entryComponents: [ AnnouncementBarComponent, TocComponent ],
|
||||
entryComponents: [ TocComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule {
|
||||
|
@ -1,109 +0,0 @@
|
||||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { Logger } from 'app/shared/logger.service';
|
||||
import { MockLogger } from 'testing/logger.service';
|
||||
import { AnnouncementBarComponent } from './announcement-bar.component';
|
||||
|
||||
const today = new Date();
|
||||
const lastWeek = changeDays(today, -7);
|
||||
const yesterday = changeDays(today, -1);
|
||||
const tomorrow = changeDays(today, 1);
|
||||
const nextWeek = changeDays(today, 7);
|
||||
|
||||
describe('AnnouncementBarComponent', () => {
|
||||
|
||||
let element: HTMLElement;
|
||||
let fixture: ComponentFixture<AnnouncementBarComponent>;
|
||||
let component: AnnouncementBarComponent;
|
||||
let httpMock: HttpTestingController;
|
||||
let mockLogger: MockLogger;
|
||||
|
||||
beforeEach(() => {
|
||||
const injector = TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule],
|
||||
declarations: [AnnouncementBarComponent],
|
||||
providers: [{ provide: Logger, useClass: MockLogger }]
|
||||
});
|
||||
|
||||
httpMock = injector.get(HttpTestingController);
|
||||
mockLogger = injector.get(Logger);
|
||||
fixture = TestBed.createComponent(AnnouncementBarComponent);
|
||||
component = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
});
|
||||
|
||||
it('should have no announcement when first created', () => {
|
||||
expect(component.announcement).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('ngOnInit', () => {
|
||||
it('should make a single request to the server', () => {
|
||||
component.ngOnInit();
|
||||
httpMock.expectOne('generated/announcements.json');
|
||||
});
|
||||
|
||||
it('should set the announcement to the first "live" one in the list loaded from `announcements.json`', () => {
|
||||
component.ngOnInit();
|
||||
const request = httpMock.expectOne('generated/announcements.json');
|
||||
request.flush([
|
||||
{ startDate: lastWeek, endDate: yesterday, message: 'Test Announcement 0' },
|
||||
{ startDate: tomorrow, endDate: nextWeek, message: 'Test Announcement 1' },
|
||||
{ startDate: yesterday, endDate: tomorrow, message: 'Test Announcement 2' },
|
||||
{ startDate: yesterday, endDate: tomorrow, message: 'Test Announcement 3' }
|
||||
]);
|
||||
expect(component.announcement.message).toEqual('Test Announcement 2');
|
||||
});
|
||||
|
||||
it('should set the announcement to `undefined` if there are no announcements in `announcements.json`', () => {
|
||||
component.ngOnInit();
|
||||
const request = httpMock.expectOne('generated/announcements.json');
|
||||
request.flush([]);
|
||||
expect(component.announcement).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle invalid data in `announcements.json`', () => {
|
||||
component.ngOnInit();
|
||||
const request = httpMock.expectOne('generated/announcements.json');
|
||||
request.flush('some random response');
|
||||
expect(component.announcement).toBeUndefined();
|
||||
expect(mockLogger.output.error[0][0]).toContain('generated/announcements.json contains invalid data:');
|
||||
});
|
||||
|
||||
it('should handle a failed request for `announcements.json`', () => {
|
||||
component.ngOnInit();
|
||||
const request = httpMock.expectOne('generated/announcements.json');
|
||||
request.error(new ErrorEvent('404'));
|
||||
expect(component.announcement).toBeUndefined();
|
||||
expect(mockLogger.output.error[0][0]).toContain('generated/announcements.json request failed:');
|
||||
});
|
||||
});
|
||||
|
||||
describe('rendering', () => {
|
||||
beforeEach(() => {
|
||||
component.announcement = {
|
||||
imageUrl: 'link/to/image',
|
||||
linkUrl: 'link/to/website',
|
||||
message: 'this is an <b>important</b> message',
|
||||
endDate: '2018-03-01',
|
||||
startDate: '2018-02-01'
|
||||
};
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display the message as HTML', () => {
|
||||
expect(element.innerHTML).toContain('this is an <b>important</b> message');
|
||||
});
|
||||
|
||||
it('should display an image', () => {
|
||||
expect(element.querySelector('img')!.src).toContain('link/to/image');
|
||||
});
|
||||
|
||||
it('should display a link', () => {
|
||||
expect(element.querySelector('a')!.href).toContain('link/to/website');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function changeDays(initial: Date, days: number) {
|
||||
return (new Date(initial.valueOf()).setDate(initial.getDate() + days));
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Logger } from 'app/shared/logger.service';
|
||||
import { CONTENT_URL_PREFIX } from 'app/documents/document.service';
|
||||
const announcementsPath = CONTENT_URL_PREFIX + 'announcements.json';
|
||||
|
||||
export interface Announcement {
|
||||
imageUrl: string;
|
||||
message: string;
|
||||
linkUrl: string;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the latest live announcement. This is used on the homepage.
|
||||
*
|
||||
* The data for the announcements is kept in `aio/content/marketing/announcements.json`.
|
||||
*
|
||||
* The format for that data file looks like:
|
||||
*
|
||||
* ```
|
||||
* [
|
||||
* {
|
||||
* "startDate": "2018-02-01",
|
||||
* "endDate": "2018-03-01",
|
||||
* "message": "This is an <b>important</b> announcement",
|
||||
* "imageUrl": "url/to/image",
|
||||
* "linkUrl": "url/to/website"
|
||||
* },
|
||||
* ...
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* Only one announcement will be shown at any time. This is determined as the first "live"
|
||||
* announcement in the file, where "live" means that its start date is before today, and its
|
||||
* end date is after today.
|
||||
*
|
||||
* **Security Note:**
|
||||
* The `message` field can contain unsanitized HTML but this field should only updated by
|
||||
* verified members of the Angular team.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'aio-announcement-bar',
|
||||
template: `
|
||||
<div class="homepage-container" *ngIf="announcement">
|
||||
<div class="announcement-bar">
|
||||
<img [src]="announcement.imageUrl">
|
||||
<p [innerHTML]="announcement.message"></p>
|
||||
<a class="button" [href]="announcement.linkUrl">Learn More</a>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
export class AnnouncementBarComponent implements OnInit {
|
||||
announcement: Announcement;
|
||||
|
||||
constructor(private http: HttpClient, private logger: Logger) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.http.get<Announcement[]>(announcementsPath)
|
||||
.catch(error => {
|
||||
this.logger.error(`${announcementsPath} request failed: ${error.message}`);
|
||||
return [];
|
||||
})
|
||||
.map(announcements => this.findCurrentAnnouncement(announcements))
|
||||
.catch(error => {
|
||||
this.logger.error(`${announcementsPath} contains invalid data: ${error.message}`);
|
||||
return [];
|
||||
})
|
||||
.subscribe(announcement => this.announcement = announcement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first date in the list that is "live" now
|
||||
*/
|
||||
private findCurrentAnnouncement(announcements: Announcement[]) {
|
||||
return announcements
|
||||
.filter(announcement => new Date(announcement.startDate).valueOf() < Date.now())
|
||||
.filter(announcement => new Date(announcement.endDate).valueOf() > Date.now())
|
||||
[0];
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ const defaultLineNumsCount = 10; // by default, show linenums over this number
|
||||
selector: 'aio-code',
|
||||
template: `
|
||||
<pre class="prettyprint lang-{{language}}">
|
||||
<button *ngIf="!hideCopy" class="material-icons copy-button no-print"
|
||||
<button *ngIf="!hideCopy" class="material-icons copy-button"
|
||||
title="Copy code snippet"
|
||||
[attr.aria-label]="ariaLabel"
|
||||
(click)="doCopy()">
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div *ngIf="type !== 'None'" class="toc-inner no-print" [class.collapsed]="isCollapsed">
|
||||
<div *ngIf="type !== 'None'" class="toc-inner" [class.collapsed]="isCollapsed">
|
||||
|
||||
<div *ngIf="type === 'EmbeddedSimple'" class="toc-heading embedded">
|
||||
Contents
|
||||
|
@ -30,9 +30,6 @@ export class GaService {
|
||||
}
|
||||
|
||||
ga(...args: any[]) {
|
||||
const gaFn = (this.window as any)['ga'];
|
||||
if (gaFn) {
|
||||
gaFn(...args);
|
||||
}
|
||||
(this.window as any)['ga'](...args);
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
import { ErrorHandler, ReflectiveInjector } from '@angular/core';
|
||||
import { Logger } from './logger.service';
|
||||
|
||||
describe('logger service', () => {
|
||||
let logSpy: jasmine.Spy;
|
||||
let warnSpy: jasmine.Spy;
|
||||
let logger: Logger;
|
||||
let errorHandler: ErrorHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
logSpy = spyOn(console, 'log');
|
||||
warnSpy = spyOn(console, 'warn');
|
||||
const injector = ReflectiveInjector.resolveAndCreate([
|
||||
Logger,
|
||||
{ provide: ErrorHandler, useClass: MockErrorHandler }
|
||||
]);
|
||||
logger = injector.get(Logger);
|
||||
errorHandler = injector.get(ErrorHandler);
|
||||
});
|
||||
|
||||
describe('log', () => {
|
||||
it('should delegate to console.log', () => {
|
||||
logger.log('param1', 'param2', 'param3');
|
||||
expect(console.log).toHaveBeenCalledWith('param1', 'param2', 'param3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('warn', () => {
|
||||
it('should delegate to console.warn', () => {
|
||||
logger.warn('param1', 'param2', 'param3');
|
||||
expect(console.warn).toHaveBeenCalledWith('param1', 'param2', 'param3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('error', () => {
|
||||
it('should delegate to ErrorHandler', () => {
|
||||
logger.error('param1', 'param2', 'param3');
|
||||
expect(errorHandler.handleError).toHaveBeenCalledWith('param1 param2 param3');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
class MockErrorHandler implements ErrorHandler {
|
||||
handleError = jasmine.createSpy('handleError');
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
import { ErrorHandler, Injectable } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class Logger {
|
||||
|
||||
constructor(private errorHandler: ErrorHandler) {}
|
||||
|
||||
log(value: any, ...rest: any[]) {
|
||||
if (!environment.production) {
|
||||
console.log(value, ...rest);
|
||||
@ -14,8 +12,7 @@ export class Logger {
|
||||
}
|
||||
|
||||
error(value: any, ...rest: any[]) {
|
||||
const message = [value, ...rest].join(' ');
|
||||
this.errorHandler.handleError(message);
|
||||
console.error(value, ...rest);
|
||||
}
|
||||
|
||||
warn(value: any, ...rest: any[]) {
|
||||
|
@ -1,64 +0,0 @@
|
||||
import { ErrorHandler, ReflectiveInjector } from '@angular/core';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { WindowToken } from 'app/shared/window';
|
||||
import { AppModule } from 'app/app.module';
|
||||
|
||||
import { ReportingErrorHandler } from './reporting-error-handler';
|
||||
|
||||
describe('ReportingErrorHandler service', () => {
|
||||
let handler: ReportingErrorHandler;
|
||||
let superHandler: jasmine.Spy;
|
||||
let onerrorSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
onerrorSpy = jasmine.createSpy('onerror');
|
||||
superHandler = spyOn(ErrorHandler.prototype, 'handleError');
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([
|
||||
{ provide: ErrorHandler, useClass: ReportingErrorHandler },
|
||||
{ provide: WindowToken, useFactory: () => ({ onerror: onerrorSpy }) }
|
||||
]);
|
||||
handler = injector.get(ErrorHandler);
|
||||
});
|
||||
|
||||
it('should be registered on the AppModule', () => {
|
||||
handler = TestBed.configureTestingModule({ imports: [AppModule] }).get(ErrorHandler);
|
||||
expect(handler).toEqual(jasmine.any(ReportingErrorHandler));
|
||||
});
|
||||
|
||||
describe('handleError', () => {
|
||||
it('should call the super class handleError', () => {
|
||||
const error = new Error();
|
||||
handler.handleError(error);
|
||||
expect(superHandler).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it('should cope with the super handler throwing an error', () => {
|
||||
const error = new Error('initial error');
|
||||
superHandler.and.throwError('super handler error');
|
||||
handler.handleError(error);
|
||||
|
||||
expect(onerrorSpy).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Error from super handler is reported first
|
||||
expect(onerrorSpy.calls.argsFor(0)[0]).toEqual('super handler error');
|
||||
expect(onerrorSpy.calls.argsFor(0)[4]).toEqual(jasmine.any(Error));
|
||||
|
||||
// Then error from initial exception
|
||||
expect(onerrorSpy.calls.argsFor(1)[0]).toEqual('initial error');
|
||||
expect(onerrorSpy.calls.argsFor(1)[4]).toEqual(error);
|
||||
});
|
||||
|
||||
it('should send an error object to window.onerror', () => {
|
||||
const error = new Error('this is an error message');
|
||||
handler.handleError(error);
|
||||
expect(onerrorSpy).toHaveBeenCalledWith(error.message, undefined, undefined, undefined, error);
|
||||
});
|
||||
|
||||
it('should send an error string to window.onerror', () => {
|
||||
const error = 'this is an error message';
|
||||
handler.handleError(error);
|
||||
expect(onerrorSpy).toHaveBeenCalledWith(error);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,37 +0,0 @@
|
||||
import { ErrorHandler, Inject, Injectable } from '@angular/core';
|
||||
import { WindowToken } from './window';
|
||||
|
||||
/**
|
||||
* Extend the default error handling to report errors to an external service - e.g Google Analytics.
|
||||
*
|
||||
* Errors outside the Angular application may also be handled by `window.onerror`.
|
||||
*/
|
||||
@Injectable()
|
||||
export class ReportingErrorHandler extends ErrorHandler {
|
||||
|
||||
constructor(@Inject(WindowToken) private window: Window) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error info to Google Analytics, in addition to the default handling.
|
||||
* @param error Information about the error.
|
||||
*/
|
||||
handleError(error: string | Error) {
|
||||
|
||||
try {
|
||||
super.handleError(error);
|
||||
} catch (e) {
|
||||
this.reportError(e);
|
||||
}
|
||||
this.reportError(error);
|
||||
}
|
||||
|
||||
private reportError(error: string | Error) {
|
||||
if (typeof error === 'string') {
|
||||
this.window.onerror(error);
|
||||
} else {
|
||||
this.window.onerror(error.message, undefined, undefined, undefined, error);
|
||||
}
|
||||
}
|
||||
}
|
@ -52,38 +52,6 @@
|
||||
</script>
|
||||
<!-- End Google Analytics -->
|
||||
|
||||
<script>
|
||||
// Report fatal errors to Google Analytics
|
||||
window.onerror = function() {
|
||||
ga('send', 'exception', {exDescription: formatError.apply(null, arguments), exFatal: true});
|
||||
|
||||
function formatError(msg, url, line, col, e) {
|
||||
var stack;
|
||||
msg = msg.replace(/^Error: /, '');
|
||||
if (e) {
|
||||
stack = e.stack
|
||||
// strip the leading "Error: " from the stack trace
|
||||
.replace(/^Error: /, '')
|
||||
// strip the message from the stack trace, if present
|
||||
.replace(msg + '\n', '')
|
||||
// strip leading spaces
|
||||
.replace(/^ +/gm, '')
|
||||
// strip all leading "at " for each frame
|
||||
.replace(/^at /gm, '')
|
||||
// replace long urls with just the last segment: `filename:line:column`
|
||||
.replace(/(?: \(|@)http.+\/([^/)]+)\)?(?:\n|$)/gm, '@$1\n')
|
||||
// replace "eval code" in Edge
|
||||
.replace(/ *\(eval code(:\d+:\d+)\)(?:\n|$)/gm, '@???$1\n')
|
||||
} else {
|
||||
line = line || '?';
|
||||
col = col || '?';
|
||||
stack = url + ':' + line + ':' + col;
|
||||
}
|
||||
return (msg + '\n' + stack).substr(0, 150);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
if (window.document.documentMode) {
|
||||
// polyfill IE11 in a blocking way
|
||||
|
@ -143,13 +143,13 @@ th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p > code, li > code, td > code, th > code {
|
||||
p > code, li > code, table code {
|
||||
font-family: $code-font;
|
||||
font-size: 85%;
|
||||
color: $darkgray;
|
||||
letter-spacing: 0;
|
||||
line-height: 1;
|
||||
padding: 2px 0;
|
||||
padding: 2px 6px;
|
||||
background-color: $backgroundgray;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
text-transform: none;
|
||||
padding: 8px 24px;
|
||||
}
|
||||
|
||||
|
||||
tbody {
|
||||
pre {
|
||||
white-space: normal;
|
||||
@ -36,44 +36,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
.api-body {
|
||||
|
||||
max-width: 1200px;
|
||||
.api-header label {
|
||||
border-radius: 4px;
|
||||
padding: 4px 16px;
|
||||
display: inline;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
margin: 0 8px 0 16px;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
display: block;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
table {
|
||||
&.api-status-label {
|
||||
background-color: $mediumgray;
|
||||
}
|
||||
|
||||
th {
|
||||
text-transform: none;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
&.api-type-label {
|
||||
background-color: $accentblue;
|
||||
|
||||
tr {
|
||||
border-bottom: 1px solid $lightgray;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.item-table {
|
||||
td {
|
||||
padding: 32px;
|
||||
@each $name, $symbol in $api-symbols {
|
||||
&.#{$name} {
|
||||
background: map-get($symbol, background);
|
||||
}
|
||||
}
|
||||
|
||||
&.list-table {
|
||||
td {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -37,11 +37,3 @@ aio-shell.page-docs {
|
||||
margin: 24px 0px;
|
||||
background: $lightgray;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
right: 24px;
|
||||
}
|
@ -12,4 +12,3 @@
|
||||
@import 'sidenav';
|
||||
@import 'table-of-contents';
|
||||
@import 'top-menu';
|
||||
@import 'print-layout';
|
@ -125,7 +125,6 @@ section#intro {
|
||||
.announcement-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
max-width: 50vw;
|
||||
|
@ -1,110 +0,0 @@
|
||||
@media print {
|
||||
|
||||
// General Adjustments
|
||||
* {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
height: 40px !important;
|
||||
color: $darkgray !important;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
|
||||
ul, ol, img, code-example, table, tr, .alert, .l-subsection, .feature {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
table tbody tr:last-child td {
|
||||
border-bottom: 1px solid $lightgray !important;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
p {
|
||||
widows: 4;
|
||||
}
|
||||
|
||||
p > code, li > code, table code {
|
||||
color: $blue !important;
|
||||
}
|
||||
|
||||
// No Print Class
|
||||
.no-print {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// Custom No Print for Sidenav Menu
|
||||
mat-sidenav.sidenav.mat-sidenav {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// Custom No Print Element Adjustments
|
||||
.mat-sidenav-content {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
mat-sidenav-container.sidenav-container {
|
||||
min-width: 100vw;
|
||||
}
|
||||
|
||||
.sidenav-content {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.filetree {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
aio-code code {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
code-example {
|
||||
pre.lang-bash code span {
|
||||
color: $mediumgray !important;
|
||||
}
|
||||
|
||||
pre.lang-sh code span {
|
||||
color: $darkgray !important;
|
||||
}
|
||||
|
||||
header {
|
||||
border: 0.5px solid $lightgray;
|
||||
color: $darkgray;
|
||||
}
|
||||
}
|
||||
|
||||
.content code {
|
||||
border: 0.5px solid $lightgray;
|
||||
}
|
||||
|
||||
.mat-tab-labels {
|
||||
div.mat-tab-label {
|
||||
&:not(.mat-tab-label-active) span {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&.mat-tab-label-active span {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.api-header label {
|
||||
color: $darkgray !important;
|
||||
font-weight: bold !important;
|
||||
margin: 2px !important;
|
||||
padding: 0 !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.feature-section img {
|
||||
max-width: 70px !important;
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
// Disable sidenav animations for the initial render.
|
||||
.starting.mat-drawer-transition .mat-drawer-content {
|
||||
transition: none;
|
||||
// Disable sidenav animations while starting the app
|
||||
// See https://github.com/angular/material2/blob/master/src/lib/sidenav/sidenav-transitions.scss
|
||||
.starting.mat-sidenav-transition {
|
||||
.mat-sidenav,
|
||||
.mat-sidenav-content,
|
||||
.mat-sidenav-backdrop.mat-sidenav-shown {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
aio-nav-menu {
|
||||
@ -37,19 +42,19 @@ mat-sidenav.mat-sidenav.sidenav {
|
||||
}
|
||||
|
||||
mat-sidenav-container.sidenav-container {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
transform: none;
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
transform: none;
|
||||
|
||||
&.has-floating-toc {
|
||||
max-width: 82%;
|
||||
}
|
||||
&.has-floating-toc {
|
||||
max-width: 82%;
|
||||
}
|
||||
}
|
||||
|
||||
mat-sidenav-container div.mat-sidenav-content {
|
||||
height: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.vertical-menu-item {
|
||||
@ -123,12 +128,6 @@ button.vertical-menu-item {
|
||||
transition-timing-function: ease-out;
|
||||
}
|
||||
|
||||
.no-animations {
|
||||
.heading-children.expanded, .heading-children.collapsed {
|
||||
transition: none! important;
|
||||
}
|
||||
}
|
||||
|
||||
.level-1 {
|
||||
font-family: $main-font;
|
||||
font-size: 14px;
|
||||
@ -160,6 +159,7 @@ button.vertical-menu-item {
|
||||
|
||||
.level-1:not(.expanded) .mat-icon, .level-2:not(.expanded) .mat-icon {
|
||||
@include rotate(0deg);
|
||||
// margin: 4px;
|
||||
}
|
||||
|
||||
aio-nav-menu.top-menu {
|
||||
|
@ -68,12 +68,9 @@ aio-shell.folder-tutorial mat-toolbar.mat-toolbar {
|
||||
height: 100%;
|
||||
margin: $hamburgerShownMargin;
|
||||
padding: 0;
|
||||
|
||||
&:not(.starting) {
|
||||
transition-duration: .4s;
|
||||
transition-property: color, margin;
|
||||
transition-timing-function: cubic-bezier(.25, .8, .25, 1);
|
||||
}
|
||||
transition-duration: .4s;
|
||||
transition-property: color, margin;
|
||||
transition-timing-function: cubic-bezier(.25, .8, .25, 1);
|
||||
|
||||
@media (min-width: 992px) {
|
||||
// Hamburger hidden by default on large screens.
|
||||
|
@ -1,102 +1,23 @@
|
||||
.api-body {
|
||||
.api-info-bar {
|
||||
max-width: 800px;
|
||||
text-align: left;
|
||||
|
||||
.class-overview {
|
||||
position: relative;
|
||||
span {
|
||||
margin: 0 16px 0 0;
|
||||
|
||||
code-example {
|
||||
clear: left;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
box-shadow: 0 2px 2px rgba(10, 16, 20, 0.24), 0 0 2px rgba(10, 16, 20, 0.12);
|
||||
border-radius: 2px;
|
||||
background: #FAFAFA;
|
||||
float: right;
|
||||
margin: 20px;
|
||||
padding: 0 24px 14px;
|
||||
|
||||
h2 {
|
||||
margin: 18px 0 4px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 14px;
|
||||
}
|
||||
}
|
||||
.inline-sidebar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.sidebar {
|
||||
display: none;
|
||||
}
|
||||
.inline-sidebar {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.method-table {
|
||||
h3 {
|
||||
margin: 6px 0;
|
||||
font-weight: bold;
|
||||
@media screen and (max-width: 600px) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.api-heading {
|
||||
padding: 5px 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.properties-table {
|
||||
font-size: 14px;
|
||||
|
||||
thead th {
|
||||
&:nth-child(1) {
|
||||
width: 20%;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.parameters-table {
|
||||
margin-top: 0;
|
||||
font-size: 14px;
|
||||
td:nth-child(1) {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
details.overloads {
|
||||
margin-left: -8px;
|
||||
|
||||
summary {
|
||||
height: inherit;
|
||||
padding: 8px 12px;
|
||||
h4 {
|
||||
margin: 0;
|
||||
clear: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.api-section aio-code {
|
||||
background-color: rgba(241, 241, 241, 0.2);
|
||||
}
|
||||
|
||||
.from-constructor {
|
||||
font-style: italic;
|
||||
color: $blue;
|
||||
}
|
||||
.api-heading {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 18px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.overloads .detail-contents {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ code-tabs mat-tab-body-content .fadeIn {
|
||||
aio-code pre {
|
||||
display: flex;
|
||||
min-height: 32px;
|
||||
margin: 16px 24px;
|
||||
margin: 16px 32px;
|
||||
white-space: pre-wrap;
|
||||
align-items: center;
|
||||
|
||||
@ -85,6 +85,7 @@ aio-code pre {
|
||||
|
||||
|
||||
.copy-button {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -32px;
|
||||
|
@ -25,13 +25,16 @@ summary {
|
||||
display: none; // Remove the built in details marker in webkit
|
||||
}
|
||||
|
||||
&::before {
|
||||
&::after {
|
||||
content: '\E5CE'; // See https://material.io/icons/#ic_expand_less
|
||||
font-family: 'Material Icons';
|
||||
font-size: 24px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
@include rotate(0deg); // We will rotate 180 degrees when details is open
|
||||
float: right;
|
||||
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +45,7 @@ details {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
&[open] > summary::before {
|
||||
&[open] > summary::after {
|
||||
@include rotate(180deg); // Rotate the icon
|
||||
}
|
||||
}
|
||||
|
@ -5,26 +5,25 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.header-link {
|
||||
box-sizing: border-box;
|
||||
color: $mediumgray;
|
||||
display: inline-block;
|
||||
margin-left: -42px;
|
||||
padding: 0 8px;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
vertical-align: middle;
|
||||
.mat-icon, .material-icons {
|
||||
visibility: hidden;
|
||||
width: 40px;
|
||||
display: inline-block;
|
||||
color: $mediumgray;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
float: right;
|
||||
margin-left: 0;
|
||||
&:hover {
|
||||
.mat-icon, .material-icons {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .header-link {
|
||||
visibility: visible;
|
||||
a.header-link {
|
||||
text-decoration: none;
|
||||
padding-left: 8px;
|
||||
margin-left: -50px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
label.raised, .api-header label {
|
||||
border-radius: 4px;
|
||||
padding: 4px 16px;
|
||||
display: inline;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
margin-right: 8px;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
display: block;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
&.page-label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: $mist;
|
||||
color: $mediumgray;
|
||||
margin-bottom: 8px;
|
||||
width: 140px;
|
||||
|
||||
.material-icons {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&.property-type-label {
|
||||
font-size: 12px;
|
||||
background-color: $darkgray;
|
||||
color: $white;
|
||||
text-transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.api-header label {
|
||||
|
||||
&.api-status-label {
|
||||
background-color: $mediumgray;
|
||||
}
|
||||
|
||||
&.api-type-label {
|
||||
background-color: $accentblue;
|
||||
|
||||
@each $name, $symbol in $api-symbols {
|
||||
&.#{$name} {
|
||||
background: map-get($symbol, background);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -30,4 +30,3 @@
|
||||
@import 'select-menu';
|
||||
@import 'deploy-theme';
|
||||
@import 'notification';
|
||||
@import 'label';
|
||||
|
@ -12,7 +12,7 @@ table {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
thead > {
|
||||
thead {
|
||||
vertical-align: middle;
|
||||
border-color: inherit;
|
||||
|
||||
@ -21,20 +21,20 @@ table {
|
||||
border-color: inherit;
|
||||
}
|
||||
|
||||
tr > th {
|
||||
th {
|
||||
background: rgba($lightgray, 0.2);
|
||||
border-bottom: 1px solid $lightgray;
|
||||
color: $darkgray;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
padding: 8px 24px;
|
||||
padding: 8px 32px;
|
||||
text-align: left;
|
||||
text-transform: uppercase;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
tbody > tr > {
|
||||
tbody {
|
||||
th,
|
||||
td {
|
||||
border-bottom: 1px solid $lightgray;
|
||||
@ -70,7 +70,7 @@ table {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
&:last-child td {
|
||||
tr:last-child td {
|
||||
border: none;
|
||||
|
||||
@media (max-width: 480px) {
|
||||
|
@ -30,7 +30,7 @@
|
||||
box-shadow: 0 2px 2px rgba(0,0,0,0.24), 0 0 2px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
table > tbody > tr > th {
|
||||
table tbody th{
|
||||
border: 1px solid rgba(mat-color($foreground, secondary-text), .03);
|
||||
}
|
||||
|
||||
|
@ -1,182 +0,0 @@
|
||||
/api/api/core/ElementRef /api/core/ElementRef
|
||||
/api/common/Control-class /api/forms/FormControl
|
||||
/api/common/CORE_DIRECTIVES /api/common/CommonModule
|
||||
/api/common/DatePipe-class /api/common/DatePipe
|
||||
/api/common/NgClass-directive.html /api/common/NgClass
|
||||
/api/common/NgFor-directive.html /api/common/NgForOf
|
||||
/api/common/NgModel-directive /api/forms/NgModel
|
||||
/api/common/SelectControlValueAccessor-directive /api/forms/SelectControlValueAccessor
|
||||
/api/common/SlicePipe-class.html /api/common/SlicePipe
|
||||
/api/core/AnimationStateDeclarationMetadata /api/animations
|
||||
/api/core/DoCheck-interface.html /api/core/DoCheck
|
||||
/api/core/HostBinding-var /api/core/HostBinding
|
||||
/api/core/OpaqueToken-class /api/core/OpaqueToken
|
||||
/api/core/OptionalMetadata-class /api/core/Optional
|
||||
/api/core/PLATFORM_PIPES /api/common/CommonModule
|
||||
/api/core/Provider-class.html /api/core/Provider
|
||||
/api/core/Renderer-class /api/core/Renderer
|
||||
/api/core/testing/async-function /api/core/testing/async
|
||||
/api/core/testing/index/async-function /api/core/testing/async
|
||||
/api/core/testing/index/TestBed-class.html /api/core/testing/TestBed
|
||||
/api/core/testing/inject-function /api/core/testing/inject
|
||||
/api/core/testing/inject-function.html /api/core/testing/inject
|
||||
/api/http/Headers-class /api/http/Headers
|
||||
/api/http/Headers-class.html /api/http/Headers
|
||||
/api/http/HTTP_PROVIDERS-let /api/http/HttpModule
|
||||
/api/http/testing/index/MockBackend-class /api/http/testing/MockBackend
|
||||
/api/http/testing/index/MockBackend-class.html /api/http/testing/MockBackend
|
||||
/api/platform-browser-dynamic/testing/index/platformBrowserDynamicTesting-let.html /api/platform-browser-dynamic/testing/platformBrowserDynamicTesting
|
||||
/api/platform-browser/AnimationDriver /api/animations/browser/AnimationDriver
|
||||
/api/router/Route-class /api/router/Route
|
||||
/api/router/RouterLink-directive /api/router/RouterLink
|
||||
/api/testing/tick-function /api/core/testing/tick
|
||||
/api/upgrade/static/downgradeComponent-function /api/upgrade/static/downgradeComponent
|
||||
/api/upgrade/static/downgradeComponent-function.html /api/upgrade/static/downgradeComponent
|
||||
/api/upgrade/static/index/downgradeComponent-function /api/upgrade/static/downgradeComponent
|
||||
/api/upgrade/static/UpgradeModule-class /api/upgrade/static/UpgradeModule
|
||||
/docs/js/latest/api/ /api
|
||||
/docs/js/latest/api/animate/AnimationBuilder-class /api/animations/AnimationBuilder
|
||||
/docs/js/latest/api/animate/CssAnimationBuilder-class.html /api/animations/CssAnimationBuilder
|
||||
/docs/js/latest/api/animations/index/trigger-function /api/animations/trigger
|
||||
/docs/js/latest/api/common/ControlGroup-class.html /api/forms/FormGroup
|
||||
/docs/js/latest/api/common/index/DatePipe-pipe /api/common/DatePipe
|
||||
/docs/js/latest/api/common/index/Location-class.html /api/common/Location
|
||||
/docs/js/latest/api/common/index/MaxLengthValidator-directive.html /api/forms/MaxLengthValidator
|
||||
/docs/js/latest/api/common/index/NgFor-directive /api/common/NgForOf
|
||||
/docs/js/latest/api/common/index/NgFor-directive.html /api/common/NgForOf
|
||||
/docs/js/latest/api/common/index/NgFor-type-alias /api/common/NgForOf
|
||||
/docs/js/latest/api/common/index/NgFor-type-alias.html /api/common/NgForOf
|
||||
/docs/js/latest/api/common/index/NgTemplateOutlet-directive /api/common/NgTemplateOutlet
|
||||
/docs/js/latest/api/common/NgStyle-directive /api/common/NgStyle
|
||||
/docs/js/latest/api/core/DynamicComponentLoader-class.html /api/core/DynamicComponentLoader
|
||||
/docs/js/latest/api/core/HostListener-var /api/core/HostListener
|
||||
/docs/js/latest/api/core/index/AfterViewChecked-class /api/core/AfterViewChecked
|
||||
/docs/js/latest/api/core/index/AnimationStateTransitionMetadata-class.html /api/core/AnimationStateTransitionMetadata
|
||||
/docs/js/latest/api/core/index/AnimationStateTransitionMetadata-type-alias /api/core/AnimationStateTransitionMetadata
|
||||
/docs/js/latest/api/core/index/ApplicationModule-class /api/core/ApplicationModule
|
||||
/docs/js/latest/api/core/index/ApplicationRef-class /api/core/ApplicationRef
|
||||
/docs/js/latest/api/core/index/ChangeDetectorRef-class /api/core/ChangeDetectorRef
|
||||
/docs/js/latest/api/core/index/ComponentFactory-class /api/core/ComponentFactory
|
||||
/docs/js/latest/api/core/index/DebugNode-class /api/core/DebugNode
|
||||
/docs/js/latest/api/core/index/destroyPlatform-function /api/core/destroyPlatform
|
||||
/docs/js/latest/api/core/index/DirectiveMetadata-class /api/core/Directive
|
||||
/docs/js/latest/api/core/index/ErrorHandler-class /api/core/ErrorHandler
|
||||
/docs/js/latest/api/core/index/EventEmitter-class /api/core/EventEmitter
|
||||
/docs/js/latest/api/core/index/EventEmitter-class.html /api/core/EventEmitter
|
||||
/docs/js/latest/api/core/index/getPlatform-function /api/core/getPlatform
|
||||
/docs/js/latest/api/core/index/NgModule-interface /api/core/NgModule
|
||||
/docs/js/latest/api/core/index/NgModuleRef-class /api/core/NgModuleRef
|
||||
/docs/js/latest/api/core/index/NgModuleRef-class.html /api/core/NgModuleRef
|
||||
/docs/js/latest/api/core/index/OnInit-class /api/core/OnInit
|
||||
/docs/js/latest/api/core/index/OnInit-class.html /api/core/OnInit
|
||||
/docs/js/latest/api/core/index/OnInit-interface /api/core/OnInit
|
||||
/docs/js/latest/api/core/index/PlatformRef-class /api/core/PlatformRef
|
||||
/docs/js/latest/api/core/index/QueryList-class.html /api/core/QueryList
|
||||
/docs/js/latest/api/core/index/RenderComponentType-class /api/core/RenderComponentType
|
||||
/docs/js/latest/api/core/index/Renderer2-class.html /api/core/Renderer2
|
||||
/docs/js/latest/api/core/index/state-function.html /api/core/state
|
||||
/docs/js/latest/api/core/index/transition-function.html /api/core/transition
|
||||
/docs/js/latest/api/core/index/trigger-function /api/core/trigger
|
||||
/docs/js/latest/api/core/index/trigger-function.html /api/core/trigger
|
||||
/docs/js/latest/api/core/index/ViewChild-decorator /api/core/ViewChild
|
||||
/docs/js/latest/api/core/index/wtfLeave-let /api/core/wtfLeave
|
||||
/docs/js/latest/api/core/Injector-class.html /api/core/Injector
|
||||
/docs/js/latest/api/core/Query-var /api/core/Query
|
||||
/docs/js/latest/api/core/ResolvedProvider-interface.html /api/core/ResolvedProvider
|
||||
/docs/js/latest/api/core/testing/index/TestBed-class /api/core/testing/TestBed
|
||||
/docs/js/latest/api/core/testing/index/tick-function /api/core/testing/tick
|
||||
/docs/js/latest/api/core/testing/index/tick-function.html /api/core/testing/tick
|
||||
/docs/js/latest/api/core/ViewContainerRef-class.html /api/core/ViewContainerRef
|
||||
/docs/js/latest/api/forms/index/AbstractControl-class /api/forms/AbstractControl
|
||||
/docs/js/latest/api/forms/index/AbstractControl-class.html /api/forms/AbstractControl
|
||||
/docs/js/latest/api/forms/index/FormArray-class.html /api/forms/FormArray
|
||||
/docs/js/latest/api/forms/index/FormBuilder-class.html /api/forms/FormBuilder
|
||||
/docs/js/latest/api/forms/index/NG_VALIDATORS-let /api/forms/NG_VALIDATORS
|
||||
/docs/js/latest/api/forms/index/Validator-interface.html /api/forms/Validator
|
||||
/docs/js/latest/api/http/ConnectionBackend-class /api/http/ConnectionBackend
|
||||
/docs/js/latest/api/http/index/Http-class.html /api/http/Http
|
||||
/docs/js/latest/api/http/index/Jsonp-class.html /api/http/Jsonp
|
||||
/docs/js/latest/api/http/index/ResponseOptions-class.html /api/http/ResponseOptions
|
||||
/docs/js/latest/api/http/index/URLSearchParams-class /api/http/URLSearchParams
|
||||
/docs/js/latest/api/http/index/XHRConnection-class /api/http/XHRConnection
|
||||
/docs/js/latest/api/http/index/XHRConnection-class.html /api/http/XHRConnection
|
||||
/docs/js/latest/api/http/testing/index/MockConnection-class.html /api/http/testing/MockConnection
|
||||
/docs/js/latest/api/http/testing/MockBackend-class /api/http/testing/MockBackend
|
||||
/docs/js/latest/api/platform-browser-dynamic/index/platformBrowserDynamic-let.html /api/platform-browser-dynamic/platformBrowserDynamic
|
||||
/docs/js/latest/api/platform-browser-dynamic/testing/index/BrowserDynamicTestingModule-class.html /api/platform-browser-dynamic/testing/BrowserDynamicTestingModule
|
||||
/docs/js/latest/api/platform-browser/animations/index/BrowserAnimationsModule-class /api/platform-browser/animations/BrowserAnimationsModule
|
||||
/docs/js/latest/api/platform-browser/animations/index/BrowserAnimationsModule-class.html /api/platform-browser/animations/BrowserAnimationsModule
|
||||
/docs/js/latest/api/platform-browser/animations/index/NoopAnimationsModule-class.html /api/platform-browser/animations/NoopAnimationsModule
|
||||
/docs/js/latest/api/platform-browser/index/DomSanitizer-class /api/platform-browser/DomSanitizer
|
||||
/docs/js/latest/api/platform-browser/index/Meta-class /api/platform-browser/Meta
|
||||
/docs/js/latest/api/platform-browser/index/MetaDefinition-type-alias /api/platform-browser/MetaDefinition
|
||||
/docs/js/latest/api/platform-browser/index/SafeUrl-interface /api/platform-browser/SafeUrl
|
||||
/docs/js/latest/api/platform-browser/index/Title-class /api/platform-browser/Title
|
||||
/docs/js/latest/api/platform-browser/index/Title-class.html /api/platform-browser/Title
|
||||
/docs/js/latest/api/platform-server/index/PlatformState-class /api/platform-server/PlatformState
|
||||
/docs/js/latest/api/platform-server/index/PlatformState-class.html /api/platform-server/PlatformState
|
||||
/docs/js/latest/api/platform-webworker /api/platform-webworker
|
||||
/docs/js/latest/api/platform-webworker/index/MessageBus-class /api/platform-webworker/MessageBus
|
||||
/docs/js/latest/api/router/index/ActivatedRoute-interface /api/router/ActivatedRoute
|
||||
/docs/js/latest/api/router/index/CanActivate-interface.html /api/router/CanActivate
|
||||
/docs/js/latest/api/router/index/CanActivateChild-interface /api/router/CanActivateChild
|
||||
/docs/js/latest/api/router/index/CanDeactivate-interface.html /api/router/CanDeactivate
|
||||
/docs/js/latest/api/router/index/CanLoad-interface /api/router/CanLoad
|
||||
/docs/js/latest/api/router/index/CanLoad-interface.html /api/router/CanLoad
|
||||
/docs/js/latest/api/router/index/NavigationEnd-class /api/router/NavigationEnd
|
||||
/docs/js/latest/api/router/index/provideRoutes-function /api/router/provideRoutes
|
||||
/docs/js/latest/api/router/index/provideRoutes-function.html /api/router/provideRoutes
|
||||
/docs/js/latest/api/router/index/Router-class /api/router/Router
|
||||
/docs/js/latest/api/router/index/RouterLink-directive /api/router/RouterLink
|
||||
/docs/js/latest/api/router/index/Routes-type-alias /api/router/Routes
|
||||
/docs/js/latest/api/router/index/UrlSegment-class /api/router/UrlSegment
|
||||
/docs/js/latest/api/router/index/UrlSerializer-class.html /api/router/UrlSerializer
|
||||
/docs/js/latest/api/router/Instruction-class /api/router/Instruction
|
||||
/docs/js/latest/api/router/Location-class /api/router/Location
|
||||
/docs/js/latest/api/router/OnActivate-interface /api/router/OnActivate
|
||||
/docs/js/latest/api/router/Redirect-class.html /api/router/Redirect
|
||||
/docs/js/latest/api/router/RouteDefinition-interface.html /api/router/RouteDefinition
|
||||
/docs/js/latest/api/router/RouteParams-class /api/router/RouteParams
|
||||
/docs/js/latest/api/router/RouteParams-class.html /api/router/RouteParams
|
||||
/docs/js/latest/api/router/Router-class.html /api/router/Router
|
||||
/docs/js/latest/api/router/testing /api/router/testing
|
||||
/docs/js/latest/api/upgrade/index/UpgradeAdapter-class.html /api/upgrade/UpgradeAdapter
|
||||
/docs/js/latest/api/upgrade/static/UpgradeModule-class /api/upgrade/static/UpgradeModule
|
||||
/docs/js/latest/api/upgrade/static/UpgradeModule-class.html /api/upgrade/static/UpgradeModule
|
||||
/docs/js/latest/cookbook/ts-to-js.html https://github.com/angular/angular/blob/master/aio/content/guide/change-log.md#es6--described-in-typescript-to-javascript-2016-11-14
|
||||
/docs/js/latest/glossary /guide/glossary
|
||||
/docs/js/latest/guide/ /docs
|
||||
/docs/js/latest/guide/lifecycle-hooks /guide/lifecycle-hooks
|
||||
/docs/js/latest/guide/ngmodule /guide/ngmodules
|
||||
/docs/js/latest/resources /resources
|
||||
/docs/latest/tutorial /tutorial
|
||||
/styleguide /guide/styleguide
|
||||
/docs/styleguide /guide/styleguide
|
||||
/docs/styleguide.html /guide/styleguide
|
||||
/docs/ts/latest/api/core/HostBinding-var.html /api/core/HostBinding
|
||||
/docs/ts/latest/api/core/index/BaseException-class.html /api/core/BaseException
|
||||
/docs/ts/latest/api/core/index/PLATFORM_PIPES-let.html /api/common/CommonModule
|
||||
/docs/ts/latest/api/core/OnInit-interface.html /api/core/OnInit
|
||||
/docs/ts/latest/api/core/OpaqueToken-class.html /api/core/OpaqueToken
|
||||
/docs/ts/latest/api/core/OptionalMetadata-class.html /api/core/Optional
|
||||
/docs/ts/latest/api/core/testing/index/async-function.html /api/core/testing/async
|
||||
/docs/ts/latest/api/core/testing/index/fakeAsync-function.html /api/core/testing/fakeAsync
|
||||
/docs/ts/latest/api/core/testing/index/TestComponentRenderer-class.html /api/core/testing/TestComponentRenderer
|
||||
/docs/ts/latest/api/core/testing/index/tick-function.html /api/core/testing/tick
|
||||
/docs/ts/latest/api/http/Connection-class.html /api/http/Connection
|
||||
/docs/ts/latest/api/http/testing/index/MockBackend-class.html /api/http/testing/MockBackend
|
||||
/docs/ts/latest/api/http/testing/index/MockConnection-class.html /api/http/testing/MockConnection
|
||||
/docs/ts/latest/api/platform-browser-dynamic/index/workerAppDynamicPlatform-let.html /api/platform-browser-dynamic/workerAppDynamicPlatform
|
||||
/docs/ts/latest/api/testing/fakeAsync-function.html /api/core/testing/fakeAsync
|
||||
/docs/ts/latest/cookbook/ts-to-js.html https://github.com/angular/angular/blob/master/aio/content/guide/change-log.md#es6--described-in-typescript-to-javascript-2016-11-14
|
||||
/guide/cli-quickstart /guide/quickstart
|
||||
/guide/learning-angular /guide/quickstart
|
||||
/guide/learning-angular.html /guide/quickstart
|
||||
/guide/metadata /guide/aot-compiler
|
||||
/guide/service-worker-getstart /guide/service-worker-getting-started
|
||||
/guide/service-worker-comm /guide/service-worker-communications
|
||||
/guide/service-worker-configref /guide/service-worker-config
|
||||
/news https://blog.angular.io/
|
||||
/news.html https://blog.angular.io/
|
||||
/testing /guide/testing
|
||||
/testing/first-app-tests.html /guide/testing
|
@ -1,49 +0,0 @@
|
||||
const { readFileSync } = require('fs');
|
||||
const path = require('canonical-path');
|
||||
const cjson = require('cjson');
|
||||
|
||||
import { FirebaseRedirector, FirebaseRedirectConfig } from '../../tools/firebase-test-utils/FirebaseRedirector';
|
||||
|
||||
export function getRedirector() {
|
||||
return new FirebaseRedirector(loadRedirects());
|
||||
}
|
||||
|
||||
export function loadRedirects(): FirebaseRedirectConfig[] {
|
||||
const pathToFirebaseJSON = path.resolve(__dirname, '../../firebase.json');
|
||||
const contents = cjson.load(pathToFirebaseJSON);
|
||||
return contents.hosting.redirects;
|
||||
}
|
||||
|
||||
export function loadSitemapUrls() {
|
||||
const pathToSiteMap = path.resolve(__dirname, '../../src/generated/sitemap.xml');
|
||||
const xml = readFileSync(pathToSiteMap, 'utf8');
|
||||
const urls: string[] = [];
|
||||
xml.replace(/<loc>([^<]+)<\/loc>/g, (_, loc) => urls.push(loc.replace('%%DEPLOYMENT_HOST%%', '')));
|
||||
return urls;
|
||||
}
|
||||
|
||||
export function loadLegacyUrls() {
|
||||
const pathToLegacyUrls = path.resolve(__dirname, 'URLS_TO_REDIRECT.txt');
|
||||
const urls = readFileSync(pathToLegacyUrls, 'utf8').split('\n').map(line => line.split('\t'));
|
||||
return urls;
|
||||
}
|
||||
|
||||
export function loadSWRoutes() {
|
||||
const pathToSWManifest = path.resolve(__dirname, '../../ngsw-manifest.json');
|
||||
const contents = cjson.load(pathToSWManifest);
|
||||
const routes = contents.routing.routes;
|
||||
return Object.keys(routes).map(route => {
|
||||
const routeConfig = routes[route];
|
||||
switch (routeConfig.match) {
|
||||
case 'exact':
|
||||
return (url) => url === route;
|
||||
case 'prefix':
|
||||
return (url) => url.startsWith(route);
|
||||
case 'regex':
|
||||
const regex = new RegExp(route);
|
||||
return (url) => regex.test(url);
|
||||
default:
|
||||
throw new Error(`unknown route config: ${route} - ${routeConfig.match}`);
|
||||
}
|
||||
});
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import { getRedirector, loadLegacyUrls, loadRedirects, loadSitemapUrls } from './helpers';
|
||||
|
||||
describe('firebase.json redirect config', () => {
|
||||
describe('with sitemap urls', () => {
|
||||
loadSitemapUrls().forEach(url => {
|
||||
it('should not redirect any urls in the sitemap', () => {
|
||||
expect(getRedirector().redirect(url)).toEqual(url);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with legacy urls', () => {
|
||||
loadLegacyUrls().forEach(urlPair => {
|
||||
it('should redirect the legacy urls', () => {
|
||||
const redirector = getRedirector();
|
||||
expect(redirector.redirect(urlPair[0])).not.toEqual(urlPair[0]);
|
||||
if (urlPair[1]) {
|
||||
expect(redirector.redirect(urlPair[0])).toEqual(urlPair[1]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('destinations', () => {
|
||||
loadRedirects().forEach(redirect => {
|
||||
it('should match pattern "^(https?:/)?/.*"', () => {
|
||||
expect(redirect.destination).toMatch(/^(https?:\/)?\/.*/);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,33 +0,0 @@
|
||||
import { loadLegacyUrls, loadSitemapUrls, loadSWRoutes } from './helpers';
|
||||
|
||||
describe('service-worker routes', () => {
|
||||
|
||||
loadSitemapUrls().forEach(url => {
|
||||
it('should process URLs in the Sitemap', () => {
|
||||
const routes = loadSWRoutes();
|
||||
expect(routes.some(test => test(url))).toBeTruthy(url);
|
||||
});
|
||||
});
|
||||
|
||||
loadLegacyUrls().forEach(urlPair => {
|
||||
const url = urlPair[0];
|
||||
it('should ignore legacy URLs that will be redirected', () => {
|
||||
const routes = loadSWRoutes();
|
||||
expect(routes.some(test => test(url))).toBeFalsy(url);
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore stackblitz URLs', () => {
|
||||
const routes = loadSWRoutes();
|
||||
expect(routes.some(test => test('/generated/live-examples/toh-pt6/stackblitz.html'))).toBeFalsy();
|
||||
expect(routes.some(test => test('/generated/live-examples/toh-pt6/stackblitz'))).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should ignore URLs to files with extensions', () => {
|
||||
const routes = loadSWRoutes();
|
||||
expect(routes.some(test => test('/generated/zips/animations/animations.zip'))).toBeFalsy();
|
||||
expect(routes.some(test => test('/generated/images/guide/animations/animation_auto.gif'))).toBeFalsy();
|
||||
expect(routes.some(test => test('/generated/ie-polyfills.min.js'))).toBeFalsy();
|
||||
expect(routes.some(test => test('/generated/docs/guide/animations.json'))).toBeFalsy();
|
||||
});
|
||||
});
|
@ -1,203 +0,0 @@
|
||||
import { browser } from 'protractor';
|
||||
import { SitePage } from './app.po';
|
||||
|
||||
/* tslint:disable:max-line-length */
|
||||
|
||||
describe('onerror handler', function() {
|
||||
let page: SitePage;
|
||||
|
||||
beforeAll(() => {
|
||||
page = new SitePage();
|
||||
page.navigateTo('');
|
||||
});
|
||||
|
||||
|
||||
it('(called without an error object) should call ga with a payload based on the message, url, row and column arguments', async () => {
|
||||
const message1 = await callOnError('Error: some error message', 'some-file.js', 12, 3, undefined);
|
||||
expect(message1).toEqual('some error message\nsome-file.js:12:3');
|
||||
const message2 = await callOnError('Error: some error message', undefined, undefined, undefined, undefined);
|
||||
expect(message2).toEqual('some error message\nnull:?:?');
|
||||
});
|
||||
|
||||
it('(called without an error object) should call ga with a payload that is no longer that 150 characters', async () => {
|
||||
const message = await callOnError(
|
||||
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' +
|
||||
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz',
|
||||
'some-file.js', 12, 3, undefined);
|
||||
expect(message).toEqual(
|
||||
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' +
|
||||
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst');
|
||||
});
|
||||
|
||||
it('(called with a Firefox on android style error) should call ga with a payload based on the error object', async () => {
|
||||
const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, {
|
||||
stack: `AppComponent@https://example.com/app/app.component.ts:31:29
|
||||
createClass@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12200:20
|
||||
createDirectiveInstance@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12049:37
|
||||
createViewNodes@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13487:53
|
||||
createRootView@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13377:5
|
||||
callWithDebugContext@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14778:39
|
||||
debugCreateRootView@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14079:12
|
||||
ComponentFactory_.prototype.create@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:10998:37
|
||||
ComponentFactoryBoundToModule.prototype.create@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:3958:16
|
||||
ApplicationRef.prototype.bootstrap@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5769:40
|
||||
PlatformRef.prototype._moduleDoBootstrap/<@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5496:74
|
||||
PlatformRef.prototype._moduleDoBootstrap@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5496:13
|
||||
PlatformRef.prototype.bootstrapModuleFactory/</</<@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5417:21
|
||||
ZoneDelegate.prototype.invoke@https://example.com/packages/zone.js@0.8.18/dist/zone.js:392:17
|
||||
forkInnerZoneWithAngularBehavior/zone._inner<.onInvoke@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:4665:24
|
||||
ZoneDelegate.prototype.invoke@https://example.com/packages/zone.js@0.8.18/dist/zone.js:391:17
|
||||
Zone.prototype.run@https://example.com/packages/zone.js@0.8.18/dist/zone.js:142:24
|
||||
scheduleResolveOrReject/<@https://example.com/packages/zone.js@0.8.18/dist/zone.js:873:52
|
||||
ZoneDelegate.prototype.invokeTask@https://example.com/packages/zone.js@0.8.18/dist/zone.js:425:17
|
||||
forkInnerZoneWithAngularBehavior/zone._inner<.onInvokeTask@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:4656:24
|
||||
ZoneDelegate.prototype.invokeTask@https://example.com/packages/zone.js@0.8.18/dist/zone.js:424:17
|
||||
Zone.prototype.runTask@https://example.com/packages/zone.js@0.8.18/dist/zone.js:192:28
|
||||
drainMicroTaskQueue@https://example.com/packages/zone.js@0.8.18/dist/zone.js:602:25` });
|
||||
|
||||
expect(message).toEqual(`something terrible has happened. oh no. oh no.
|
||||
AppComponent@app.component.ts:31:29
|
||||
createClass@core.umd.js:12200:20
|
||||
createDirectiveInstance@core.umd.j`);
|
||||
});
|
||||
|
||||
it('(called with a Safari 11 style error) should call ga with a payload based on the error object', async () => {
|
||||
const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, {
|
||||
stack: `AppComponent
|
||||
createClass
|
||||
createDirectiveInstance
|
||||
createViewNodes
|
||||
createRootView
|
||||
callWithDebugContext
|
||||
create
|
||||
bootstrap
|
||||
forEach@[native code]
|
||||
_moduleDoBootstrap
|
||||
|
||||
onInvoke
|
||||
run
|
||||
|
||||
onInvokeTask
|
||||
runTask
|
||||
drainMicroTaskQueue
|
||||
promiseReactionJob@[native code]` });
|
||||
|
||||
expect(message).toEqual(`something terrible has happened. oh no. oh no.
|
||||
AppComponent
|
||||
createClass
|
||||
createDirectiveInstance
|
||||
createViewNodes
|
||||
createRootView
|
||||
callWithDebugContext
|
||||
cr`);
|
||||
});
|
||||
|
||||
it('(called with a Opera 50 style error) should call ga with a payload based on the error object', async () => {
|
||||
const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, {
|
||||
stack: `Error: something terrible has happened. oh no. oh no.
|
||||
at new AppComponent (https://example.com/app/app.component.ts:31:29)
|
||||
at createClass (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12200:20)
|
||||
at createDirectiveInstance (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12049:37)
|
||||
at createViewNodes (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13487:53)
|
||||
at createRootView (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13377:5)
|
||||
at callWithDebugContext (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14778:42)
|
||||
at Object.debugCreateRootView [as createRootView] (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14079:12)
|
||||
at ComponentFactory_.create (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:10998:46)
|
||||
at ComponentFactoryBoundToModule.create (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:3958:29)
|
||||
at ApplicationRef.bootstrap (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5769:57)` });
|
||||
|
||||
expect(message).toEqual(`something terrible has happened. oh no. oh no.
|
||||
new AppComponent@app.component.ts:31:29
|
||||
createClass@core.umd.js:12200:20
|
||||
createDirectiveInstance@core.u`);
|
||||
});
|
||||
|
||||
it('(called with a Chrome 64 style error) should call ga with a payload based on the error object', async () => {
|
||||
const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, {
|
||||
stack: `Error: something terrible has happened. oh no. oh no.
|
||||
at new AppComponent (https://example.com/app/app.component.ts:31:29)
|
||||
at createClass (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12200:20)
|
||||
at createDirectiveInstance (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12049:37)
|
||||
at createViewNodes (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13487:53)
|
||||
at createRootView (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13377:5)
|
||||
at callWithDebugContext (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14778:42)
|
||||
at Object.debugCreateRootView [as createRootView] (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14079:12)
|
||||
at ComponentFactory_.create (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:10998:46)
|
||||
at ComponentFactoryBoundToModule.create (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:3958:29)
|
||||
at ApplicationRef.bootstrap (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5769:57)` });
|
||||
|
||||
expect(message).toEqual(`something terrible has happened. oh no. oh no.
|
||||
new AppComponent@app.component.ts:31:29
|
||||
createClass@core.umd.js:12200:20
|
||||
createDirectiveInstance@core.u`);
|
||||
});
|
||||
|
||||
it('(called with a Firefox 58 style error) should call ga with a payload based on the error object', async () => {
|
||||
const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, {
|
||||
stack: `AppComponent@https://example.com/app/app.component.ts:31:29
|
||||
createClass@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12200:20
|
||||
createDirectiveInstance@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12049:37
|
||||
createViewNodes@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13487:53
|
||||
createRootView@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13377:5
|
||||
callWithDebugContext@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14778:39
|
||||
debugCreateRootView@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14079:12
|
||||
ComponentFactory_.prototype.create@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:10998:37
|
||||
ComponentFactoryBoundToModule.prototype.create@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:3958:16
|
||||
ApplicationRef.prototype.bootstrap@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5769:40
|
||||
PlatformRef.prototype._moduleDoBootstrap/<@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5496:74
|
||||
PlatformRef.prototype._moduleDoBootstrap@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5496:13
|
||||
PlatformRef.prototype.bootstrapModuleFactory/</</<@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5417:21
|
||||
ZoneDelegate.prototype.invoke@https://example.com/packages/zone.js@0.8.18/dist/zone.js:392:17
|
||||
onInvoke@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:4665:24
|
||||
ZoneDelegate.prototype.invoke@https://example.com/packages/zone.js@0.8.18/dist/zone.js:391:17
|
||||
Zone.prototype.run@https://example.com/packages/zone.js@0.8.18/dist/zone.js:142:24
|
||||
scheduleResolveOrReject/<@https://example.com/packages/zone.js@0.8.18/dist/zone.js:873:52
|
||||
ZoneDelegate.prototype.invokeTask@https://example.com/packages/zone.js@0.8.18/dist/zone.js:425:17
|
||||
onInvokeTask@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:4656:24
|
||||
ZoneDelegate.prototype.invokeTask@https://example.com/packages/zone.js@0.8.18/dist/zone.js:424:17
|
||||
Zone.prototype.runTask@https://example.com/packages/zone.js@0.8.18/dist/zone.js:192:28
|
||||
drainMicroTaskQueue@https://example.com/packages/zone.js@0.8.18/dist/zone.js:602:25` });
|
||||
|
||||
expect(message).toEqual(`something terrible has happened. oh no. oh no.
|
||||
AppComponent@app.component.ts:31:29
|
||||
createClass@core.umd.js:12200:20
|
||||
createDirectiveInstance@core.umd.j`);
|
||||
});
|
||||
|
||||
it('(called with a Edge 16 style error) should call ga with a payload based on the error object', async () => {
|
||||
const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, {
|
||||
stack: `Error: something terrible has happened. oh no. oh no.
|
||||
at AppComponent (eval code:31:21)
|
||||
at createClass (eval code:12200:13)
|
||||
at createDirectiveInstance (eval code:12049:5)
|
||||
at createViewNodes (eval code:13487:21)
|
||||
at createRootView (eval code:13377:5)
|
||||
at callWithDebugContext (eval code:14778:9)
|
||||
at debugCreateRootView (eval code:14079:5)
|
||||
at ComponentFactory_.prototype.create (eval code:10998:9)
|
||||
at ComponentFactoryBoundToModule.prototype.create (eval code:3958:9)
|
||||
at ApplicationRef.prototype.bootstrap (eval code:5769:9)` });
|
||||
|
||||
expect(message).toEqual(`something terrible has happened. oh no. oh no.
|
||||
AppComponent@???:31:21
|
||||
createClass@???:12200:13
|
||||
createDirectiveInstance@???:12049:5
|
||||
createViewNodes@???`);
|
||||
});
|
||||
|
||||
async function callOnError(message, url, line, column, error) {
|
||||
await browser.executeScript(function() {
|
||||
// reset the ga queue
|
||||
(window as any).ga.q.length = 0;
|
||||
// post the error to the handler
|
||||
window.onerror(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
|
||||
}, message, url, line, column, error);
|
||||
const gaCalls = await page.ga();
|
||||
const exceptionCall = gaCalls.find(call => call[0] === 'send' && call[1] === 'exception');
|
||||
if (exceptionCall) {
|
||||
const payload = exceptionCall[2];
|
||||
expect(payload.exFatal).toBe(true);
|
||||
return payload.exDescription;
|
||||
}
|
||||
}
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"scripts": [
|
||||
{ "name": "ng", "command": "ng" },
|
||||
{ "name": "build", "command": "ng build --prod" },
|
||||
{ "name": "build", "command": "ng build" },
|
||||
{ "name": "start", "command": "ng serve" },
|
||||
{ "name": "test", "command": "ng test" },
|
||||
{ "name": "lint", "command": "ng lint" },
|
||||
|
@ -1,57 +1,74 @@
|
||||
# Overview
|
||||
|
||||
Many of the documentation pages contain snippets of code examples. Extract these snippets from
|
||||
Many of the documentation pages contain snippets of code examples. We extract these snippets from
|
||||
real working example applications, which are stored in subfolders of the `/aio/content/examples`
|
||||
folder. Each example can be built and run independently. Each example also provides e2e specs, which
|
||||
are run as part of our Travis build tasks, to verify that the examples continue to work as expected,
|
||||
as changes are made to the core Angular libraries.
|
||||
|
||||
In order to build, run and test these examples independently you need to install dependencies into
|
||||
In order to build, run and test these examples independently we need to install dependencies into
|
||||
their sub-folder. Also there are a number of common boilerplate files that are needed to configure
|
||||
each example's project. Maintain these common boilerplate files centrally to reduce the amount
|
||||
each example's project. We maintain these common boilerplate files centrally to reduce the amount
|
||||
of effort if one of them needs to change.
|
||||
|
||||
## Boilerplate overview
|
||||
|
||||
As mentioned, many of the documentation pages contain snippets extracted from real example applications.
|
||||
To achieve that, all those applications needs to contain a basic boilerplate. E.g. a `node_modules`
|
||||
folder, `package.json` with scripts, etc.
|
||||
folder, `package.json` with scripts, `system.js` configuration, etc.
|
||||
|
||||
No one wants to maintain the boilerplate on each example, so the goal of this tool is to provide a
|
||||
set of boilerplates that works in all the examples.
|
||||
generic boilerplate that works in all the examples.
|
||||
|
||||
### Boilerplate files
|
||||
|
||||
Inside `/aio/tools/examples/shared/boilerplate` you will find a set of folders representing each
|
||||
boilerplate.
|
||||
Inside `/aio/tools/examples/shared/boilerplate` you will see all the common boilerplate you can find
|
||||
in any Angular application using System.js. This is the boilerplate that will be carried to each example.
|
||||
|
||||
Currently you will find the next boilerplates:
|
||||
Among these files, there are a few special ones:
|
||||
|
||||
|
||||
* CLI - For CLI based examples. This is the default one, to be used in the majority of the examples.
|
||||
* systemjs - Currently in deprecation, only used in a a few examples.
|
||||
* i18n - Based on the CLI one, features a few scripts for i18n.
|
||||
* universal - Based on the cli with a extra server for universal.
|
||||
|
||||
There is also a `common` folder that contains files used in all different examples.
|
||||
* **src/systemjs.config.js** - This is the configuration of System.js used to run the example locally.
|
||||
* **src/systemjs.config.web.js** - This configuration replaces the previous one on Stackblitz.
|
||||
* **src/systemjs.config.web.build.js** - Same as the previous one but for using angular's `-builds`
|
||||
versions.
|
||||
* **src/systemjs-angular-loader.js** - It is a System.js plugin that removes the need of `moduleId`.
|
||||
* **package.json** - This package.json only contains scripts, no dependencies. It contains the
|
||||
different tasks needed to run any example. Doesn't matter if CLI, System.js or Webpack.
|
||||
* **stackblitz.json** - This file is used by the Stackblitz tool to generate a stackblitz for an example. This
|
||||
concrete file is just a placeholder. Authors needs to tweak it for each guide. More at the
|
||||
[stackblitz docs](../stackblitz-builder/README.md).
|
||||
* **example-config.json** - This file serves as a flag to indicate that the current folder is an
|
||||
example. This concrete file is just a placeholder. More on this later in this readme.
|
||||
|
||||
### The example-config.json
|
||||
|
||||
Each example is identified by an **example-config.json** configuration file in its root folder.
|
||||
This configuration file indicates what type of boilerplate this example needs. E.g.
|
||||
So what is this **example-config.json** again? If an author wants to create a new example, say
|
||||
`/aio/content/examples/awesome-example`. The author needs to create an empty `example-config.json`
|
||||
in that folder. That serves as a flag so this tool will say "Hey, that is an example, let's copy
|
||||
all the boilerplate there".
|
||||
|
||||
So when the tool runs, it finds **all** the folders with an `example-config.json` file, and puts
|
||||
a copy of the boilerplate in those folders.
|
||||
|
||||
Normally the file is empty, but we can add information in it, for example:
|
||||
|
||||
```json
|
||||
{ projectType: 'universal' }
|
||||
{
|
||||
"build": "build:cli",
|
||||
"run": "serve:cli"
|
||||
}
|
||||
```
|
||||
|
||||
If the file is empty then the default type of cli is assumed.
|
||||
When the boilerplate tooling runs, it will copy into the example folder all of the appropriate boilerplate files.
|
||||
In this case, this would indicate that this is a CLI example. Won't make any difference on the
|
||||
boilerplate, but will be useful for e2e tests (more on this later). Also works as a hint for
|
||||
the example to know how is executed.
|
||||
|
||||
|
||||
### A node_modules to share
|
||||
|
||||
With all the boilerplate files in place, the only missing piece are the installed packages. For
|
||||
that you have a `/aio/tools/examples/shared/package.json` which contains **all** the packages
|
||||
needed to run all the examples through all different boilerplates.
|
||||
that we have a `/aio/tools/examples/shared/package.json` which contains **all** the packages
|
||||
needed to run all the examples.
|
||||
|
||||
After installing these dependencies, a `node_modules` will be created at
|
||||
`/aio/tools/examples/shared/node_modules`. This folder will be **symlinked** into each example.
|
||||
@ -60,13 +77,12 @@ may require admin rights.
|
||||
|
||||
### End to end tests
|
||||
|
||||
End to end changes between boilerplates.
|
||||
Each example contains an `e2e-spec.ts` file. We can find all the related configuration files for
|
||||
e2e in the `/aio/tools/examples/shared` folder.
|
||||
|
||||
For CLI applications, create a `app.e2e-spec.ts` inside the `e2e` folder. The tooling will run
|
||||
`ng e2e` for each CLI based examples.
|
||||
|
||||
For SystemJS, each example contains an `e2e-spec.ts` file. You can find all the related configuration files
|
||||
in the `/aio/tools/examples/shared` folder.
|
||||
This tool expects all the examples to be build with `npm run build`. If an example is not built
|
||||
with that script, the author would need to specify the new build command in the `example-config.json`
|
||||
as shown earlier.
|
||||
|
||||
### example-boilerplate.js
|
||||
|
||||
|
@ -1,53 +0,0 @@
|
||||
# How to update the CLI boilerplate
|
||||
|
||||
The boilerplate is updated by hand so you normally update it every minor version unless there is a major bug to fix.
|
||||
|
||||
## Getting a new boilerplate
|
||||
|
||||
The first thing would be updating the CLI globally
|
||||
|
||||
```
|
||||
npm i -g @angular/cli
|
||||
```
|
||||
|
||||
Then create a new dummy project in a temporary folder outside angular
|
||||
|
||||
```
|
||||
ng new dummy
|
||||
```
|
||||
|
||||
Now you have a fresh application to get our new boilerplate files.
|
||||
|
||||
## Updating files
|
||||
|
||||
From `dummy` you can replace the following files into `aio/tools/examples/shared/boilerplate/cli`:
|
||||
|
||||
* tslint.json
|
||||
* tsconfig.json
|
||||
* package.json
|
||||
* protractor.conf.js
|
||||
* karma.conf.js
|
||||
* .editorconfig
|
||||
* angular-cli.json
|
||||
* src/tsconfig.spec.json
|
||||
* src/test.ts
|
||||
* src/polyfills.js
|
||||
* src/typings.d.ts
|
||||
* src/environments/environment.prod.ts
|
||||
* src/environments/environment.ts
|
||||
|
||||
### .angular-cli.json
|
||||
|
||||
Update the `project > name` to `angular.io-example`.
|
||||
|
||||
### package.json
|
||||
|
||||
Update the `name` to `angular.io-example`.
|
||||
|
||||
### src/polyfills.ts
|
||||
|
||||
Uncomment the `import 'web-animations-js';` line to enable `web-animations-js` package.
|
||||
|
||||
### src/tsconfig.app.json
|
||||
|
||||
This file is small enough and there are a few new excludes, update by hand.
|
@ -5,45 +5,46 @@
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build --prod",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^5.2.0",
|
||||
"@angular/common": "^5.2.0",
|
||||
"@angular/compiler": "^5.2.0",
|
||||
"@angular/core": "^5.2.0",
|
||||
"@angular/forms": "^5.2.0",
|
||||
"@angular/http": "^5.2.0",
|
||||
"@angular/platform-browser": "^5.2.0",
|
||||
"@angular/platform-browser-dynamic": "^5.2.0",
|
||||
"@angular/router": "^5.2.0",
|
||||
"@angular/animations": "^5.0.0",
|
||||
"@angular/common": "^5.0.0",
|
||||
"@angular/compiler": "^5.0.0",
|
||||
"@angular/core": "^5.0.0",
|
||||
"@angular/forms": "^5.0.0",
|
||||
"@angular/http": "^5.0.0",
|
||||
"@angular/platform-browser": "^5.0.0",
|
||||
"@angular/platform-browser-dynamic": "^5.0.0",
|
||||
"@angular/router": "^5.0.0",
|
||||
"angular-in-memory-web-api": "~0.5.0",
|
||||
"core-js": "^2.4.1",
|
||||
"rxjs": "^5.5.6",
|
||||
"zone.js": "^0.8.19"
|
||||
"rxjs": "^5.5.2",
|
||||
"zone.js": "^0.8.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.6.5",
|
||||
"@angular/compiler-cli": "^5.2.0",
|
||||
"@angular/language-service": "^5.2.0",
|
||||
"@types/jasmine": "~2.8.3",
|
||||
"@angular/cli": "1.5.4",
|
||||
"@angular/compiler-cli": "^5.0.0",
|
||||
"@angular/language-service": "^5.0.0",
|
||||
"@types/jasmine": "~2.8.0",
|
||||
"@types/jasminewd2": "~2.0.2",
|
||||
"@types/node": "~6.0.60",
|
||||
"codelyzer": "^4.0.1",
|
||||
"jasmine-core": "~2.8.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~2.0.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"jasmine-spec-reporter": "~4.1.0",
|
||||
"karma": "~1.7.0",
|
||||
"karma-chrome-launcher": "~2.1.1",
|
||||
"karma-cli": "~1.0.1",
|
||||
"karma-coverage-istanbul-reporter": "^1.2.1",
|
||||
"karma-jasmine": "~1.1.0",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.1.2",
|
||||
"ts-node": "~4.1.0",
|
||||
"tslint": "~5.9.1",
|
||||
"typescript": "~2.5.3"
|
||||
"ts-node": "~3.2.0",
|
||||
"tslint": "~5.7.0",
|
||||
"typescript": "~2.4.2"
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ import 'core-js/es7/reflect';
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
* Zone JS is required by Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
@ -64,3 +64,13 @@ import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Date, currency, decimal and percent pipes.
|
||||
* Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
|
||||
*/
|
||||
// import 'intl'; // Run `npm install --save intl`.
|
||||
/**
|
||||
* Need to import at least one locale-data with intl.
|
||||
*/
|
||||
// import 'intl/locale-data/jsonp/en';
|
||||
|
@ -11,9 +11,6 @@
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warn"
|
||||
},
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [
|
||||
@ -130,7 +127,6 @@
|
||||
"app",
|
||||
"kebab-case"
|
||||
],
|
||||
"no-output-on-prefix": true,
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
@ -139,6 +135,7 @@
|
||||
"use-life-cycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true
|
||||
"directive-class-suffix": true,
|
||||
"invoke-injectable": true
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user