Compare commits

..

143 Commits
5.2x ... 5.2.4

Author SHA1 Message Date
530b824faa docs: add changelog for 5.2.4 2018-02-07 10:19:39 -08:00
e22d3a605c release: cut the 5.2.4 release 2018-02-07 10:16:42 -08:00
c6645e7a04 fix(core): fix proper propagation of subscriptions in EventEmitter (#22016)
Closes #21999

PR Close #22016
2018-02-06 07:56:34 -08:00
f0396f1e54 docs(aio): fix swap value (#20905)
'http.get' has been swapped in for 'of'

PR Close #20905
2018-02-05 13:05:58 -08:00
adb1d62967 docs: clarify npm/yarn commands, add blank lines to mix md/html in table (#21606)
PR Close #21606
2018-02-05 13:02:14 -08:00
cfe83939a4 docs: update browser support (#21606)
PR Close #21606
2018-02-05 13:02:14 -08:00
973607fe9d ci: mark PRs with rejection as not green (#21922)
PR Close #21922
2018-02-05 13:01:12 -08:00
664f7fa477 build(aio): add API static members to search index (#21988)
Previously searching for `compose` did not include `Validators`
in the search results because we were not including all the
`static` members of API docs in the index.

PR Close #21988
2018-02-05 13:00:47 -08:00
b155ae116b ci: add config for g3 status (#21996)
Ref #21642
PR Close #21996
2018-02-05 12:59:59 -08:00
ce51ea93a1 fix(core): fix #20582, don't need to wrap zone in location change listener (#22007)
PR Close #22007
2018-02-05 12:59:05 -08:00
d38e08812e feat(aio): dynamically, pre-emptively, add noindex (#21992)
These tags are removed when the doc is ready and valid, but this will
allow us to block indexing in the case that the Angular app fails to
bootstrap or load the document for some non-404 reason.

This should get around the problem with hardcoded tags. See
c3fb820473

Closes #21941

PR Close #21992
2018-02-05 12:58:27 -08:00
aa9ba7f9fe fix(core): should check Zone existance when scheduleMicroTask (#20656)
PR Close #20656
2018-02-02 07:53:55 -08:00
102d06b974 docs: consistency fix in describing a custom tag (#21747)
PR Close #21747
2018-02-02 07:53:18 -08:00
11ec80a053 docs: add docs for IE (#21824)
PR Close #21824
2018-02-02 07:51:47 -08:00
75eecdc351 docs: add missing underline (#21892)
PR Close #21892
2018-02-02 07:49:33 -08:00
965eecc587 build(aio): move zip and live-example generation to yarn predocs task (#21970)
This will prevent the confusing errors for first time users who
try to generate the docs with `yarn docs` and are told there are
dangling links.

Closes #21944

PR Close #21970
2018-02-02 07:48:42 -08:00
c4fb696189 fix(common): don't convert null to a string when flushing a mock request (#21417)
A bug in TestRequest caused null response bodies to be stringified. This
change causes null to be treated faithfully.

Fixes #20744

PR Close #21417
2018-02-01 08:32:44 -08:00
72df747dd6 docs(aio): add missing closing <code-examle> tag (#21771)
PR Close #21771
2018-02-01 08:31:21 -08:00
579bed1a7a docs: add changelog for 5.2.3 2018-01-31 12:47:02 -08:00
b59fb23f4a release: cut the 5.2.3 release 2018-01-31 12:45:17 -08:00
2aa460b30e docs: add http guide sample and adjust text (#21326)
PR Close #21326
2018-01-31 10:24:43 -08:00
e0022ae9cd docs: Fix platform-detection example for Universal (#21796)
PR Close #21796
2018-01-31 10:21:04 -08:00
f2e923edd8 build(aio): upgrade to dgeni-packages 0.24.0 (#21802)
This has two benefits:

* it prepares the way for the API docs update, which need parameter docs
* it doesn't incorrectly report dangling links for non-latin anchors

Closes #21306

PR Close #21802
2018-01-31 10:20:37 -08:00
c2f5ed545c fix(common): generate closure-locale data file with exported plural functions (#21873)
Fixes #21870
PR Close #21873
2018-01-30 11:42:31 -08:00
5d75df8fb1 ci: unblock master by ignoring date pipe tests while we fix it (#21906)
PR Close #21906
2018-01-30 11:33:46 -08:00
ed2b71799c fix(common): allow HttpInterceptors to inject HttpClient (#19809)
Previously, an interceptor attempting to inject HttpClient directly
would receive a circular dependency error, as HttpClient was
constructed via a factory which injected the interceptor instances.
Users want to inject HttpClient into interceptors to make supporting
requests (ex: to retrieve an authentication token). Currently this is
only possible by injecting the Injector and using it to resolve
HttpClient at request time.

Either HttpClient or the user has to deal specially with the circular
dependency. This change moves that responsibility into HttpClient
itself. By utilizing a new class HttpInterceptingHandler which lazily
loads the set of interceptors at request time, it's possible to inject
HttpClient directly into interceptors as construction of HttpClient no
longer requires the interceptor chain to be constructed.

Fixes #18224.

PR Close #19809
2018-01-29 16:12:32 -08:00
fad99cca0e fix(forms): inserting and removing controls should work in re-bound form arrays (#21822)
Closes #21501

PR Close #21822
2018-01-29 16:11:41 -08:00
3f5ead3845 fix(aio): missing plural s in preserveWhiteSpaces example (#21854)
PR Close #21854
2018-01-29 11:35:13 -08:00
a89e709515 docs: change ”it's" to "its" as needed in several docs. (#21867)
Most of them are in content but one is in common and needs special approval.

PR Close #21867
2018-01-29 11:34:47 -08:00
6a7689d4ea build: update to latest bazel rules (#21821)
PR Close #21821
2018-01-27 10:55:45 -08:00
696ba01a4e fix(aio): don't set noindex metatag in the static index.html (#21816)
This seems to be causing crawling issues for google.

Ref #21665

PR Close #21816
2018-01-26 16:08:31 -08:00
81d64d6bec fix(core): fix retrieving the binding name when an expression changes (#21814)
fixes #21735
fixes #21788

PR Close #21814
2018-01-26 15:34:48 -08:00
7410941a7c build: merge-pr now checks that PR status is green before proceeding (#21810)
Optionally one can use `--force` to override and merge no non-green PR.

PR Close #21810
2018-01-26 14:50:41 -08:00
d159ad8b88 build(aio): prevent Windows error on serve-and-sync (#21806)
Running `yarn start` (which watches the `src/` directory) and
`yarn docs-watch` (which cleans up files in `src/generated/api/`) often
results in `ENOTEMPTY` errors.

This commit solves it by ensuring that `yarn docs` has been completed
before running `yarn start`.

PR Close #21806
2018-01-26 14:50:15 -08:00
250c8da768 fix(language-service): ensure correct paths are passed to TypeScript (#21812)
The 2.6 version of TypeScript's `resolveModuleName`  started to
require paths passed to be separated by '/' instead of being
able to handle '\'.

`ngc` and `ng` already do this transformation.

Fixes: #21811

PR Close #21812
2018-01-26 14:49:23 -08:00
778e6e759f fix(language-service): spell diagnostics correctly (#21812)
PR Close #21812
2018-01-26 14:49:23 -08:00
35a0721217 fix(router): remove @internal tag on ParamInheritanceType (#21773)
This is a more defensive approach to ensure that references to
ParamInheritanceType from the published declarations do not cause
compilation errors when compiling Angular from the published packages.

Fixes #21456

PR Close #21773
2018-01-26 10:28:34 -08:00
ba045e88d7 docs: add notes on email used for CLA (#21754)
Closes #20034

PR Close #21754
2018-01-26 10:28:18 -08:00
67806a7b25 fix(aio): close SideNav on non-sidenav doc on wide screen (#21538)
Partly addresses #21520.

PR Close #21538
2018-01-26 10:25:16 -08:00
9778a23be8 fix(aio): fix SideNav height on narrow screens (#21538)
Since we specify `bottom: 0`, specifying the height is unnecessary and
leads to wrong height (unless updated) on narrow screens where the
topbar height is decreased.

Partly addresses #21520.

PR Close #21538
2018-01-26 10:25:15 -08:00
87e06d765e ci: Add back the CLI integration test with pinning (#21555)
The CLI app is now checked in, rather than generated dynamically with
`ng new`. This loses some assertion power, but gains hermeticity.
It also checks in lock files for all integration tests, avoiding
floating version numbers.

We'll need another place to integration test between changes in
the various repositories - but the angular/angular PR-blocking status
is not the right place to do this.

PR Close #21555
2018-01-25 22:18:56 -08:00
56f3e18c1c fix(forms): allow FormBuilder to create controls with any formState type (#20917)
Align formState type in FormBuilder#control with FormControl#constructor

Fixes #20368

PR Close #20917
2018-01-25 22:17:43 -08:00
637515e71b build: autosquashes SHAs as part of merge-pr script (#21791)
To support `git checkin --fixup` and `git checkin —squash`
we need to make sure that `merge-pr` squashes the sepecial
commits before they are merged.

For more details see:
https://robots.thoughtbot.com/autosquashing-git-commits

PR Close #21791
2018-01-25 22:12:11 -08:00
27ecd077d4 docs(aio): fix missing stylesheet in component-styles example (#21772)
The code in the example was referring to `hero-app.component.css` but this did
not exist.

PR Close #21772
2018-01-25 13:38:14 -08:00
4db1be0292 docs(aio): fix paths to imported CSS stylesheets (#21772)
The AOT compiler needs relative paths so that it can find
the imported stylesheets.

PR Close #21772
2018-01-25 13:38:14 -08:00
a0dbef9ea4 build(aio): upgrade CLI version to cope with new Angular 6.0.0-beta.1 release (#21772)
Before version 1.6 of Angular CLI there was a check that prevented use of Angular
compiler CLI with major version 6.

PR Close #21772
2018-01-25 13:38:13 -08:00
3aaf43f73c docs: add changelog for 5.2.2 2018-01-24 21:26:17 -08:00
d952ae24dd release: cut the 5.2.2 release 2018-01-24 21:23:04 -08:00
da9e57b3d5 build: Update to latest rules_typescript. (#21675)
Fixes #21481

PR Close #21675
2018-01-24 20:47:41 -08:00
44d4f82dae docs(aio): added a link to Angular-RU (#21687)
Angular-RU Community on GitHub is a single point for all resources, chats, podcasts and meetups for Angular in Russia

PR Close #21687
2018-01-24 20:47:40 -08:00
bde2b4425c ci: use sudo: false on Travis (#21641)
Related to #21422.

PR Close #21641
2018-01-24 20:47:40 -08:00
2a3de802a0 fix(aio): fix code highlight in API docs templates (#21630)
Fixes #21108

PR Close #21630
2018-01-24 20:47:40 -08:00
71f9eaa743 fix(common): extract plural function from i18n locale data files for TS 2.6 (#21626)
Fixes #21608

PR Close #21626
2018-01-24 20:47:40 -08:00
a62c186d15 fix(common): don't remove special characters when extracting CLDR data (#21626)
PR Close #21626
2018-01-24 20:47:40 -08:00
c8bf281174 build(aio): generate sitemap from the generated pages (#21689)
Closes #21684

PR Close #21689
2018-01-24 20:47:40 -08:00
de6c6445af fix(compiler): Don't strip /*# sourceURL ... */ (#16088)
Currently, `shimCssText` only keep `/*# sourceMappingUrl ... */` comments and strip `/*# sourceURL ... */` comments. So, Chrome can't find the source maps for component style(that's created in new `style` tags)

PR Close #16088
2018-01-24 12:35:31 -08:00
54238822e6 build: merge PR to all branches per target: label (#21739)
PR Close #21739
2018-01-24 12:35:13 -08:00
8b3fbb5bf4 fix(router): don't use ParamsInheritanceStrategy in declarations (#21574)
ParamsInheritanceStrategy is internal, so any references to it from the
published .d.ts files will fail.

Fixes #21456.

PR Close #21574
2018-01-23 21:34:37 -08:00
2f61d3c320 fix(aio): remove remaining plnkr references (#20165)
PR Close #20165
2018-01-23 21:33:55 -08:00
5894f6ee1c build(aio): check for obsolete plnkr.json and missing main files (#20165)
Also, remove `plnkr.json` for `service-worker-getting-started` guide,
since it is not used and ServiceWorker cannot work correctly in
plnkr/stackblitz anyway (e.g. no build step to re-compute hashes).
A zipper might be useful and can be added in a subsequent PR, but it is
currently broken (e.g. no dependency on `@angular/service-worker`).

PR Close #20165
2018-01-23 21:33:55 -08:00
6d9fcd62de build(aio): upgrade sample package.json files to jasmine@~2.8.0 (#20165)
- Update tooling to support revised testing guide (PR #20697).
- Require jasmine upgrade for examples that use marble testing.
- Copy `cli/package.json` to `testing/` and add `jasmine-marbles`.
- Resolve merge conflicts created by `NgModules` guides.

PR Close #20165
2018-01-23 21:33:55 -08:00
0cbccc06dd build(aio): migrate plunker to stackblitz (#20165)
PR Close #20165
2018-01-23 21:33:52 -08:00
ed670a36fb docs: update ICU select messages to use male/female (#21713)
fixes #21694

PR Close #21713
2018-01-23 16:32:24 -08:00
8e44577df3 fix(compiler): fix ICU select messages to use male/female/other (#21713)
related to #21694

PR Close #21713
2018-01-23 16:32:24 -08:00
6921c20ea1 test(forms): Better description and coverage for #19256 (#21652)
fixes #21575

PR Close #21652
2018-01-23 16:31:45 -08:00
52970c09e1 fix(compiler-cli): do not fold errors past calls in the collector (#21708)
Folding errors passed calls prevented the static reflector from
begin able to ignore errors in annotations it doesn't know as
the call to the unknown annotation was elided from the metadata.

Fixes: #21273

PR Close #21708
2018-01-23 13:33:26 -08:00
eecdf3414e docs: fix #19989, add zone flags(blacklist/module) in guide (#21701)
PR Close #21701
2018-01-23 13:33:11 -08:00
21f766968d refactor(bazel): pass around tsconfig as a file, not a path (#21614)
this unlocks the ability to replay ts compilations with different settings

PR Close #21614
2018-01-23 10:06:05 -08:00
4b68fdce6f build: Update to latest rules_typescript. (#21675)
Fixes #21481

PR Close #21675
2018-01-22 15:34:48 -08:00
c12ea3a1f0 fix(common): A null value should remove the style on IE (#21679)
fixes #21064

PR Close #21679
2018-01-22 12:57:23 -08:00
d7dbdc5c36 docs: fix stray div and reformat paragraph (#21676)
PR Close #21676
2018-01-19 20:42:04 -08:00
0112a903f9 ci: add github bot config to triage issues (#21672)
Fixes #21635
PR Close #21672
2018-01-19 20:41:15 -08:00
66bbc84127 ci(aio): do not limit size of gzip7 and gzip 9 (#21601)
PR Close #21601
2018-01-19 20:41:01 -08:00
554129d6fe feat(aio): update metatags to control search engine crawling (#21665)
The `<meta name="robots" content="noindex">` tag is used
to indicate to search engine crawlers that they should not index
the current page. This is set dynamically by the the document
viewer component to ensure that 404 and other erroring pages
are not added to the search index.

This relies upon the idea that the crawling bot will run the JS
and wait to see if this meta tag has been added or not.

Since we believe that the `googebot` will do this, we also
pre-emptively add a hard-coded noindex tag specifically for
this bot, so that if anything else fails in bootstrapping the app,
the failed page will not be added to the index.

Closes #21317

PR Close #21665
2018-01-19 20:31:45 -08:00
e32a0cabfe fix(aio): add a required comma in firebase.json (#21618)
PR Close #21618
2018-01-19 20:31:30 -08:00
c828e5627b build: Remove angular_src nested workspace (#21096)
PR Close #21096
2018-01-19 13:10:09 -08:00
1626e74c59 docs: clarify the use of classes and interfaces in style guide (#20919)
PR Close #20919
2018-01-19 13:09:58 -08:00
a15a2b46d1 ci: add "PR action: cleanup" to the bot's forbiddenLabels list (#21562)
PR Close #21562
2018-01-19 13:09:41 -08:00
379ed75593 docs: improve/simplify example for providers guide (#21589)
PR Close #21589
2018-01-19 13:09:31 -08:00
0f619896b3 docs: fix/improve example for singleton-services guide (#21589)
PR Close #21589
2018-01-19 13:09:31 -08:00
7060655806 docs: several minor NgModule guide fixes/improvements (#21589)
PR Close #21589
2018-01-19 13:09:31 -08:00
b5fc3eb9de docs: minor fixes (anchor tags, redundant whitespace, consistent code-snippets lang) (#21589)
PR Close #21589
2018-01-19 13:09:31 -08:00
451bdb9a75 docs: change titles to sentence case (#21620)
PR Close #21620
2018-01-19 13:09:25 -08:00
983ccc02ad build(aio): fix zips testing commands (#21629)
PR Close #21629
2018-01-19 13:09:17 -08:00
00f99b3c4c ci: update github bot messages (#21634)
Fixes #21633
PR Close #21634
2018-01-19 13:09:11 -08:00
ba4ea82f68 fix(compiler-cli): do not lower expressions in non-modules (#21649)
Fixes: #21651

PR Close #21649
2018-01-19 13:09:04 -08:00
982eb7bba8 fix(common): fallback to last defined value for named date and time formats (#21299)
closes #21282

PR Close #21299
2018-01-19 13:08:57 -08:00
3606c55410 docs: edit entry component FAQ (#21487)
PR Close #21487
2018-01-19 13:08:50 -08:00
2c65027391 docs: add server side redirect and fix NgModule FAQ links (#21487)
PR Close #21487
2018-01-19 13:08:50 -08:00
4ee92f14a6 docs: fix lazy loading example dir name (#21475)
PR Close #21475
2018-01-19 13:08:30 -08:00
c9b65914d3 build: add mhevery to bazel approvers (#21314)
PR Close #21314
2018-01-19 13:08:19 -08:00
02352bcd9e fix(compiler): add support for marker tags in xliff serializers (#21250)
The Xliff serializer now supports the tags `seg-source` and `mrk`, while the Xliff2 serializer now supports `mrk`.
Fixes #21078
PR Close #21250
2018-01-19 13:08:10 -08:00
0d55600fd8 Revert "fix(core): fix chained http call (#20924)"
This reverts commit 54e75766ad.
2018-01-19 13:06:33 -08:00
af4eb00c91 docs: add changelog for 5.2.1 2018-01-17 09:39:46 -08:00
d3e7ebb3b4 release: cut the 5.2.1 release 2018-01-17 09:37:50 -08:00
420f5c4275 build(bazel): remove spurious file (#21455)
PR Close #21455
2018-01-17 08:24:34 -08:00
b773a4ab98 docs(aio): change df-question to app-question (#21438)
closes: #21404
PR Close #21438
2018-01-17 07:20:52 -08:00
55f15c54d9 docs(aio): add description and docs links for code samples (#21561)
PR Close #21561
2018-01-17 07:19:37 -08:00
4556532c26 feat(core): add binding name to content changed error (#20352)
Adding the binding name to the error message recieved by the user gives
extra context on what exactly changed. The tests are also updated to
reflect the new error message.

PR Close #20352
2018-01-17 07:17:00 -08:00
54e75766ad fix(core): fix chained http call (#20924)
Fixes an issue where chained http calls would prematurely call
testability whenStable callbacks after the first http call.

Fixes #20921

PR Close #20924
2018-01-17 07:14:55 -08:00
d3333f04ba refactor(core): refactor WrappedValue (#20997)
- Improve `WrappedValue` by adding `unwrap` symetrical to `wrap`.
- remove dead code - `ValueUnwrapper`

The property `wrapped` is an implementation details and should never be accessed
directly - use `unwrap(wrappedValue)`. Will change to protected in Angular 7.

PR Close #20997
2018-01-16 07:13:24 -08:00
75f8522b8d feat(forms): handle string with and without line boundary on pattern validator (#19256)
PR Close #19256
2018-01-16 07:12:14 -08:00
a771ee5d90 build(aio): move file cleaning to later in the doc gen (#21540)
Previously the generated files were cleaned out before
doc-gen began (via a yarn pre-script). This can cause a
race condition in the CLI server, which prevents the new
generated files from being picked up.

Now we delay the cleaning until the last minute to ensure
that they ar still picked up by the webpack server.

PR Close #21540
2018-01-16 07:11:01 -08:00
a4cbe3542a ci: disable integration/cli-hello-world test (#21492)
it is non-hermetic and breaks often due to unpinned dependencies.

PR Close #21492
2018-01-12 14:57:45 -08:00
cc9419d1ca fix(language-service): Clear caches when program changes (#21337)
This commit fixes a bug whereby the caches are not cleared when the
program changes. This subsequently produces the incorrect error of
'Component ... is not included in a module ...'.

PR Close #19405

PR Close #21337
2018-01-12 14:43:34 -08:00
d5393c7f91 docs(compiler): document the $any type cast function (#20968)
Closes #20966

PR Close #20968
2018-01-12 14:38:42 -08:00
71dd92bbb8 style(aio): enforce strict TypeScript checks (#21342)
Closes #20646

PR Close #21342
2018-01-12 14:37:02 -08:00
977978edb5 test(common): make date pipe tests work in more timezones (#21379)
Fixes #21112
PR Close #21379
2018-01-12 13:50:06 -08:00
eb70966065 fix(aio): correctly handle redirects (#21416)
- Fixes handling of some redirects by the ServiceWorker.
- Fixes redirect for old `NgFor` to new `NgForOf` URL.

Fixes #21318

PR Close #21416
2018-01-12 13:49:10 -08:00
cf4bea587d ci(aio): run e2e tests in production mode (#21470)
This will enable catching errors introduced by build optimizations that
do not appear in `development` mode.

Fixes #21446

PR Close #21470
2018-01-12 13:46:00 -08:00
8e9cd57951 fix(common): set correct timezone for ISO8601 dates in Safari (#21506)
Fixes #21491
PR Close #21506
2018-01-12 13:21:11 -08:00
f23896f519 docs: fix release schedule date (#21474)
PR Close #21474
2018-01-12 12:10:26 -08:00
0e59d18fc2 ci: add angular robot config file (#21489)
PR Close #21489
2018-01-12 10:12:28 -08:00
54c8a321a9 ci: update pullapprove rules now that we allow selfapprovals (#21494)
PR Close #21494
2018-01-12 10:11:37 -08:00
9005a6f3cd feat(aio): implement survey notification link (#21371)
Closes #21094

PR Close #21371
2018-01-12 10:06:08 -08:00
3c6a5063f7 fix(benchpress): should still support selenium_webdriver < 3.6.0 (#21477)
PR Close #21477
2018-01-11 10:54:11 -08:00
b49d54e606 docs(forms): clarify note in reactive forms doc (#21134)
PR Close #21134
2018-01-11 07:04:15 -08:00
55fd82e587 docs: fix release schedule date (#21469)
PR Close #21469
2018-01-11 06:45:49 -08:00
7f3d0bbf97 build: update polyfill size (#21461)
PR Close #21461
2018-01-10 17:07:32 -08:00
3db02d244a docs: fix lazy-loading example (#20306)
PR Close #20306
2018-01-10 16:26:28 -08:00
50b605686e docs: fix yarn.lock (#20306)
PR Close #20306
2018-01-10 16:26:28 -08:00
64d4aafbc7 docs(aio): add NgModule docs (#20306)
PR Close #20306
2018-01-10 16:26:28 -08:00
a931a419fa fix(compiler): make .ngsummary.json files idempotent (#21448)
Fixes: #21432

PR Close #21448
2018-01-10 16:21:32 -08:00
6a97b5b722 docs(ivy): add Ivy as a recognized label (#21428)
PR Close #21428
2018-01-10 15:32:59 -08:00
aad1126446 docs: update the release schedule with v6 info (#21435)
Fixes #20649

PR Close #21435
2018-01-10 15:20:27 -08:00
7b463df52b fix(aio): preserve static Observable methods (#21351)
PR Close #21351
2018-01-10 14:30:42 -08:00
a2432c9f10 build(aio): turn on namedChunks option to make debugging, profiling and tracking easier (#21351)
PR Close #21351
2018-01-10 14:30:42 -08:00
e500484ccc build(aio): upgrade to angular@5.2.0 (#21351)
-rw-r--r--  1 iminar  eng   72498 Jan  9 22:20 dist/0.0d2802b63e9f4f4615cd.chunk.js
-rw-r--r--  1 iminar  eng   14872 Jan  9 22:20 dist/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1558 Jan  9 22:20 dist/inline.cb4b7a639193fc489d3b.bundle.js
-rw-r--r--  1 iminar  eng  454654 Jan  9 22:20 dist/main.b65f32ffc92e075e64e0.bundle.js
-rw-r--r--  1 iminar  eng   40264 Jan  9 22:20 dist/polyfills.87edf5d695f14a29bf91.bundle.js
-rw-r--r--  1 iminar  eng   54001 Jan  9 22:20 dist/worker-basic.min.js

PR Close #21351
2018-01-10 14:30:42 -08:00
a0dcb0b828 ci(aio): track sizes of all js files (#21351)
PR Close #21351
2018-01-10 14:30:42 -08:00
c4b71920d1 build(aio): upgrade to angular@5.2.0-rc.0 (#21351)
Because of c2b3792 one of the test assertions had to be adjusted (more info: https://github.com/angular/angular/pull/21351#issuecomment-356083940).

PR Close #21351
2018-01-10 14:30:42 -08:00
650f5fb5c7 build(bazel): fix merge conflict between c4f02e2 and ef956a2 (#21453)
PR Close #21453
2018-01-10 12:57:38 -08:00
c32e83334b fix(compiler): cache external reference resolution (#21359)
Cache reference resolution for external references as finding
the declaration of a symbol is expensive and does not change
for a program once created.

This resolves a signficant performance regression in the langauge
service.

PR Close #21359
2018-01-10 12:34:07 -08:00
7bdd9aecbd build: upgrade yarn to 1.3.2 (#21406)
Fixes #20566
PR Close #21406
2018-01-10 12:32:47 -08:00
5ede67c345 build: move repeated tsconfig attributes to a macro (#20964)
This helps ensure we use the same tsconfig.json file for all compilations.
Next steps are to make it the same tsconfig.json file used by the editor

PR Close #20964
2018-01-10 12:30:44 -08:00
31b671ab54 fix(aio): support multibyte character in heading (#21414)
PR Close #21414
2018-01-10 12:25:45 -08:00
3804d20b6d docs(bazel): document an installation issue (#21401)
observed by Igor on a Mac

PR Close #21401
2018-01-10 12:24:03 -08:00
0a5a87887e build(aio): upgrade to uglify-es@3.3.5 (#21350)
This should fix the size regression spotted via the previous commit.

-rw-r--r--  1 iminar  eng   72498 Jan  8 00:03 dist/0.86a7a08f7866e6cdc36f.chunk.js
-rw-r--r--  1 iminar  eng   14872 Jan  8 00:03 dist/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1558 Jan  8 00:03 dist/inline.7722895d8c844f710bcd.bundle.js
-rw-r--r--  1 iminar  eng  453905 Jan  8 00:03 dist/main.faff0e2da95443f759f5.bundle.js
-rw-r--r--  1 iminar  eng   40264 Jan  8 00:03 dist/polyfills.87edf5d695f14a29bf91.bundle.js
-rw-r--r--  1 iminar  eng   54001 Jan  8 00:03 dist/worker-basic.min.js

PR Close #21350
2018-01-10 12:22:12 -08:00
c46afce0f5 build(aio): upgrade to @angular/cli@1.6.3 (#21350)
This change introduces a size regression of 9kb for main.js :-(

I filed an issue for this: https://github.com/angular/angular-cli/issues/9108

-rw-r--r--  1 iminar  eng   72546 Jan  5 19:27 dist.cli-1.6.3/0.86a7a08f7866e6cdc36f.chunk.js
-rw-r--r--  1 iminar  eng   14893 Jan  5 19:27 dist.cli-1.6.3/4.c719ac5645940382cdce.chunk.js
-rw-r--r--  1 iminar  eng    1558 Jan  5 19:27 dist.cli-1.6.3/inline.7722895d8c844f710bcd.bundle.js
-rw-r--r--  1 iminar  eng  466484 Jan  5 19:27 dist.cli-1.6.3/main.faff0e2da95443f759f5.bundle.js
-rw-r--r--  1 iminar  eng   40363 Jan  5 19:27 dist.cli-1.6.3/polyfills.87edf5d695f14a29bf91.bundle.js
-rw-r--r--  1 iminar  eng   54001 Jan  5 19:27 dist.cli-1.6.3/worker-basic.min.js

PR Close #21350
2018-01-10 12:22:12 -08:00
76c781fd37 docs(router): remove extra brackets (#21294)
PR Close #21294
2018-01-10 12:20:48 -08:00
51eb3d418e fix(service-worker): properly handle invalid hashes in all scenarios (#21288)
When the SW fetches URLs listed in a manifest with hashes, it checks
the content hash against the manifest to make sure it has the correct
version of the URL. In the event of a mismatch, the SW is supposed to
consider the manifest invalid, and avoid using it. There are 3 cases
to consider by which this can happen.

Case 1: during the initial SW installation, a manifest is activated
without waiting for every URL to be fully loaded. In the background,
every prefetch URL listed by the manifest is requested and cached.
One such prefetch request could fail the hash test, and cause the
manifest to be treated as invalid. In such a case, the SW should
enter a state of EXISTING_CLIENTS_ONLY, as the latest manifest is
invalid.

This case works today.

Case 2: during the initial SW installation, as in Case 1, a manifest
is activated without waiting for each URL to fully load. However,
it's possible that the application could request a URL with a bad
hash before background initialization tries to load that URL. This
happens if, for example, the application has a broken index.html.

In this case, the SW should enter a state of EXISTING_CLIENTS_ONLY,
and serve the request from the network instead.

What happens today is that the internal error escapes the SW and
is returned as a rejected Promise to respondWith(), causing a
browser-level error that the site cannot be loaded, breaking the
site.

This change allows the SW to detect the error and enter the correct
state, falling back on the network if needed.

Case 3: during checkForUpdate(), the SW will try to fully cache the
new update before making it the latest version. Failure here is
complicated - if the page fails to load due to transient network
conditions (timeouts, 500s, etc), then it makes sense to continue
serving the existing cached version, and attempt to activate the
update on the next cycle.

If the page fails due to non-transient conditions though (400 error,
hash mismatch, etc), then the SW should consider the updated
manifest invalid, and enter a state of EXISTING_CLIENTS_ONLY.

Currently, all errors are treated as transient.

This change causes the SW to treat all errors during updates as
non-transient, which can cause the SW to unnecessarily enter a
safe mode. A future change can allow the SW to remain in normal mode
if the error is provably transient.

PR Close #21288
2018-01-10 12:18:55 -08:00
48c18985cc fix(animations): fix increment/decrement aliases example (#18323)
PR Close #18323
2018-01-10 12:07:24 -08:00
167cbed266 build: add bazel rulse for benchmarks (#21436)
PR Close #21436
2018-01-10 12:01:17 -08:00
70e8802540 docs(core): provide note for unit test changes with the ng-star-inserted className (#21450)
PR Close #21450
2018-01-10 11:14:28 -08:00
1054 changed files with 6421 additions and 35947 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -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:"

View File

@ -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

View File

@ -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

View File

@ -32,7 +32,6 @@ filegroup(
"reflect-metadata",
"source-map-support",
"minimist",
"tslib",
] for ext in [
"*.js",
"*.json",

View File

@ -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)

View File

@ -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.

View File

@ -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",
)

View File

@ -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": {

View File

@ -15,7 +15,6 @@ describe('Form Validation Tests', function () {
});
tests('Template-Driven Form');
bobTests();
});
describe('Reactive form', () => {

View File

@ -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)

View File

@ -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 -->

View File

@ -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 ]
})

View File

@ -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>

View File

@ -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', () => {

View File

@ -51,7 +51,7 @@
}
/* #docregion additions */
button {
.button {
background-color: #eee;
border: none;
padding: 5px 10px;

View File

@ -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.

View File

@ -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=&quot;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">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">NgModuleFactory</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;</span></a><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAsync"><span class="pln">compileModuleAsync</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun">&lt;</span><span class="typ">NgModuleFactory</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;&gt;</span></a><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsSync"><span class="pln">compileModuleAndAllComponentsSync</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">ModuleWithComponentFactories</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;</span></a><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsAsync"><span class="pln">compileModuleAndAllComponentsAsync</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun">&lt;</span><span class="typ">ModuleWithComponentFactories</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;&gt;</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">&lt;</span><span class="pln">any</span><span class="pun">&gt;)</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>

View File

@ -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.

View File

@ -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>&lt;div <b>[ngStyle]</b>="{'property': 'value'}"&gt;</code><br><code>&lt;div <b>[ngStyle]</b>="dynamicStyles()"&gt;</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">

View File

@ -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 doesnt 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.

View File

@ -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>

View File

@ -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">

View File

@ -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

View File

@ -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"

View File

@ -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.

View File

@ -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'>

View File

@ -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` decorators `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` isnt being in their own file, like JavaScript modules; its the presence of `@NgModule` and its metadata.
NgModules are classes decorated with `@NgModule`. The `@NgModule` decorators `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` isnt being in their own file, like JavaScript modules; its 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).

View File

@ -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.

View File

@ -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">

View File

@ -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, its 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, its 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

View File

@ -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>

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -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/"
}
]

View File

@ -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">

View File

@ -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">

View File

@ -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/"
}
}
}

View File

@ -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",

View File

@ -29,7 +29,7 @@ and annotate the component class with `@Component`.
The CLI generated three metadata properties:
1. `selector`&mdash; the component's CSS element selector
1. `selector`&mdash; the components CSS element selector
1. `templateUrl`&mdash; the location of the component's template file.
1. `styleUrls`&mdash; the location of the component's private CSS styles.

View File

@ -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`

View File

@ -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>

View File

@ -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());
}

View File

@ -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();
});

View File

@ -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();

View File

@ -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": [
{

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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() {

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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

View File

@ -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', () => {

View File

@ -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 {

View File

@ -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));
}

View File

@ -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];
}
}

View File

@ -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()">

View File

@ -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

View File

@ -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);
}
}

View File

@ -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');
}

View File

@ -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[]) {

View File

@ -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);
});
});
});

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}

View File

@ -12,4 +12,3 @@
@import 'sidenav';
@import 'table-of-contents';
@import 'top-menu';
@import 'print-layout';

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}
}

View File

@ -30,4 +30,3 @@
@import 'select-menu';
@import 'deploy-theme';
@import 'notification';
@import 'label';

View File

@ -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) {

View File

@ -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);
}

View File

@ -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

View File

@ -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}`);
}
});
}

View File

@ -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?:\/)?\/.*/);
});
});
});
});
});

View File

@ -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();
});
});

View File

@ -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;
}
}
});

View File

@ -1,14 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View File

@ -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" },

View File

@ -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

View File

@ -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.

View File

@ -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"
}
}

View File

@ -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';

View File

@ -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
}
}

View File

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