Compare commits
323 Commits
6.0.0-rc.3
...
4.4.5
Author | SHA1 | Date | |
---|---|---|---|
912068e71c | |||
df8e57dc5d | |||
f27f6e498f | |||
01bfbcb84a | |||
a15abbb324 | |||
28c29d560e | |||
65ca7fd4aa | |||
3e3f918bb3 | |||
fc1dcffbdd | |||
ee3c681f98 | |||
6225fedcb8 | |||
2905069559 | |||
47202dd747 | |||
fb130c4eae | |||
734378c90b | |||
3959b7ef28 | |||
e292548523 | |||
c2506a78a1 | |||
34f70c6de2 | |||
3d9c2a6352 | |||
3232125650 | |||
c9f8718d2a | |||
f89ac92e5e | |||
f82efcf942 | |||
dc22f4dc69 | |||
173ccf03ab | |||
1d5c3c1c9b | |||
e4dac421db | |||
c639cdd3b3 | |||
5bcfa7cdfe | |||
d8fd892e71 | |||
074a997302 | |||
62616f541a | |||
156442f80d | |||
37112f549a | |||
cf4b4d53ba | |||
d45e3aa433 | |||
ccc25ee901 | |||
3052063c05 | |||
e107322f5c | |||
f0774254de | |||
6c66031c4a | |||
8f668807cf | |||
f98eb35179 | |||
cc8ae32503 | |||
95f3b1dbe6 | |||
6b96b069bf | |||
ecfe85b06c | |||
5439d4cd49 | |||
df91fd032d | |||
2d5ef15e08 | |||
544a7ad0a5 | |||
ec2c1bec4a | |||
e064d2607d | |||
d489ad595d | |||
0a3753bcce | |||
7fc2dceaf5 | |||
c3b39bac52 | |||
2cd88bfb0f | |||
0cefb0b79b | |||
55a7443974 | |||
f9ebaf1b90 | |||
bc81fbdd27 | |||
c7aa8a132d | |||
5c99b01512 | |||
992ba33a28 | |||
17e7c58981 | |||
b8f15d2b77 | |||
5f9a10aab9 | |||
04bc5257a6 | |||
5bca58e748 | |||
526a67f8f4 | |||
53a27e07b1 | |||
ba0fb1e055 | |||
ed2c8aa6f8 | |||
9226760120 | |||
b9ee8b46a0 | |||
e7eb0b8b7c | |||
ae52851458 | |||
e63cf3b89e | |||
9624fda082 | |||
e19b6a8f38 | |||
2aa6b54201 | |||
fe8550d278 | |||
e2e8ba6ffa | |||
60cdf9dc38 | |||
0371538d10 | |||
351331a81b | |||
0a54713f8a | |||
49d122e560 | |||
ff8729423e | |||
0c72f7d358 | |||
818f4a751e | |||
4e7d2bd5bf | |||
395ac510f7 | |||
b20c5d2c37 | |||
ea02b1ccfa | |||
0bafd03e85 | |||
e8d1858c64 | |||
d1efc5ae90 | |||
86f7b4170c | |||
9d93c859d7 | |||
5baa069b16 | |||
12b7d00747 | |||
d777d79c61 | |||
062a772e48 | |||
3618cc6d34 | |||
9413ca8a2e | |||
1302e54947 | |||
edf423af3d | |||
37086748bf | |||
6c3f1f70ba | |||
8a8c4d37aa | |||
f6a7183c52 | |||
c86e16db5f | |||
c3907893c1 | |||
d61c6f996a | |||
bd04cd61f8 | |||
96dcfafe45 | |||
991a802a8e | |||
48ae1a6574 | |||
dd2d1be006 | |||
5369de80d6 | |||
552dbfc2f1 | |||
0aa4cbdbc8 | |||
9f16c2620c | |||
9b256a9144 | |||
0f1476be33 | |||
769b2aada2 | |||
301236e1a5 | |||
aeb98dbcdf | |||
8036d05412 | |||
7d137d7f88 | |||
b8b551cf2b | |||
7ec28fe9af | |||
1cc3fe21b6 | |||
ba7d70e5e0 | |||
497e0178cc | |||
8821723526 | |||
a203a959ae | |||
dfe2bad663 | |||
f09a266e01 | |||
3853fff795 | |||
641be64544 | |||
bcf211bdb3 | |||
ee5591d583 | |||
1f43713506 | |||
325b9b4562 | |||
88abdbd50b | |||
14d34c9bdf | |||
e1f45a33b7 | |||
9a754f9f0f | |||
c3dcbf9cb3 | |||
5d68c830d2 | |||
ac58914b97 | |||
77ebd2b020 | |||
fec3b1a0e9 | |||
3b571a4f3d | |||
efee81eb57 | |||
a7a698c36f | |||
b5f1dc32d1 | |||
eef28144ce | |||
f9b290570e | |||
4852f55875 | |||
793f31b9b3 | |||
7e94405271 | |||
6076a8d7bb | |||
a1624f217c | |||
b2f4d53bf0 | |||
7662cefe6f | |||
1cb607697a | |||
1990c3c722 | |||
b589d85d6f | |||
03ec3a2169 | |||
a5baed6b97 | |||
259fc91305 | |||
a618d6e4ce | |||
b315a84ba0 | |||
972538be7a | |||
d7be4f12b5 | |||
b9c1c913c1 | |||
06e479ff66 | |||
0065868f37 | |||
77fa3c3e48 | |||
f4cb45345d | |||
9329bfb86a | |||
3efc88fb81 | |||
954b09022a | |||
71f5e78bcb | |||
f0c3ed0f14 | |||
c8fd3f5237 | |||
e0660b1b72 | |||
5a165ebcef | |||
3212f8c826 | |||
c421ccaae9 | |||
bbec7db7ba | |||
00134ae4e0 | |||
07bd459baa | |||
302adf1081 | |||
1a6a13425b | |||
072a772ca6 | |||
5f0e0a46fd | |||
c7b72aa575 | |||
732eb61957 | |||
e7e7622971 | |||
4176832266 | |||
71de92a189 | |||
e0021d4cf5 | |||
4e44102e31 | |||
111b70d108 | |||
5e4054b8f3 | |||
5afc7abcb0 | |||
65d0888708 | |||
adfd2373b8 | |||
3a82af3bde | |||
3af62306b4 | |||
afe339396f | |||
c4b51bf689 | |||
b65fe3e44e | |||
116ee334fb | |||
dbc5c5817a | |||
baf4ce0dd0 | |||
24db1ed938 | |||
82798e9d04 | |||
da8bb1b45b | |||
f5cbc2ee25 | |||
cbc1986c6f | |||
0982f993cb | |||
a5a29b0591 | |||
a8f3197f24 | |||
e6f37120fe | |||
6840b7bda9 | |||
68f458909a | |||
12acecf756 | |||
cfbed40ab6 | |||
fe1a6b8e42 | |||
13e29c4e89 | |||
fd52b178ed | |||
ca1f071b2e | |||
296adbbb72 | |||
c795ee1176 | |||
b550618afd | |||
d08d6eebff | |||
e9789abd05 | |||
f2ec2cbb99 | |||
8de2ace80a | |||
c977994864 | |||
12b8e1af55 | |||
9a188485f5 | |||
45a10419bc | |||
2245748c14 | |||
bcea196530 | |||
b9e32c833a | |||
be49e0ee93 | |||
bf95655a1a | |||
6bf5b84fa4 | |||
4836565ca7 | |||
750e4e8156 | |||
a0846194b7 | |||
bcf6b90c95 | |||
3ca2a0aa37 | |||
b4be96c65d | |||
434ff5fecb | |||
a1bb9c2d42 | |||
7e626bef0a | |||
a1e83a8ed2 | |||
cbeb197aa5 | |||
0330fa6b82 | |||
97135e8fd5 | |||
35bd07fc7b | |||
a8ac77b645 | |||
9ecd377a51 | |||
76171bd8b4 | |||
1f106d75bc | |||
a4fae8c405 | |||
33c07b3394 | |||
c9d06e676f | |||
c7c65d9fda | |||
257a9e3e6f | |||
c7c0a1688e | |||
7e95e2b0ba | |||
ddc286f4b5 | |||
3d17a3672e | |||
61d253f5fd | |||
54be25a7a1 | |||
b1757037fb | |||
f0476fcff0 | |||
a5c4bb5b96 | |||
4c1f32b0db | |||
383d8969ab | |||
333ffd8d32 | |||
d4679a0bc2 | |||
4ce29f3a5b | |||
17b7bc3e06 | |||
f19bd5f4f3 | |||
d503d25f29 | |||
5d275e994a | |||
d8c8b13bb8 | |||
4671168635 | |||
1ac78bfd5d | |||
4340beacea | |||
ec89f378fc | |||
4dd6863bc2 | |||
37c626e673 | |||
f0a110928b | |||
c39e7d1eb2 | |||
799bffb431 | |||
fda607cc2f | |||
cc3aa68123 | |||
306621d2d6 | |||
d204f7aa2a | |||
a94f5e8cbb | |||
1390afef23 | |||
b0346a6e45 | |||
e5da059994 | |||
ac92c3bb26 | |||
87157d7089 | |||
611dd12f0f | |||
969ce9dc2b | |||
34834a9e79 | |||
6e2ddccc2c | |||
55742e4737 | |||
0091b1e8db |
6
.bazelrc
Normal file
6
.bazelrc
Normal file
@ -0,0 +1,6 @@
|
||||
# Disable sandboxing because it's too slow.
|
||||
# https://github.com/bazelbuild/bazel/issues/2424
|
||||
build --spawn_strategy=standalone
|
||||
|
||||
# Performance: avoid stat'ing input files
|
||||
build --watchfs
|
@ -1,39 +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
|
||||
|
||||
# Print all the options that apply to the build.
|
||||
# This helps us diagnose which options override others
|
||||
# (e.g. /etc/bazel.bazelrc vs. tools/bazel.rc)
|
||||
build --announce_rc
|
||||
|
||||
# Create dist/bin symlink to $(bazel info bazel-bin)
|
||||
# We use this when uploading artifacts after the build finishes
|
||||
build --symlink_prefix=dist/
|
||||
|
||||
# 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
|
||||
|
||||
# Save downloaded repositories such as the go toolchain
|
||||
# This directory can then be included in the CircleCI cache
|
||||
# It should save time running the first build
|
||||
build --experimental_repository_cache=/home/circleci/bazel_repository_cache
|
||||
|
||||
# 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 "xlarge" class
|
||||
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
|
||||
build --local_resources=14336,8.0,1.0
|
||||
|
||||
# Retry in the event of flakes, eg. https://circleci.com/gh/angular/angular/31309
|
||||
test --flaky_test_attempts=2
|
@ -7,32 +7,17 @@
|
||||
# To validate changes, use an online parser, eg.
|
||||
# http://yaml-online-parser.appspot.com/
|
||||
|
||||
# Variables
|
||||
|
||||
## IMPORTANT
|
||||
# If you change the `docker_image` version, also change the `cache_key` suffix and the version of
|
||||
# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file.
|
||||
var_1: &docker_image angular/ngcontainer:0.1.0
|
||||
var_2: &cache_key v2-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
|
||||
docker:
|
||||
- image: *docker_image
|
||||
- image: angular/ngcontainer:0.0.2
|
||||
|
||||
# After checkout, rebase on top of master.
|
||||
# Similar to travis behavior, but not quite the same.
|
||||
# See https://discuss.circleci.com/t/1662
|
||||
anchor_2: &post_checkout
|
||||
post: git pull --ff-only origin "refs/pull/${CIRCLE_PULL_REQUEST//*pull\//}/merge"
|
||||
post: git pull --ff-only origin "refs/pull/${CI_PULL_REQUEST//*pull\//}/merge"
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
@ -41,77 +26,26 @@ jobs:
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
|
||||
# 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
|
||||
key: angular-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
|
||||
- run: yarn install --frozen-lockfile --non-interactive
|
||||
- run: yarn install --freeze-lockfile --non-interactive
|
||||
- run: ./node_modules/.bin/gulp lint
|
||||
|
||||
build:
|
||||
<<: *job_defaults
|
||||
resource_class: xlarge
|
||||
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
|
||||
key: angular-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
|
||||
- run: ls /home/circleci/bazel_repository_cache || true
|
||||
- run: bazel info release
|
||||
- run: bazel run @yarn//:yarn
|
||||
# We could use bazel query so that we explicitly ask for all buildable targets to be built as well
|
||||
# This would avoid 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 //... | xargs bazel test
|
||||
# However it makes it more confusing for Angular developers who are still novice at Bazel
|
||||
# So keep it simple for now
|
||||
- run: bazel build //...
|
||||
- run: 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/todo/bundle.min.js
|
||||
destination: packages/core/test/bundling/todo/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
|
||||
- store_artifacts:
|
||||
path: dist/bin/packages/core/test/bundling/todo/bundle.min.js.brotli
|
||||
destination: packages/core/test/bundling/todo/bundle.min.js.brotli
|
||||
|
||||
- run: bazel build ...
|
||||
- save_cache:
|
||||
key: *cache_key
|
||||
key: angular-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- "node_modules"
|
||||
- "~/bazel_repository_cache"
|
||||
|
||||
aio_monitoring:
|
||||
<<: *job_defaults
|
||||
steps:
|
||||
- checkout:
|
||||
<<: *post_checkout
|
||||
- restore_cache:
|
||||
key: *cache_key
|
||||
- run: xvfb-run --auto-servernum ./aio/scripts/test-production.sh
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
@ -119,13 +53,3 @@ workflows:
|
||||
jobs:
|
||||
- lint
|
||||
- build
|
||||
aio_monitoring:
|
||||
jobs:
|
||||
- aio_monitoring
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "0 0 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Install bazel remote cache proxy
|
||||
# This is temporary until the feature is no longer experimental on CircleCI.
|
||||
# See remote cache documentation in /docs/BAZEL.md
|
||||
|
||||
set -u -e
|
||||
|
||||
readonly DOWNLOAD_URL="https://5-116431813-gh.circle-artifacts.com/0/pkg/bazel-remote-proxy-$(uname -s)_$(uname -m)"
|
||||
|
||||
curl --fail -o ~/bazel-remote-proxy "$DOWNLOAD_URL"
|
||||
chmod +x ~/bazel-remote-proxy
|
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -25,7 +25,7 @@ ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
|
||||
## Minimal reproduction of the problem with instructions
|
||||
<!--
|
||||
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
|
||||
https://stackblitz.com or similar (you can use this template as a starting point: https://stackblitz.com/fork/angular-gitter).
|
||||
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).
|
||||
-->
|
||||
|
||||
## What is the motivation / use case for changing the behavior?
|
||||
|
111
.github/angular-robot.yml
vendored
111
.github/angular-robot.yml
vendored
@ -1,111 +0,0 @@
|
||||
# Configuration for angular-robot
|
||||
|
||||
# options for the merge plugin
|
||||
merge:
|
||||
# the status will be added to your pull requests
|
||||
status:
|
||||
# set to true to disable
|
||||
disabled: false
|
||||
# the name of the status
|
||||
context: "ci/angular: merge status"
|
||||
# text to show when all checks pass
|
||||
successText: "All checks passed!"
|
||||
# text to show when some checks are failing
|
||||
failureText: "The following checks are failing:"
|
||||
|
||||
# the g3 status will be added to your pull requests if they include files that match the patterns
|
||||
g3Status:
|
||||
# set to true to disable
|
||||
disabled: false
|
||||
# the name of the status
|
||||
context: "google3"
|
||||
# text to show when the status is pending, {{PRNumber}} will be replaced by the PR number
|
||||
pendingDesc: "Googler: run g3sync presubmit {{PRNumber}}"
|
||||
# text to show when the status is success
|
||||
successDesc: "Does not affect google3"
|
||||
# link to use for the details
|
||||
url: "http://go/angular-g3sync"
|
||||
# list of patterns to check for the files changed by the PR
|
||||
# this list must be manually kept in sync with google3/third_party/javascript/angular2/copy.bara.sky
|
||||
include:
|
||||
- "LICENSE"
|
||||
- "modules/**"
|
||||
- "packages/**"
|
||||
# list of patterns to ignore for the files changed by the PR
|
||||
exclude:
|
||||
- "packages/language-service/**"
|
||||
- "**/.gitignore"
|
||||
- "**/.gitkeep"
|
||||
- "**/tsconfig-build.json"
|
||||
- "**/tsconfig.json"
|
||||
- "**/rollup.config.js"
|
||||
- "**/BUILD.bazel"
|
||||
- "packages/**/test/**"
|
||||
|
||||
# comment that will be added to a PR when there is a conflict, leave empty or set to false to disable
|
||||
mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges.
|
||||
\nPlease help to unblock it by resolving these conflicts. Thanks!"
|
||||
|
||||
# label to monitor
|
||||
mergeLabel: "PR action: merge"
|
||||
|
||||
# list of checks that will determine if the merge label can be added
|
||||
checks:
|
||||
# whether the PR shouldn't have a conflict with the base branch
|
||||
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: *"
|
||||
- "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
|
||||
requiredStatuses:
|
||||
- "continuous-integration/travis-ci/pr"
|
||||
- "code-review/pullapprove"
|
||||
- "ci/circleci: build"
|
||||
- "ci/circleci: lint"
|
||||
|
||||
# the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable
|
||||
# {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option
|
||||
# {{PLACEHOLDER}} will be replaced by the list of failing checks
|
||||
mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing:
|
||||
\n{{PLACEHOLDER}}
|
||||
\n
|
||||
\n**If you want your PR to be merged, it has to pass all the CI checks.**
|
||||
\n
|
||||
\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help."
|
||||
|
||||
# options for the triage plugin
|
||||
triage:
|
||||
# number of the milestone to apply when the issue has not been triaged yet
|
||||
needsTriageMilestone: 83,
|
||||
# number of the milestone to apply when the issue is triaged
|
||||
defaultMilestone: 82,
|
||||
# arrays of labels that determine if an issue has been triaged by the caretaker
|
||||
l1TriageLabels:
|
||||
-
|
||||
- "comp: *"
|
||||
# arrays of labels that determine if an issue has been fully triaged
|
||||
l2TriageLabels:
|
||||
-
|
||||
- "type: bug/fix"
|
||||
- "severity*"
|
||||
- "freq*"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: feature"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: refactor"
|
||||
- "comp: *"
|
||||
-
|
||||
- "type: RFC / Discussion / question"
|
||||
- "comp: *"
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,7 +5,6 @@ bazel-*
|
||||
e2e_test.*
|
||||
node_modules
|
||||
bower_components
|
||||
tools/gulp-tasks/cldr/cldr-data/
|
||||
|
||||
# Include when developing application packages.
|
||||
pubspec.lock
|
||||
|
139
.pullapprove.yml
139
.pullapprove.yml
@ -7,24 +7,23 @@
|
||||
#
|
||||
# alexeagle - Alex Eagle
|
||||
# alxhub - Alex Rickabaugh
|
||||
# andrewseguin - Andrew Seguin
|
||||
# brocco - Mike Brocchi
|
||||
# chuckjaz - Chuck Jazdzewski
|
||||
# filipesilva - Filipe Silva
|
||||
# Foxandxss - Jesús Rodríguez
|
||||
# gkalpak - George Kalpakas
|
||||
# hansl - Hans Larsen
|
||||
# IgorMinar - Igor Minar
|
||||
# jasonaden - Jason Aden
|
||||
# kapunahelewong - Kapunahele Wong
|
||||
# juleskremer - Jules Kremer
|
||||
# kara - Kara Erickson
|
||||
# matsko - Matias Niemelä
|
||||
# mhevery - Misko Hevery
|
||||
# petebacondarwin - Pete Bacon Darwin
|
||||
# pkozlowski-opensource - Pawel Kozlowski
|
||||
# robwormald - Rob Wormald
|
||||
# tbosch - Tobias Bosch
|
||||
# tinayuangao - Tina Gao
|
||||
# vicb - Victor Berchet
|
||||
# vikerman - Vikram Subramanian
|
||||
# wardbell - Ward Bell
|
||||
|
||||
|
||||
version: 2
|
||||
@ -35,41 +34,20 @@ group_defaults:
|
||||
enabled: true
|
||||
approve_by_comment:
|
||||
enabled: false
|
||||
# see http://docs.pullapprove.com/groups/author_approval/
|
||||
author_approval:
|
||||
# If the author is a reviewer on the PR, they will automatically have an "approved" status.
|
||||
auto: true
|
||||
|
||||
groups:
|
||||
# Require all PRs to have at least one approval from *someone*
|
||||
all:
|
||||
users: all
|
||||
required: 1
|
||||
rejection_value: -999
|
||||
# In this group, your self-approval does not count
|
||||
author_approval:
|
||||
auto: false
|
||||
ignored: true
|
||||
files:
|
||||
include:
|
||||
- "*"
|
||||
|
||||
root:
|
||||
conditions:
|
||||
files:
|
||||
include:
|
||||
- "*"
|
||||
exclude:
|
||||
- "WORKSPACE"
|
||||
- "BUILD.bazel"
|
||||
- ".circleci/*"
|
||||
- "aio/*"
|
||||
- "integration/*"
|
||||
- "modules/*"
|
||||
- "packages/*"
|
||||
- "tools/*"
|
||||
users:
|
||||
- alexeagle
|
||||
- IgorMinar
|
||||
- mhevery
|
||||
|
||||
@ -82,22 +60,6 @@ groups:
|
||||
- IgorMinar
|
||||
- mhevery
|
||||
|
||||
bazel:
|
||||
conditions:
|
||||
files:
|
||||
include:
|
||||
- "WORKSPACE"
|
||||
- "*.bazel"
|
||||
- "*.bzl"
|
||||
- "packages/bazel/*"
|
||||
- "tools/bazel.rc"
|
||||
users:
|
||||
- alexeagle #primary
|
||||
- chuckjaz
|
||||
- IgorMinar #fallback
|
||||
- mhevery
|
||||
- vikerman #fallback
|
||||
|
||||
build-and-ci:
|
||||
conditions:
|
||||
files:
|
||||
@ -107,7 +69,7 @@ groups:
|
||||
- "*.lock"
|
||||
- "tools/*"
|
||||
exclude:
|
||||
- "tools/bazel.rc"
|
||||
- "tools/@angular/tsc-wrapped/*"
|
||||
- "tools/public_api_guard/*"
|
||||
- "aio/*"
|
||||
users:
|
||||
@ -123,27 +85,30 @@ groups:
|
||||
users:
|
||||
- alexeagle
|
||||
- mhevery
|
||||
- tbosch
|
||||
- vicb
|
||||
- IgorMinar #fallback
|
||||
|
||||
|
||||
core:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/core/*"
|
||||
users:
|
||||
- mhevery #primary
|
||||
- tbosch #primary
|
||||
- chuckjaz
|
||||
- kara
|
||||
- mhevery
|
||||
- vicb
|
||||
- IgorMinar #fallback
|
||||
|
||||
animations:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/animations/*"
|
||||
- "packages/animation/*"
|
||||
- "packages/platform-browser/animations/*"
|
||||
users:
|
||||
- matsko #primary
|
||||
- chuckjaz #fallback
|
||||
- mhevery #fallback
|
||||
- IgorMinar #fallback
|
||||
|
||||
@ -153,7 +118,7 @@ groups:
|
||||
- "packages/compiler/src/i18n/*"
|
||||
users:
|
||||
- vicb #primary
|
||||
- chuckjaz
|
||||
- tbosch
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
@ -162,43 +127,29 @@ groups:
|
||||
files:
|
||||
- "packages/compiler/*"
|
||||
users:
|
||||
- chuckjaz #primary
|
||||
- tbosch #primary
|
||||
- vicb
|
||||
- chuckjaz
|
||||
- mhevery
|
||||
- IgorMinar #fallback
|
||||
|
||||
compiler-cli/ngtools:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/compiler-cli/src/ngtools*"
|
||||
users:
|
||||
- hansl
|
||||
- filipesilva #fallback
|
||||
- brocco #fallback
|
||||
- IgorMinar #fallback
|
||||
|
||||
compiler-cli:
|
||||
conditions:
|
||||
files:
|
||||
include:
|
||||
- "packages/compiler-cli/*"
|
||||
- "packages/bazel/*"
|
||||
exclude:
|
||||
- "packages/compiler-cli/src/ngtools*"
|
||||
- "tools/@angular/tsc-wrapped/*"
|
||||
- "packages/compiler-cli/*"
|
||||
users:
|
||||
- alexeagle
|
||||
- chuckjaz
|
||||
- vicb
|
||||
- tbosch
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
common:
|
||||
conditions:
|
||||
files:
|
||||
include:
|
||||
- "packages/common/*"
|
||||
exclude:
|
||||
- "packages/common/http/*"
|
||||
- "packages/common/*"
|
||||
users:
|
||||
- pkozlowski-opensource #primary
|
||||
- vicb
|
||||
@ -209,12 +160,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
|
||||
@ -224,11 +169,11 @@ groups:
|
||||
http:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/common/http/*"
|
||||
- "packages/http/*"
|
||||
users:
|
||||
- alxhub #primary
|
||||
- IgorMinar
|
||||
- vikerman #primary
|
||||
- alxhub
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
language-service:
|
||||
@ -237,7 +182,7 @@ groups:
|
||||
- "packages/language-service/*"
|
||||
users:
|
||||
- chuckjaz #primary
|
||||
# needs secondary
|
||||
- tbosch #secondary
|
||||
- vicb
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
@ -247,7 +192,7 @@ groups:
|
||||
files:
|
||||
- "packages/router/*"
|
||||
users:
|
||||
- jasonaden #primary
|
||||
- jasonaden
|
||||
- vicb
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
@ -267,8 +212,8 @@ groups:
|
||||
files:
|
||||
- "packages/platform-browser/*"
|
||||
users:
|
||||
- vicb #primary
|
||||
# needs secondary
|
||||
- tbosch #primary
|
||||
- vicb #secondary
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
@ -278,8 +223,9 @@ groups:
|
||||
- "packages/platform-server/*"
|
||||
users:
|
||||
- vikerman #primary
|
||||
- alxhub #secondary
|
||||
- alxhub
|
||||
- vicb
|
||||
- tbosch
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
@ -289,36 +235,18 @@ groups:
|
||||
- "packages/platform-webworker/*"
|
||||
users:
|
||||
- vicb #primary
|
||||
# needs secondary
|
||||
- tbosch #secondary
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
service-worker:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/service-worker/*"
|
||||
users:
|
||||
- alxhub #primary
|
||||
- gkalpak
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
elements:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/elements/*"
|
||||
users:
|
||||
- andrewseguin #primary
|
||||
- gkalpak
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
benchpress:
|
||||
conditions:
|
||||
files:
|
||||
- "packages/benchpress/*"
|
||||
users:
|
||||
- alxhub # primary
|
||||
- tbosch #primary
|
||||
# needs secondary
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
@ -346,11 +274,13 @@ groups:
|
||||
- "aio/content/navigation.json"
|
||||
- "aio/content/license.md"
|
||||
users:
|
||||
- kapunahelewong
|
||||
- juleskremer #primary
|
||||
- Foxandxss
|
||||
- stephenfluin
|
||||
- wardbell
|
||||
- petebacondarwin
|
||||
- gkalpak
|
||||
- IgorMinar
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
||||
angular.io-marketing:
|
||||
@ -361,8 +291,9 @@ groups:
|
||||
- "aio/content/navigation.json"
|
||||
- "aio/content/license.md"
|
||||
users:
|
||||
- juleskremer #primary
|
||||
- stephenfluin
|
||||
- petebacondarwin
|
||||
- gkalpak
|
||||
- IgorMinar
|
||||
- IgorMinar #fallback
|
||||
- mhevery #fallback
|
||||
|
@ -1,10 +1,12 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
# force trusty as Google Chrome addon is not supported on Precise
|
||||
dist: trusty
|
||||
node_js:
|
||||
- '8.9.1'
|
||||
- '6.9.5'
|
||||
|
||||
addons:
|
||||
chrome: stable
|
||||
# firefox: "38.0"
|
||||
apt:
|
||||
sources:
|
||||
@ -48,14 +50,14 @@ env:
|
||||
- CI_MODE=e2e_2
|
||||
- CI_MODE=js
|
||||
- CI_MODE=saucelabs_required
|
||||
# deactivated, see #19768
|
||||
# - CI_MODE=browserstack_required
|
||||
- CI_MODE=browserstack_required
|
||||
- CI_MODE=saucelabs_optional
|
||||
- CI_MODE=browserstack_optional
|
||||
- CI_MODE=aio_tools_test
|
||||
- CI_MODE=aio
|
||||
- CI_MODE=aio_e2e AIO_SHARD=0
|
||||
- CI_MODE=aio_e2e AIO_SHARD=1
|
||||
- CI_MODE=bazel
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
72
BUILD.bazel
72
BUILD.bazel
@ -1,55 +1,25 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
exports_files(["tsconfig.json"])
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "node_modules_filegroup")
|
||||
|
||||
exports_files([
|
||||
"tsconfig.json",
|
||||
"LICENSE",
|
||||
])
|
||||
|
||||
# Developers should always run `bazel run :install`
|
||||
# This ensures that package.json in subdirectories get installed as well.
|
||||
alias(
|
||||
name = "install",
|
||||
actual = "@yarn//:yarn",
|
||||
)
|
||||
|
||||
node_modules_filegroup(
|
||||
# This rule belongs in node_modules/BUILD
|
||||
# It's here as a workaround for
|
||||
# https://github.com/bazelbuild/bazel/issues/374#issuecomment-296217940
|
||||
filegroup(
|
||||
name = "node_modules",
|
||||
packages = [
|
||||
"bytebuffer",
|
||||
"hammerjs",
|
||||
"jasmine",
|
||||
"minimist",
|
||||
"protobufjs",
|
||||
"reflect-metadata",
|
||||
"source-map-support",
|
||||
"tsickle",
|
||||
"tslib",
|
||||
"tsutils",
|
||||
"typescript",
|
||||
"zone.js",
|
||||
"@types",
|
||||
"@webcomponents/custom-elements",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "web_test_bootstrap_scripts",
|
||||
# do not sort
|
||||
srcs = [
|
||||
"//:node_modules/reflect-metadata/Reflect.js",
|
||||
"//:node_modules/zone.js/dist/zone.js",
|
||||
"//:node_modules/zone.js/dist/zone-testing.js",
|
||||
"//:node_modules/zone.js/dist/task-tracking.js",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "angularjs",
|
||||
# do not sort
|
||||
srcs = [
|
||||
"//:node_modules/angular/angular.js",
|
||||
"//:node_modules/angular-mocks/angular-mocks.js",
|
||||
],
|
||||
srcs = glob([
|
||||
# Performance workaround: list individual files
|
||||
# This won't scale in the general case.
|
||||
# TODO(alexeagle): figure out what to do
|
||||
"node_modules/typescript/**",
|
||||
"node_modules/zone.js/**",
|
||||
"node_modules/rxjs/**/*.d.ts",
|
||||
"node_modules/rxjs/**/*.js",
|
||||
"node_modules/@types/**/*.d.ts",
|
||||
"node_modules/tsickle/**",
|
||||
"node_modules/hammerjs/**/*.d.ts",
|
||||
"node_modules/protobufjs/**",
|
||||
"node_modules/bytebuffer/**",
|
||||
"node_modules/reflect-metadata/**",
|
||||
"node_modules/minimist/**/*.js",
|
||||
]),
|
||||
)
|
||||
|
1114
CHANGELOG.md
1114
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
||||
# Contributor Code of Conduct
|
||||
## Version 0.3b-angular
|
||||
|
||||
As contributors and maintainers of the Angular project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
|
||||
|
||||
Communication through any of Angular's channels (GitHub, Gitter, IRC, mailing lists, Google+, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
||||
|
||||
We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Angular project to do the same.
|
||||
|
||||
If any member of the community violates this code of conduct, the maintainers of the Angular project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate.
|
||||
|
||||
If you are subject to or witness unacceptable behavior, or have any other concerns, please email us at [conduct@angular.io](mailto:conduct@angular.io).
|
@ -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).
|
||||
|
||||
@ -69,37 +69,36 @@ You can file new issues by filling out our [new issue form](https://github.com/a
|
||||
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
||||
Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
|
||||
1. Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
|
||||
* Search [GitHub](https://github.com/angular/angular/pulls) for an open or closed PR
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
1. Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
||||
We cannot accept code without this. Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository.
|
||||
1. Fork the angular/angular repo.
|
||||
1. Make your changes in a new git branch:
|
||||
* Please sign our [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
||||
We cannot accept code without this.
|
||||
* Make your changes in a new git branch:
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
```
|
||||
|
||||
1. Create your patch, **including appropriate test cases**.
|
||||
1. Follow our [Coding Rules](#rules).
|
||||
1. Run the full Angular test suite, as described in the [developer documentation][dev-doc],
|
||||
* Create your patch, **including appropriate test cases**.
|
||||
* Follow our [Coding Rules](#rules).
|
||||
* Run the full Angular test suite, as described in the [developer documentation][dev-doc],
|
||||
and ensure that all tests pass.
|
||||
1. Commit your changes using a descriptive commit message that follows our
|
||||
* Commit your changes using a descriptive commit message that follows our
|
||||
[commit message conventions](#commit). Adherence to these conventions
|
||||
is necessary because release notes are automatically generated from these messages.
|
||||
|
||||
```shell
|
||||
git commit -a
|
||||
```
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
|
||||
1. Push your branch to GitHub:
|
||||
* Push your branch to GitHub:
|
||||
|
||||
```shell
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
|
||||
1. In GitHub, send a pull request to `angular:master`.
|
||||
* In GitHub, send a pull request to `angular:master`.
|
||||
* If we suggest changes then:
|
||||
* Make the required updates.
|
||||
* Re-run the Angular test suites to ensure tests are still passing.
|
||||
@ -173,12 +172,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 +202,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:
|
||||
|
||||
@ -212,7 +211,6 @@ The following is the list of supported scopes:
|
||||
* **compiler**
|
||||
* **compiler-cli**
|
||||
* **core**
|
||||
* **elements**
|
||||
* **forms**
|
||||
* **http**
|
||||
* **language-service**
|
||||
@ -222,8 +220,8 @@ The following is the list of supported scopes:
|
||||
* **platform-webworker**
|
||||
* **platform-webworker-dynamic**
|
||||
* **router**
|
||||
* **service-worker**
|
||||
* **upgrade**
|
||||
* **tsc-wrapped**
|
||||
|
||||
There are currently a few exceptions to the "use package name" rule:
|
||||
|
||||
@ -233,10 +231,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
|
||||
@ -260,19 +258,6 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
|
||||
* For corporations we'll need you to
|
||||
[print, sign and one of scan+email, fax or mail the form][corporate-cla].
|
||||
|
||||
<hr>
|
||||
|
||||
If you have more than one Git identity, you must make sure that you sign the CLA using the primary email address associated with the ID that has been granted access to the Angular repository. Git identities can be associated with more than one email address, and only one is primary. Here are some links to help you sort out multiple Git identities and email addresses:
|
||||
|
||||
* 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/
|
||||
|
||||
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.
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
[angular-group]: https://groups.google.com/forum/#!forum/angular
|
||||
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014-2018 Google, Inc. http://angular.io
|
||||
Copyright (c) 2014-2017 Google, Inc. http://angular.io
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,13 +1,14 @@
|
||||
[](https://travis-ci.org/angular/angular)
|
||||
[](https://circleci.com/gh/angular/angular/tree/master)
|
||||
[](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)
|
||||
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](https://www.npmjs.com/@angular/core)
|
||||
|
||||
|
||||
[](https://saucelabs.com/u/angular2-ci)
|
||||
|
||||
*Safari (7+), iOS (7+) and IE mobile (11) are tested on [BrowserStack][browserstack].*
|
||||
*Safari (7+), iOS (7+), Edge (14) and IE mobile (11) are tested on [BrowserStack][browserstack].*
|
||||
|
||||
# Angular
|
||||
|
||||
@ -22,7 +23,7 @@ Angular is a development platform for building mobile and desktop web applicatio
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
|
||||
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
|
||||
|
||||
[browserstack]: https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06
|
||||
[browserstack]: https://www.browserstack.com/
|
||||
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
|
||||
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
|
||||
[ng]: http://angular.io
|
||||
|
101
WORKSPACE
101
WORKSPACE
@ -1,94 +1,17 @@
|
||||
workspace(name = "angular")
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_rules_nodejs",
|
||||
url = "https://github.com/bazelbuild/rules_nodejs/archive/99166f8eb7fc628ca561acf9f9a51a1c26edadad.zip",
|
||||
strip_prefix = "rules_nodejs-99166f8eb7fc628ca561acf9f9a51a1c26edadad",
|
||||
sha256 = "338e8495e5d1fa16de7190106c5675372ff4a347f6004e203e84a168db96281e",
|
||||
git_repository(
|
||||
name = "build_bazel_rules_typescript",
|
||||
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
||||
tag = "0.0.5",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
|
||||
load("@build_bazel_rules_typescript//:defs.bzl", "node_repositories")
|
||||
|
||||
check_bazel_version("0.9.0")
|
||||
node_repositories(package_json = ["//:package.json"])
|
||||
node_repositories(package_json = "//:package.json")
|
||||
|
||||
yarn_install(
|
||||
name = "ts-api-guardian_runtime_deps",
|
||||
package_json = "//tools/ts-api-guardian:package.json",
|
||||
yarn_lock = "//tools/ts-api-guardian:yarn.lock",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_rules_typescript",
|
||||
url = "https://github.com/bazelbuild/rules_typescript/archive/0.11.1.zip",
|
||||
strip_prefix = "rules_typescript-0.11.1",
|
||||
sha256 = "7406bea7954e1c906f075115dfa176551a881119f6820b126ea1eacb09f34a1a",
|
||||
)
|
||||
|
||||
load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace")
|
||||
|
||||
ts_setup_workspace()
|
||||
|
||||
local_repository(
|
||||
name = "rxjs",
|
||||
path = "node_modules/rxjs/src",
|
||||
)
|
||||
|
||||
# Point to the integration test workspace just so that Bazel doesn't descend into it
|
||||
# when expanding the //... pattern
|
||||
local_repository(
|
||||
name = "bazel_integration_test",
|
||||
path = "integration/bazel",
|
||||
)
|
||||
|
||||
# This commit matches the version of buildifier in angular/ngcontainer
|
||||
# If you change this, also check if it matches the version in the angular/ngcontainer
|
||||
# version in /.circleci/config.yml
|
||||
BAZEL_BUILDTOOLS_VERSION = "b3b620e8bcff18ed3378cd3f35ebeb7016d71f71"
|
||||
|
||||
http_archive(
|
||||
name = "com_github_bazelbuild_buildtools",
|
||||
url = "https://github.com/bazelbuild/buildtools/archive/%s.zip" % BAZEL_BUILDTOOLS_VERSION,
|
||||
strip_prefix = "buildtools-%s" % BAZEL_BUILDTOOLS_VERSION,
|
||||
sha256 = "dad19224258ed67cbdbae9b7befb785c3b966e5a33b04b3ce58ddb7824b97d73",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
url = "https://github.com/bazelbuild/rules_go/releases/download/0.7.1/rules_go-0.7.1.tar.gz",
|
||||
sha256 = "341d5eacef704415386974bc82a1783a8b7ffbff2ab6ba02375e1ca20d9b031c",
|
||||
)
|
||||
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
|
||||
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains()
|
||||
|
||||
# Fetching the Bazel source code allows us to compile the Skylark linter
|
||||
http_archive(
|
||||
name = "io_bazel",
|
||||
url = "https://github.com/bazelbuild/bazel/archive/9755c72b48866ed034bd28aa033e9abd27431b1e.zip",
|
||||
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/c6333e1e79fb62ea088443f192293f964409b04e.zip",
|
||||
strip_prefix = "brotli-c6333e1e79fb62ea088443f192293f964409b04e",
|
||||
sha256 = "3f781988dee7dd3bcce2bf238294663cfaaf3b6433505bdb762e24d0a284d1dc",
|
||||
)
|
||||
git_repository(
|
||||
name = "build_bazel_rules_angular",
|
||||
remote = "https://github.com/bazelbuild/rules_angular.git",
|
||||
tag = "0.0.1",
|
||||
)
|
@ -13,9 +13,7 @@
|
||||
"app/search/search-worker.js",
|
||||
"favicon.ico",
|
||||
"pwa-manifest.json",
|
||||
"google385281288605d160.html",
|
||||
{ "glob": "custom-elements.min.js", "input": "../node_modules/@webcomponents/custom-elements", "output": "./assets/js" },
|
||||
{ "glob": "native-shim.js", "input": "../node_modules/@webcomponents/custom-elements/src", "output": "./assets/js" }
|
||||
"google385281288605d160.html"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
@ -41,7 +39,7 @@
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "tests/e2e/protractor.conf.js"
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
@ -52,22 +50,18 @@
|
||||
"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": {
|
||||
"styleExt": "scss",
|
||||
"component": {
|
||||
"inlineStyle": true
|
||||
},
|
||||
"build": {
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn"
|
||||
}
|
||||
}
|
||||
|
3
aio/.gitignore
vendored
3
aio/.gitignore
vendored
@ -30,7 +30,6 @@
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
debug.log
|
||||
npm-debug.log
|
||||
testem.log
|
||||
/typings
|
||||
@ -46,4 +45,4 @@ protractor-results*.txt
|
||||
Thumbs.db
|
||||
|
||||
# copied dependencies
|
||||
src/assets/js/lunr*
|
||||
src/assets/js/lunr*
|
@ -4,7 +4,7 @@ Everything in this folder is part of the documentation project. This includes
|
||||
|
||||
* the web site for displaying the documentation
|
||||
* the dgeni configuration for converting source files to rendered files that can be viewed in the web site.
|
||||
* the tooling for setting up examples for development; and generating live-example and zip files from the examples.
|
||||
* the tooling for setting up examples for development; and generating plunkers and zip files from the examples.
|
||||
|
||||
## Developer tasks
|
||||
|
||||
@ -13,7 +13,7 @@ You should run all these tasks from the `angular/aio` folder.
|
||||
Here are the most important tasks you might need to use:
|
||||
|
||||
* `yarn` - install all the dependencies.
|
||||
* `yarn setup` - install all the dependencies, boilerplate, stackblitz, zips and run dgeni on the docs.
|
||||
* `yarn setup` - install all the dependencies, boilerplate, plunkers, zips and run dgeni on the docs.
|
||||
* `yarn setup-local` - same as `setup`, but use the locally built Angular packages for aio and docs examples boilerplate.
|
||||
|
||||
* `yarn build` - create a production build of the application (after installing dependencies, boilerplate, etc).
|
||||
@ -32,7 +32,7 @@ Here are the most important tasks you might need to use:
|
||||
|
||||
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally. Add the option `--local` to use your local version of Angular contained in the "dist" folder.
|
||||
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
|
||||
* `yarn generate-stackblitz` - generate the stackblitz files that are used by the `live-example` tags in the docs.
|
||||
* `yarn generate-plunkers` - generate the plunker files that are used by the `live-example` tags in the docs.
|
||||
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
|
||||
|
||||
* `yarn example-e2e` - run all e2e tests for examples
|
||||
@ -68,11 +68,6 @@ The content is written in markdown.
|
||||
All other content is written using markdown in text files, located in the `angular/aio/content` folder.
|
||||
More specifically, there are sub-folders that contain particular types of content: guides, tutorial and marketing.
|
||||
|
||||
* **Code examples**: code examples need to be testable to ensure their accuracy.
|
||||
Also, our examples have a specific look and feel and allow the user to copy the source code. For larger
|
||||
examples they are rendered in a tabbed interface (e.g. template, HTML, and TypeScript on separate
|
||||
tabs). Additionally, some are live examples, which provide links where the code can be edited, executed, and/or downloaded. For details on working with code examples, please read the [Code snippets](https://angular.io/guide/docs-style-guide#code-snippets), [Source code markup](https://angular.io/guide/docs-style-guide#source-code-markup), and [Live examples](https://angular.io/guide/docs-style-guide#live-examples) pages of the [Authors Style Guide](https://angular.io/guide/docs-style-guide).
|
||||
|
||||
We use the [dgeni](https://github.com/angular/dgeni) tool to convert these files into docs that can be viewed in the doc-viewer.
|
||||
|
||||
The [Authors Style Guide](https://angular.io/guide/docs-style-guide) prescribes guidelines for
|
||||
@ -105,7 +100,8 @@ The general setup is as follows:
|
||||
* Open a terminal, ensure the dependencies are installed; run an initial doc generation; then start the doc-viewer:
|
||||
|
||||
```bash
|
||||
yarn setup
|
||||
yarn
|
||||
yarn docs
|
||||
yarn start
|
||||
```
|
||||
|
||||
|
@ -19,8 +19,8 @@ ARG AIO_DOMAIN_NAME=ngbuilds.io
|
||||
ARG TEST_AIO_DOMAIN_NAME=$AIO_DOMAIN_NAME.localhost
|
||||
ARG AIO_GITHUB_ORGANIZATION=angular
|
||||
ARG TEST_AIO_GITHUB_ORGANIZATION=angular
|
||||
ARG AIO_GITHUB_TEAM_SLUGS=team,aio-contributors
|
||||
ARG TEST_AIO_GITHUB_TEAM_SLUGS=team,aio-contributors
|
||||
ARG AIO_GITHUB_TEAM_SLUGS=angular-core,aio-contributors
|
||||
ARG TEST_AIO_GITHUB_TEAM_SLUGS=angular-core,aio-contributors
|
||||
ARG AIO_NGINX_HOSTNAME=$AIO_DOMAIN_NAME
|
||||
ARG TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_DOMAIN_NAME
|
||||
ARG AIO_NGINX_PORT_HTTP=80
|
||||
@ -156,7 +156,7 @@ RUN find $AIO_SCRIPTS_SH_DIR -maxdepth 1 -type f -printf "%P\n" \
|
||||
# Set up the Node.js scripts
|
||||
COPY scripts-js/ $AIO_SCRIPTS_JS_DIR/
|
||||
WORKDIR $AIO_SCRIPTS_JS_DIR/
|
||||
RUN yarn install --production --frozen-lockfile
|
||||
RUN yarn install --production --freeze-lockfile
|
||||
|
||||
|
||||
# Set up health check
|
||||
|
@ -9,7 +9,7 @@ Necessary secrets:
|
||||
- Used for:
|
||||
- Retrieving open PRs without rate-limiting.
|
||||
- Retrieving PR author.
|
||||
- Retrieving members of the trusted GitHub teams.
|
||||
- Retrieving members of the `angular-core` team.
|
||||
- Posting comments with preview links on PRs.
|
||||
|
||||
2. `PREVIEW_DEPLOYMENT_TOKEN`
|
||||
|
@ -74,7 +74,7 @@ sudo docker run \
|
||||
## Example
|
||||
The following command would start a docker container based on the previously created `foobar-builds`
|
||||
docker image, alias it as 'foobar-builds-1' and map predefined directories on the host VM to be used
|
||||
by the container for accessing secrets and SSL certificates and keeping the build artifacts and logs.
|
||||
by the container for accesing secrets and SSL certificates and keeping the build artifacts and logs.
|
||||
|
||||
```
|
||||
sudo docker run \
|
||||
|
@ -9,7 +9,7 @@ readonly defaultImageNameAndTag="aio-builds:latest"
|
||||
# (Necessary, because only `scripts-js/dist/` is copied to the docker image.)
|
||||
(
|
||||
cd "$SCRIPTS_JS_DIR"
|
||||
yarn install --frozen-lockfile --non-interactive
|
||||
yarn install --freeze-lockfile --non-interactive
|
||||
yarn build
|
||||
)
|
||||
|
||||
|
@ -7,6 +7,6 @@ source "`dirname $0`/_env.sh"
|
||||
# Test `scripts-js/`
|
||||
(
|
||||
cd "$SCRIPTS_JS_DIR"
|
||||
yarn install --frozen-lockfile --non-interactive
|
||||
yarn install --freeze-lockfile --non-interactive
|
||||
yarn test
|
||||
)
|
||||
|
@ -3,7 +3,7 @@
|
||||
set -eux -o pipefail
|
||||
exec 3>&1
|
||||
|
||||
echo "\n\n[`date`] - Updating the preview server..."
|
||||
echo "[`date`] - Updating the preview server..."
|
||||
|
||||
# Input
|
||||
readonly HOST_REPO_DIR=$1
|
||||
@ -37,7 +37,7 @@ readonly CONTAINER_NAME=aio
|
||||
fi
|
||||
|
||||
# Create and verify a new docker image.
|
||||
aio/aio-builds-setup/scripts/create-image.sh "$PROVISIONAL_IMAGE_NAME" --no-cache
|
||||
aio/aio-builds-setup/scripts/create-image.sh "$PROVISIONAL_IMAGE_NAME"
|
||||
readonly imageVerified=$(sudo docker run --dns 127.0.0.1 --rm --volume $HOST_SECRETS_DIR:/aio-secrets:ro "$PROVISIONAL_IMAGE_NAME" /bin/bash -c "aio-init && aio-health-check && aio-verify-setup" >> /dev/fd/3 && echo "true" || echo "false")
|
||||
|
||||
if [[ "$imageVerified" != "true" ]]; then
|
||||
|
BIN
aio/content/examples/.DS_Store
vendored
BIN
aio/content/examples/.DS_Store
vendored
Binary file not shown.
38
aio/content/examples/.gitignore
vendored
38
aio/content/examples/.gitignore
vendored
@ -1,23 +1,8 @@
|
||||
# boilerplate files
|
||||
**/src/environments/environment.prod.ts
|
||||
**/src/environments/environment.ts
|
||||
**/src/assets/.gitkeep
|
||||
**/src/favicon.ico
|
||||
**/src/styles.css
|
||||
**/src/systemjs-angular-loader.js
|
||||
**/src/systemjs.config.js
|
||||
**/src/tsconfig.json
|
||||
**/src/favicon.ico
|
||||
**/src/polyfills.ts
|
||||
**/src/test.ts
|
||||
**/src/tsconfig.app.json
|
||||
**/src/tsconfig.spec.json
|
||||
**/src/typings.d.ts
|
||||
**/e2e/app.po.ts
|
||||
**/e2e/tsconfig.e2e.json
|
||||
**/.angular-cli.json
|
||||
**/.editorconfig
|
||||
**/tsconfig.json
|
||||
**/bs-config.e2e.json
|
||||
**/bs-config.json
|
||||
**/package.json
|
||||
@ -30,7 +15,11 @@
|
||||
# built files
|
||||
*.map
|
||||
_test-output
|
||||
protractor-helpers.js
|
||||
*/e2e-spec.js
|
||||
**/*.js
|
||||
**/ts/**/*.js
|
||||
**/js-es6*/**/*.js
|
||||
dist/
|
||||
|
||||
|
||||
@ -54,31 +43,24 @@ dist/
|
||||
**/app/**/*.ajs.js
|
||||
|
||||
# aot
|
||||
**/*.ngsummary.json
|
||||
*/aot/**/*
|
||||
!*/aot/bs-config.json
|
||||
!*/aot/index.html
|
||||
!rollup-config.js
|
||||
aot-compiler/**/*.d.ts
|
||||
aot-compiler/**/*.factory.d.ts
|
||||
|
||||
# i18n
|
||||
!i18n/src/systemjs-text-plugin.js
|
||||
|
||||
# testing
|
||||
!testing/src/browser-test-shim.js
|
||||
!testing/karma*.js
|
||||
|
||||
# webpack
|
||||
!webpack/**/config/*.js
|
||||
!webpack/**/*webpack*.js
|
||||
!webpack/src/polyfills.ts
|
||||
|
||||
# styleguide
|
||||
!styleguide/src/systemjs.custom.js
|
||||
|
||||
# universal
|
||||
!universal/webpack.server.config.js
|
||||
|
||||
# stackblitz
|
||||
*stackblitz.no-link.html
|
||||
|
||||
# ngUpgrade testing
|
||||
!upgrade-phonecat-*/**/karma.conf.js
|
||||
!upgrade-phonecat-*/**/karma-test-shim.js
|
||||
# plunkers
|
||||
*plnkr.no-link.html
|
||||
|
@ -1,62 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "angular.io-example"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
// #docregion styles
|
||||
"styles": [
|
||||
"styles.css"
|
||||
],
|
||||
// #enddocregion styles
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"component": {}
|
||||
}
|
||||
}
|
115
aio/content/examples/ajs-quick-reference/e2e-spec.ts
Normal file
115
aio/content/examples/ajs-quick-reference/e2e-spec.ts
Normal file
@ -0,0 +1,115 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('AngularJS to Angular Quick Reference Tests', function () {
|
||||
|
||||
beforeAll(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('should display no poster images after bootstrap', function () {
|
||||
testImagesAreDisplayed(false);
|
||||
});
|
||||
|
||||
it('should display proper movie data', function () {
|
||||
// We check only a few samples
|
||||
let expectedSamples: any[] = [
|
||||
{row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true},
|
||||
{row: 0, column: 2, value: 'Celeritas'},
|
||||
{row: 1, column: 3, matches: /Dec 1[678], 2015/}, // absorb timezone dif; we care about date format
|
||||
{row: 1, column: 5, value: '$14.95'},
|
||||
{row: 2, column: 4, value: 'PG-13'},
|
||||
{row: 2, column: 7, value: '100%'},
|
||||
{row: 2, column: 0, element: 'img', attr: 'src', value: 'images/ng-logo.png', contains: true},
|
||||
];
|
||||
|
||||
// Go through the samples
|
||||
let movieRows = getMovieRows();
|
||||
for (let i = 0; i < expectedSamples.length; i++) {
|
||||
let sample = expectedSamples[i];
|
||||
let tableCell = movieRows.get(sample.row)
|
||||
.all(by.tagName('td')).get(sample.column);
|
||||
// Check the cell or its nested element
|
||||
let elementToCheck = sample.element
|
||||
? tableCell.element(by.tagName(sample.element))
|
||||
: tableCell;
|
||||
|
||||
// Check element attribute or text
|
||||
let valueToCheck = sample.attr
|
||||
? elementToCheck.getAttribute(sample.attr)
|
||||
: elementToCheck.getText();
|
||||
|
||||
// Test for equals/contains/match
|
||||
if (sample.contains) {
|
||||
expect(valueToCheck).toContain(sample.value);
|
||||
} else if (sample.matches) {
|
||||
expect(valueToCheck).toMatch(sample.matches);
|
||||
} else {
|
||||
expect(valueToCheck).toEqual(sample.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should display images after Show Poster', function () {
|
||||
testPosterButtonClick('Show Poster', true);
|
||||
});
|
||||
|
||||
it('should hide images after Hide Poster', function () {
|
||||
testPosterButtonClick('Hide Poster', false);
|
||||
});
|
||||
|
||||
it('should display no movie when no favorite hero is specified', function () {
|
||||
testFavoriteHero(null, 'Please enter your favorite hero.');
|
||||
});
|
||||
|
||||
it('should display no movie for Magneta', function () {
|
||||
testFavoriteHero('Magneta', 'No movie, sorry!');
|
||||
});
|
||||
|
||||
it('should display a movie for Mr. Nice', function () {
|
||||
testFavoriteHero('Mr. Nice', 'Excellent choice!');
|
||||
});
|
||||
|
||||
function testImagesAreDisplayed(isDisplayed: boolean) {
|
||||
let expectedMovieCount = 3;
|
||||
|
||||
let movieRows = getMovieRows();
|
||||
expect(movieRows.count()).toBe(expectedMovieCount);
|
||||
for (let i = 0; i < expectedMovieCount; i++) {
|
||||
let movieImage = movieRows.get(i).element(by.css('td > img'));
|
||||
expect(movieImage.isDisplayed()).toBe(isDisplayed);
|
||||
}
|
||||
}
|
||||
|
||||
function testPosterButtonClick(expectedButtonText: string, isDisplayed: boolean) {
|
||||
let posterButton = element(by.css('movie-list tr > th > button'));
|
||||
expect(posterButton.getText()).toBe(expectedButtonText);
|
||||
|
||||
posterButton.click().then(function () {
|
||||
testImagesAreDisplayed(isDisplayed);
|
||||
});
|
||||
}
|
||||
|
||||
function getMovieRows() {
|
||||
return element.all(by.css('movie-list tbody > tr'));
|
||||
}
|
||||
|
||||
function testFavoriteHero(heroName: string, expectedLabel: string) {
|
||||
let movieListComp = element(by.tagName('movie-list'));
|
||||
let heroInput = movieListComp.element(by.tagName('input'));
|
||||
let favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
|
||||
let resultLabel = movieListComp.element(by.css('span > p'));
|
||||
|
||||
heroInput.clear().then(function () {
|
||||
heroInput.sendKeys(heroName || '');
|
||||
expect(resultLabel.getText()).toBe(expectedLabel);
|
||||
if (heroName) {
|
||||
expect(favoriteHeroLabel.isDisplayed()).toBe(true);
|
||||
expect(favoriteHeroLabel.getText()).toContain(heroName);
|
||||
} else {
|
||||
expect(favoriteHeroLabel.isDisplayed()).toBe(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -1,115 +0,0 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('AngularJS to Angular Quick Reference Tests', function () {
|
||||
|
||||
beforeAll(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('should display no poster images after bootstrap', function () {
|
||||
testImagesAreDisplayed(false);
|
||||
});
|
||||
|
||||
it('should display proper movie data', function () {
|
||||
// We check only a few samples
|
||||
let expectedSamples: any[] = [
|
||||
{row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true},
|
||||
{row: 0, column: 2, value: 'Celeritas'},
|
||||
{row: 1, column: 3, matches: /Dec 1[678], 2015/}, // absorb timezone dif; we care about date format
|
||||
{row: 1, column: 5, value: '$14.95'},
|
||||
{row: 2, column: 4, value: 'PG-13'},
|
||||
{row: 2, column: 7, value: '100%'},
|
||||
{row: 2, column: 0, element: 'img', attr: 'src', value: 'images/ng-logo.png', contains: true},
|
||||
];
|
||||
|
||||
// Go through the samples
|
||||
let movieRows = getMovieRows();
|
||||
for (let i = 0; i < expectedSamples.length; i++) {
|
||||
let sample = expectedSamples[i];
|
||||
let tableCell = movieRows.get(sample.row)
|
||||
.all(by.tagName('td')).get(sample.column);
|
||||
// Check the cell or its nested element
|
||||
let elementToCheck = sample.element
|
||||
? tableCell.element(by.tagName(sample.element))
|
||||
: tableCell;
|
||||
|
||||
// Check element attribute or text
|
||||
let valueToCheck = sample.attr
|
||||
? elementToCheck.getAttribute(sample.attr)
|
||||
: elementToCheck.getText();
|
||||
|
||||
// Test for equals/contains/match
|
||||
if (sample.contains) {
|
||||
expect(valueToCheck).toContain(sample.value);
|
||||
} else if (sample.matches) {
|
||||
expect(valueToCheck).toMatch(sample.matches);
|
||||
} else {
|
||||
expect(valueToCheck).toEqual(sample.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should display images after Show Poster', function () {
|
||||
testPosterButtonClick('Show Poster', true);
|
||||
});
|
||||
|
||||
it('should hide images after Hide Poster', function () {
|
||||
testPosterButtonClick('Hide Poster', false);
|
||||
});
|
||||
|
||||
it('should display no movie when no favorite hero is specified', function () {
|
||||
testFavoriteHero(null, 'Please enter your favorite hero.');
|
||||
});
|
||||
|
||||
it('should display no movie for Magneta', function () {
|
||||
testFavoriteHero('Magneta', 'No movie, sorry!');
|
||||
});
|
||||
|
||||
it('should display a movie for Mr. Nice', function () {
|
||||
testFavoriteHero('Mr. Nice', 'Excellent choice!');
|
||||
});
|
||||
|
||||
function testImagesAreDisplayed(isDisplayed: boolean) {
|
||||
let expectedMovieCount = 3;
|
||||
|
||||
let movieRows = getMovieRows();
|
||||
expect(movieRows.count()).toBe(expectedMovieCount);
|
||||
for (let i = 0; i < expectedMovieCount; i++) {
|
||||
let movieImage = movieRows.get(i).element(by.css('td > img'));
|
||||
expect(movieImage.isDisplayed()).toBe(isDisplayed);
|
||||
}
|
||||
}
|
||||
|
||||
function testPosterButtonClick(expectedButtonText: string, isDisplayed: boolean) {
|
||||
let posterButton = element(by.css('app-movie-list tr > th > button'));
|
||||
expect(posterButton.getText()).toBe(expectedButtonText);
|
||||
|
||||
posterButton.click().then(function () {
|
||||
testImagesAreDisplayed(isDisplayed);
|
||||
});
|
||||
}
|
||||
|
||||
function getMovieRows() {
|
||||
return element.all(by.css('app-movie-list tbody > tr'));
|
||||
}
|
||||
|
||||
function testFavoriteHero(heroName: string, expectedLabel: string) {
|
||||
let movieListComp = element(by.tagName('app-movie-list'));
|
||||
let heroInput = movieListComp.element(by.tagName('input'));
|
||||
let favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
|
||||
let resultLabel = movieListComp.element(by.css('span > p'));
|
||||
|
||||
heroInput.clear().then(function () {
|
||||
heroInput.sendKeys(heroName || '');
|
||||
expect(resultLabel.getText()).toBe(expectedLabel);
|
||||
if (heroName) {
|
||||
expect(favoriteHeroLabel.isDisplayed()).toBe(true);
|
||||
expect(favoriteHeroLabel.getText()).toContain(heroName);
|
||||
} else {
|
||||
expect(favoriteHeroLabel.isDisplayed()).toBe(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
10
aio/content/examples/ajs-quick-reference/plnkr.json
Normal file
10
aio/content/examples/ajs-quick-reference/plnkr.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description": "AngularJS to Angular Quick Reference",
|
||||
"basePath": "src/",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1].*"
|
||||
],
|
||||
"tags":["cookbook", "angularjs"]
|
||||
}
|
@ -4,7 +4,7 @@ import { MovieService } from './movie.service';
|
||||
import { IMovie } from './movie';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
selector: 'my-app',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: [ './app.component.css' ],
|
||||
providers: [ MovieService ]
|
||||
|
@ -8,7 +8,7 @@ import { MovieService } from './movie.service';
|
||||
|
||||
// #docregion component
|
||||
@Component({
|
||||
selector: 'app-movie-list',
|
||||
selector: 'movie-list',
|
||||
templateUrl: './movie-list.component.html',
|
||||
// #docregion style-url
|
||||
styleUrls: [ './movie-list.component.css' ],
|
||||
|
@ -8,7 +8,7 @@ export class MovieService {
|
||||
return [
|
||||
{
|
||||
hero: 'Celeritas',
|
||||
imageurl: 'assets/images/hero.png',
|
||||
imageurl: 'images/hero.png',
|
||||
movieId: 1,
|
||||
mpaa: 'pg-13',
|
||||
releaseDate: '2015-12-19T00:00:00',
|
||||
@ -19,7 +19,7 @@ export class MovieService {
|
||||
},
|
||||
{
|
||||
hero: 'Mr. Nice',
|
||||
imageurl: 'assets/images/villain.png',
|
||||
imageurl: 'images/villain.png',
|
||||
movieId: 2,
|
||||
mpaa: 'pg-13',
|
||||
releaseDate: '2015-12-18T00:00:00',
|
||||
@ -30,7 +30,7 @@ export class MovieService {
|
||||
},
|
||||
{
|
||||
hero: 'Angular',
|
||||
imageurl: 'assets/images/ng-logo.png',
|
||||
imageurl: 'images/ng-logo.png',
|
||||
movieId: 3,
|
||||
mpaa: 'pg-13',
|
||||
releaseDate: '2015-12-17T00:00:00',
|
||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@ -1,14 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<base href="/">
|
||||
<meta charset="UTF-8">
|
||||
<title>AngularJS to Angular Quick Reference</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- #docregion style -->
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<!-- #enddocregion style -->
|
||||
|
||||
<!-- Polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('main.js').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<my-app>Loading app...</my-app>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -1,12 +1,5 @@
|
||||
// #docregion
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"description": "AngularJS to Angular Quick Reference",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1].*"
|
||||
],
|
||||
"tags":["cookbook", "angularjs"]
|
||||
}
|
351
aio/content/examples/animations/e2e-spec.ts
Normal file
351
aio/content/examples/animations/e2e-spec.ts
Normal file
@ -0,0 +1,351 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by, ElementFinder } from 'protractor';
|
||||
import { logging, promise } from 'selenium-webdriver';
|
||||
|
||||
/**
|
||||
* The tests here basically just checking that the end styles
|
||||
* of each animation are in effect.
|
||||
*
|
||||
* Relies on the Angular testability only becoming stable once
|
||||
* animation(s) have finished.
|
||||
*
|
||||
* Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations
|
||||
* but they're not supported in Chrome at the moment. The upcoming nganimate polyfill
|
||||
* may also add some introspection support.
|
||||
*/
|
||||
describe('Animation Tests', () => {
|
||||
|
||||
const INACTIVE_COLOR = 'rgba(238, 238, 238, 1)';
|
||||
const ACTIVE_COLOR = 'rgba(207, 216, 220, 1)';
|
||||
const NO_TRANSFORM_MATRIX_REGEX = /matrix\(1,\s*0,\s*0,\s*1,\s*0,\s*0\)/;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
describe('basic states', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('hero-list-basic'));
|
||||
});
|
||||
|
||||
it('animates between active and inactive', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('styles inline in transitions', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(function() {
|
||||
host = element(by.css('hero-list-inline-styles'));
|
||||
});
|
||||
|
||||
it('are not kept after animation', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('combined transition syntax', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('hero-list-combined-transitions'));
|
||||
});
|
||||
|
||||
it('animates between active and inactive', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('two-way transition syntax', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('hero-list-twoway'));
|
||||
});
|
||||
|
||||
it('animates between active and inactive', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('enter & leave', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('hero-list-enter-leave'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('enter & leave & states', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(function() {
|
||||
host = element(by.css('hero-list-enter-leave-states'));
|
||||
});
|
||||
|
||||
it('adds and removes and animates between active and inactive', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('auto style calc', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(function() {
|
||||
host = element(by.css('hero-list-auto'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('height')).toBe('50px');
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('different timings', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('hero-list-timings'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
expect(li.getCssValue('opacity')).toMatch('1');
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('multiple keyframes', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('hero-list-multistep'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
expect(li.getCssValue('opacity')).toMatch('1');
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('parallel groups', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('hero-list-groups'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
expect(li.getCssValue('opacity')).toMatch('1');
|
||||
|
||||
removeHero(700);
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('adding active heroes', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('hero-list-basic'));
|
||||
});
|
||||
|
||||
it('animates between active and inactive', () => {
|
||||
addActiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
});
|
||||
});
|
||||
|
||||
describe('callbacks', () => {
|
||||
it('fires a callback on start and done', () => {
|
||||
addActiveHero();
|
||||
browser.manage().logs().get(logging.Type.BROWSER)
|
||||
.then((logs: logging.Entry[]) => {
|
||||
const animationMessages = logs.filter((log) => {
|
||||
return log.message.indexOf('Animation') !== -1 ? true : false;
|
||||
});
|
||||
|
||||
expect(animationMessages.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function addActiveHero(sleep?: number) {
|
||||
sleep = sleep || 500;
|
||||
element(by.buttonText('Add active hero')).click();
|
||||
browser.driver.sleep(sleep);
|
||||
}
|
||||
|
||||
function addInactiveHero(sleep?: number) {
|
||||
sleep = sleep || 500;
|
||||
element(by.buttonText('Add inactive hero')).click();
|
||||
browser.driver.sleep(sleep);
|
||||
}
|
||||
|
||||
function removeHero(sleep?: number) {
|
||||
sleep = sleep || 500;
|
||||
element(by.buttonText('Remove hero')).click();
|
||||
browser.driver.sleep(sleep);
|
||||
}
|
||||
|
||||
function getScaleX(el: ElementFinder) {
|
||||
return Promise.all([
|
||||
getBoundingClientWidth(el),
|
||||
getOffsetWidth(el)
|
||||
]).then(function(promiseResolutions) {
|
||||
let clientWidth = promiseResolutions[0];
|
||||
let offsetWidth = promiseResolutions[1];
|
||||
return clientWidth / offsetWidth;
|
||||
});
|
||||
}
|
||||
|
||||
function getBoundingClientWidth(el: ElementFinder) {
|
||||
return browser.executeScript(
|
||||
'return arguments[0].getBoundingClientRect().width',
|
||||
el.getWebElement()
|
||||
) as PromiseLike<number>;
|
||||
}
|
||||
|
||||
function getOffsetWidth(el: ElementFinder) {
|
||||
return browser.executeScript(
|
||||
'return arguments[0].offsetWidth',
|
||||
el.getWebElement()
|
||||
) as PromiseLike<number>;
|
||||
}
|
||||
});
|
@ -1,351 +0,0 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by, ElementFinder } from 'protractor';
|
||||
import { logging, promise } from 'selenium-webdriver';
|
||||
|
||||
/**
|
||||
* The tests here basically just checking that the end styles
|
||||
* of each animation are in effect.
|
||||
*
|
||||
* Relies on the Angular testability only becoming stable once
|
||||
* animation(s) have finished.
|
||||
*
|
||||
* Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations
|
||||
* but they're not supported in Chrome at the moment. The upcoming nganimate polyfill
|
||||
* may also add some introspection support.
|
||||
*/
|
||||
describe('Animation Tests', () => {
|
||||
|
||||
const INACTIVE_COLOR = 'rgba(238, 238, 238, 1)';
|
||||
const ACTIVE_COLOR = 'rgba(207, 216, 220, 1)';
|
||||
const NO_TRANSFORM_MATRIX_REGEX = /matrix\(1,\s*0,\s*0,\s*1,\s*0,\s*0\)/;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
describe('basic states', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('app-hero-list-basic'));
|
||||
});
|
||||
|
||||
it('animates between active and inactive', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('styles inline in transitions', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(function() {
|
||||
host = element(by.css('app-hero-list-inline-styles'));
|
||||
});
|
||||
|
||||
it('are not kept after animation', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('combined transition syntax', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('app-hero-list-combined-transitions'));
|
||||
});
|
||||
|
||||
it('animates between active and inactive', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('two-way transition syntax', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('app-hero-list-twoway'));
|
||||
});
|
||||
|
||||
it('animates between active and inactive', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('enter & leave', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('app-hero-list-enter-leave'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('enter & leave & states', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(function() {
|
||||
host = element(by.css('app-hero-list-enter-leave-states'));
|
||||
});
|
||||
|
||||
it('adds and removes and animates between active and inactive', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('auto style calc', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(function() {
|
||||
host = element(by.css('app-hero-list-auto'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('height')).toBe('50px');
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('different timings', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('app-hero-list-timings'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
expect(li.getCssValue('opacity')).toMatch('1');
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('multiple keyframes', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('app-hero-list-multistep'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
expect(li.getCssValue('opacity')).toMatch('1');
|
||||
|
||||
removeHero();
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('parallel groups', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('app-hero-list-groups'));
|
||||
});
|
||||
|
||||
it('adds and removes element', () => {
|
||||
addInactiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
|
||||
expect(li.getCssValue('opacity')).toMatch('1');
|
||||
|
||||
removeHero(700);
|
||||
expect(li.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('adding active heroes', () => {
|
||||
|
||||
let host: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
host = element(by.css('app-hero-list-basic'));
|
||||
});
|
||||
|
||||
it('animates between active and inactive', () => {
|
||||
addActiveHero();
|
||||
|
||||
let li = host.element(by.css('li'));
|
||||
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.0);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
|
||||
|
||||
li.click();
|
||||
browser.driver.sleep(300);
|
||||
expect(getScaleX(li)).toBe(1.1);
|
||||
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
|
||||
});
|
||||
});
|
||||
|
||||
describe('callbacks', () => {
|
||||
it('fires a callback on start and done', () => {
|
||||
addActiveHero();
|
||||
browser.manage().logs().get(logging.Type.BROWSER)
|
||||
.then((logs: logging.Entry[]) => {
|
||||
const animationMessages = logs.filter((log) => {
|
||||
return log.message.indexOf('Animation') !== -1 ? true : false;
|
||||
});
|
||||
|
||||
expect(animationMessages.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function addActiveHero(sleep?: number) {
|
||||
sleep = sleep || 500;
|
||||
element(by.buttonText('Add active hero')).click();
|
||||
browser.driver.sleep(sleep);
|
||||
}
|
||||
|
||||
function addInactiveHero(sleep?: number) {
|
||||
sleep = sleep || 500;
|
||||
element(by.buttonText('Add inactive hero')).click();
|
||||
browser.driver.sleep(sleep);
|
||||
}
|
||||
|
||||
function removeHero(sleep?: number) {
|
||||
sleep = sleep || 500;
|
||||
element(by.buttonText('Remove hero')).click();
|
||||
browser.driver.sleep(sleep);
|
||||
}
|
||||
|
||||
function getScaleX(el: ElementFinder) {
|
||||
return Promise.all([
|
||||
getBoundingClientWidth(el),
|
||||
getOffsetWidth(el)
|
||||
]).then(function(promiseResolutions) {
|
||||
let clientWidth = promiseResolutions[0];
|
||||
let offsetWidth = promiseResolutions[1];
|
||||
return clientWidth / offsetWidth;
|
||||
});
|
||||
}
|
||||
|
||||
function getBoundingClientWidth(el: ElementFinder) {
|
||||
return browser.executeScript(
|
||||
'return arguments[0].getBoundingClientRect().width',
|
||||
el.getWebElement()
|
||||
) as PromiseLike<number>;
|
||||
}
|
||||
|
||||
function getOffsetWidth(el: ElementFinder) {
|
||||
return browser.executeScript(
|
||||
'return arguments[0].offsetWidth',
|
||||
el.getWebElement()
|
||||
) as PromiseLike<number>;
|
||||
}
|
||||
});
|
8
aio/content/examples/animations/plnkr.json
Normal file
8
aio/content/examples/animations/plnkr.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"description": "Angular Animations",
|
||||
"basePath": "src/",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js"
|
||||
]
|
||||
}
|
@ -13,7 +13,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-auto',
|
||||
selector: 'hero-list-auto',
|
||||
// #docregion template
|
||||
template: `
|
||||
<ul>
|
||||
|
@ -17,7 +17,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-basic',
|
||||
selector: 'hero-list-basic',
|
||||
// #enddocregion
|
||||
/* The click event calls hero.toggleState(), which
|
||||
* causes the state of that hero to switch from
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-combined-transitions',
|
||||
selector: 'hero-list-combined-transitions',
|
||||
// #docregion template
|
||||
template: `
|
||||
<ul>
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-enter-leave-states',
|
||||
selector: 'hero-list-enter-leave-states',
|
||||
// #docregion template
|
||||
template: `
|
||||
<ul>
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-enter-leave',
|
||||
selector: 'hero-list-enter-leave',
|
||||
// #docregion template
|
||||
template: `
|
||||
<ul>
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-groups',
|
||||
selector: 'hero-list-groups',
|
||||
template: `
|
||||
<ul>
|
||||
<li *ngFor="let hero of heroes"
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-inline-styles',
|
||||
selector: 'hero-list-inline-styles',
|
||||
// #docregion template
|
||||
template: `
|
||||
<ul>
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-multistep',
|
||||
selector: 'hero-list-multistep',
|
||||
// #docregion template
|
||||
template: `
|
||||
<ul>
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-timings',
|
||||
selector: 'hero-list-timings',
|
||||
template: `
|
||||
<ul>
|
||||
<li *ngFor="let hero of heroes"
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
import { Hero } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-list-twoway',
|
||||
selector: 'hero-list-twoway',
|
||||
// #docregion template
|
||||
template: `
|
||||
<ul>
|
||||
|
@ -3,7 +3,7 @@ import { Component } from '@angular/core';
|
||||
import { Hero, HeroService } from './hero.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
selector: 'hero-team-builder',
|
||||
template: `
|
||||
<div class="buttons">
|
||||
<button [disabled]="!heroService.canAdd()" (click)="heroService.addInactive()">Add inactive hero</button>
|
||||
@ -15,27 +15,27 @@ import { Hero, HeroService } from './hero.service';
|
||||
<div class="column">
|
||||
<h4>Basic State</h4>
|
||||
<p>Switch between active/inactive on click.</p>
|
||||
<app-hero-list-basic [heroes]="heroes"></app-hero-list-basic>
|
||||
<hero-list-basic [heroes]="heroes"></hero-list-basic>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4>Styles inline in transitions</h4>
|
||||
<p>Animated effect on click, no persistend end styles.</p>
|
||||
<app-hero-list-inline-styles [heroes]="heroes"></app-hero-list-inline-styles>
|
||||
<p>Animated effect on click, no persistent end styles.</p>
|
||||
<hero-list-inline-styles [heroes]="heroes"></hero-list-inline-styles>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4>Combined transition syntax</h4>
|
||||
<p>Switch between active/inactive on click. Define just one transition used in both directions.</p>
|
||||
<app-hero-list-combined-transitions [heroes]="heroes"></app-hero-list-combined-transitions>
|
||||
<hero-list-combined-transitions [heroes]="heroes"></hero-list-combined-transitions>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4>Two-way transition syntax</h4>
|
||||
<p>Switch between active/inactive on click. Define just one transition used in both directions using the <=> syntax.</p>
|
||||
<app-hero-list-twoway [heroes]="heroes"></app-hero-list-twoway>
|
||||
<hero-list-twoway [heroes]="heroes"></hero-list-twoway>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4>Enter & Leave</h4>
|
||||
<p>Enter and leave animations using the void state.</p>
|
||||
<app-hero-list-enter-leave [heroes]="heroes"></app-hero-list-enter-leave>
|
||||
<hero-list-enter-leave [heroes]="heroes"></hero-list-enter-leave>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
@ -45,27 +45,27 @@ import { Hero, HeroService } from './hero.service';
|
||||
Enter and leave animations combined with active/inactive state animations.
|
||||
Different enter and leave transitions depending on state.
|
||||
</p>
|
||||
<app-hero-list-enter-leave-states [heroes]="heroes"></app-hero-list-enter-leave-states>
|
||||
<hero-list-enter-leave-states [heroes]="heroes"></hero-list-enter-leave-states>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4>Auto Style Calc</h4>
|
||||
<p>Leave animation from the current computed height using the auto-style value *.</p>
|
||||
<app-hero-list-auto [heroes]="heroes"></app-hero-list-auto>
|
||||
<hero-list-auto [heroes]="heroes"></hero-list-auto>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4>Different Timings</h4>
|
||||
<p>Enter and leave animations with different easings, ease-in for enter, ease-out for leave.</p>
|
||||
<app-hero-list-timings [heroes]="heroes"></app-hero-list-timings>
|
||||
<hero-list-timings [heroes]="heroes"></hero-list-timings>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4>Multiple Keyframes</h4>
|
||||
<p>Enter and leave animations with three keyframes in each, to give the transition some bounce.</p>
|
||||
<app-hero-list-multistep [heroes]="heroes"></app-hero-list-multistep>
|
||||
<hero-list-multistep [heroes]="heroes"></hero-list-multistep>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4>Parallel Groups</h4>
|
||||
<p>Enter and leave animations with multiple properties animated in parallel with different timings.</p>
|
||||
<app-hero-list-groups [heroes]="heroes"></app-hero-list-groups>
|
||||
<hero-list-groups [heroes]="heroes"></hero-list-groups>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
@ -5,11 +5,26 @@
|
||||
<title>Animations</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<!-- Polyfill for Web Animations -->
|
||||
<script src="https://unpkg.com/web-animations-js@2.2.1"></script>
|
||||
|
||||
<!-- Polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('main.js').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 style="visibility: hidden;">External H1 Title for E2E test</h1>
|
||||
<app-root></app-root>
|
||||
<hero-team-builder></hero-team-builder>
|
||||
<button style="visibility: hidden;">External button for E2E test</button>
|
||||
<ul style="visibility: hidden;">
|
||||
<li>External list for E2E test</li>
|
||||
|
@ -1,11 +1,4 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"description": "Angular Animations",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js"
|
||||
]
|
||||
}
|
27
aio/content/examples/aot-compiler/e2e-spec.ts
Normal file
27
aio/content/examples/aot-compiler/e2e-spec.ts
Normal file
@ -0,0 +1,27 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
/* tslint:disable:quotemark */
|
||||
describe('AOT Compilation', function () {
|
||||
|
||||
beforeAll(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('should load page and click button', function (done: any) {
|
||||
let headingSelector = element.all(by.css('h1')).get(0);
|
||||
expect(headingSelector.getText()).toEqual('Hello Angular');
|
||||
|
||||
expect(element.all(by.xpath('//div[text()="Magneta"]')).get(0).isPresent()).toBe(true);
|
||||
expect(element.all(by.xpath('//div[text()="Bombasto"]')).get(0).isPresent()).toBe(true);
|
||||
expect(element.all(by.xpath('//div[text()="Magma"]')).get(0).isPresent()).toBe(true);
|
||||
expect(element.all(by.xpath('//div[text()="Tornado"]')).get(0).isPresent()).toBe(true);
|
||||
|
||||
let toggleButton = element.all(by.css('button')).get(0);
|
||||
toggleButton.click().then(function() {
|
||||
expect(headingSelector.isPresent()).toBe(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
3
aio/content/examples/aot-compiler/example-config.json
Normal file
3
aio/content/examples/aot-compiler/example-config.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"build": "build:aot"
|
||||
}
|
33
aio/content/examples/aot-compiler/rollup-config.js
Normal file
33
aio/content/examples/aot-compiler/rollup-config.js
Normal file
@ -0,0 +1,33 @@
|
||||
// #docregion
|
||||
import nodeResolve from 'rollup-plugin-node-resolve';
|
||||
import commonjs from 'rollup-plugin-commonjs';
|
||||
import uglify from 'rollup-plugin-uglify';
|
||||
|
||||
// #docregion config
|
||||
export default {
|
||||
entry: 'src/main.js',
|
||||
dest: 'src/build.js', // output a single application bundle
|
||||
sourceMap: false,
|
||||
format: 'iife',
|
||||
onwarn: function(warning) {
|
||||
// Skip certain warnings
|
||||
|
||||
// should intercept ... but doesn't in some rollup versions
|
||||
if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
|
||||
|
||||
// console.warn everything else
|
||||
console.warn( warning.message );
|
||||
},
|
||||
plugins: [
|
||||
nodeResolve({jsnext: true, module: true}),
|
||||
// #docregion commonjs
|
||||
commonjs({
|
||||
include: 'node_modules/rxjs/**',
|
||||
}),
|
||||
// #enddocregion commonjs
|
||||
// #docregion uglify
|
||||
uglify()
|
||||
// #enddocregion uglify
|
||||
]
|
||||
};
|
||||
// #enddocregion config
|
@ -0,0 +1,7 @@
|
||||
<!-- #docregion -->
|
||||
<button (click)="toggleHeading()">Toggle Heading</button>
|
||||
<h1 *ngIf="showHeading">Hello Angular</h1>
|
||||
|
||||
<h3>List of Heroes</h3>
|
||||
<div *ngFor="let hero of heroes">{{hero}}</div>
|
||||
|
15
aio/content/examples/aot-compiler/src/app/app.component.ts
Normal file
15
aio/content/examples/aot-compiler/src/app/app.component.ts
Normal file
@ -0,0 +1,15 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent {
|
||||
showHeading = true;
|
||||
heroes = ['Magneta', 'Bombasto', 'Magma', 'Tornado'];
|
||||
|
||||
toggleHeading() {
|
||||
this.showHeading = !this.showHeading;
|
||||
}
|
||||
}
|
12
aio/content/examples/aot-compiler/src/app/app.module.ts
Normal file
12
aio/content/examples/aot-compiler/src/app/app.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ BrowserModule ],
|
||||
declarations: [ AppComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
24
aio/content/examples/aot-compiler/src/index-jit.html
Normal file
24
aio/content/examples/aot-compiler/src/index-jit.html
Normal file
@ -0,0 +1,24 @@
|
||||
<!-- #docregion -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ahead of time compilation (JIT)</title>
|
||||
<base href="/">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<!-- #docregion jit -->
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('main-jit.js').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
<!-- #enddocregion jit -->
|
||||
</head>
|
||||
<body>
|
||||
<my-app>Loading...</my-app>
|
||||
</body>
|
||||
</html>
|
20
aio/content/examples/aot-compiler/src/index.html
Normal file
20
aio/content/examples/aot-compiler/src/index.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!-- #docregion -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ahead of time compilation</title>
|
||||
<base href="/">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<my-app>Loading...</my-app>
|
||||
</body>
|
||||
<!-- #docregion bundle -->
|
||||
<script src="build.js"></script>
|
||||
<!-- #enddocregion bundle -->
|
||||
</html>
|
6
aio/content/examples/aot-compiler/src/main-jit.ts
Normal file
6
aio/content/examples/aot-compiler/src/main-jit.ts
Normal file
@ -0,0 +1,6 @@
|
||||
// #docregion
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
console.log('Running JIT compiled');
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
6
aio/content/examples/aot-compiler/src/main.ts
Normal file
6
aio/content/examples/aot-compiler/src/main.ts
Normal file
@ -0,0 +1,6 @@
|
||||
// #docregion
|
||||
import { platformBrowser } from '@angular/platform-browser';
|
||||
import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory';
|
||||
|
||||
console.log('Running AOT compiled');
|
||||
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
26
aio/content/examples/aot-compiler/tsconfig-aot.json
Normal file
26
aio/content/examples/aot-compiler/tsconfig-aot.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["es2015", "dom"],
|
||||
"noImplicitAny": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types/"
|
||||
]
|
||||
},
|
||||
|
||||
"files": [
|
||||
"src/app/app.module.ts",
|
||||
"src/main.ts"
|
||||
],
|
||||
|
||||
"angularCompilerOptions": {
|
||||
"genDir": "aot",
|
||||
"skipMetadataEmit" : true
|
||||
}
|
||||
}
|
100
aio/content/examples/architecture/e2e-spec.ts
Normal file
100
aio/content/examples/architecture/e2e-spec.ts
Normal file
@ -0,0 +1,100 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { protractor, browser, element, by, ElementFinder } from 'protractor';
|
||||
|
||||
const nameSuffix = 'X';
|
||||
|
||||
class Hero {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
describe('Architecture', () => {
|
||||
|
||||
const expectedTitle = 'Architecture of Angular';
|
||||
const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
|
||||
|
||||
beforeAll(() => browser.get(''));
|
||||
|
||||
it(`has title '${expectedTitle}'`, () => {
|
||||
expect(browser.getTitle()).toEqual(expectedTitle);
|
||||
});
|
||||
|
||||
it(`has h2 '${expectedH2}'`, () => {
|
||||
let h2 = element.all(by.css('h2')).map((elt: any) => elt.getText());
|
||||
expect(h2).toEqual(expectedH2);
|
||||
});
|
||||
|
||||
describe('Hero', heroTests);
|
||||
describe('Salex tax', salesTaxTests);
|
||||
});
|
||||
|
||||
function heroTests() {
|
||||
|
||||
const targetHero: Hero = { id: 2, name: 'Mr. Nice' };
|
||||
|
||||
it('has the right number of heroes', () => {
|
||||
let page = getPageElts();
|
||||
expect(page.heroes.count()).toEqual(3);
|
||||
});
|
||||
|
||||
it('has no hero details initially', function () {
|
||||
let page = getPageElts();
|
||||
expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail');
|
||||
});
|
||||
|
||||
it('shows selected hero details', async () => {
|
||||
await element(by.cssContainingText('li', targetHero.name)).click();
|
||||
let page = getPageElts();
|
||||
let hero = await heroFromDetail(page.heroDetail);
|
||||
expect(hero.id).toEqual(targetHero.id);
|
||||
expect(hero.name).toEqual(targetHero.name);
|
||||
});
|
||||
|
||||
it(`shows updated hero name in details`, async () => {
|
||||
let input = element.all(by.css('input')).first();
|
||||
input.sendKeys(nameSuffix);
|
||||
let page = getPageElts();
|
||||
let hero = await heroFromDetail(page.heroDetail);
|
||||
let newName = targetHero.name + nameSuffix;
|
||||
expect(hero.id).toEqual(targetHero.id);
|
||||
expect(hero.name).toEqual(newName);
|
||||
});
|
||||
}
|
||||
|
||||
function salesTaxTests() {
|
||||
it('has no sales tax initially', function () {
|
||||
let page = getPageElts();
|
||||
expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info');
|
||||
});
|
||||
|
||||
it('shows sales tax', async function () {
|
||||
let page = getPageElts();
|
||||
page.salesTaxAmountInput.sendKeys('10', protractor.Key.ENTER);
|
||||
expect(page.salesTaxDetail.getText()).toEqual('The sales tax is $1.00');
|
||||
});
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
function getPageElts() {
|
||||
return {
|
||||
heroes: element.all(by.css('my-app li')),
|
||||
heroDetail: element(by.css('my-app hero-detail')),
|
||||
salesTaxAmountInput: element(by.css('my-app sales-tax input')),
|
||||
salesTaxDetail: element(by.css('my-app sales-tax div'))
|
||||
};
|
||||
}
|
||||
|
||||
async function heroFromDetail(detail: ElementFinder): Promise<Hero> {
|
||||
// Get hero id from the first <div>
|
||||
// let _id = await detail.all(by.css('div')).first().getText();
|
||||
let _id = await detail.all(by.css('div')).first().getText();
|
||||
// Get name from the h2
|
||||
// let _name = await detail.element(by.css('h4')).getText();
|
||||
let _name = await detail.element(by.css('h4')).getText();
|
||||
return {
|
||||
id: +_id.substr(_id.indexOf(' ') + 1),
|
||||
name: _name.substr(0, _name.lastIndexOf(' '))
|
||||
};
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { protractor, browser, element, by, ElementFinder } from 'protractor';
|
||||
|
||||
const nameSuffix = 'X';
|
||||
|
||||
class Hero {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
describe('Architecture', () => {
|
||||
|
||||
const expectedTitle = 'Architecture of Angular';
|
||||
const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
|
||||
|
||||
beforeAll(() => browser.get(''));
|
||||
|
||||
it(`has title '${expectedTitle}'`, () => {
|
||||
expect(browser.getTitle()).toEqual(expectedTitle);
|
||||
});
|
||||
|
||||
it(`has h2 '${expectedH2}'`, () => {
|
||||
let h2 = element.all(by.css('h2')).map((elt: any) => elt.getText());
|
||||
expect(h2).toEqual(expectedH2);
|
||||
});
|
||||
|
||||
describe('Hero', heroTests);
|
||||
describe('Salex tax', salesTaxTests);
|
||||
});
|
||||
|
||||
function heroTests() {
|
||||
|
||||
const targetHero: Hero = { id: 2, name: 'Mr. Nice' };
|
||||
|
||||
it('has the right number of heroes', () => {
|
||||
let page = getPageElts();
|
||||
expect(page.heroes.count()).toEqual(3);
|
||||
});
|
||||
|
||||
it('has no hero details initially', function () {
|
||||
let page = getPageElts();
|
||||
expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail');
|
||||
});
|
||||
|
||||
it('shows selected hero details', async () => {
|
||||
await element(by.cssContainingText('li', targetHero.name)).click();
|
||||
let page = getPageElts();
|
||||
let hero = await heroFromDetail(page.heroDetail);
|
||||
expect(hero.id).toEqual(targetHero.id);
|
||||
expect(hero.name).toEqual(targetHero.name);
|
||||
});
|
||||
|
||||
it(`shows updated hero name in details`, async () => {
|
||||
let input = element.all(by.css('input')).first();
|
||||
input.sendKeys(nameSuffix);
|
||||
let page = getPageElts();
|
||||
let hero = await heroFromDetail(page.heroDetail);
|
||||
let newName = targetHero.name + nameSuffix;
|
||||
expect(hero.id).toEqual(targetHero.id);
|
||||
expect(hero.name).toEqual(newName);
|
||||
});
|
||||
}
|
||||
|
||||
function salesTaxTests() {
|
||||
it('has no sales tax initially', function () {
|
||||
let page = getPageElts();
|
||||
expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info');
|
||||
});
|
||||
|
||||
it('shows sales tax', async function () {
|
||||
let page = getPageElts();
|
||||
page.salesTaxAmountInput.sendKeys('10', protractor.Key.ENTER);
|
||||
expect(page.salesTaxDetail.getText()).toEqual('The sales tax is $1.00');
|
||||
});
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
function getPageElts() {
|
||||
return {
|
||||
heroes: element.all(by.css('app-root li')),
|
||||
heroDetail: element(by.css('app-root app-hero-detail')),
|
||||
salesTaxAmountInput: element(by.css('app-root app-sales-tax input')),
|
||||
salesTaxDetail: element(by.css('app-root app-sales-tax div'))
|
||||
};
|
||||
}
|
||||
|
||||
async function heroFromDetail(detail: ElementFinder): Promise<Hero> {
|
||||
// Get hero id from the first <div>
|
||||
// let _id = await detail.all(by.css('div')).first().getText();
|
||||
let _id = await detail.all(by.css('div')).first().getText();
|
||||
// Get name from the h2
|
||||
// let _name = await detail.element(by.css('h4')).getText();
|
||||
let _name = await detail.element(by.css('h4')).getText();
|
||||
return {
|
||||
id: +_id.substr(_id.indexOf(' ') + 1),
|
||||
name: _name.substr(0, _name.lastIndexOf(' '))
|
||||
};
|
||||
}
|
9
aio/content/examples/architecture/plnkr.json
Normal file
9
aio/content/examples/architecture/plnkr.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"description": "Intro to Angular",
|
||||
"basePath": "src/",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!app/hero-list.component.1.*"
|
||||
]
|
||||
}
|
@ -3,10 +3,10 @@ import { Component } from '@angular/core';
|
||||
// #enddocregion import
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
selector: 'my-app',
|
||||
template: `
|
||||
<app-hero-list></app-hero-list>
|
||||
<app-sales-tax></app-sales-tax>
|
||||
<hero-list></hero-list>
|
||||
<sales-tax></sales-tax>
|
||||
`
|
||||
})
|
||||
// #docregion export
|
||||
|
@ -1,10 +1,9 @@
|
||||
<hr>
|
||||
<h4>{{hero.name}} Detail</h4>
|
||||
<div>Id: {{hero.id}}</div>
|
||||
<label>Name:
|
||||
<div>Name:
|
||||
<!-- #docregion ngModel -->
|
||||
<input [(ngModel)]="hero.name">
|
||||
<!-- #enddocregion ngModel -->
|
||||
</label>
|
||||
<br />
|
||||
<label>Power: <input [(ngModel)]="hero.power"></label>
|
||||
</div>
|
||||
<div>Power:<input [(ngModel)]="hero.power"></div>
|
||||
|
@ -3,7 +3,7 @@ import { Component, Input } from '@angular/core';
|
||||
import { Hero } from './hero';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero-detail',
|
||||
selector: 'hero-detail',
|
||||
templateUrl: './hero-detail.component.html'
|
||||
})
|
||||
export class HeroDetailComponent {
|
||||
|
@ -1,9 +1,9 @@
|
||||
<!--#docregion binding -->
|
||||
<li>{{hero.name}}</li>
|
||||
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
|
||||
<hero-detail [hero]="selectedHero"></hero-detail>
|
||||
<li (click)="selectHero(hero)"></li>
|
||||
<!--#enddocregion binding -->
|
||||
|
||||
<!--#docregion structural -->
|
||||
<li *ngFor="let hero of heroes"></li>
|
||||
<app-hero-detail *ngIf="selectedHero"></app-hero-detail>
|
||||
<hero-detail *ngIf="selectedHero"></hero-detail>
|
||||
|
@ -8,4 +8,4 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<app-hero-detail *ngIf="selectedHero" [hero]="selectedHero"></app-hero-detail>
|
||||
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>
|
||||
|
@ -5,7 +5,7 @@ import { HeroService } from './hero.service';
|
||||
|
||||
// #docregion metadata, providers
|
||||
@Component({
|
||||
selector: 'app-hero-list',
|
||||
selector: 'hero-list',
|
||||
templateUrl: './hero-list.component.html',
|
||||
providers: [ HeroService ]
|
||||
})
|
||||
|
@ -4,10 +4,10 @@ import { SalesTaxService } from './sales-tax.service';
|
||||
import { TaxRateService } from './tax-rate.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sales-tax',
|
||||
selector: 'sales-tax',
|
||||
template: `
|
||||
<h2>Sales Tax Calculator</h2>
|
||||
<label>Amount: <input #amountBox (change)="0"></label>
|
||||
Amount: <input #amountBox (change)="0">
|
||||
|
||||
<div *ngIf="amountBox.value">
|
||||
The sales tax is
|
||||
|
@ -1,13 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<title>Architecture of Angular</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<base href="/">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<!-- Polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('main.js').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<my-app>Loading...</my-app>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -1,12 +1,5 @@
|
||||
// #docregion
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"description": "Intro to Angular",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1].*"
|
||||
],
|
||||
"file": "src/app/app.module.ts"
|
||||
}
|
10
aio/content/examples/attribute-directives/plnkr.json
Normal file
10
aio/content/examples/attribute-directives/plnkr.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description": "Attribute Directive",
|
||||
"basePath": "src/",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!app/*.[1,2,3].*"
|
||||
],
|
||||
"tags": ["attribute", "directive"]
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
<!-- #docregion -->
|
||||
<h1>My First Attribute Directive</h1>
|
||||
<!-- #docregion applied -->
|
||||
<p appHighlight>Highlight me!</p>
|
||||
<p myHighlight>Highlight me!</p>
|
||||
<!-- #enddocregion applied, -->
|
||||
|
||||
<!-- #docregion color-1 -->
|
||||
<p appHighlight highlightColor="yellow">Highlighted in yellow</p>
|
||||
<p appHighlight [highlightColor]="'orange'">Highlighted in orange</p>
|
||||
<p myHighlight highlightColor="yellow">Highlighted in yellow</p>
|
||||
<p myHighlight [highlightColor]="'orange'">Highlighted in orange</p>
|
||||
<!-- #enddocregion color-1 -->
|
||||
|
||||
<!-- #docregion color-2 -->
|
||||
<p appHighlight [highlightColor]="color">Highlighted with parent component's color</p>
|
||||
<p myHighlight [highlightColor]="color">Highlighted with parent component's color</p>
|
||||
<!-- #enddocregion color-2 -->
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
selector: 'my-app',
|
||||
templateUrl: './app.component.1.html'
|
||||
})
|
||||
// #docregion class
|
||||
|
@ -8,11 +8,11 @@
|
||||
<input type="radio" name="colors" (click)="color='cyan'">Cyan
|
||||
</div>
|
||||
<!-- #docregion color -->
|
||||
<p [appHighlight]="color">Highlight me!</p>
|
||||
<p [myHighlight]="color">Highlight me!</p>
|
||||
<!-- #enddocregion color, v2 -->
|
||||
|
||||
<!-- #docregion defaultColor -->
|
||||
<p [appHighlight]="color" defaultColor="violet">
|
||||
<p [myHighlight]="color" defaultColor="violet">
|
||||
Highlight me too!
|
||||
</p>
|
||||
<!-- #enddocregion defaultColor, -->
|
||||
@ -20,5 +20,5 @@
|
||||
<hr>
|
||||
<p><i>Mouse over the following lines to see fixed highlights</i></p>
|
||||
|
||||
<p [appHighlight]="'yellow'">Highlighted in yellow</p>
|
||||
<p appHighlight="orange">Highlighted in orange</p>
|
||||
<p [myHighlight]="'yellow'">Highlighted in yellow</p>
|
||||
<p myHighlight="orange">Highlighted in orange</p>
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
selector: 'my-app',
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
// #docregion class
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Not used. Keep away from stackblitz
|
||||
// Not used. Keep away from plunker
|
||||
// Keeps ATLS from complaining about undeclared directives.
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
@ -1,9 +0,0 @@
|
||||
// #docregion
|
||||
import { Directive } from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[appHighlight]'
|
||||
})
|
||||
export class HighlightDirective {
|
||||
constructor() { }
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
/* tslint:disable:no-unused-variable */
|
||||
// #docregion
|
||||
import { Directive, ElementRef } from '@angular/core';
|
||||
import { Directive, ElementRef, Input } from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[appHighlight]'
|
||||
})
|
||||
@Directive({ selector: '[myHighlight]' })
|
||||
export class HighlightDirective {
|
||||
constructor(el: ElementRef) {
|
||||
el.nativeElement.style.backgroundColor = 'yellow';
|
||||
|
@ -1,13 +1,10 @@
|
||||
/* tslint:disable:no-unused-variable member-ordering */
|
||||
// #docplaster
|
||||
// #docregion imports,
|
||||
import { Directive, ElementRef, HostListener } from '@angular/core';
|
||||
// #enddocregion imports,
|
||||
import { Input } from '@angular/core';
|
||||
// #docregion
|
||||
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
|
||||
|
||||
@Directive({
|
||||
selector: '[appHighlight]'
|
||||
selector: '[myHighlight]'
|
||||
})
|
||||
export class HighlightDirective {
|
||||
// #docregion ctor
|
||||
@ -38,7 +35,7 @@ export class HighlightDirective {
|
||||
// #enddocregion color
|
||||
|
||||
// #docregion color-2
|
||||
@Input() appHighlight: string;
|
||||
@Input() myHighlight: string;
|
||||
// #enddocregion color-2
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,15 @@
|
||||
/* tslint:disable:member-ordering */
|
||||
// #docregion, imports
|
||||
// #docregion
|
||||
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
|
||||
// #enddocregion imports
|
||||
|
||||
@Directive({
|
||||
selector: '[appHighlight]'
|
||||
selector: '[myHighlight]'
|
||||
})
|
||||
export class HighlightDirective {
|
||||
|
||||
constructor(private el: ElementRef) { }
|
||||
|
||||
@Input('appHighlight') highlightColor: string;
|
||||
@Input('myHighlight') highlightColor: string;
|
||||
|
||||
// #docregion mouse-enter
|
||||
@HostListener('mouseenter') onMouseEnter() {
|
||||
|
@ -1,8 +1,10 @@
|
||||
/* tslint:disable:member-ordering */
|
||||
// #docregion imports,
|
||||
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
|
||||
// #enddocregion imports
|
||||
|
||||
@Directive({
|
||||
selector: '[appHighlight]'
|
||||
selector: '[myHighlight]'
|
||||
})
|
||||
export class HighlightDirective {
|
||||
|
||||
@ -13,7 +15,7 @@ export class HighlightDirective {
|
||||
// #enddocregion defaultColor
|
||||
|
||||
// #docregion color
|
||||
@Input('appHighlight') highlightColor: string;
|
||||
@Input('myHighlight') highlightColor: string;
|
||||
// #enddocregion color
|
||||
|
||||
// #docregion mouse-enter
|
||||
|
@ -1,13 +1,25 @@
|
||||
<!-- #docregion -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Attribute Directives</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<!-- Polyfills -->
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('main.js').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<my-app>loading...</my-app>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,12 +1,5 @@
|
||||
// #docregion
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"description": "Attribute Directive",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1,2,3].*"
|
||||
],
|
||||
"tags": ["attribute", "directive"]
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"server": {
|
||||
"baseDir": "src",
|
||||
"routes": {
|
||||
"/node_modules": "node_modules"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('feature-modules App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display message saying app works', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('app works!');
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user