Compare commits
420 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2549313eab | |||
| 26fccb9943 | |||
| efb822c58d | |||
| b7d1e0fbdb | |||
| 31ea071f2e | |||
| abe6acf598 | |||
| f04e04e0e6 | |||
| 4355dee21d | |||
| 2f0ac696cb | |||
| da3d96c0ea | |||
| bc775759c8 | |||
| fa4451d57f | |||
| a0c55af985 | |||
| d1dd6a3624 | |||
| e5eaecc32b | |||
| 24ddbafbdf | |||
| 980b69dcae | |||
| 52e46683bf | |||
| 0b0a122888 | |||
| b166f2b34a | |||
| ac06fb6592 | |||
| 20dbc1161f | |||
| f78268fbf7 | |||
| 85286bd863 | |||
| 1faf7ec30d | |||
| 20724da544 | |||
| 3964598bcf | |||
| cd700f65f4 | |||
| f36f25f17a | |||
| fcc26063c5 | |||
| 0b66753488 | |||
| b30a925d54 | |||
| fe599dbb72 | |||
| a7dfa7cd83 | |||
| a19a17e288 | |||
| b3224671fb | |||
| 2953e47da4 | |||
| 96bee0c659 | |||
| 5b87647243 | |||
| 6f10c2d9d1 | |||
| 76882169ba | |||
| f93c770cc2 | |||
| 06f5069813 | |||
| 8681fce27b | |||
| 5a022524a3 | |||
| 5acfac894c | |||
| a879e82a9b | |||
| c03fda012a | |||
| 976e34bab6 | |||
| 9a1b7c9fa1 | |||
| c33fd13254 | |||
| 336bad182f | |||
| 553ca78406 | |||
| 0722ab0ba1 | |||
| ee8e05cfaf | |||
| 9509feba99 | |||
| b0b3a2b6cb | |||
| 3abe5b77b3 | |||
| 858807ad5d | |||
| 7436063a7d | |||
| d1bc780304 | |||
| 28f273e473 | |||
| 1cdc72f3a5 | |||
| c3c5c5eea2 | |||
| 4cc7701700 | |||
| 5dc07667de | |||
| 212e5132ab | |||
| 00162655e7 | |||
| 09f1325065 | |||
| c01dad694d | |||
| c4586513d1 | |||
| 7a1270cf4b | |||
| 559e93c7ce | |||
| 9d058de04b | |||
| 1d826e2f1e | |||
| 5789094546 | |||
| cf92c33a32 | |||
| 5d8f5a8be7 | |||
| 74a2808487 | |||
| 9ba181b80f | |||
| 44c16b5b51 | |||
| 70a42fcaee | |||
| 3bd62d2d59 | |||
| b9ef6585e1 | |||
| e06b4fb62c | |||
| 9204a1a153 | |||
| f4d49f3769 | |||
| d5c35b44d7 | |||
| 551375c736 | |||
| 17691790e9 | |||
| e47dead052 | |||
| 1a2532601b | |||
| cb862aaaa0 | |||
| fa2034c167 | |||
| 750b43b6f6 | |||
| 048f5e3ab8 | |||
| 13c566cc03 | |||
| 45834eac09 | |||
| 3673909896 | |||
| 8302981a08 | |||
| d2a7b5162f | |||
| 2ecd85b989 | |||
| 2bdf712687 | |||
| 0de02973c1 | |||
| 55516da2df | |||
| e8adbf8d5a | |||
| c169c60535 | |||
| 0b6ec6b3ab | |||
| d2511cfac0 | |||
| 155efa421b | |||
| f33d95cfcf | |||
| 57b626a673 | |||
| b168aef861 | |||
| 6c4d2707b7 | |||
| 9c95f6d5e0 | |||
| cab9ebfd5a | |||
| 8a739fb4fa | |||
| c4003fd034 | |||
| ab856d8ae3 | |||
| 83e6eef68e | |||
| 87270cb79f | |||
| e06ebfdbb5 | |||
| ddeb1df15a | |||
| 358a69fa8b | |||
| 417aefd45d | |||
| 6ad4c8d1b4 | |||
| 3ef612afa0 | |||
| cc8486f994 | |||
| b990fa91cd | |||
| 17f7d8c5c8 | |||
| 1e8dd0e65c | |||
| b1a18ef381 | |||
| 3470ab5696 | |||
| 5d39a118df | |||
| 421a5856f8 | |||
| 85f40a15fb | |||
| b919a2737e | |||
| a675ea0343 | |||
| 8fb8d52664 | |||
| d60d904747 | |||
| 62afb6204c | |||
| 1eaf4ab414 | |||
| 1de5d181da | |||
| 73088bb7ee | |||
| 898140edb7 | |||
| dab60352e5 | |||
| df4955fe78 | |||
| 14519488ce | |||
| 569e906a58 | |||
| 18b8a63a3c | |||
| 6e78fee732 | |||
| 6a99eaf1c8 | |||
| c94e44b9f8 | |||
| bbca6b0893 | |||
| 1555a4911a | |||
| dbba98b9ae | |||
| 3e2cb6c15c | |||
| 1391e99c7f | |||
| 7a5f06d55d | |||
| bf78beeb6d | |||
| 2e892e4072 | |||
| 8f88ea57dc | |||
| 24b0b516b6 | |||
| 1fcf5949d2 | |||
| 46ccaee9be | |||
| 86c9990813 | |||
| 4a34c8e1b8 | |||
| fec2ea8c1b | |||
| 7566c7d26f | |||
| 02a19c0f39 | |||
| 6e6e4eec9d | |||
| 46f14fa4b8 | |||
| bad2249bcd | |||
| c2148ec15c | |||
| 474e40498e | |||
| e9a6792d7f | |||
| adc1501caa | |||
| 7a53707c8f | |||
| 57fe5b320d | |||
| 671bebde0a | |||
| b51ded6736 | |||
| 3ec1819b91 | |||
| 009ebec64c | |||
| 9256dbc420 | |||
| 7504656a26 | |||
| e74cdf4b59 | |||
| 9d6c3f3ec2 | |||
| ac0e260765 | |||
| 28c0213ee5 | |||
| 8b4d85c015 | |||
| 2aeda67909 | |||
| ad68ee192e | |||
| 970ba117eb | |||
| 30e097b389 | |||
| e8e02b8bce | |||
| e36a3e89f5 | |||
| 1102c41196 | |||
| e970c8fce9 | |||
| 04271d6b2c | |||
| 2e1163ef5c | |||
| 75befe723a | |||
| 5e2bc5bbf3 | |||
| 079c485b92 | |||
| 19a0c9324c | |||
| 9ef02e72ab | |||
| 2101126ce7 | |||
| a222d0b452 | |||
| 1b8eb231c9 | |||
| 06baf1869b | |||
| 82597fc12b | |||
| ff52b188a7 | |||
| dc41f465ba | |||
| 6e3b5a57cd | |||
| f003d93a3d | |||
| aac5623247 | |||
| aa03812fd0 | |||
| bcb6a494de | |||
| a1e3f8728e | |||
| 9e8e3e187d | |||
| c6554433cf | |||
| 43d2a75f4e | |||
| 37d2b50812 | |||
| 8f31f1ff43 | |||
| cf84fcf544 | |||
| f63bc3cfde | |||
| a77943110e | |||
| ec97686f2f | |||
| 4ff7b7aa48 | |||
| 57b837bd5c | |||
| 6daca023e4 | |||
| 91b4eb0f69 | |||
| e50ed4da9e | |||
| fe5dd1da8f | |||
| df4c03fa33 | |||
| 8d4e626326 | |||
| 92aef5d456 | |||
| eed13cf732 | |||
| e90200b4de | |||
| 7f36ba77a0 | |||
| 457c58827b | |||
| aae768611f | |||
| ce5ffbf667 | |||
| ab114af850 | |||
| 2759788737 | |||
| c643323c17 | |||
| 9b97a033b0 | |||
| a3226d01fa | |||
| 510d0f946f | |||
| 0b962d4881 | |||
| 71b4daa4e1 | |||
| e0b02a5040 | |||
| a0dd9b0fdd | |||
| 498bef199a | |||
| 17d34b7a98 | |||
| 72359fd097 | |||
| 72882190f2 | |||
| fd2d8a5755 | |||
| fbe84f95a1 | |||
| 3671a43be4 | |||
| f6a1ad528d | |||
| d9128e7b23 | |||
| 0b54c1d4a9 | |||
| 608d623b55 | |||
| 9f30bb5475 | |||
| 182fb18f00 | |||
| 3a9fdceeee | |||
| ee4ac72170 | |||
| eb9fc571a0 | |||
| b4d1e5e492 | |||
| 60394a9d91 | |||
| f5ddb10b56 | |||
| 6a448d3459 | |||
| 6a8c0f5f4a | |||
| 584308fc06 | |||
| 48ad2c44bf | |||
| 100998330a | |||
| b9e85c62be | |||
| 77fad099d2 | |||
| e1f8a6e82b | |||
| 132d767647 | |||
| 9cde98cbc7 | |||
| 1ddbb3ec3e | |||
| 34f40266b2 | |||
| b8c06e3f1b | |||
| a6cf648b3c | |||
| aebde27f1b | |||
| c9be327d53 | |||
| 3dc7d22d90 | |||
| c10c6cac74 | |||
| cee2c4c569 | |||
| a5160c82dc | |||
| 8853312197 | |||
| 049b24de21 | |||
| a9f987a0c9 | |||
| ad4a20d3d2 | |||
| b3972d1b65 | |||
| c3e0d58b3c | |||
| f08156ea9b | |||
| 4bacf5a5da | |||
| df88873bb7 | |||
| c4b1c5e8f1 | |||
| 9822711ad2 | |||
| 30cd764b6d | |||
| 38b75cdb2d | |||
| 6cb8b39af8 | |||
| ebaa336614 | |||
| ef5f567f91 | |||
| 64e5afc478 | |||
| 1e582e4fa4 | |||
| 7421235f24 | |||
| 09ba69078d | |||
| 3536e83d8a | |||
| 3bb1dd5d7f | |||
| 95f964b827 | |||
| c8f78a8ca9 | |||
| f34d48087b | |||
| 2c9ecd01b1 | |||
| a584fb6e15 | |||
| 1f13313f40 | |||
| 5b60303781 | |||
| 10e2552a7d | |||
| ef48b0aa55 | |||
| f57872bca0 | |||
| 2deaf2877e | |||
| 7a146c9cd5 | |||
| 2796ec172b | |||
| 6997c1bf0c | |||
| 4a030f3834 | |||
| f78d8b8ff3 | |||
| f27d19ed60 | |||
| 4a5eaf7bec | |||
| 8513674911 | |||
| 97b74ad6fb | |||
| a47ea79023 | |||
| 5ca0de6487 | |||
| 50a449f053 | |||
| d7422da7d7 | |||
| c7cbc978c6 | |||
| 27146e8a7f | |||
| 5e418b1145 | |||
| f4bb973eb7 | |||
| 848857aa5b | |||
| ee8a05d3f1 | |||
| 275ebbf0ec | |||
| 0f23df4c06 | |||
| 11f700f7bd | |||
| 5785f2a991 | |||
| 2546c29f81 | |||
| 19ea708c9d | |||
| 5cf05d67f2 | |||
| 0377c6f0e8 | |||
| 9c13866824 | |||
| 419a4813e3 | |||
| 131af8272d | |||
| c219a46f59 | |||
| 25f008f541 | |||
| 4a593db79b | |||
| ad4fef0431 | |||
| 8a15fcc1f5 | |||
| f01212ab52 | |||
| 28693a1a67 | |||
| 29fd499552 | |||
| 2f97d9d647 | |||
| 4146b38459 | |||
| 05aab660ce | |||
| 5ecb64849e | |||
| 59dfe1b5a0 | |||
| 50ebfb735c | |||
| 0bdbfe5069 | |||
| 3fc4d6028c | |||
| 2eb12a052b | |||
| bd63b2235c | |||
| f418ffd083 | |||
| 6ab5f8ce4b | |||
| becfeb5aa3 | |||
| eb968c4a68 | |||
| 7f2af3f923 | |||
| cce98ff53a | |||
| b607618342 | |||
| fa50fbaf57 | |||
| f135e2dc05 | |||
| 780351db5e | |||
| a50bb0bfec | |||
| 4d86df6f48 | |||
| bb464d16b4 | |||
| 85b2eb1472 | |||
| 7608f92c6a | |||
| c0bf8db63c | |||
| c95a6737fb | |||
| cd43d24402 | |||
| 086c5d0354 | |||
| 2a2ac5f53a | |||
| 21deaf637a | |||
| 72e15a3a83 | |||
| 174cb4a8c8 | |||
| 33f769b0a1 | |||
| c8abf20558 | |||
| 6dbb183e75 | |||
| bc4844d3b2 | |||
| 708f8b47de | |||
| 5518126d42 | |||
| 5fe73fdc3a | |||
| 394c496bf2 | |||
| 8e1aeba715 | |||
| 0e6e7eb477 | |||
| 183f636816 | |||
| 5f8ed63f2a | |||
| e4f3c94e31 | |||
| 1e5cbcbd93 | |||
| dcf3ec160f | |||
| a7beb5b6d3 | |||
| 1d3b65adc2 | |||
| d528644fe3 | |||
| 6f1bcfc14e | |||
| 996914c6b0 | |||
| fff048d099 | |||
| dcb0da8225 | |||
| b664e20d12 | |||
| 3d68b95028 | |||
| 163aca336d |
@@ -1,509 +0,0 @@
|
||||
# Configuration file for https://circleci.com/gh/angular/angular.js
|
||||
|
||||
# Note: YAML anchors allow an object to be re-used, reducing duplication.
|
||||
# The ampersand declares an alias for an object, then later the `<<: *name`
|
||||
# syntax dereferences it.
|
||||
# See http://blog.daemonl.com/2016/02/yaml.html
|
||||
# To validate changes, use an online parser, eg.
|
||||
# http://yaml-online-parser.appspot.com/
|
||||
|
||||
# CircleCI configuration version
|
||||
# Version 2.1 allows for extra config reuse features
|
||||
# https://circleci.com/docs/2.0/reusing-config/#getting-started-with-config-reuse
|
||||
version: 2.1
|
||||
|
||||
# Workspace persisted by the `setup` job to share build artifacts with other jobs.
|
||||
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
|
||||
# https://circleci.com/blog/deep-diving-into-circleci-workspaces/
|
||||
var_workspace_location: &workspace_location ~/
|
||||
|
||||
# Executor Definitions
|
||||
# https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-executors
|
||||
# **NOTE 1**: Pin to exact images using an ID (SHA). See https://circleci.com/docs/2.0/circleci-images/#using-a-docker-image-id-to-pin-an-image-to-a-fixed-version.
|
||||
# (Using the tag in not necessary when pinning by ID, but include it anyway for documentation purposes.)
|
||||
executors:
|
||||
default-executor:
|
||||
parameters:
|
||||
resource_class:
|
||||
type: string
|
||||
default: medium
|
||||
docker:
|
||||
- image: circleci/node:14.16.1@sha256:b094e85848b43209ca83d9bb114d406fe62c75cb73b18c9d8eb1a9c6462c97d4
|
||||
resource_class: << parameters.resource_class >>
|
||||
working_directory: ~/ng
|
||||
cloud-sdk:
|
||||
description: The docker container to use when running gcp-gcs commands
|
||||
docker:
|
||||
- image: google/cloud-sdk:alpine@sha256:7d0cae28cb282b76f2d9babe278c63c910d54f0cceca7a65fdf6806e2b43882e
|
||||
working_directory: ~/ng
|
||||
|
||||
|
||||
# Filter Definitions
|
||||
|
||||
# Filter to run a job on all branches and any `v1.X.Y(-Z)` tags.
|
||||
# Since the jobs need to run on tagged builds too, a `tags` section has to be explicitly specified.
|
||||
# (The `branches` section could be omitted, since it defaults to all branches - just being explicit
|
||||
# here).
|
||||
# See also https://circleci.com/docs/2.0/workflows/#executing-workflows-for-a-git-tag.
|
||||
var-filter-run-always: &run-always
|
||||
filters:
|
||||
branches:
|
||||
only: /.*/
|
||||
tags:
|
||||
only: /v1\.\d+\.\d.*/
|
||||
|
||||
# Filter to run a job when code might need to be deployed - i.e. on builds for the `master` branch.
|
||||
# (Further checks are needed to determine whether a deployment is actually needed, but these are not
|
||||
# possible via filters.)
|
||||
var-filter-run-on-master: &run-on-master
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
tags:
|
||||
ignore: /.*/
|
||||
|
||||
# Filter to run a job when code/docs might need to be deployed - i.e. on tagged builds and on builds
|
||||
# for master and `v1.*.x` branches.
|
||||
# (Further checks are needed to determine whether a deployment is actually needed, but these are not
|
||||
# possible via filters.)
|
||||
var-filter-run-on-tags-and-master-and-version-branches: &run-on-tags-and-master-and-version-branches
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /v1\.\d+\.x/
|
||||
tags:
|
||||
only: /v1\.\d+\.\d.*/
|
||||
|
||||
# Filter to run a job when docs might need to be deployed - i.e. on builds for `v1.*.x` branches,
|
||||
# which might correspond to the stable branch.
|
||||
# (Further checks are needed to determine whether a deployment is actually needed, but these are not
|
||||
# possible via filters.)
|
||||
var-filter-run-on-version-branches: &run-on-version-branches
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /v1\.\d+\.x/
|
||||
tags:
|
||||
ignore: /.*/
|
||||
|
||||
|
||||
# Command Definitions
|
||||
# https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-commands
|
||||
commands:
|
||||
skip_on_pr_and_fork_builds:
|
||||
description: Skip a job on pull request and fork builds
|
||||
steps:
|
||||
- run:
|
||||
name: Skip this job if this is a pull request or fork build
|
||||
# Note: Using `CIRCLE_*` env variables (instead of those defined in `env.sh` so that this
|
||||
# step can be run before `init_environment`.
|
||||
command: >
|
||||
if [[ -n "$CIRCLE_PR_NUMBER" ]] ||
|
||||
[[ "$CIRCLE_PROJECT_USERNAME" != "angular" ]] ||
|
||||
[[ "$CIRCLE_PROJECT_REPONAME" != "angular.js" ]]; then
|
||||
echo "Skipping this job, because this is either a pull request or a fork build."
|
||||
circleci step halt
|
||||
fi
|
||||
|
||||
skip_unless_stable_branch:
|
||||
description: Skip a job unless this is the stable branch
|
||||
steps:
|
||||
- run:
|
||||
name: Skip this job unless this is the stable branch
|
||||
command: >
|
||||
if [[ "$DIST_TAG" != "latest" ]]; then
|
||||
echo "Skipping deployment, because this is not the stable branch."
|
||||
circleci step halt
|
||||
fi
|
||||
|
||||
skip_unless_tag_or_master_or_stable_branch:
|
||||
description: Skip a job unless this is a tag or the master or stable branch
|
||||
steps:
|
||||
- run:
|
||||
name: Skip this job unless this is a tag or the master or stable branch
|
||||
command: >
|
||||
if [[ "$CI_GIT_TAG" == "false" ]] &&
|
||||
[[ "$CI_BRANCH" != "master" ]] &&
|
||||
[[ "$DIST_TAG" != "latest" ]]; then
|
||||
echo "Skipping this job, because this is neither a tag nor the master or stable branch."
|
||||
circleci step halt
|
||||
fi
|
||||
|
||||
|
||||
custom_attach_workspace:
|
||||
description: Attach workspace at a predefined location
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: *workspace_location
|
||||
|
||||
# Java is needed for running the Closure Compiler (during the `minall` task).
|
||||
install_java:
|
||||
description: Install java
|
||||
steps:
|
||||
- run:
|
||||
name: Install java
|
||||
command: |
|
||||
sudo apt-get update
|
||||
# Install java runtime
|
||||
sudo apt-get install default-jre
|
||||
|
||||
# Initializes the CI environment by setting up common environment variables.
|
||||
init_environment:
|
||||
description: Initializing environment (setting up variables)
|
||||
steps:
|
||||
- run:
|
||||
name: Set up environment
|
||||
environment:
|
||||
CIRCLE_GIT_BASE_REVISION: << pipeline.git.base_revision >>
|
||||
CIRCLE_GIT_REVISION: << pipeline.git.revision >>
|
||||
command: ./.circleci/env.sh
|
||||
- run:
|
||||
# Configure git as the CircleCI `checkout` command does.
|
||||
# This is needed because we only checkout on the setup job.
|
||||
# Add GitHub to known hosts
|
||||
name: Configure git
|
||||
command: |
|
||||
mkdir -p ~/.ssh
|
||||
echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' >> ~/.ssh/known_hosts
|
||||
git config --global url."ssh://git@github.com".insteadOf "https://github.com" || true
|
||||
git config --global gc.auto 0 || true
|
||||
|
||||
init_saucelabs_environment:
|
||||
description: Sets up a domain that resolves to the local host.
|
||||
steps:
|
||||
- run:
|
||||
name: Preparing environment for running tests on Saucelabs.
|
||||
command: |
|
||||
# For SauceLabs jobs, we set up a domain which resolves to the machine which launched
|
||||
# the tunnel. We do this because devices are sometimes not able to properly resolve
|
||||
# `localhost` or `127.0.0.1` through the SauceLabs tunnel. Using a domain that does not
|
||||
# resolve to anything on SauceLabs VMs ensures that such requests are always resolved
|
||||
# through the tunnel, and resolve to the actual tunnel host machine (i.e. the CircleCI VM).
|
||||
# More context can be found in: https://github.com/angular/angular/pull/35171.
|
||||
setPublicVar SAUCE_LOCALHOST_ALIAS_DOMAIN "angular-ci.local"
|
||||
setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev)
|
||||
- run:
|
||||
# Sets up a local domain in the machine's host file that resolves to the local
|
||||
# host. This domain is helpful in Saucelabs tests where devices are not able to
|
||||
# properly resolve `localhost` or `127.0.0.1` through the sauce-connect tunnel.
|
||||
name: Setting up alias domain for local host.
|
||||
command: echo "127.0.0.1 $SAUCE_LOCALHOST_ALIAS_DOMAIN" | sudo tee -a /etc/hosts
|
||||
|
||||
start_saucelabs:
|
||||
steps:
|
||||
- run:
|
||||
name: Starting Saucelabs tunnel service
|
||||
command: ./lib/saucelabs/sauce-service.sh start-ready-wait
|
||||
|
||||
stop_saucelabs:
|
||||
steps:
|
||||
- run:
|
||||
name: Stopping Saucelabs tunnel service
|
||||
command: ./lib/saucelabs/sauce-service.sh stop
|
||||
|
||||
run_e2e_tests:
|
||||
parameters:
|
||||
specs:
|
||||
type: string
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- init_saucelabs_environment
|
||||
- start_saucelabs
|
||||
- run:
|
||||
command: yarn grunt test:circleci-protractor --specs="<< parameters.specs >>"
|
||||
no_output_timeout: 30m
|
||||
- stop_saucelabs
|
||||
|
||||
run_e2e_tests_jquery:
|
||||
parameters:
|
||||
specs:
|
||||
type: string
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- init_saucelabs_environment
|
||||
- start_saucelabs
|
||||
- run:
|
||||
environment:
|
||||
USE_JQUERY: 1
|
||||
command: yarn grunt test:circleci-protractor --specs="<< parameters.specs >>"
|
||||
no_output_timeout: 30m
|
||||
- stop_saucelabs
|
||||
|
||||
# Job definitions
|
||||
# Jobs can include parameters that are passed in the workflow job invocation.
|
||||
# https://circleci.com/docs/2.0/reusing-config/#authoring-parameterized-jobs
|
||||
jobs:
|
||||
setup:
|
||||
executor: default-executor
|
||||
steps:
|
||||
- checkout
|
||||
- init_environment
|
||||
- install_java
|
||||
- run:
|
||||
name: Running Yarn install
|
||||
command: yarn install --frozen-lockfile --non-interactive
|
||||
# Yarn's requests sometimes take more than 10mins to complete.
|
||||
no_output_timeout: 45m
|
||||
- run: yarn grunt package
|
||||
# Persist any changes at this point to be reused by further jobs.
|
||||
# **NOTE**: To add new content to the workspace, always persist on the same root.
|
||||
- persist_to_workspace:
|
||||
root: *workspace_location
|
||||
paths:
|
||||
- ./ng
|
||||
|
||||
lint:
|
||||
executor: default-executor
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- run: yarn grunt ci-checks
|
||||
- run: yarn commitplease "$CI_COMMIT_RANGE"
|
||||
- run: yarn grunt validate-angular-files
|
||||
|
||||
unit-test:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- install_java
|
||||
- init_saucelabs_environment
|
||||
- run: yarn grunt test:promises-aplus
|
||||
- run:
|
||||
command: yarn grunt test:jqlite --browsers="$BROWSERS" --reporters=spec
|
||||
no_output_timeout: 10m
|
||||
- run:
|
||||
command: yarn grunt test:modules --browsers="$BROWSERS" --reporters=spec
|
||||
no_output_timeout: 10m
|
||||
- run:
|
||||
command: yarn grunt test:docs --browsers="$BROWSERS" --reporters=spec
|
||||
no_output_timeout: 10m
|
||||
|
||||
unit-test-jquery:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- init_saucelabs_environment
|
||||
- run:
|
||||
command: yarn grunt test:jquery --browsers="$BROWSERS" --reporters=spec
|
||||
no_output_timeout: 10m
|
||||
- run:
|
||||
command: yarn grunt test:jquery-2.2 --browsers="$BROWSERS" --reporters=spec
|
||||
no_output_timeout: 10m
|
||||
- run:
|
||||
command: yarn grunt test:jquery-2.1 --browsers="$BROWSERS" --reporters=spec
|
||||
no_output_timeout: 10m
|
||||
|
||||
e2e-test-1:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- run_e2e_tests:
|
||||
specs: test/e2e/tests/**/*.js
|
||||
|
||||
e2e-test-2a:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- run_e2e_tests:
|
||||
specs: build/docs/ptore2e/example-ng*/**/default_test.js
|
||||
|
||||
e2e-test-2b:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- run_e2e_tests:
|
||||
specs: "build/docs/ptore2e/!(example-ng*)/**/default_test.js"
|
||||
|
||||
e2e-test-jquery-1:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- run_e2e_tests_jquery:
|
||||
specs: test/e2e/tests/**/*.js
|
||||
|
||||
e2e-test-jquery-2a:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- run_e2e_tests_jquery:
|
||||
specs: build/docs/ptore2e/example-ng*/**/jquery_test.js
|
||||
|
||||
e2e-test-jquery-2b:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- run_e2e_tests_jquery:
|
||||
specs: build/docs/ptore2e/!(example-ng*)/**/jquery_test.js
|
||||
|
||||
prepare-deployment:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- skip_on_pr_and_fork_builds
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- run: yarn grunt prepareDeploy
|
||||
# Write the deployment files to the workspace to be used by deploy-docs and deploy-code
|
||||
- persist_to_workspace:
|
||||
root: *workspace_location
|
||||
paths:
|
||||
- ./ng
|
||||
|
||||
# The `deploy-code-files` job should only run when all of these conditions are true for the build:
|
||||
# - It is for the `angular/angular.js` repository (not a fork).
|
||||
# - It is not for a pull request.
|
||||
# - It is for a tag or the master branch or the stable branch(*).
|
||||
#
|
||||
# *: The stable branch is the one that has the value `latest` in `package.json > distTag`.
|
||||
deploy-code-files:
|
||||
executor:
|
||||
name: cloud-sdk
|
||||
steps:
|
||||
- skip_on_pr_and_fork_builds
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- skip_unless_tag_or_master_or_stable_branch
|
||||
- run: ls scripts/code.angularjs.org-firebase/deploy
|
||||
- run:
|
||||
name: Authenticate and configure Docker
|
||||
command: |
|
||||
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
|
||||
gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
|
||||
- run:
|
||||
name: Sync files to code.angularjs.org
|
||||
command: |
|
||||
gsutil -m rsync -r scripts/code.angularjs.org-firebase/deploy gs://code-angularjs-org-338b8.appspot.com
|
||||
|
||||
# The `deploy-code-firebase` job should only run when all of these conditions are true for the build:
|
||||
# - It is for the `angular/angular.js` repository (not a fork).
|
||||
# - It is not for a pull request.
|
||||
# - It is for the master branch.
|
||||
# (This is enforced via job filters, so we don't need to a step to check it here.)
|
||||
deploy-code-firebase:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- skip_on_pr_and_fork_builds
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
# Install dependencies for Firebase functions to prevent parsing errors during deployment.
|
||||
# See https://github.com/angular/angular.js/pull/16453.
|
||||
- run:
|
||||
name: Install dependencies in `scripts/code.angularjs.org-firebase/functions/`.
|
||||
working_directory: scripts/code.angularjs.org-firebase/functions
|
||||
command: yarn install --frozen-lockfile --ignore-engines --non-interactive
|
||||
- run:
|
||||
name: Deploy to Firebase from `scripts/code.angularjs.org-firebase/`.
|
||||
working_directory: scripts/code.angularjs.org-firebase
|
||||
command: |
|
||||
# Do not use `yarn firebase` as that causes the Firebase CLI to look for `firebase.json`
|
||||
# in the root directory, even if run from inside `scripts/code.angularjs.org-firebase/`.
|
||||
firebase=$(yarn bin)/firebase
|
||||
$firebase use
|
||||
$firebase deploy --message "Commit:\ $CI_COMMIT" --non-interactive --token "$FIREBASE_TOKEN"
|
||||
|
||||
# The `deploy-docs` job should only run when all of these conditions are true for the build:
|
||||
# - It is for the `angular/angular.js` repository (not a fork).
|
||||
# - It is not for a pull request.
|
||||
# - It is for the stable branch(*).
|
||||
#
|
||||
# *: The stable branch is the one that has the value `latest` in `package.json > distTag`.
|
||||
deploy-docs:
|
||||
executor:
|
||||
name: default-executor
|
||||
steps:
|
||||
- skip_on_pr_and_fork_builds
|
||||
- custom_attach_workspace
|
||||
- init_environment
|
||||
- skip_unless_stable_branch
|
||||
# Install dependencies for Firebase functions to prevent parsing errors during deployment.
|
||||
# See https://github.com/angular/angular.js/pull/16453.
|
||||
- run:
|
||||
name: Install dependencies in `scripts/docs.angularjs.org-firebase/functions/`.
|
||||
working_directory: scripts/docs.angularjs.org-firebase/functions
|
||||
command: yarn install --frozen-lockfile --ignore-engines --non-interactive
|
||||
- run:
|
||||
name: Deploy to Firebase from `scripts/docs.angularjs.org-firebase/`.
|
||||
working_directory: scripts/docs.angularjs.org-firebase
|
||||
command: |
|
||||
# Do not use `yarn firebase` as that causes the Firebase CLI to look for `firebase.json`
|
||||
# in the root directory, even if run from inside `scripts/docs.angularjs.org-firebase/`.
|
||||
firebase=$(yarn bin)/firebase
|
||||
$firebase use
|
||||
$firebase deploy --message "Commit:\ $CI_COMMIT" --non-interactive --token "$FIREBASE_TOKEN"
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
default_workflow:
|
||||
jobs:
|
||||
- setup:
|
||||
<<: *run-always
|
||||
- lint:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- unit-test:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- unit-test-jquery:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- e2e-test-1:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- e2e-test-2a:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- e2e-test-2b:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- e2e-test-jquery-1:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- e2e-test-jquery-2a:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- e2e-test-jquery-2b:
|
||||
<<: *run-always
|
||||
requires:
|
||||
- setup
|
||||
- prepare-deployment:
|
||||
<<: *run-on-tags-and-master-and-version-branches
|
||||
requires:
|
||||
- setup
|
||||
- lint
|
||||
- unit-test
|
||||
- unit-test-jquery
|
||||
- e2e-test-1
|
||||
- e2e-test-2a
|
||||
- e2e-test-2b
|
||||
- e2e-test-jquery-1
|
||||
- e2e-test-jquery-2a
|
||||
- e2e-test-jquery-2b
|
||||
- deploy-code-files:
|
||||
<<: *run-on-tags-and-master-and-version-branches
|
||||
requires:
|
||||
- prepare-deployment
|
||||
- deploy-code-firebase:
|
||||
<<: *run-on-master
|
||||
requires:
|
||||
- prepare-deployment
|
||||
- deploy-docs:
|
||||
<<: *run-on-version-branches
|
||||
requires:
|
||||
- prepare-deployment
|
||||
@@ -1,73 +0,0 @@
|
||||
####################################################################################################
|
||||
# Helpers for defining environment variables for CircleCI.
|
||||
#
|
||||
# In CircleCI, each step runs in a new shell. The way to share ENV variables across steps is to
|
||||
# export them from `$BASH_ENV`, which is automatically sourced at the beginning of every step (for
|
||||
# the default `bash` shell).
|
||||
#
|
||||
# See also https://circleci.com/docs/2.0/env-vars/#using-bash_env-to-set-environment-variables.
|
||||
####################################################################################################
|
||||
|
||||
# Set and print an environment variable.
|
||||
#
|
||||
# Use this function for setting environment variables that are public, i.e. it is OK for them to be
|
||||
# visible to anyone through the CI logs.
|
||||
#
|
||||
# Usage: `setPublicVar <name> <value>`
|
||||
function setPublicVar() {
|
||||
setSecretVar $1 "$2";
|
||||
echo "$1=$2";
|
||||
}
|
||||
|
||||
# Set (without printing) an environment variable.
|
||||
#
|
||||
# Use this function for setting environment variables that are secret, i.e. should not be visible to
|
||||
# everyone through the CI logs.
|
||||
#
|
||||
# Usage: `setSecretVar <name> <value>`
|
||||
function setSecretVar() {
|
||||
# WARNING: Secrets (e.g. passwords, access tokens) should NOT be printed.
|
||||
# (Keep original shell options to restore at the end.)
|
||||
local -r originalShellOptions=$(set +o);
|
||||
set +x -eu -o pipefail;
|
||||
|
||||
echo "export $1=\"${2:-}\";" >> $BASH_ENV;
|
||||
|
||||
# Restore original shell options.
|
||||
eval "$originalShellOptions";
|
||||
}
|
||||
|
||||
|
||||
# Create a function to set an environment variable, when called.
|
||||
#
|
||||
# Use this function for creating setter for public environment variables that require expensive or
|
||||
# time-consuming computaions and may not be needed. When needed, you can call this function to set
|
||||
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
|
||||
#
|
||||
# Arguments:
|
||||
# - `<name>`: The name of the environment variable. The generated setter function will be
|
||||
# `setPublicVar_<name>`.
|
||||
# - `<code>`: The code to run to compute the value for the variable. Since this code should be
|
||||
# executed lazily, it must be properly escaped. For example:
|
||||
# ```sh
|
||||
# # DO NOT do this:
|
||||
# createPublicVarSetter MY_VAR "$(whoami)"; # `whoami` will be evaluated eagerly
|
||||
#
|
||||
# # DO this isntead:
|
||||
# createPublicVarSetter MY_VAR "\$(whoami)"; # `whoami` will NOT be evaluated eagerly
|
||||
# ```
|
||||
#
|
||||
# Usage: `createPublicVarSetter <name> <code>`
|
||||
#
|
||||
# Example:
|
||||
# ```sh
|
||||
# createPublicVarSetter MY_VAR 'echo "FOO"';
|
||||
# echo $MY_VAR; # Not defined
|
||||
#
|
||||
# setPublicVar_MY_VAR;
|
||||
# source $BASH_ENV;
|
||||
# echo $MY_VAR; # FOO
|
||||
# ```
|
||||
function createPublicVarSetter() {
|
||||
echo "setPublicVar_$1() { setPublicVar $1 \"$2\"; }" >> $BASH_ENV;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Variables
|
||||
readonly projectDir=$(realpath "$(dirname ${BASH_SOURCE[0]})/..")
|
||||
readonly envHelpersPath="$projectDir/.circleci/env-helpers.inc.sh";
|
||||
|
||||
# Load helpers and make them available everywhere (through `$BASH_ENV`).
|
||||
source $envHelpersPath;
|
||||
echo "source $envHelpersPath;" >> $BASH_ENV;
|
||||
|
||||
####################################################################################################
|
||||
# Define PUBLIC environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
# See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info.
|
||||
####################################################################################################
|
||||
setPublicVar CI "$CI"
|
||||
setPublicVar PROJECT_ROOT "$projectDir";
|
||||
# This is the branch being built; e.g. `pull/12345` for PR builds.
|
||||
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
|
||||
setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL";
|
||||
setPublicVar CI_COMMIT "$CIRCLE_SHA1";
|
||||
setPublicVar CI_GIT_BASE_REVISION "${CIRCLE_GIT_BASE_REVISION}";
|
||||
setPublicVar CI_GIT_REVISION "${CIRCLE_GIT_REVISION}";
|
||||
setPublicVar CI_GIT_TAG "${CIRCLE_TAG:-false}";
|
||||
setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION";
|
||||
setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}";
|
||||
setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME";
|
||||
setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME";
|
||||
setPublicVar CI_PR_REPONAME "$CIRCLE_PR_REPONAME";
|
||||
setPublicVar CI_PR_USERNAME "$CIRCLE_PR_USERNAME";
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Define SauceLabs environment variables for CircleCI.
|
||||
####################################################################################################
|
||||
setPublicVar BROWSER_PROVIDER "saucelabs"
|
||||
|
||||
# The currently latest-1 version of desktop Safari on Saucelabs (v12.0) is unstable and disconnects
|
||||
# consistently. The latest version (v12.1) works fine.
|
||||
# TODO: Add `SL_Safari-1` back, once it no longer corresponds to v12.0.
|
||||
setPublicVar BROWSERS "SL_Chrome,SL_Chrome-1,\
|
||||
SL_Firefox,SL_Firefox-1,\
|
||||
SL_Safari,\
|
||||
SL_iOS,SL_iOS-1,\
|
||||
SL_IE_9,SL_IE_10,SL_IE_11,\
|
||||
SL_EDGE,SL_EDGE-1"
|
||||
|
||||
setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log
|
||||
setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock
|
||||
setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock
|
||||
setPublicVar SAUCE_TUNNEL_IDENTIFIER "angularjs-framework-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX}"
|
||||
# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not
|
||||
# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout.
|
||||
setPublicVar SAUCE_READY_FILE_TIMEOUT 120
|
||||
|
||||
####################################################################################################
|
||||
# Define additional environment variables
|
||||
####################################################################################################
|
||||
|
||||
# NOTE: Make sure the tools used to compute this are available in all executors in `config.yml`.
|
||||
setPublicVar DIST_TAG $( cat package.json | grep distTag | sed -E 's/^\s*"distTag"\s*:\s*"([^"]+)"\s*,\s*$/\1/' )
|
||||
|
||||
####################################################################################################
|
||||
####################################################################################################
|
||||
## Source `$BASH_ENV` to make the variables available immediately. ##
|
||||
## *** NOTE: This must remain the last command in this script. *** ##
|
||||
####################################################################################################
|
||||
####################################################################################################
|
||||
source $BASH_ENV;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# https://editorconfig.org
|
||||
# http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
build/**
|
||||
docs/bower_components/**
|
||||
docs/app/assets/js/angular-bootstrap/**
|
||||
docs/config/templates/**
|
||||
node_modules/**
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
// Stylistic issues
|
||||
"block-spacing": ["error", "always"],
|
||||
"comma-spacing": "error",
|
||||
"id-denylist": ["error", "event"],
|
||||
"id-blacklist": ["error", "event"],
|
||||
"indent": ["error", 2],
|
||||
"key-spacing": ["error", { "beforeColon": false, "afterColon": true, "mode": "minimum" }],
|
||||
"object-curly-spacing": ["error", "never"],
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# AngularJS is in LTS mode
|
||||
We are no longer accepting changes that are not critical bug fixes into this project.
|
||||
See https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c for more detail.
|
||||
|
||||
<!--
|
||||
IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOUT INVESTIGATION
|
||||
-->
|
||||
@@ -13,9 +9,8 @@ IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOU
|
||||
|
||||
**I'm submitting a ...**
|
||||
<!-- (check one with "x") -->
|
||||
- [ ] regression from 1.7.0
|
||||
- [ ] security issue
|
||||
- [ ] issue caused by a new browser version
|
||||
- [ ] bug report
|
||||
- [ ] feature request
|
||||
- [ ] other <!--(Please do not submit support requests here - see above)-->
|
||||
|
||||
**Current behavior:**
|
||||
@@ -31,11 +26,11 @@ please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the
|
||||
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:yBpEi4).
|
||||
-->
|
||||
|
||||
**AngularJS version:** 1.8.x
|
||||
**AngularJS version:** 1.x.y
|
||||
<!-- Check whether this is still an issue in the most recent stable or in the snapshot AngularJS
|
||||
version (https://code.angularjs.org/snapshot/) -->
|
||||
|
||||
**Browser:** [all | Chrome XX | Firefox XX | Edge XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView | Opera XX ]
|
||||
**Browser:** [all | Chrome XX | Firefox XX | Edge XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
|
||||
<!-- All browsers where this could be reproduced (and Operating System if relevant) -->
|
||||
|
||||
**Anything else:**
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
# AngularJS is in LTS mode
|
||||
We are no longer accepting changes that are not critical bug fixes into this project.
|
||||
See https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c for more detail.
|
||||
<!-- General PR submission guidelines https://github.com/angular/angular.js/CONTRIBUTING.md#submit-pr -->
|
||||
**What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)**
|
||||
|
||||
<!-- General PR submission guidelines https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#submit-pr -->
|
||||
**Does this PR fix a regression since 1.7.0, a security flaw, or a problem caused by a new browser version?**
|
||||
|
||||
<!-- If the answer is no, then we will not merge this PR -->
|
||||
|
||||
|
||||
**What is the current behavior? (You can also link to an open issue here)**
|
||||
@@ -21,8 +16,8 @@ See https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c
|
||||
|
||||
|
||||
**Please check if the PR fulfills these requirements**
|
||||
- [ ] The commit message follows our [guidelines](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits)
|
||||
- [ ] Fix/Feature: [Docs](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#documentation) have been added/updated
|
||||
- [ ] The commit message follows our [guidelines](../DEVELOPERS.md#commits)
|
||||
- [ ] Fix/Feature: [Docs](../DEVELOPERS.md#documentation) have been added/updated
|
||||
- [ ] Fix/Feature: Tests have been added; existing tests pass
|
||||
|
||||
**Other information**:
|
||||
|
||||
+1
-4
@@ -1,4 +1,5 @@
|
||||
/build/
|
||||
/deploy/
|
||||
/benchpress-build/
|
||||
.DS_Store
|
||||
gen_docs.disable
|
||||
@@ -11,7 +12,6 @@ performance/temp*.html
|
||||
angular.js.tmproj
|
||||
node_modules/
|
||||
angular.xcodeproj
|
||||
.firebase/
|
||||
.idea
|
||||
*.iml
|
||||
.agignore
|
||||
@@ -22,6 +22,3 @@ npm-debug.log
|
||||
.vscode
|
||||
*.log
|
||||
*.stackdump
|
||||
scripts/code.angularjs.org-firebase/deploy
|
||||
scripts/docs.angularjs.org-firebase/deploy
|
||||
scripts/docs.angularjs.org-firebase/functions/content
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '8'
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
|
||||
branches:
|
||||
except:
|
||||
- "/^g3_.*$/"
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- JOB=ci-checks
|
||||
- JOB=unit-core BROWSER_PROVIDER=saucelabs
|
||||
- JOB=unit-jquery BROWSER_PROVIDER=saucelabs
|
||||
- JOB=docs-app BROWSER_PROVIDER=saucelabs
|
||||
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=saucelabs
|
||||
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=saucelabs
|
||||
global:
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
- LOGS_DIR=/tmp/angular-build/logs
|
||||
- BROWSER_PROVIDER_READY_FILE=/tmp/browsersprovider-tunnel-ready
|
||||
- secure: oTBjhnOKhs0qDSKTf7fE4f6DYiNDPycvB7qfSF5QRIbJK/LK/J4UtFwetXuXj79HhUZG9qnoT+5e7lPaiaMlpsIKn9ann7ffqFWN1E8TMtpJF+AGigx3djYElwfgf5nEnFUFhwjFzvbfpZNnxVGgX5YbIZpe/WUbHkP4ffU0Wks=
|
||||
|
||||
before_install:
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.3.2
|
||||
- export PATH="$HOME/.yarn/bin:$PATH"
|
||||
|
||||
before_script:
|
||||
- du -sh ./node_modules || true
|
||||
- "./scripts/travis/before_build.sh"
|
||||
|
||||
script:
|
||||
- "./scripts/travis/build.sh"
|
||||
|
||||
after_script:
|
||||
- "./scripts/travis/tear_down_browser_provider.sh"
|
||||
- "./scripts/travis/print_logs.sh"
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/d2120f3f2bb39a4531b2
|
||||
- http://104.197.9.155:8484/hubot/travis/activity #hubot-server
|
||||
on_success: always # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: always # default: false
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: deploy
|
||||
# Don't deploy from PRs. Only deploy from our default branches, or if commit is tagged.
|
||||
# This is a Travis-specific boolean language: https://docs.travis-ci.com/user/conditional-builds-stages-jobs#Specifying-conditions
|
||||
# The deployment logic for pushed branches is further defined in scripts\travis\build.sh
|
||||
if: type != pull_request and (branch =~ ^(v1\.\d+\.x|master)$ or tag IS present)
|
||||
env:
|
||||
- JOB=deploy
|
||||
before_script: skip
|
||||
script:
|
||||
# Export the variables into the current process
|
||||
- . ./scripts/travis/build.sh
|
||||
- "echo DEPLOY_DOCS: $DEPLOY_DOCS, DEPLOY_CODE: $DEPLOY_CODE"
|
||||
after_script: skip
|
||||
# Work around the 10min Travis timeout so the code.angularjs firebase+gcs code deploy can complete
|
||||
# Only run the keep_alive once (before_deploy is run for each provider)
|
||||
before_deploy: |
|
||||
if ! [ "$BEFORE_DEPLOY_RUN" ]; then
|
||||
export BEFORE_DEPLOY_RUN=1;
|
||||
|
||||
function keep_alive() {
|
||||
while true; do
|
||||
echo -en "\a"
|
||||
sleep 10
|
||||
done
|
||||
}
|
||||
keep_alive &
|
||||
fi
|
||||
deploy:
|
||||
- provider: firebase
|
||||
# the upload folder for firebase is configured in /firebase.json
|
||||
skip_cleanup: true
|
||||
project: docs-angularjs-org-9p2
|
||||
token:
|
||||
secure: $FIREBASE_TOKEN
|
||||
on:
|
||||
repo: angular/angular.js
|
||||
all_branches: true
|
||||
condition: "$DEPLOY_DOCS == true"
|
||||
- provider: gcs
|
||||
skip_cleanup: true
|
||||
access_key_id: GOOGLDB7W2J3LFHICF3R
|
||||
secret_access_key:
|
||||
secure: tHIFdSq55qkyZf9zT/3+VkhUrTvOTMuswxXU3KyWaBrSieZqG0UnUDyNm+n3lSfX95zEl/+rJAWbfvhVSxZi13ndOtvRF+MdI1cvow2JynP0aDSiPffEvVrZOmihD6mt2SlMfhskr5FTduQ69kZG6DfLcve1PPDaIwnbOv3phb8=
|
||||
bucket: code-angularjs-org-338b8.appspot.com
|
||||
local-dir: deploy/code
|
||||
detect_encoding: true # detects gzip compression
|
||||
on:
|
||||
repo: angular/angular.js
|
||||
all_branches: true
|
||||
condition: "$DEPLOY_CODE == true"
|
||||
|
||||
+2
-2103
File diff suppressed because it is too large
Load Diff
+6
-6
@@ -49,6 +49,7 @@ If you find a bug in the source code, you can help us by submitting an issue to
|
||||
**Special Note for Localization Issues:** AngularJS uses the [Google Closure I18N library] to
|
||||
generate its own I18N files (the ngLocale module). This means that any changes to these files
|
||||
would be lost the next time that we import the library.
|
||||
|
||||
Since the Closure library i18n data is itself auto-generated from the data of the
|
||||
[Common Locale Data Repository (CLDR)] project, errors in the data should
|
||||
be reported there. See also the [Closure guide to i18n changes].
|
||||
@@ -125,8 +126,8 @@ Before you submit your pull request consider the following guidelines:
|
||||
* Follow our [Coding Rules][developers.rules].
|
||||
* If the changes affect public APIs, change or add relevant [documentation][developers.documentation].
|
||||
* Run the AngularJS [unit][developers.tests-unit] and [E2E test][developers.tests-e2e] suites, and ensure that all tests
|
||||
pass. It is generally sufficient to run the tests only on Chrome, as our continuous integration test will
|
||||
run the tests on additional browsers.
|
||||
pass. It is generally sufficient to run the tests only on Chrome, as our Travis integration will
|
||||
run the tests on all supported browsers.
|
||||
* Run `yarn grunt eslint` to check that you have followed the automatically enforced coding rules
|
||||
* Commit your changes using a descriptive commit message that follows our
|
||||
[commit message conventions][developers.commits]. Adherence to the
|
||||
@@ -151,9 +152,9 @@ Before you submit your pull request consider the following guidelines:
|
||||
```
|
||||
|
||||
* In GitHub, send a pull request to `angular.js:master`. This will trigger the check of the
|
||||
[Contributor License Agreement](#cla) and the continuous integration tests.
|
||||
[Contributor License Agreement](#cla) and the Travis integration.
|
||||
|
||||
* If you find that the continuous integration tests have failed, look into the logs to find out
|
||||
* If you find that the Travis integration has failed, look into the logs on Travis to find out
|
||||
if your changes caused test failures, the commit message was malformed etc. If you find that the
|
||||
tests failed or times out for unrelated reasons, you can ping a team member so that the build can be
|
||||
restarted.
|
||||
@@ -164,7 +165,6 @@ restarted.
|
||||
* Re-run the AngularJS test suite to ensure tests are still passing.
|
||||
* Commit your changes to your branch (e.g. `my-fix-branch`).
|
||||
* Push the changes to your GitHub repository (this will update your Pull Request).
|
||||
|
||||
You can also amend the initial commits and force push them to the branch.
|
||||
|
||||
```shell
|
||||
@@ -172,7 +172,7 @@ restarted.
|
||||
git push origin my-fix-branch -f
|
||||
```
|
||||
|
||||
This is generally easier to follow, but separate commits are useful if the Pull Request contains
|
||||
This is generally easier to follow, but seperate commits are useful if the Pull Request contains
|
||||
iterations that might be interesting to see side-by-side.
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
+3
-2
@@ -249,7 +249,7 @@ format that includes a **type**, a **scope** and a **subject**:
|
||||
|
||||
The **header** is mandatory and the **scope** of the header is optional.
|
||||
|
||||
Any line of the commit message cannot be longer than 100 characters! This allows the message to be easier
|
||||
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.
|
||||
|
||||
### Revert
|
||||
@@ -257,6 +257,7 @@ If the commit reverts a previous commit, it should begin with `revert: `, follow
|
||||
of the reverted commit.
|
||||
In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit
|
||||
being reverted.
|
||||
A commit with this format is automatically created by the [`git revert`][git-revert] command.
|
||||
|
||||
### Type
|
||||
Must be one of the following:
|
||||
@@ -428,7 +429,7 @@ if it is enclosed in <pre>...</pre> tags and the code lines themselv
|
||||
It is possible to embed examples in the documentation along with appropriate e2e tests. These
|
||||
examples and scenarios will be converted to runnable code within the documentation. So it is
|
||||
important that they work correctly. To ensure this, all these e2e scenarios are run as part of the
|
||||
continuous integration tests.
|
||||
automated Travis tests.
|
||||
|
||||
If you are adding an example with an e2e test, you should [run the test locally](#e2e-tests) first
|
||||
to ensure it passes. You can change `it(...)` to `fit(...)` to run only your test,
|
||||
|
||||
+55
-74
@@ -4,7 +4,6 @@ var serveFavicon = require('serve-favicon');
|
||||
var serveStatic = require('serve-static');
|
||||
var serveIndex = require('serve-index');
|
||||
var files = require('./angularFiles').files;
|
||||
var mergeFilesFor = require('./angularFiles').mergeFilesFor;
|
||||
var util = require('./lib/grunt/utils.js');
|
||||
var versionInfo = require('./lib/versions/version-info');
|
||||
var path = require('path');
|
||||
@@ -14,8 +13,7 @@ var semver = require('semver');
|
||||
var exec = require('shelljs').exec;
|
||||
var pkg = require(__dirname + '/package.json');
|
||||
|
||||
var codeScriptFolder = util.codeScriptFolder;
|
||||
var docsScriptFolder = util.docsScriptFolder;
|
||||
var docsScriptFolder = 'scripts/docs.angularjs.org-firebase';
|
||||
|
||||
// Node.js version checks
|
||||
if (!semver.satisfies(process.version, pkg.engines.node)) {
|
||||
@@ -32,7 +30,7 @@ if (!semver.satisfies(currentYarnVersion, expectedYarnVersion)) {
|
||||
}
|
||||
|
||||
// Grunt CLI version checks
|
||||
var expectedGruntVersion = pkg.engines['grunt-cli'];
|
||||
var expectedGruntVersion = pkg.engines.grunt;
|
||||
var currentGruntVersions = exec('grunt --version', {silent: true}).stdout;
|
||||
var match = /^grunt-cli v(.+)$/m.exec(currentGruntVersions);
|
||||
if (!match) {
|
||||
@@ -46,7 +44,7 @@ if (!match) {
|
||||
}
|
||||
|
||||
// Ensure Node.js dependencies have been installed
|
||||
if (!process.env.CI) {
|
||||
if (!process.env.TRAVIS && !process.env.JENKINS_HOME) {
|
||||
var yarnOutput = exec('yarn install');
|
||||
if (yarnOutput.code !== 0) {
|
||||
throw new Error('Yarn install failed: ' + yarnOutput.stderr);
|
||||
@@ -110,14 +108,16 @@ module.exports = function(grunt) {
|
||||
},
|
||||
testserver: {
|
||||
options: {
|
||||
// We start the webserver as a separate process from the E2E tests
|
||||
// We use end2end task (which does not start the webserver)
|
||||
// and start the webserver as a separate process (in travis_build.sh)
|
||||
// to avoid https://github.com/joyent/libuv/issues/826
|
||||
port: 8000,
|
||||
hostname: '0.0.0.0',
|
||||
middleware: function(connect, options) {
|
||||
var base = Array.isArray(options.base) ? options.base[options.base.length - 1] : options.base;
|
||||
return [
|
||||
function(req, resp, next) {
|
||||
// cache GET requests to speed up tests
|
||||
// cache get requests to speed up tests on travis
|
||||
if (req.method === 'GET') {
|
||||
resp.setHeader('Cache-control', 'public, max-age=3600');
|
||||
}
|
||||
@@ -141,9 +141,7 @@ module.exports = function(grunt) {
|
||||
'jquery-2.2': 'karma-jquery-2.2.conf.js',
|
||||
'jquery-2.1': 'karma-jquery-2.1.conf.js',
|
||||
docs: 'karma-docs.conf.js',
|
||||
modules: 'karma-modules.conf.js',
|
||||
'modules-ngAnimate': 'karma-modules-ngAnimate.conf.js',
|
||||
'modules-ngMock': 'karma-modules-ngMock.conf.js'
|
||||
modules: 'karma-modules.conf.js'
|
||||
},
|
||||
|
||||
|
||||
@@ -159,7 +157,8 @@ module.exports = function(grunt) {
|
||||
|
||||
protractor: {
|
||||
normal: 'protractor-conf.js',
|
||||
circleci: 'protractor-circleci-conf.js'
|
||||
travis: 'protractor-travis-conf.js',
|
||||
jenkins: 'protractor-jenkins-conf.js'
|
||||
},
|
||||
|
||||
|
||||
@@ -167,9 +166,9 @@ module.exports = function(grunt) {
|
||||
build: ['build'],
|
||||
tmp: ['tmp'],
|
||||
deploy: [
|
||||
codeScriptFolder + '/deploy',
|
||||
docsScriptFolder + '/deploy',
|
||||
docsScriptFolder + '/functions/content'
|
||||
'deploy/docs',
|
||||
'deploy/code',
|
||||
docsScriptFolder + '/functions/html'
|
||||
]
|
||||
},
|
||||
|
||||
@@ -186,6 +185,7 @@ module.exports = function(grunt) {
|
||||
'test/**/*.js',
|
||||
'i18n/**/*.js',
|
||||
'!docs/app/assets/js/angular-bootstrap/**',
|
||||
'!docs/bower_components/**',
|
||||
'!docs/config/templates/**',
|
||||
'!src/angular.bind.js',
|
||||
'!i18n/closure/**',
|
||||
@@ -195,6 +195,16 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
build: {
|
||||
scenario: {
|
||||
dest: 'build/angular-scenario.js',
|
||||
src: [
|
||||
'bower_components/jquery/dist/jquery.js',
|
||||
util.wrap([files['angularSrc'], files['angularScenario']], 'ngScenario/angular')
|
||||
],
|
||||
styles: {
|
||||
css: ['css/angular.css', 'css/angular-scenario.css']
|
||||
}
|
||||
},
|
||||
angular: {
|
||||
dest: 'build/angular.js',
|
||||
src: util.wrap([files['angularSrc']], 'angular'),
|
||||
@@ -212,12 +222,6 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-touch.js',
|
||||
src: util.wrap(files['angularModules']['ngTouch'], 'module')
|
||||
},
|
||||
touchModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-touch.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngTouch'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
mocks: {
|
||||
dest: 'build/angular-mocks.js',
|
||||
src: util.wrap(files['angularModules']['ngMock'], 'module'),
|
||||
@@ -227,42 +231,18 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-sanitize.js',
|
||||
src: util.wrap(files['angularModules']['ngSanitize'], 'module')
|
||||
},
|
||||
sanitizeModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-sanitize.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngSanitize'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
resource: {
|
||||
dest: 'build/angular-resource.js',
|
||||
src: util.wrap(files['angularModules']['ngResource'], 'module')
|
||||
},
|
||||
resourceModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-resource.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngResource'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
messageformat: {
|
||||
dest: 'build/angular-message-format.js',
|
||||
src: util.wrap(files['angularModules']['ngMessageFormat'], 'module')
|
||||
},
|
||||
messageformatModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-message-format.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngMessageFormat'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
messages: {
|
||||
dest: 'build/angular-messages.js',
|
||||
src: util.wrap(files['angularModules']['ngMessages'], 'module')
|
||||
},
|
||||
messagesModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-messages.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngMessages'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
animate: {
|
||||
dest: 'build/angular-animate.js',
|
||||
src: util.wrap(files['angularModules']['ngAnimate'], 'module')
|
||||
@@ -271,32 +251,14 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-route.js',
|
||||
src: util.wrap(files['angularModules']['ngRoute'], 'module')
|
||||
},
|
||||
routeModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-route.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngRoute'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
cookies: {
|
||||
dest: 'build/angular-cookies.js',
|
||||
src: util.wrap(files['angularModules']['ngCookies'], 'module')
|
||||
},
|
||||
cookiesModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-cookies.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngCookies'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
aria: {
|
||||
dest: 'build/angular-aria.js',
|
||||
src: util.wrap(files['angularModules']['ngAria'], 'module')
|
||||
},
|
||||
ariaModuleTestBundle: {
|
||||
dest: 'build/test-bundles/angular-aria.js',
|
||||
prefix: 'src/module.prefix',
|
||||
src: mergeFilesFor('karmaModules-ngAria'),
|
||||
suffix: 'src/module.suffix'
|
||||
},
|
||||
parseext: {
|
||||
dest: 'build/angular-parse-ext.js',
|
||||
src: util.wrap(files['angularModules']['ngParseExt'], 'module')
|
||||
@@ -328,7 +290,9 @@ module.exports = function(grunt) {
|
||||
files: [
|
||||
'src/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/ngScenario/DescribeSpec.js',
|
||||
'!src/ng/directive/attrs.js', // legitimate xit here
|
||||
'!src/ngScenario/**/*.js',
|
||||
'!test/helpers/privateMocks*.js'
|
||||
],
|
||||
options: {
|
||||
@@ -370,10 +334,11 @@ module.exports = function(grunt) {
|
||||
},
|
||||
deployFirebaseCode: {
|
||||
files: [
|
||||
// copy files that are not handled by compress
|
||||
{
|
||||
cwd: 'build',
|
||||
src: '**',
|
||||
dest: codeScriptFolder + '/deploy/' + deployVersion + '/',
|
||||
src: '**/*.{zip,jpg,jpeg,png}',
|
||||
dest: 'deploy/code/' + deployVersion + '/',
|
||||
expand: true
|
||||
}
|
||||
]
|
||||
@@ -383,19 +348,19 @@ module.exports = function(grunt) {
|
||||
// The source files are needed by the embedded examples in the docs app.
|
||||
{
|
||||
src: ['build/angular*.{js,js.map,min.js}', 'build/sitemap.xml'],
|
||||
dest: docsScriptFolder + '/deploy/',
|
||||
dest: 'deploy/docs/',
|
||||
expand: true,
|
||||
flatten: true
|
||||
},
|
||||
{
|
||||
cwd: 'build/docs',
|
||||
src: ['**', '!ptore2e/**', '!index*.html'],
|
||||
dest: docsScriptFolder + '/deploy/',
|
||||
dest: 'deploy/docs/',
|
||||
expand: true
|
||||
},
|
||||
{
|
||||
src: 'build/docs/index-production.html',
|
||||
dest: docsScriptFolder + '/deploy/index.html'
|
||||
dest: 'deploy/docs/index.html'
|
||||
},
|
||||
{
|
||||
src: 'build/docs/index-production.html',
|
||||
@@ -404,7 +369,7 @@ module.exports = function(grunt) {
|
||||
{
|
||||
cwd: 'build/docs',
|
||||
src: 'partials/**',
|
||||
dest: docsScriptFolder + '/functions/content/',
|
||||
dest: docsScriptFolder + '/functions/content',
|
||||
expand: true
|
||||
}
|
||||
]
|
||||
@@ -420,6 +385,16 @@ module.exports = function(grunt) {
|
||||
expand: true,
|
||||
dot: true,
|
||||
dest: dist + '/'
|
||||
},
|
||||
deployFirebaseCode: {
|
||||
options: {
|
||||
mode: 'gzip'
|
||||
},
|
||||
// Already compressed files should not be compressed again
|
||||
src: ['**', '!**/*.{zip,png,jpeg,jpg}'],
|
||||
cwd: 'build',
|
||||
expand: true,
|
||||
dest: 'deploy/code/' + deployVersion + '/'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -468,9 +443,7 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('test:jquery-2.1', 'Run the jQuery 2.1 unit tests with Karma', ['tests:jquery-2.1']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', [
|
||||
'build',
|
||||
'tests:modules',
|
||||
'tests:modules-ngAnimate',
|
||||
'tests:modules-ngMock'
|
||||
'tests:modules'
|
||||
]);
|
||||
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
|
||||
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', [
|
||||
@@ -485,9 +458,14 @@ module.exports = function(grunt) {
|
||||
'connect:testserver',
|
||||
'protractor:normal'
|
||||
]);
|
||||
grunt.registerTask('test:circleci-protractor', 'Run the end to end tests with Protractor for CircleCI builds', [
|
||||
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', [
|
||||
'connect:testserver',
|
||||
'protractor:circleci'
|
||||
'protractor:travis'
|
||||
]);
|
||||
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', [
|
||||
'webdriver',
|
||||
'connect:testserver',
|
||||
'protractor:jenkins'
|
||||
]);
|
||||
grunt.registerTask('test:e2e', 'Alias for test:protractor', ['test:protractor']);
|
||||
grunt.registerTask('test:promises-aplus',[
|
||||
@@ -517,7 +495,10 @@ module.exports = function(grunt) {
|
||||
'eslint'
|
||||
]);
|
||||
grunt.registerTask('prepareDeploy', [
|
||||
'package',
|
||||
'compress:deployFirebaseCode',
|
||||
'copy:deployFirebaseCode',
|
||||
'firebaseDocsJsonForTravis',
|
||||
'copy:deployFirebaseDocs'
|
||||
]);
|
||||
grunt.registerTask('default', ['package']);
|
||||
@@ -525,7 +506,7 @@ module.exports = function(grunt) {
|
||||
|
||||
|
||||
function reportOrFail(message) {
|
||||
if (process.env.CI) {
|
||||
if (process.env.TRAVIS || process.env.JENKINS_HOME) {
|
||||
throw new Error(message);
|
||||
} else {
|
||||
console.log('===============================================================================');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2010-2020 Google LLC. http://angularjs.org
|
||||
Copyright (c) 2010-2018 Google, Inc. http://angularjs.org
|
||||
|
||||
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,4 +1,4 @@
|
||||
AngularJS [](https://circleci.com/gh/angular/workflows/angular.js/tree/master)
|
||||
AngularJS [](https://travis-ci.org/angular/angular.js)
|
||||
=========
|
||||
|
||||
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
|
||||
@@ -14,11 +14,9 @@ piece of cake. Best of all? It makes development fun!
|
||||
|
||||
--------------------
|
||||
|
||||
**AngularJS support has officially ended as of January 2022.
|
||||
[See what ending support means](https://docs.angularjs.org/misc/version-support-status)
|
||||
and [read the end of life announcement](https://goo.gle/angularjs-end-of-life).**
|
||||
##### AngularJS will be moving to Long Term Support (LTS) mode on July 1st 2018: [Find out more](https://docs.angularjs.org/misc/version-support-status)
|
||||
|
||||
**Visit [angular.io](https://angular.io) for the actively supported Angular.**
|
||||
##### Looking for the new Angular? Go here: https://github.com/angular/angular
|
||||
|
||||
--------------------
|
||||
|
||||
@@ -57,12 +55,11 @@ component in an interconnected way like a well-oiled machine. AngularJS is JavaS
|
||||
and done right. (Well it is not really MVC, read on, to understand what this means.)
|
||||
|
||||
#### MVC, no, MV* done the right way!
|
||||
[MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller), short for
|
||||
Model-View-Controller, is a design pattern, i.e. how the code should be organized and how the
|
||||
different parts of an application separated for proper readability and debugging. Model is the data
|
||||
and the database. View is the user interface and what the user sees. Controller is the main link
|
||||
between Model and View. These are the three pillars of major programming frameworks present on the
|
||||
market today. On the other hand AngularJS works on MV*, short for Model-View-_Whatever_. The
|
||||
MVC, short for Model-View-Controller, is a design pattern, i.e. how the code should be organized and
|
||||
how the different parts of an application separated for proper readability and debugging. Model is
|
||||
the data and the database. View is the user interface and what the user sees. Controller is the main
|
||||
link between Model and View. These are the three pillars of major programming frameworks present on
|
||||
the market today. On the other hand AngularJS works on MV*, short for Model-View-_Whatever_. The
|
||||
_Whatever_ is AngularJS's way of telling that you may create any kind of linking between the Model
|
||||
and the View here.
|
||||
|
||||
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
# AngularJS Release instructions
|
||||
|
||||
|
||||
## Compare the list of commits between stable and unstable
|
||||
|
||||
There is a script - compare-master-to-stable.js - that helps with this.
|
||||
We just want to make sure that good commits (low risk fixes + docs fixes) got cherry-picked into stable branch and nothing interesting got merged only into stable branch.
|
||||
|
||||
|
||||
## Pick a release name (for this version)
|
||||
|
||||
A super-heroic power (adverb-verb phrase).
|
||||
|
||||
|
||||
## Generate release notes
|
||||
|
||||
Example Commit: https://github.com/angular/angular.js/commit/7ab5098c14ee4f195dbfe2681e402fe2dfeacd78
|
||||
|
||||
1) Run
|
||||
|
||||
```bash
|
||||
node_modules/.bin/changez -o changes.md -v <new version> <base branch>
|
||||
```
|
||||
|
||||
2) Review the generated file and manually fix typos, group and reorder stuff if needed.
|
||||
3) Move the content into CHANGELOG.md add release code-names to headers.
|
||||
4) Push the changes to your private github repo and review.
|
||||
5) cherry-pick the release notes commit to the appropriate branches.
|
||||
|
||||
|
||||
## Pick a commit to release (for this version)
|
||||
|
||||
Usually this will be the commit containing the release notes, but it may also be in the past.
|
||||
|
||||
|
||||
## Run "release" script
|
||||
|
||||
```bash
|
||||
scripts/release/release.sh --git-push-dryrun=false --commit-sha=8822a4f --version-number=1.7.6 --version-name=gravity-manipulation
|
||||
```
|
||||
|
||||
1) The SHA is of the commit to release (could be in the past).
|
||||
|
||||
2) The version number and code-name that should be released, not the next version number (e.g. to release 1.2.12 you enter 1.2.12 as release version and the code-name that was picked for 1.2.12, cauliflower-eradication).
|
||||
|
||||
3) You will need to have write access to all the AngularJS github dist repositories and publish rights for the AngularJS packages on npm.
|
||||
|
||||
|
||||
## Update GitHub milestones
|
||||
|
||||
1) Create the next milestone if it doesn't exist yet-giving ita due date.
|
||||
2) Move all open issues and PRs for the current milestone to the next milestone<br>
|
||||
You can do this by filtering the current milestone, selecting via checklist, and moving to the next milestone within the GH issues page.
|
||||
|
||||
3) Close the current milestone click the milestones tab and close from there.
|
||||
4) Create a new holding milestone for the release after next-but don't give it a due date otherwise that will mess up the dashboard.
|
||||
|
||||
|
||||
## Push build artifacts to CDN
|
||||
|
||||
Google CDNs are fed with data from google3 every day at 11:15am PT it takes only few minutes for the import to propagate).
|
||||
If we want to make our files available, we need submit our CLs before this time on the day of the release.
|
||||
|
||||
|
||||
## Don't update the package.json (branchVersion) until the CDN has updated
|
||||
|
||||
This is the version used to compute what version to link to in the CDN. If you update this too early then the CDN lookup fails and you end up with 'null, for the version, which breaks the docs.
|
||||
|
||||
|
||||
## Verify angularjs.org download modal has latest version (updates via CI job)
|
||||
|
||||
The versions in the modal are updated (based on the versions available on CDN) as part of the CI deploy stage.
|
||||
(You may need to explicitly trigger the CI job. e.g. re-running the last `deploy` job.)
|
||||
|
||||
|
||||
## Announce the release (via official Google accounts)
|
||||
|
||||
Double check that angularjs.org is up to date with the new release version before sharing.
|
||||
|
||||
1) Collect a list of contributors
|
||||
|
||||
use: `git log --format='%aN' v1.2.12..v1.2.13 | sort -u`
|
||||
|
||||
2) Write a blog post (for minor releases, not patch releases) and publish it with the "release" tag
|
||||
3) Post on twitter as yourself (tweet from your heart; there is no template for this), retweet as @AngularJS
|
||||
|
||||
|
||||
## Party!
|
||||
|
||||
|
||||
## Major Release Tasks
|
||||
|
||||
1) Update angularjs.org to use the latest branch.
|
||||
2) Write up a migration document.
|
||||
3) Create a new git branch for the version that has been released (e.g. 1.8.x).
|
||||
4) Check that the build and release scripts still work.
|
||||
5) Update the dist-tag of the old branch, see https://github.com/angular/angular.js/pull/12722.
|
||||
6) Write a blog post.
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
**AngularJS support has officially ended as of January 2022.**
|
||||
[See what ending support means](https://docs.angularjs.org/misc/version-support-status)
|
||||
and [read the end of life announcement](https://goo.gle/angularjs-end-of-life).
|
||||
|
||||
Visit [angular.io](https://angular.io) for the actively supported Angular.
|
||||
|
||||
| Version | Supported | Status | Comments |
|
||||
| ----------- | ------------------ | --------------------- | ------------------------------------ |
|
||||
| 1.8.x | :x: | All support ended | |
|
||||
| 1.3.x-1.7.x | :x: | All support ended | |
|
||||
| 1.2.x | :x: | All support ended | Last version to provide IE 8 support |
|
||||
| <1.2.0 | :x: | All support ended | |
|
||||
Vendored
+42
-80
@@ -28,7 +28,6 @@ var angularFiles = {
|
||||
'src/ng/httpBackend.js',
|
||||
'src/ng/interpolate.js',
|
||||
'src/ng/interval.js',
|
||||
'src/ng/intervalFactory.js',
|
||||
'src/ng/jsonpCallbacks.js',
|
||||
'src/ng/locale.js',
|
||||
'src/ng/location.js',
|
||||
@@ -41,7 +40,6 @@ var angularFiles = {
|
||||
'src/ng/sanitizeUri.js',
|
||||
'src/ng/sce.js',
|
||||
'src/ng/sniffer.js',
|
||||
'src/ng/taskTrackerFactory.js',
|
||||
'src/ng/templateRequest.js',
|
||||
'src/ng/testability.js',
|
||||
'src/ng/timeout.js',
|
||||
@@ -76,7 +74,6 @@ var angularFiles = {
|
||||
'src/ng/directive/ngNonBindable.js',
|
||||
'src/ng/directive/ngOptions.js',
|
||||
'src/ng/directive/ngPluralize.js',
|
||||
'src/ng/directive/ngRef.js',
|
||||
'src/ng/directive/ngRepeat.js',
|
||||
'src/ng/directive/ngShowHide.js',
|
||||
'src/ng/directive/ngStyle.js',
|
||||
@@ -106,13 +103,13 @@ var angularFiles = {
|
||||
'src/ngAnimate/animateJs.js',
|
||||
'src/ngAnimate/animateJsDriver.js',
|
||||
'src/ngAnimate/animateQueue.js',
|
||||
'src/ngAnimate/animateCache.js',
|
||||
'src/ngAnimate/animation.js',
|
||||
'src/ngAnimate/ngAnimateSwap.js',
|
||||
'src/ngAnimate/module.js'
|
||||
],
|
||||
'ngCookies': [
|
||||
'src/ngCookies/cookies.js',
|
||||
'src/ngCookies/cookieStore.js',
|
||||
'src/ngCookies/cookieWriter.js'
|
||||
],
|
||||
'ngMessageFormat': [
|
||||
@@ -134,7 +131,6 @@ var angularFiles = {
|
||||
],
|
||||
'ngRoute': [
|
||||
'src/shallowCopy.js',
|
||||
'src/routeToRegExp.js',
|
||||
'src/ngRoute/route.js',
|
||||
'src/ngRoute/routeParams.js',
|
||||
'src/ngRoute/directive/ngView.js'
|
||||
@@ -144,13 +140,13 @@ var angularFiles = {
|
||||
'src/ngSanitize/filter/linky.js'
|
||||
],
|
||||
'ngMock': [
|
||||
'src/routeToRegExp.js',
|
||||
'src/ngMock/angular-mocks.js',
|
||||
'src/ngMock/browserTrigger.js'
|
||||
],
|
||||
'ngTouch': [
|
||||
'src/ngTouch/touch.js',
|
||||
'src/ngTouch/swipe.js',
|
||||
'src/ngTouch/directive/ngClick.js',
|
||||
'src/ngTouch/directive/ngSwipe.js'
|
||||
],
|
||||
'ngAria': [
|
||||
@@ -158,8 +154,26 @@ var angularFiles = {
|
||||
]
|
||||
},
|
||||
|
||||
'angularScenario': [
|
||||
'src/ngScenario/Scenario.js',
|
||||
'src/ngScenario/Application.js',
|
||||
'src/ngScenario/Describe.js',
|
||||
'src/ngScenario/Future.js',
|
||||
'src/ngScenario/ObjectModel.js',
|
||||
'src/ngScenario/Runner.js',
|
||||
'src/ngScenario/SpecRunner.js',
|
||||
'src/ngScenario/dsl.js',
|
||||
'src/ngScenario/matchers.js',
|
||||
'src/ngScenario/output/Html.js',
|
||||
'src/ngScenario/output/Json.js',
|
||||
'src/ngScenario/output/Xml.js',
|
||||
'src/ngScenario/output/Object.js'
|
||||
],
|
||||
|
||||
'angularTest': [
|
||||
'test/helpers/*.js',
|
||||
'test/ngScenario/*.js',
|
||||
'test/ngScenario/output/*.js',
|
||||
'test/*.js',
|
||||
'test/auto/*.js',
|
||||
'test/ng/**/*.js',
|
||||
@@ -180,81 +194,37 @@ var angularFiles = {
|
||||
'test/jquery_remove.js',
|
||||
'@angularSrc',
|
||||
'@angularSrcModules',
|
||||
'@angularScenario',
|
||||
'@angularTest'
|
||||
],
|
||||
|
||||
'karmaExclude': [
|
||||
'test/jquery_alias.js',
|
||||
'src/angular-bootstrap.js',
|
||||
'src/ngScenario/angular-bootstrap.js',
|
||||
'src/angular.bind.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngAnimate': [
|
||||
'karmaScenario': [
|
||||
'build/angular-scenario.js',
|
||||
'build/docs/docs-scenario.js'
|
||||
],
|
||||
|
||||
'karmaModules': [
|
||||
'build/angular.js',
|
||||
'build/angular-mocks.js',
|
||||
'@angularSrcModules',
|
||||
'test/modules/no_bootstrap.js',
|
||||
'test/helpers/matchers.js',
|
||||
'test/helpers/privateMocks.js',
|
||||
'test/helpers/support.js',
|
||||
'test/helpers/testabilityPatch.js',
|
||||
'@angularSrcModuleNgAnimate',
|
||||
'test/ngAnimate/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngAria': [
|
||||
'@angularSrcModuleNgAria',
|
||||
'test/ngAria/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngCookies': [
|
||||
'@angularSrcModuleNgCookies',
|
||||
'test/ngCookies/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngMessageFormat': [
|
||||
'@angularSrcModuleNgMessageFormat',
|
||||
'test/ngMessageFormat/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngMessages': [
|
||||
'build/angular-animate.js',
|
||||
'@angularSrcModuleNgMessages',
|
||||
'test/ngMessages/**/*.js'
|
||||
],
|
||||
|
||||
// ngMock doesn't include the base because it must use the ngMock src files
|
||||
'karmaModules-ngMock': [
|
||||
'build/angular.js',
|
||||
'src/ngMock/*.js',
|
||||
'test/modules/no_bootstrap.js',
|
||||
'test/helpers/matchers.js',
|
||||
'test/helpers/privateMocks.js',
|
||||
'test/helpers/support.js',
|
||||
'test/helpers/testabilityPatch.js',
|
||||
'src/routeToRegExp.js',
|
||||
'build/angular-animate.js',
|
||||
'test/ngMock/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngResource': [
|
||||
'@angularSrcModuleNgResource',
|
||||
'test/ngResource/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngRoute': [
|
||||
'build/angular-animate.js',
|
||||
'@angularSrcModuleNgRoute',
|
||||
'test/ngRoute/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngSanitize': [
|
||||
'@angularSrcModuleNgSanitize',
|
||||
'test/ngSanitize/**/*.js'
|
||||
],
|
||||
|
||||
'karmaModules-ngTouch': [
|
||||
'@angularSrcModuleNgTouch',
|
||||
'test/ngTouch/**/*.js'
|
||||
'test/helpers/*.js',
|
||||
'test/ngAnimate/*.js',
|
||||
'test/ngMessageFormat/*.js',
|
||||
'test/ngMessages/*.js',
|
||||
'test/ngMock/*.js',
|
||||
'test/ngCookies/*.js',
|
||||
'test/ngRoute/**/*.js',
|
||||
'test/ngResource/*.js',
|
||||
'test/ngSanitize/**/*.js',
|
||||
'test/ngTouch/**/*.js',
|
||||
'test/ngAria/*.js'
|
||||
],
|
||||
|
||||
'karmaJquery': [
|
||||
@@ -262,11 +232,13 @@ var angularFiles = {
|
||||
'test/jquery_alias.js',
|
||||
'@angularSrc',
|
||||
'@angularSrcModules',
|
||||
'@angularScenario',
|
||||
'@angularTest'
|
||||
],
|
||||
|
||||
'karmaJqueryExclude': [
|
||||
'src/angular-bootstrap.js',
|
||||
'src/ngScenario/angular-bootstrap.js',
|
||||
'test/jquery_remove.js',
|
||||
'src/angular.bind.js'
|
||||
]
|
||||
@@ -283,16 +255,6 @@ var angularFiles = {
|
||||
});
|
||||
});
|
||||
|
||||
angularFiles['angularSrcModuleNgAnimate'] = angularFiles['angularModules']['ngAnimate'];
|
||||
angularFiles['angularSrcModuleNgAria'] = angularFiles['angularModules']['ngAria'];
|
||||
angularFiles['angularSrcModuleNgCookies'] = angularFiles['angularModules']['ngCookies'];
|
||||
angularFiles['angularSrcModuleNgMessageFormat'] = angularFiles['angularModules']['ngMessageFormat'];
|
||||
angularFiles['angularSrcModuleNgMessages'] = angularFiles['angularModules']['ngMessages'];
|
||||
angularFiles['angularSrcModuleNgResource'] = angularFiles['angularModules']['ngResource'];
|
||||
angularFiles['angularSrcModuleNgRoute'] = angularFiles['angularModules']['ngRoute'];
|
||||
angularFiles['angularSrcModuleNgSanitize'] = angularFiles['angularModules']['ngSanitize'];
|
||||
angularFiles['angularSrcModuleNgTouch'] = angularFiles['angularModules']['ngTouch'];
|
||||
|
||||
angularFiles['angularSrcModules'] = [].concat(
|
||||
angularFiles['angularModules']['ngAnimate'],
|
||||
angularFiles['angularModules']['ngMessageFormat'],
|
||||
|
||||
@@ -29,16 +29,19 @@ app.directive('bmPeWatch', function() {
|
||||
};
|
||||
});
|
||||
|
||||
//Executes the specified expression as a collection watcher
|
||||
app.directive('bmPeWatchCollection', function() {
|
||||
//Executes the specified expression as a watcher
|
||||
//Adds a simple wrapper method to allow use of $watch instead of $watchCollection
|
||||
app.directive('bmPeWatchLiteral', function($parse) {
|
||||
function retZero() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
compile: function($element, $attrs) {
|
||||
$element.text($attrs.bmPeWatchCollection);
|
||||
$element.text($attrs.bmPeWatchLiteral);
|
||||
return function($scope, $element, $attrs) {
|
||||
$scope.$watchCollection($attrs.bmPeWatchCollection, function(val) {
|
||||
$element.text(val);
|
||||
});
|
||||
$scope.$watch($parse($attrs.bmPeWatchLiteral, retZero));
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -69,7 +72,8 @@ app.controller('DataController', function($scope, $rootScope) {
|
||||
date2: new Date(Math.random() * Date.now()),
|
||||
func: function() { return star; },
|
||||
obj: data[i - 1],
|
||||
keys: data[i - 1] && (data[i - 1].keys || Object.keys(data[i - 1]))
|
||||
keys: data[i - 1] && (data[i - 1].keys || Object.keys(data[i - 1])),
|
||||
constructor: data[i - 1]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
<label for="complexPath">Complex Paths</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="constructorPath" id="constructorPath">
|
||||
<label for="constructorPath">Constructor Paths</label>
|
||||
($parse special cases "constructor" for security)
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="fieldAccess" id="fieldAccess">
|
||||
<label for="fieldAccess">Field Accessors</label>
|
||||
@@ -60,16 +66,6 @@
|
||||
<input type="radio" ng-model="expressionType" value="arrayLiterals" id="arrayLiterals">
|
||||
<label for="arrayLiterals">Array Literals</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="watchCollection" id="watchCollection">
|
||||
<label for="watchCollection">$watchCollection</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="watchCollectionLiterals" id="watchCollectionLiterals">
|
||||
<label for="watchCollectionLiterals">$watchCollection Literals</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!--
|
||||
@@ -92,6 +88,17 @@
|
||||
<span bm-pe-watch="row.keys"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="constructorPath" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="row.index"></span>
|
||||
<span bm-pe-watch="row.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.constructor.constructor.index"></span>
|
||||
<span bm-pe-watch="row.constructor.constructor.constructor.index"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="complexPath" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="row.index"></span>
|
||||
<span bm-pe-watch="row.num0"></span>
|
||||
@@ -208,44 +215,27 @@
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="objectLiterals" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="{foo: rowIdx}"></span>
|
||||
<span bm-pe-watch="{foo: row, bar: rowIdx}"></span>
|
||||
<span bm-pe-watch="{0: row, 1: rowIdx, 2: 3}"></span>
|
||||
<span bm-pe-watch="{str: 'foo', num: rowIdx, b: true}"></span>
|
||||
<span bm-pe-watch="{a: {b: {c: {d: {e: {f: rowIdx}}}}}}"></span>
|
||||
<span bm-pe-watch="{a: rowIdx, b: 1, c: 2, d: 3, e: 4, f: 5, g: rowIdx, h: 6, i: 7, j: 8, k: rowIdx}"></span>
|
||||
<span bm-pe-watch-literal="{foo: rowIdx}"></span>
|
||||
<span bm-pe-watch-literal="{foo: row, bar: rowIdx}"></span>
|
||||
<span bm-pe-watch-literal="{0: row, 1: rowIdx, 2: 3}"></span>
|
||||
<span bm-pe-watch-literal="{str: 'foo', num: rowIdx, b: true}"></span>
|
||||
<span bm-pe-watch-literal="{a: {b: {c: {d: {e: {f: rowIdx}}}}}}"></span>
|
||||
<span bm-pe-watch-literal="{a: rowIdx, b: 1, c: 2, d: 3, e: 4, f: 5, g: rowIdx, h: 6, i: 7, j: 8, k: rowIdx}"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="arrayLiterals" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="[rowIdx]"></span>
|
||||
<span bm-pe-watch="[rowIdx, 0]"></span>
|
||||
<span bm-pe-watch="[rowIdx, 0, 1]"></span>
|
||||
<span bm-pe-watch="[rowIdx, 0, 1, 2]"></span>
|
||||
<span bm-pe-watch="[rowIdx, 0, 1, 2, 3]"></span>
|
||||
<span bm-pe-watch="[[], [rowIdx], [], [], [3], [[[]]]]"></span>
|
||||
<span bm-pe-watch="[rowIdx, undefined, null, true, false]"></span>
|
||||
<span bm-pe-watch="[[][0], [0][0], [][rowIdx]]"></span>
|
||||
<span bm-pe-watch="[0, rowIdx]"></span>
|
||||
<span bm-pe-watch="[0, 1, rowIdx]"></span>
|
||||
<span bm-pe-watch="[0, 1, 2, rowIdx]"></span>
|
||||
<span bm-pe-watch="[0, 1, 2, 3, rowIdx]"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="watchCollection" ng-repeat="(rowIdx, row) in data">
|
||||
<span bm-pe-watch-collection="data"></span>
|
||||
<span bm-pe-watch-collection="row.keys"></span>
|
||||
<span bm-pe-watch-collection="thisProbablyDoesntHaveAValue"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="watchCollectionLiterals" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch-collection="[rowIdx, row]"></span>
|
||||
<span bm-pe-watch-collection="[rowIdx, row, num0, str0, date0, obj, g, h, i, j, k, l, m, n, o, p]"></span>
|
||||
<span bm-pe-watch-collection="{a: rowIdx, b: row, c: num0, d: str0, e: date0, f: obj, g: g, h: h, i: i, j: j, k: k, l: l, m: m, n: n, o: o, p: p}"></span>
|
||||
|
||||
<!-- primitive/valueOf-compatible -->
|
||||
<span bm-pe-watch-collection="[rowIdx, row]"></span>
|
||||
<span bm-pe-watch-collection="[rowIdx, num0, str0, date0, date1, h, i, j, k, l, m, n, o, p]"></span>
|
||||
<span bm-pe-watch-collection="{a: rowIdx, c: num0, d: str0, e: date0, g: date1, h: h, i: i, j: j, k: k, l: l, m: m, n: n, o: o, p: p}"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1, 2]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1, 2, 3]"></span>
|
||||
<span bm-pe-watch-literal="[[], [rowIdx], [], [], [3], [[[]]]]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, undefined, null, true, false]"></span>
|
||||
<span bm-pe-watch-literal="[[][0], [0][0], [][rowIdx]]"></span>
|
||||
<span bm-pe-watch-literal="[0, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, 2, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, 2, 3, rowIdx]"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('repeatAnimateBenchmark', ['ngAnimate'])
|
||||
.config(function($animateProvider) {
|
||||
$animateProvider.classNameFilter(/animate-/);
|
||||
})
|
||||
.run(function($rootScope) {
|
||||
$rootScope.fileType = 'classfilter';
|
||||
});
|
||||
@@ -1,6 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('repeatAnimateBenchmark', [])
|
||||
.run(function($rootScope) {
|
||||
$rootScope.fileType = 'noanimate';
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('repeatAnimateBenchmark', ['ngAnimate'])
|
||||
.run(function($rootScope) {
|
||||
$rootScope.fileType = 'default';
|
||||
});
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [
|
||||
{
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
},
|
||||
{
|
||||
id: 'angular-animate',
|
||||
src: '/build/angular-animate.js'
|
||||
},
|
||||
{
|
||||
id: 'app',
|
||||
src: 'app.js'
|
||||
},
|
||||
{
|
||||
src: 'common.js'
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -1,120 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
var app = angular.module('repeatAnimateBenchmark');
|
||||
|
||||
app.config(function($compileProvider, $animateProvider) {
|
||||
if ($compileProvider.debugInfoEnabled) {
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
app.run(function($animate) {
|
||||
if ($animate.enabled) {
|
||||
$animate.enabled(true);
|
||||
}
|
||||
});
|
||||
|
||||
app.controller('DataController', function($scope, $rootScope, $animate) {
|
||||
var totalRows = 500;
|
||||
var totalColumns = 20;
|
||||
|
||||
var data = $scope.data = [];
|
||||
|
||||
function fillData() {
|
||||
if ($animate.enabled) {
|
||||
$animate.enabled($scope.benchmarkType !== 'globallyDisabled');
|
||||
}
|
||||
|
||||
for (var i = 0; i < totalRows; i++) {
|
||||
data[i] = [];
|
||||
for (var j = 0; j < totalColumns; j++) {
|
||||
data[i][j] = {
|
||||
i: i
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'enter',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
fillData();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'leave',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
data = $scope.data = [];
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.directive('disableAnimations', function($animate) {
|
||||
return {
|
||||
link: {
|
||||
pre: function(s, e) {
|
||||
$animate.enabled(e, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
app.directive('noop', function($animate) {
|
||||
return {
|
||||
link: {
|
||||
pre: angular.noop
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
app.directive('baseline', function($document) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function($scope, $element) {
|
||||
var document = $document[0];
|
||||
|
||||
var i, j, row, cell, comment;
|
||||
var template = document.createElement('span');
|
||||
template.setAttribute('ng-repeat', 'foo in foos');
|
||||
template.classList.add('ng-scope');
|
||||
template.appendChild(document.createElement('span'));
|
||||
template.appendChild(document.createTextNode(':'));
|
||||
|
||||
function createList() {
|
||||
for (i = 0; i < $scope.data.length; i++) {
|
||||
row = document.createElement('div');
|
||||
$element[0].appendChild(row);
|
||||
for (j = 0; j < $scope.data[i].length; j++) {
|
||||
cell = template.cloneNode(true);
|
||||
row.appendChild(cell);
|
||||
cell.childNodes[0].textContent = i;
|
||||
cell.ng339 = 'xxx';
|
||||
comment = document.createComment('ngRepeat end: bar in foo');
|
||||
row.appendChild(comment);
|
||||
}
|
||||
|
||||
comment = document.createComment('ngRepeat end: foo in foos');
|
||||
$element[0].appendChild(comment);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watch('data.length', function(newVal) {
|
||||
if (newVal === 0) {
|
||||
while ($element[0].firstChild) {
|
||||
$element[0].removeChild($element[0].firstChild);
|
||||
}
|
||||
} else {
|
||||
createList();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
})();
|
||||
@@ -1,70 +0,0 @@
|
||||
<div ng-app="repeatAnimateBenchmark" ng-cloak>
|
||||
<div ng-controller="DataController">
|
||||
<div class="container-fluid">
|
||||
<p>
|
||||
Tests rendering of an ngRepeat with 500 elements.<br>
|
||||
Animations can be enabled / disabled in different ways.<br>
|
||||
Two tests require reloading the app with different module / app configurations.
|
||||
</p>
|
||||
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="none">none: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="baseline">baseline (vanilla Javascript): </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'default'" value="enabled">enabled : </label> (requires <a href="./">app.js</a>)</div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'default' && fileType !== 'classfilter'" value="globallyDisabled">globally disabled:</label> (requires <a href="./">app.js</a> or <a href="?app=app-classfilter.js">app-classfilter.js</a>)</div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'default'" value="disabledParentElement">disabled by $animate.enabled() on parent element: </label> (requires <a href="./">app.js</a>)</div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'noanimate'" value="noanimate">Without ngAnimate:</label> (requires <a href="?app=app-noanimate.js">app-noanimate.js</a>)</div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" ng-disabled="fileType !== 'classfilter'" value="disabledClassFilter">disabled by classNameFilter on element:</label> (requires <a href="?app=app-classfilter.js">app-classfilter.js</a>)</div>
|
||||
|
||||
<ng-switch on="benchmarkType">
|
||||
<baseline ng-switch-when="baseline">
|
||||
</baseline>
|
||||
<div ng-switch-when="noanimate">
|
||||
<div noop>
|
||||
<div ng-repeat="row in data">
|
||||
<span ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="enabled">
|
||||
<div noop>
|
||||
<div ng-repeat="row in data">
|
||||
<span ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="globallyDisabled">
|
||||
<div noop>
|
||||
<div ng-repeat="row in data">
|
||||
<span ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="disabledClassFilter">
|
||||
<div noop>
|
||||
<div ng-repeat="row in data">
|
||||
<span class="disable-animations" ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-switch-when="disabledParentElement">
|
||||
<div disable-animations>
|
||||
<div ng-repeat="row in data">
|
||||
<span ng-repeat="column in row">
|
||||
<span>{{column.i}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-switch>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -13,8 +13,7 @@ body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#json,
|
||||
#xml {
|
||||
#json, #xml {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
+2
-6
@@ -1,11 +1,7 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
[ng\:cloak],
|
||||
[ng-cloak],
|
||||
[data-ng-cloak],
|
||||
[x-ng-cloak],
|
||||
.ng-cloak,
|
||||
.x-ng-cloak,
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
|
||||
.ng-cloak, .x-ng-cloak,
|
||||
.ng-hide:not(.ng-hide-animate) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -478,10 +478,10 @@ iframe.example {
|
||||
#navbar-sub {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
background: rgba(245,245,245,1);
|
||||
background: rgba(245,245,245,0.88);
|
||||
box-shadow: 0 0 2px #999;
|
||||
z-index: 1028;
|
||||
top: 57px;
|
||||
top: 83px;
|
||||
}
|
||||
|
||||
.main-body-grid {
|
||||
@@ -982,7 +982,7 @@ toc-container > div > toc-tree > ul > li > toc-tree > ul > li toc-tree > ul li {
|
||||
|
||||
#navbar-sub {
|
||||
position: relative;
|
||||
top: 0;
|
||||
top: 17px;
|
||||
margin-top: 80px;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
describe('table of contents', function() {
|
||||
|
||||
it('on provider pages', function() {
|
||||
browser.get('build/docs/index.html#!/api/ng/provider/$controllerProvider');
|
||||
browser.get('build/docs/index.html#!/api/ng/provider/$interpolateProvider');
|
||||
|
||||
var toc = element.all(by.css('toc-container > div > toc-tree'));
|
||||
toc.getText().then(function(text) {
|
||||
@@ -19,7 +19,7 @@ describe('table of contents', function() {
|
||||
var tocFirstLevel = element.all(by.css('toc-container > div > toc-tree > ul > li'));
|
||||
|
||||
tocFirstLevel.then(function(match) {
|
||||
expect(match.length).toBe(2);
|
||||
expect(match.length).toBe(3);
|
||||
|
||||
expect(match[1].all(by.css('li')).count()).toBe(2);
|
||||
});
|
||||
|
||||
@@ -91,16 +91,13 @@ directivesModule
|
||||
.component('tocTree', {
|
||||
template: '<ul>' +
|
||||
'<li ng-repeat="item in $ctrl.items">' +
|
||||
'<a ng-href="{{ $ctrl.path }}#{{item.fragment}}">{{item.title}}</a>' +
|
||||
'<a ng-href="#{{item.fragment}}">{{item.title}}</a>' +
|
||||
'<toc-tree ng-if="::item.children.length > 0" items="item.children"></toc-tree>' +
|
||||
'</li>' +
|
||||
'</ul>',
|
||||
bindings: {
|
||||
items: '<'
|
||||
},
|
||||
controller: ['$location', /** @this */ function($location) {
|
||||
this.path = $location.path().replace(/^\/?(.+?)(\/index)?\/?$/, '$1');
|
||||
}]
|
||||
}
|
||||
})
|
||||
.directive('tocContainer', function() {
|
||||
return {
|
||||
|
||||
@@ -55,7 +55,7 @@ angular.module('examples', [])
|
||||
return function(url, newWindow, fields) {
|
||||
/**
|
||||
* If the form posts to target="_blank", pop-up blockers can cause it not to work.
|
||||
* If a user chooses to bypass pop-up blocker one time and click the link, they will arrive at
|
||||
* If a user choses to bypass pop-up blocker one time and click the link, they will arrive at
|
||||
* a new default plnkr, not a plnkr with the desired template. Given this undesired behavior,
|
||||
* some may still want to open the plnk in a new window by opting-in via ctrl+click. The
|
||||
* newWindow param allows for this possibility.
|
||||
@@ -74,7 +74,7 @@ angular.module('examples', [])
|
||||
}])
|
||||
|
||||
.factory('createCopyrightNotice', function() {
|
||||
var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google LLC. All Rights Reserved.\n'
|
||||
var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google Inc. All Rights Reserved.\n'
|
||||
+ 'Use of this source code is governed by an MIT-style license that\n'
|
||||
+ 'can be found in the LICENSE file at http://angular.io/license';
|
||||
var COPYRIGHT_JS_CSS = '\n\n/*\n' + COPYRIGHT + '\n*/';
|
||||
|
||||
@@ -148,7 +148,6 @@ module.exports = new Package('angularjs', [
|
||||
|
||||
.config(function(checkAnchorLinksProcessor) {
|
||||
checkAnchorLinksProcessor.base = '/';
|
||||
checkAnchorLinksProcessor.errorOnUnmatchedLinks = true;
|
||||
// We are only interested in docs that have an area (i.e. they are pages)
|
||||
checkAnchorLinksProcessor.checkDoc = function(doc) { return doc.area; };
|
||||
})
|
||||
|
||||
@@ -5,36 +5,18 @@
|
||||
* @description
|
||||
* Process "error" docType docs and generate errorNamespace docs
|
||||
*/
|
||||
module.exports = function errorDocsProcessor(log, errorNamespaceMap, getMinerrInfo) {
|
||||
module.exports = function errorDocsProcessor(errorNamespaceMap, getMinerrInfo) {
|
||||
return {
|
||||
$runAfter: ['tags-extracted'],
|
||||
$runBefore: ['extra-docs-added'],
|
||||
$process: function(docs) {
|
||||
|
||||
// Get the extracted min errors to compare with the error docs, and report any mismatch
|
||||
var collectedErrors = require('../../../build/errors.json').errors;
|
||||
var flatErrors = [];
|
||||
|
||||
for (var namespace in collectedErrors) {
|
||||
for (var error in collectedErrors[namespace]) {
|
||||
flatErrors.push(namespace + ':' + error);
|
||||
}
|
||||
}
|
||||
|
||||
// Create error namespace docs and attach error docs to each
|
||||
docs.forEach(function(doc) {
|
||||
var parts, namespaceDoc;
|
||||
|
||||
if (doc.docType === 'error') {
|
||||
|
||||
var matchingMinErr = flatErrors.indexOf(doc.name);
|
||||
|
||||
if (matchingMinErr === -1) {
|
||||
log.warn('Error doc: ' + doc.name + ' has no matching min error');
|
||||
} else {
|
||||
flatErrors.splice(matchingMinErr, 1);
|
||||
}
|
||||
|
||||
// Parse out the error info from the id
|
||||
parts = doc.name.split(':');
|
||||
doc.namespace = parts[0];
|
||||
@@ -59,10 +41,6 @@ module.exports = function errorDocsProcessor(log, errorNamespaceMap, getMinerrIn
|
||||
}
|
||||
});
|
||||
|
||||
flatErrors.forEach(function(value) {
|
||||
log.warn('No error doc exists for min error: ' + value);
|
||||
});
|
||||
|
||||
errorNamespaceMap.forEach(function(errorNamespace) {
|
||||
docs.push(errorNamespace);
|
||||
});
|
||||
|
||||
@@ -47,13 +47,13 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
|
||||
}
|
||||
|
||||
areasToSearch = _.keyBy(this.areasToSearch);
|
||||
propertiesToIgnore = _.keyBy(this.propertiesToIgnore);
|
||||
areasToSearch = _.indexBy(this.areasToSearch);
|
||||
propertiesToIgnore = _.indexBy(this.propertiesToIgnore);
|
||||
log.debug('Properties to ignore', propertiesToIgnore);
|
||||
docTypesToIgnore = _.keyBy(this.docTypesToIgnore);
|
||||
docTypesToIgnore = _.indexBy(this.docTypesToIgnore);
|
||||
log.debug('Doc types to ignore', docTypesToIgnore);
|
||||
|
||||
var ignoreWordsMap = _.keyBy(wordsToIgnore);
|
||||
var ignoreWordsMap = _.indexBy(wordsToIgnore);
|
||||
|
||||
// If the title contains a name starting with ng, e.g. "ngController", then add the module name
|
||||
// without the ng to the title text, e.g. "controller".
|
||||
|
||||
@@ -224,7 +224,7 @@ module.exports = function generatePagesDataProcessor(log) {
|
||||
.map(function(doc) {
|
||||
return _.pick(doc, ['name', 'area', 'path']);
|
||||
})
|
||||
.keyBy('path')
|
||||
.indexBy('path')
|
||||
.value();
|
||||
|
||||
docs.push({
|
||||
|
||||
@@ -13,11 +13,11 @@ module.exports = function generateVersionDocProcessor(gitData) {
|
||||
return {
|
||||
$runAfter: ['generatePagesDataProcessor'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
// Remove rogue builds that are in the npm repository but not on code.angularjs.org
|
||||
ignoredBuilds: ['1.3.4-build.3588'],
|
||||
// the blacklist is to remove rogue builds that are in the npm repository but not on code.angularjs.org
|
||||
blacklist: ['1.3.4-build.3588'],
|
||||
$process: function(docs) {
|
||||
|
||||
var ignoredBuilds = this.ignoredBuilds;
|
||||
var blacklist = this.blacklist;
|
||||
var currentVersion = require('../../../build/version.json');
|
||||
var output = exec('yarn info angular versions --json', { silent: true }).stdout.split('\n')[0];
|
||||
var allVersions = processAllVersionsResponse(JSON.parse(output).data);
|
||||
@@ -57,7 +57,7 @@ module.exports = function generateVersionDocProcessor(gitData) {
|
||||
|
||||
versions = versions
|
||||
.filter(function(versionStr) {
|
||||
return ignoredBuilds.indexOf(versionStr) === -1;
|
||||
return blacklist.indexOf(versionStr) === -1;
|
||||
})
|
||||
.map(function(versionStr) {
|
||||
return semver.parse(versionStr);
|
||||
|
||||
@@ -15,7 +15,7 @@ var cdnUrl = googleCdnUrl + versionInfo.cdnVersion;
|
||||
// docs.angularjs.org and code.angularjs.org need them.
|
||||
var versionPath = versionInfo.currentVersion.isSnapshot ?
|
||||
'snapshot' :
|
||||
versionInfo.currentVersion.version;
|
||||
(versionInfo.currentVersion.version || versionInfo.currentVersion.version);
|
||||
var examplesDependencyPath = angularCodeUrl + versionPath + '/';
|
||||
|
||||
module.exports = function productionDeployment(getVersion) {
|
||||
|
||||
@@ -1,12 +1,3 @@
|
||||
{# Macros #}
|
||||
{%- macro addTag(name, attributes) %}
|
||||
<{$ name $}
|
||||
{%- for attrName, attrValue in attributes -%}
|
||||
{$ ' ' + attrName $}="{$ attrValue $}"
|
||||
{%- endfor -%}
|
||||
></{$ name $}>
|
||||
{%- endmacro -%}
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en" ng-app="docsApp" ng-strict-di ng-controller="DocsController">
|
||||
<head>
|
||||
@@ -33,27 +24,50 @@
|
||||
})();
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// Dynamically add `<base>` tag.
|
||||
// dynamically add base tag as well as css and javascript files.
|
||||
// we can't add css/js the usual way, because some browsers (FF) eagerly prefetch resources
|
||||
// before the base attribute is added, causing 404 and terribly slow loading of the docs app.
|
||||
(function() {
|
||||
var indexFile = (location.pathname.match(/\/(index[^.]*\.html)/) || ['', ''])[1],
|
||||
rUrl = /(#!\/|api|guide|misc|tutorial|error|index[^.]*\.html).*$/,
|
||||
var indexFile = (location.pathname.match(/\/(index[^\.]*\.html)/) || ['', ''])[1],
|
||||
rUrl = /(#!\/|api|guide|misc|tutorial|error|index[^\.]*\.html).*$/,
|
||||
baseUrl = location.href.replace(rUrl, indexFile),
|
||||
production = location.hostname === 'docs.angularjs.org',
|
||||
headEl = document.getElementsByTagName('head')[0],
|
||||
baseEl = document.createElement('base');
|
||||
sync = true;
|
||||
|
||||
baseEl.setAttribute('href', baseUrl);
|
||||
headEl.appendChild(baseEl);
|
||||
addTag('base', {href: baseUrl});
|
||||
|
||||
|
||||
{% for stylesheet in doc.stylesheets %}addTag('link', {rel: 'stylesheet', href: '{$ stylesheet $}', type: 'text/css'});
|
||||
{% endfor %}
|
||||
|
||||
{% for script in doc.scripts %}addTag('script', {src: '{$ script $}' }, sync);
|
||||
{% endfor %}
|
||||
|
||||
function addTag(name, attributes, sync) {
|
||||
var el = document.createElement(name),
|
||||
attrName;
|
||||
|
||||
for (attrName in attributes) {
|
||||
el.setAttribute(attrName, attributes[attrName]);
|
||||
}
|
||||
|
||||
sync ? document.write(outerHTML(el)) : headEl.appendChild(el);
|
||||
}
|
||||
|
||||
function outerHTML(node){
|
||||
// if IE, Chrome take the internal method otherwise build one
|
||||
return node.outerHTML || (
|
||||
function(n){
|
||||
var div = document.createElement('div'), h;
|
||||
div.appendChild(n);
|
||||
h = div.innerHTML;
|
||||
div = null;
|
||||
return h;
|
||||
})(node);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
{% for stylesheet in doc.stylesheets %}
|
||||
{$- addTag('link', {rel: 'stylesheet', href: stylesheet, type: 'text/css'}) -$}
|
||||
{% endfor %}
|
||||
{% for script in doc.scripts %}
|
||||
{$- addTag('script', {src: script}) -$}
|
||||
{% endfor %}
|
||||
|
||||
<script type="text/javascript">
|
||||
// GA asynchronous tracker
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-8594346-3']);
|
||||
@@ -142,18 +156,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<nav id="navbar-notice" class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<p class="site-notice visible-phone">
|
||||
This site refers to AngularJS (v1.x). <a href="https://angular.io/">Go to the latest Angular</a>.
|
||||
</p>
|
||||
<p class="site-notice visible-desktop">
|
||||
This site and all of its contents are referring to AngularJS (version 1.x),
|
||||
if you are looking for the latest Angular, please visit <a href="https://angular.io/">angular.io</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<nav id="navbar-sub" class="sup-header navbar navbar-fixed-top" scroll-y-offset-element ng-cloak>
|
||||
<div class="container main-grid main-header-grid">
|
||||
<p class="site-notice">
|
||||
AngularJS support has officially ended as of January 2022.
|
||||
<a href="https://docs.angularjs.org/misc/version-support-status">
|
||||
See what ending support means
|
||||
</a> and
|
||||
<a href="https://goo.gle/angularjs-end-of-life">
|
||||
read the end of life announcement</a>.<br>
|
||||
Visit <a href="https://angular.io">angular.io</a> for the actively supported
|
||||
Angular.
|
||||
</p>
|
||||
<div class="grid-left">
|
||||
<version-picker></version-picker>
|
||||
</div>
|
||||
@@ -205,7 +222,7 @@
|
||||
<p class="pull-right"><a back-to-top>Back to top</a></p>
|
||||
|
||||
<p>
|
||||
Super-powered by Google ©2010-2020
|
||||
Super-powered by Google ©2010-2018
|
||||
(<a id="version"
|
||||
ng-href="https://github.com/angular/angular.js/blob/master/CHANGELOG.md#{{versionNumber}}"
|
||||
ng-bind-template="v{{version}}" title="Changelog of this version of AngularJS">
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if method.this %}
|
||||
<h4>Method's `this`</h4>
|
||||
<h4>Method's {% code %}this{% endcode %}</h4>
|
||||
{$ method.this | marked $}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% if doc.this %}
|
||||
<h3>Method's `this`</h3>
|
||||
<h3>Method's {% code %}this{% endcode %}</h3>
|
||||
{$ doc.this | marked $}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -3,12 +3,9 @@
|
||||
@description
|
||||
|
||||
# AngularJS API Docs
|
||||
<div class="alert alert-warning">
|
||||
AngularJS support has officially ended as of January 2022.
|
||||
[See what ending support means](https://docs.angularjs.org/misc/version-support-status)
|
||||
and [read the end of life announcement](https://goo.gle/angularjs-end-of-life).
|
||||
|
||||
Visit [angular.io](https://angular.io) for the actively supported Angular.
|
||||
<div class="alert alert-warning">
|
||||
**AngularJS will be moving to Long Term Support (LTS) mode on July 1st 2018.**: [Find out more](misc/version-support-status).
|
||||
</div>
|
||||
|
||||
## Welcome to the AngularJS API docs page.
|
||||
@@ -225,7 +222,11 @@ Use the ngCookies module to handle cookie management within your application.
|
||||
{@link ngCookies#service Services / Factories}
|
||||
</td>
|
||||
<td>
|
||||
The {@link ngCookies.$cookies $cookies} service is a convenient wrapper to store simple data within browser cookies.
|
||||
The following services are used for cookie management:
|
||||
<ul>
|
||||
<li>The {@link ngCookies.$cookies $cookie} service is a convenient wrapper to store simple data within browser cookies.</li>
|
||||
<li>{@link ngCookies.$cookieStore $cookieStore} is used to store more complex data using serialization.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $compile:ctxoverride
|
||||
@fullName DOM Property Security Context Override
|
||||
@description
|
||||
|
||||
This error occurs when the security context for a property is defined via {@link ng.$compileProvider#addPropertySecurityContext addPropertySecurityContext()} multiple times under different security contexts.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
$compileProvider.addPropertySecurityContext("my-element", "src", $sce.MEDIA_URL);
|
||||
$compileProvider.addPropertySecurityContext("my-element", "src", $sce.RESOURCE_URL); //throws
|
||||
```
|
||||
@@ -10,15 +10,13 @@ myModule.directive('directiveName', function factory() {
|
||||
return {
|
||||
...
|
||||
scope: {
|
||||
'localName': '@', // OK
|
||||
'localName2': '&attr', // OK
|
||||
'localName3': '<?attr', // OK
|
||||
'localName4': ' = attr', // OK
|
||||
'localName5': ' =*attr', // OK
|
||||
'localName6': 'attr', // ERROR: missing mode @&=<
|
||||
'localName7': 'attr=', // ERROR: must be prefixed with @&=<
|
||||
'localName8': '=attr?', // ERROR: ? must come directly after the mode
|
||||
'localName9': '<*' // ERROR: * is only valid with =
|
||||
'attrName': '@', // OK
|
||||
'attrName2': '=localName', // OK
|
||||
'attrName3': '<?localName', // OK
|
||||
'attrName4': ' = name', // OK
|
||||
'attrName5': 'name', // ERROR: missing mode @&=
|
||||
'attrName6': 'name=', // ERROR: must be prefixed with @&=
|
||||
'attrName7': '=name?', // ERROR: ? must come directly after the mode
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
@@ -3,34 +3,6 @@
|
||||
@fullName Missing required attribute
|
||||
@description
|
||||
|
||||
This error may occur only when {@link $compileProvider#strictComponentBindingsEnabled `$compileProvider.strictComponentBindingsEnabled`} is set to `true`.
|
||||
|
||||
If that is the case, then all {@link $compileProvider#component component} controller bindings and
|
||||
{@link $compileProvider#directive directive} scope / controller bindings that are non-optional,
|
||||
must be provided when the directive is instantiated.
|
||||
|
||||
To make a binding optional, add '?' to the definition.
|
||||
|
||||
## Example:
|
||||
|
||||
```js
|
||||
|
||||
app.component('myTest', {
|
||||
bindings: {
|
||||
first: '=?', // optional
|
||||
second: '='
|
||||
},
|
||||
controller: function() {
|
||||
...
|
||||
},
|
||||
template: '...'
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
This component will throw `missingattr` for the `second` binding when used as follows:
|
||||
|
||||
```html
|
||||
<my-test></my-test>
|
||||
```
|
||||
|
||||
This error may occur only when `$compileProvider.strictComponentBindingsEnabled` is set to `true`.
|
||||
Then all attributes mentioned in `bindings` without `?` must be set. If one or more aren't set,
|
||||
the first one will throw an error.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
@ngdoc error
|
||||
@name $compile:nodomevents
|
||||
@fullName Event Attribute/Property Binding
|
||||
@fullName Interpolated Event Attributes
|
||||
@description
|
||||
|
||||
This error occurs when one tries to create a binding for event handler attributes or properties like `onclick`, `onload`, `onsubmit`, etc.
|
||||
This error occurs when one tries to create a binding for event handler attributes like `onclick`, `onload`, `onsubmit`, etc.
|
||||
|
||||
There is no practical value in binding to these attributes/properties and doing so only exposes your application to security vulnerabilities like XSS.
|
||||
For these reasons binding to event handler attributes and properties (`formaction` and all starting with `on`) is not supported.
|
||||
There is no practical value in binding to these attributes and doing so only exposes your application to security vulnerabilities like XSS.
|
||||
For these reasons binding to event handler attributes (all attributes that start with `on` and `formaction` attribute) is not supported.
|
||||
|
||||
|
||||
An example code that would allow XSS vulnerability by evaluating user input in the window context could look like this:
|
||||
@@ -17,4 +17,4 @@ An example code that would allow XSS vulnerability by evaluating user input in t
|
||||
|
||||
Since the `onclick` evaluates the value as JavaScript code in the window context, setting the `username` model to a value like `javascript:alert('PWND')` would result in script injection when the `div` is clicked.
|
||||
|
||||
Please use the `ng-*` or `ng-on-*` versions instead (such as `ng-click` or `ng-on-click` rather than `onclick`).
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $compile:srcset
|
||||
@fullName Invalid value passed to `attr.$set('srcset', value)`
|
||||
@description
|
||||
|
||||
This error occurs if you try to programmatically set the `srcset` attribute with a non-string value.
|
||||
|
||||
This can be the case if you tried to avoid the automatic sanitization of the `srcset` value by
|
||||
passing a "trusted" value provided by calls to `$sce.trustAsMediaUrl(value)`.
|
||||
|
||||
If you want to programmatically set explicitly trusted unsafe URLs, you should use `$sce.trustAsHtml`
|
||||
on the whole `img` tag and inject it into the DOM using the `ng-bind-html` directive.
|
||||
@@ -0,0 +1,11 @@
|
||||
@ngdoc error
|
||||
@name $compile:tpload
|
||||
@fullName Error Loading Template
|
||||
@description
|
||||
|
||||
This error occurs when {@link ng.$compile `$compile`} attempts to fetch a template from some URL, and the request fails.
|
||||
|
||||
To resolve this error, ensure that the URL of the template is spelled correctly and resolves to correct absolute URL.
|
||||
The [Chrome Developer Tools](https://developers.google.com/chrome-developer-tools/docs/network#network_panel_overview) might also be helpful in determining why the request failed.
|
||||
|
||||
If you are using {@link ng.$templateCache} to pre-load templates, ensure that the cache was populated with the template.
|
||||
@@ -9,7 +9,7 @@ value is `JSON_CALLBACK`.
|
||||
|
||||
`$http` JSONP requests need to attach a callback query parameter to the URL. The name of this
|
||||
parameter is specified in the configuration object (or in the defaults) via the `jsonpCallbackParam`
|
||||
property. You must not provide your own parameter with this name in the configuration of the request.
|
||||
property. You must not provide your own parameter with this name in the configuratio of the request.
|
||||
|
||||
In previous versions of AngularJS, you specified where to add the callback parameter value via the
|
||||
`JSON_CALLBACK` placeholder. This is no longer allowed.
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $interval:badprom
|
||||
@fullName Non-$interval promise
|
||||
@description
|
||||
|
||||
This error occurs when calling {@link ng.$interval#cancel $interval.cancel()} with a promise that
|
||||
was not generated by the {@link ng.$interval $interval} service. This can, for example, happen when
|
||||
calling {@link ng.$q#the-promise-api then()/catch()} on the returned promise, which creates a new
|
||||
promise, and pass that new promise to {@link ng.$interval#cancel $interval.cancel()}.
|
||||
|
||||
Example of incorrect usage that leads to this error:
|
||||
|
||||
```js
|
||||
var promise = $interval(doSomething, 1000, 5).then(doSomethingElse);
|
||||
$interval.cancel(promise);
|
||||
```
|
||||
|
||||
To fix the example above, keep a reference to the promise returned by
|
||||
{@link ng.$interval $interval()} and pass that to {@link ng.$interval#cancel $interval.cancel()}:
|
||||
|
||||
```js
|
||||
var promise = $interval(doSomething, 1000, 5);
|
||||
var newPromise = promise.then(doSomethingElse);
|
||||
$interval.cancel(promise);
|
||||
```
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
Occurs when an expression is trying to assign a value to a non-assignable expression.
|
||||
|
||||
This can happen if the left side of an assignment is not a valid reference to a variable
|
||||
This can happen if the left side of an assigment is not a valid reference to a variable
|
||||
or property. E.g. In the following snippet `1+2` is not assignable.
|
||||
|
||||
```
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@fullName Invalid matcher (only string patterns and RegExp instances are supported)
|
||||
@description
|
||||
|
||||
Please see {@link $sceDelegateProvider#trustedResourceUrlList
|
||||
$sceDelegateProvider.trustedResourceUrlList} and {@link
|
||||
$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList} for the
|
||||
Please see {@link $sceDelegateProvider#resourceUrlWhitelist
|
||||
$sceDelegateProvider.resourceUrlWhitelist} and {@link
|
||||
$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} for the
|
||||
list of acceptable items.
|
||||
|
||||
@@ -15,8 +15,8 @@ By default, only URLs that belong to the same origin are trusted. These are urls
|
||||
The {@link ng.directive:ngInclude ngInclude} directive and {@link guide/directive directives} that specify a `templateUrl` require a trusted resource URL.
|
||||
|
||||
To load templates from other domains and/or protocols, either adjust the {@link
|
||||
ng.$sceDelegateProvider#trustedResourceUrlList trusted resource URL list}/ {@link
|
||||
ng.$sceDelegateProvider#bannedResourceUrlList banned resource URL list} or wrap the URL with a call to {@link
|
||||
ng.$sceDelegateProvider#resourceUrlWhitelist whitelist}/ {@link
|
||||
ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@link
|
||||
ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl}.
|
||||
|
||||
**Note**: The browser's [Same Origin
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@fullName The sequence *** is not a valid pattern wildcard
|
||||
@description
|
||||
|
||||
The strings in {@link $sceDelegateProvider#trustedResourceUrlList
|
||||
$sceDelegateProvider.trustedResourceUrlList} and {@link
|
||||
$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList} may not
|
||||
The strings in {@link $sceDelegateProvider#resourceUrlWhitelist
|
||||
$sceDelegateProvider.resourceUrlWhitelist} and {@link
|
||||
$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} may not
|
||||
contain the undefined sequence `***`. Only `*` and `**` wildcard patterns are defined.
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $templateRequest:tpload
|
||||
@fullName Error Loading Template
|
||||
@description
|
||||
|
||||
This error occurs when {@link $templateRequest} attempts to fetch a template from some URL, and
|
||||
the request fails.
|
||||
|
||||
The template URL might be defined in a directive/component definition, an instance of `ngInclude`,
|
||||
an instance of `ngMessagesInclude` or a templated route in a `$route` route definition.
|
||||
|
||||
To resolve this error, ensure that the URL of the template is spelled correctly and resolves to
|
||||
correct absolute URL.
|
||||
The [Chrome Developer Tools](https://developers.google.com/chrome-developer-tools/docs/network#network_panel_overview)
|
||||
might also be helpful in determining why the request failed.
|
||||
|
||||
If you are using {@link ng.$templateCache} to pre-load templates, ensure that the cache was
|
||||
populated with the template.
|
||||
@@ -1,25 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $timeout:badprom
|
||||
@fullName Non-$timeout promise
|
||||
@description
|
||||
|
||||
This error occurs when calling {@link ng.$timeout#cancel $timeout.cancel()} with a promise that
|
||||
was not generated by the {@link ng.$timeout $timeout} service. This can, for example, happen when
|
||||
calling {@link ng.$q#the-promise-api then()/catch()} on the returned promise, which creates a new
|
||||
promise, and pass that new promise to {@link ng.$timeout#cancel $timeout.cancel()}.
|
||||
|
||||
Example of incorrect usage that leads to this error:
|
||||
|
||||
```js
|
||||
var promise = $timeout(doSomething, 1000).then(doSomethingElse);
|
||||
$timeout.cancel(promise);
|
||||
```
|
||||
|
||||
To fix the example above, keep a reference to the promise returned by
|
||||
{@link ng.$timeout $timeout()} and pass that to {@link ng.$timeout#cancel $timeout.cancel()}:
|
||||
|
||||
```js
|
||||
var promise = $timeout(doSomething, 1000);
|
||||
var newPromise = promise.then(doSomethingElse);
|
||||
$timeout.cancel(promise);
|
||||
```
|
||||
@@ -3,9 +3,12 @@
|
||||
@fullName Unsupported Selector Lookup
|
||||
@description
|
||||
|
||||
In order to keep AngularJS small, AngularJS implements only a subset of the selectors in {@link angular.element#angularjs-s-jqlite jqLite}.
|
||||
In order to keep AngularJS small, AngularJS implements only a subset of the selectors in
|
||||
{@link angular.element#angularjs-s-jqlite jqLite}.
|
||||
This error occurs when a jqLite instance is invoked with a selector other than this subset.
|
||||
|
||||
In order to resolve this error, rewrite your code to only use tag name selectors and manually traverse the DOM using the APIs provided by jqLite.
|
||||
In order to resolve this error, rewrite your code to only use tag name selectors and manually
|
||||
traverse the DOM using the APIs provided by jqLite.
|
||||
|
||||
Alternatively, you can include a full version of jQuery, which AngularJS will automatically use and that will make all selectors available.
|
||||
Alternatively, you can include a full version of jQuery, which AngularJS will automatically use
|
||||
and that will make all selectors available.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
@ngdoc error
|
||||
@name ngRef:noctrl
|
||||
@fullName A controller for the value of `ngRefRead` could not be found on the element.
|
||||
@description
|
||||
|
||||
This error occurs when the {@link ng.ngRef ngRef directive} specifies
|
||||
a value in `ngRefRead` that cannot be resolved to a directive / component controller.
|
||||
|
||||
Causes for this error can be:
|
||||
|
||||
1. Your `ngRefRead` value has a typo.
|
||||
2. You have a typo in the *registered* directive / component name.
|
||||
3. The directive / component does not have a controller.
|
||||
|
||||
Note that `ngRefRead` takes the name of the component / directive, not the name of controller, and
|
||||
also not the combination of directive and 'Controller'. For example, for a directive called 'myDirective',
|
||||
the correct declaration is `<div ng-ref="$ctrl.ref" ng-ref-read="myDirective">`.
|
||||
@@ -1,27 +0,0 @@
|
||||
@ngdoc error
|
||||
@name ngRef:nonassign
|
||||
@fullName Non-Assignable Expression
|
||||
@description
|
||||
|
||||
This error occurs when ngRef defines an expression that is not-assignable.
|
||||
|
||||
In order for ngRef to work, it must be possible to write the reference into the path defined with the expression.
|
||||
|
||||
For example, the following expressions are non-assignable:
|
||||
|
||||
```
|
||||
<my-directive ng-ref="{}"></my-directive>
|
||||
|
||||
<my-directive ng-ref="myFn()"></my-directive>
|
||||
|
||||
<!-- missing attribute value is also invalid -->
|
||||
<my-directive ng-ref></my-directive>
|
||||
|
||||
```
|
||||
|
||||
To resolve this error, use a path expression that is assignable:
|
||||
|
||||
```
|
||||
<my-directive ng-ref="$ctrl.reference"></my-directive>
|
||||
|
||||
```
|
||||
@@ -3,7 +3,7 @@
|
||||
@sortOrder 500
|
||||
@description
|
||||
|
||||
# Using the `$location` service
|
||||
# What does it do?
|
||||
|
||||
The `$location` service parses the URL in the browser address bar (based on [`window.location`](https://developer.mozilla.org/en/window.location)) and makes the URL available to
|
||||
your application. Changes to the URL in the address bar are reflected into the `$location` service and
|
||||
@@ -76,7 +76,7 @@ the current URL in the browser.
|
||||
It does not cause a full page reload when the browser URL is changed. To reload the page after
|
||||
changing the URL, use the lower-level API, `$window.location.href`.
|
||||
|
||||
## General overview of the API
|
||||
# General overview of the API
|
||||
|
||||
The `$location` service can behave differently, depending on the configuration that was provided to
|
||||
it when it was instantiated. The default configuration is suitable for many applications, for
|
||||
@@ -85,7 +85,7 @@ others customizing the configuration can enable new features.
|
||||
Once the `$location` service is instantiated, you can interact with it via jQuery-style getter and
|
||||
setter methods that allow you to get or change the current URL in the browser.
|
||||
|
||||
### `$location` service configuration
|
||||
## `$location` service configuration
|
||||
|
||||
To configure the `$location` service, retrieve the
|
||||
{@link ng.$locationProvider $locationProvider} and set the parameters as follows:
|
||||
@@ -113,12 +113,12 @@ To configure the `$location` service, retrieve the
|
||||
Prefix used for Hashbang URLs (used in Hashbang mode or in legacy browsers in HTML5 mode).<br />
|
||||
Default: `'!'`
|
||||
|
||||
#### Example configuration
|
||||
### Example configuration
|
||||
```js
|
||||
$locationProvider.html5Mode(true).hashPrefix('*');
|
||||
```
|
||||
|
||||
### Getter and setter methods
|
||||
## Getter and setter methods
|
||||
|
||||
`$location` service provides getter methods for read-only parts of the URL (absUrl, protocol, host,
|
||||
port) and getter / setter methods for url, path, search, hash:
|
||||
@@ -137,7 +137,7 @@ change multiple segments in one go, chain setters like this:
|
||||
$location.path('/newValue').search({key: value});
|
||||
```
|
||||
|
||||
### Replace method
|
||||
## Replace method
|
||||
|
||||
There is a special `replace` method which can be used to tell the $location service that the next
|
||||
time the $location service is synced with the browser, the last history record should be replaced
|
||||
@@ -173,7 +173,7 @@ encoded.
|
||||
`/path?search=a&b=c#hash`. The segments are encoded as well.
|
||||
|
||||
|
||||
## Hashbang and HTML5 Modes
|
||||
# Hashbang and HTML5 Modes
|
||||
|
||||
`$location` service has two configuration modes which control the format of the URL in the browser
|
||||
address bar: **Hashbang mode** (the default) and the **HTML5 mode** which is based on using the
|
||||
@@ -221,7 +221,7 @@ facilitate the browser URL change and history management.
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Hashbang mode (default mode)
|
||||
## Hashbang mode (default mode)
|
||||
|
||||
In this mode, `$location` uses Hashbang URLs in all browsers.
|
||||
AngularJS also does not intercept and rewrite links in this mode. I.e. links work
|
||||
@@ -229,7 +229,7 @@ as expected and also perform full page reloads when other parts of the url
|
||||
than the hash fragment was changed.
|
||||
|
||||
|
||||
#### Example
|
||||
### Example
|
||||
|
||||
```js
|
||||
it('should show example', function() {
|
||||
@@ -255,7 +255,7 @@ it('should show example', function() {
|
||||
});
|
||||
```
|
||||
|
||||
### HTML5 mode
|
||||
## HTML5 mode
|
||||
|
||||
In HTML5 mode, the `$location` service getters and setters interact with the browser URL address
|
||||
through the HTML5 history API. This allows for use of regular URL path and search segments,
|
||||
@@ -271,7 +271,7 @@ Note that in this mode, AngularJS intercepts all links (subject to the "Html lin
|
||||
and updates the url in a way that never performs a full page reload.
|
||||
|
||||
|
||||
#### Example
|
||||
### Example
|
||||
|
||||
```js
|
||||
it('should show example', function() {
|
||||
@@ -320,14 +320,14 @@ it('should show example (when browser doesn\'t support HTML5 mode', function() {
|
||||
});
|
||||
```
|
||||
|
||||
#### Fallback for legacy browsers
|
||||
### Fallback for legacy browsers
|
||||
|
||||
For browsers that support the HTML5 history API, `$location` uses the HTML5 history API to write
|
||||
path and search. If the history API is not supported by a browser, `$location` supplies a Hashbang
|
||||
URL. This frees you from having to worry about whether the browser viewing your app supports the
|
||||
history API or not; the `$location` service makes this transparent to you.
|
||||
|
||||
#### HTML link rewriting
|
||||
### HTML link rewriting
|
||||
|
||||
When you use HTML5 history API mode, you will not need special hashbang links. All you have to do
|
||||
is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
|
||||
@@ -361,7 +361,7 @@ Note that [attribute name normalization](guide/directive#normalization) does not
|
||||
`'internalLink'` will **not** match `'internal-link'`.
|
||||
|
||||
|
||||
#### Relative links
|
||||
### Relative links
|
||||
|
||||
Be sure to check all relative links, images, scripts etc. AngularJS requires you to specify the url
|
||||
base in the head of your main html file (`<base href="/my-base/index.html">`) unless `html5Mode.requireBase`
|
||||
@@ -374,14 +374,14 @@ will only change `$location.hash()` and not modify the url otherwise. This is us
|
||||
to anchors on the same page without needing to know on which page the user currently is.
|
||||
|
||||
|
||||
#### Server side
|
||||
### Server side
|
||||
|
||||
Using this mode requires URL rewriting on server side, basically you have to rewrite all your links
|
||||
to entry point of your application (e.g. index.html). Requiring a `<base>` tag is also important for
|
||||
this case, as it allows AngularJS to differentiate between the part of the url that is the application
|
||||
base and the path that should be handled by the application.
|
||||
|
||||
#### Base href constraints
|
||||
### Base href constraints
|
||||
|
||||
The `$location` service is not able to function properly if the current URL is outside the URL given
|
||||
as the base href. This can have subtle confusing consequences...
|
||||
@@ -403,7 +403,7 @@ legacy browsers and hashbang links in modern browser:
|
||||
- Modern browser will rewrite hashbang URLs to regular URLs.
|
||||
- Older browsers will redirect regular URLs to hashbang URLs.
|
||||
|
||||
#### Example
|
||||
### Example
|
||||
|
||||
Here you can see two `$location` instances that show the difference between **Html5 mode** and **Html5 Fallback mode**.
|
||||
Note that to simulate different levels of browser support, the `$location` instances are connected to
|
||||
@@ -415,7 +415,7 @@ redirect to regular / hashbang url, as this conversion happens only during parsi
|
||||
|
||||
In these examples we use `<base href="/base/index.html" />`. The inputs represent the address bar of the browser.
|
||||
|
||||
##### Browser in HTML5 mode
|
||||
#### Browser in HTML5 mode
|
||||
<example module="html5-mode" name="location-html5-mode">
|
||||
<file name="index.html">
|
||||
<div ng-controller="LocationController">
|
||||
@@ -565,7 +565,7 @@ In these examples we use `<base href="/base/index.html" />`. The inputs represen
|
||||
|
||||
</example>
|
||||
|
||||
##### Browser in HTML5 Fallback mode (Hashbang mode)
|
||||
#### Browser in HTML5 Fallback mode (Hashbang mode)
|
||||
<example module="hashbang-mode" name="location-hashbang-mode">
|
||||
<file name="index.html">
|
||||
<div ng-controller="LocationController">
|
||||
@@ -718,15 +718,15 @@ In these examples we use `<base href="/base/index.html" />`. The inputs represen
|
||||
|
||||
</example>
|
||||
|
||||
## Caveats
|
||||
# Caveats
|
||||
|
||||
### Page reload navigation
|
||||
## Page reload navigation
|
||||
|
||||
The `$location` service allows you to change only the URL; it does not allow you to reload the
|
||||
page. When you need to change the URL and reload the page or navigate to a different page, please
|
||||
use a lower level API, {@link ng.$window $window.location.href}.
|
||||
|
||||
### Using $location outside of the scope life-cycle
|
||||
## Using $location outside of the scope life-cycle
|
||||
|
||||
`$location` knows about AngularJS's {@link ng.$rootScope.Scope scope} life-cycle. When a URL changes in
|
||||
the browser it updates the `$location` and calls `$apply` so that all
|
||||
@@ -738,7 +738,7 @@ propagate this change into browser and will notify all the {@link ng.$rootScope.
|
||||
When you want to change the `$location` from outside AngularJS (for example, through a DOM Event or
|
||||
during testing) - you must call `$apply` to propagate the changes.
|
||||
|
||||
### $location.path() and ! or / prefixes
|
||||
## $location.path() and ! or / prefixes
|
||||
|
||||
A path should always begin with forward slash (`/`); the `$location.path()` setter will add the
|
||||
forward slash if it is missing.
|
||||
@@ -746,17 +746,22 @@ forward slash if it is missing.
|
||||
Note that the `!` prefix in the hashbang mode is not part of `$location.path()`; it is actually
|
||||
`hashPrefix`.
|
||||
|
||||
### Crawling your app
|
||||
## Crawling your app
|
||||
|
||||
Most modern search engines are able to crawl AJAX applications with dynamic content, provided all
|
||||
included resources are available to the crawler bots.
|
||||
To allow indexing of your AJAX application, you have to add special meta tag in the head section of
|
||||
your document:
|
||||
|
||||
There also exists a special
|
||||
[AJAX crawling scheme](http://code.google.com/web/ajaxcrawling/docs/specification.html) developed by
|
||||
Google that allows bots to crawl the static equivalent of a dynamically generated page,
|
||||
but this schema has been deprecated, and support for it may vary by search engine.
|
||||
```html
|
||||
<meta name="fragment" content="!" />
|
||||
```
|
||||
|
||||
## Testing with the $location service
|
||||
This will cause crawler bot to request links with `_escaped_fragment_` param so that your server
|
||||
can recognize the crawler and serve a HTML snapshots. For more information about this technique,
|
||||
see [Making AJAX Applications
|
||||
Crawlable](http://code.google.com/web/ajaxcrawling/docs/specification.html).
|
||||
|
||||
|
||||
# Testing with the $location service
|
||||
|
||||
When using `$location` service during testing, you are outside of the angular's {@link
|
||||
ng.$rootScope.Scope scope} life-cycle. This means it's your responsibility to call `scope.$apply()`.
|
||||
@@ -779,6 +784,85 @@ describe('serviceUnderTest', function() {
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
# Migrating from earlier AngularJS releases
|
||||
|
||||
In earlier releases of AngularJS, `$location` used `hashPath` or `hashSearch` to process path and
|
||||
search methods. With this release, the `$location` service processes path and search methods and
|
||||
then uses the information it obtains to compose hashbang URLs (such as
|
||||
`http://server.com/#!/path?search=a`), when necessary.
|
||||
|
||||
## Changes to your code
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr class="head">
|
||||
<th>Navigation inside the app</th>
|
||||
<th>Change to</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
|
||||
/>$location.updateHash(value)</td>
|
||||
<td>$location.path(path).search(search)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.hashPath = path</td>
|
||||
<td>$location.path(path)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.hashSearch = search</td>
|
||||
<td>$location.search(search)</td>
|
||||
</tr>
|
||||
|
||||
<tr class="head">
|
||||
<th>Navigation outside the app</td>
|
||||
<th>Use lower level API</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.href = value<br />$location.update(value)</td>
|
||||
<td>$window.location.href = value</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location[protocol | host | port | path | search]</td>
|
||||
<td>$window.location[protocol | host | port | path | search]</td>
|
||||
</tr>
|
||||
|
||||
<tr class="head">
|
||||
<th>Read access</td>
|
||||
<th>Change to</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.hashPath</td>
|
||||
<td>$location.path()</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.hashSearch</td>
|
||||
<td>$location.search()</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
|
||||
/>$location.hash</td>
|
||||
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
|
||||
/>$location.path() + $location.search()</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.path<br />$location.search</td>
|
||||
<td>$window.location.path<br />$window.location.search</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Two-way binding to $location
|
||||
|
||||
Because `$location` uses getters/setters, you can use `ng-model-options="{ getterSetter: true }"`
|
||||
@@ -800,6 +884,6 @@ angular.module('locationExample', [])
|
||||
</file>
|
||||
</example>
|
||||
|
||||
## Related API
|
||||
# Related API
|
||||
|
||||
* {@link ng.$location `$location` API}
|
||||
|
||||
@@ -327,7 +327,7 @@ The default CSS for `ngHide`, the inverse method to `ngShow`, makes ngAria redun
|
||||
|
||||
<h2><span id="ngclick">ngClick</span> and <span id="ngdblclick">ngDblclick</span></h2>
|
||||
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex="0"` to any element not in
|
||||
the list of built in aria nodes:
|
||||
a node blacklist:
|
||||
|
||||
* Button
|
||||
* Anchor
|
||||
@@ -337,8 +337,7 @@ the list of built in aria nodes:
|
||||
* Details/Summary
|
||||
|
||||
To fix widespread accessibility problems with `ng-click` on `div` elements, ngAria will
|
||||
dynamically bind a keypress event by default as long as the element isn't in a node from the list of
|
||||
built in aria nodes.
|
||||
dynamically bind a keypress event by default as long as the element isn't in the node blacklist.
|
||||
You can turn this functionality on or off with the `bindKeypress` configuration option.
|
||||
|
||||
ngAria will also add the `button` role to communicate to users of assistive technologies. This can
|
||||
|
||||
@@ -222,26 +222,23 @@ triggered:
|
||||
|
||||
| Directive | Supported Animations |
|
||||
|-------------------------------------------------------------------------------|---------------------------------------------------------------------------|
|
||||
| {@link ng.directive:form#animations form / ngForm} | add and remove ({@link ng.directive:form#css-classes various classes}) |
|
||||
| {@link ngAnimate.directive:ngAnimateSwap#animations ngAnimateSwap} | enter and leave |
|
||||
| {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave, and move |
|
||||
| {@link ng.directive:ngIf#animations ngIf} | enter and leave |
|
||||
| {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
|
||||
| {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
|
||||
| {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
|
||||
| {@link module:ngMessages#animations ngMessage / ngMessageExp} | enter and leave |
|
||||
| {@link ng.directive:ngClass#animations ngClass / {{class}​}} | add and remove |
|
||||
| {@link ng.directive:ngClassEven#animations ngClassEven} | add and remove |
|
||||
| {@link ng.directive:ngClassOdd#animations ngClassOdd} | add and remove |
|
||||
| {@link ng.directive:ngHide#animations ngHide} | add and remove (the `ng-hide` class) |
|
||||
| {@link ng.directive:ngIf#animations ngIf} | enter and leave |
|
||||
| {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
|
||||
| {@link module:ngMessages#animations ngMessage / ngMessageExp} | enter and leave |
|
||||
| {@link module:ngMessages#animations ngMessages} | add and remove (the `ng-active`/`ng-inactive` classes) |
|
||||
| {@link ng.directive:ngModel#animations ngModel} | add and remove ({@link ng.directive:ngModel#css-classes various classes}) |
|
||||
| {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave, and move |
|
||||
| {@link ng.directive:ngShow#animations ngShow} | add and remove (the `ng-hide` class) |
|
||||
| {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
|
||||
| {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
|
||||
|
||||
(More information can be found by visiting the documentation associated with each directive.)
|
||||
| {@link ng.directive:ngModel#animations ngModel} | add and remove ({@link ng.directive:ngModel#css-classes various classes}) |
|
||||
| {@link ng.directive:form#animations form / ngForm} | add and remove ({@link ng.directive:form#css-classes various classes}) |
|
||||
| {@link module:ngMessages#animations ngMessages} | add and remove (the `ng-active`/`ng-inactive` classes) |
|
||||
|
||||
For a full breakdown of the steps involved during each animation event, refer to the
|
||||
{@link ng.$animate `$animate` API docs}.
|
||||
{@link ng.$animate API docs}.
|
||||
|
||||
## How do I use animations in my own directives?
|
||||
|
||||
@@ -471,7 +468,7 @@ You can also use one of the other
|
||||
strategies to disable animations}.
|
||||
|
||||
|
||||
## Enable animations outside of the application DOM tree: {@link ng.$animate#pin $animate.pin()}
|
||||
### Enable animations for elements outside of the AngularJS application DOM tree: {@link ng.$animate#pin $animate.pin()}
|
||||
|
||||
Before animating, `ngAnimate` checks if the animated element is inside the application DOM tree. If
|
||||
not, no animation is run. Usually, this is not a problem since most apps use the `html` or `body`
|
||||
|
||||
@@ -14,7 +14,6 @@ This guide describes the Component Router for AngularJS.
|
||||
|
||||
<div class="alert alert-info">
|
||||
If you are looking for information about the default router for AngularJS have a look at the {@link ngRoute} module.
|
||||
|
||||
If you are looking for information about the Component Router for the new Angular then
|
||||
check out the [Angular Router Guide](https://angular.io/docs/ts/latest/guide/router.html).
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@ When not to use Components:
|
||||
|
||||
## Creating and configuring a Component
|
||||
|
||||
Components can be registered using the {@link ng.$compileProvider#component `.component()`} method of an AngularJS module (returned by {@link module `angular.module()`}). The method takes two arguments:
|
||||
Components can be registered using the `.component()` method of an AngularJS module (returned by {@link module `angular.module()`}). The method takes two arguments:
|
||||
|
||||
* The name of the Component (as string).
|
||||
* The Component config object. (Note that, unlike the `.directive()` method, this method does **not** take a factory function.)
|
||||
@@ -143,7 +143,7 @@ components should follow a few simple conventions:
|
||||
}
|
||||
```
|
||||
|
||||
- **Components have a well-defined lifecycle:**
|
||||
- **Components have a well-defined lifecycle**
|
||||
Each component can implement "lifecycle hooks". These are methods that will be called at certain points in the life
|
||||
of the component. The following hook methods can be implemented:
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ Right now, the `InvoiceController` contains all logic of our example. When the a
|
||||
is a good practice to move view-independent logic from the controller into a
|
||||
<a name="service">{@link services service}</a>, so it can be reused by other parts
|
||||
of the application as well. Later on, we could also change that service to load the exchange rates
|
||||
from the web, e.g. by calling the [exchangeratesapi.io](https://exchangeratesapi.io) exchange rate API, without changing the controller.
|
||||
from the web, e.g. by calling the [Fixer.io](http://fixer.io) exchange rate API, without changing the controller.
|
||||
|
||||
Let's refactor our example and move the currency conversion into a service in another file:
|
||||
|
||||
@@ -300,7 +300,7 @@ to something shorter like `a`.
|
||||
|
||||
## Accessing the backend
|
||||
|
||||
Let's finish our example by fetching the exchange rates from the [exchangeratesapi.io](https://exchangeratesapi.io) exchange rate API.
|
||||
Let's finish our example by fetching the exchange rates from the [Fixer.io](http://fixer.io) exchange rate API.
|
||||
The following example shows how this is done with AngularJS:
|
||||
|
||||
<example name="guide-concepts-3" ng-app-included="true">
|
||||
@@ -331,7 +331,7 @@ The following example shows how this is done with AngularJS:
|
||||
};
|
||||
|
||||
var refresh = function() {
|
||||
var url = 'https://api.exchangeratesapi.io/latest?base=USD&symbols=' + currencies.join(",");
|
||||
var url = 'https://api.fixer.io/latest?base=USD&symbols=' + currencies.join(",");
|
||||
return $http.get(url).then(function(response) {
|
||||
usdToForeignRates = response.data.rates;
|
||||
usdToForeignRates['USD'] = 1;
|
||||
|
||||
@@ -116,6 +116,7 @@ objects (or primitives) assigned to the scope become model properties. Any metho
|
||||
the scope are available in the template/view, and can be invoked via AngularJS expressions
|
||||
and `ng` event handler directives (e.g. {@link ng.directive:ngClick ngClick}).
|
||||
|
||||
|
||||
## Simple Spicy Controller Example
|
||||
|
||||
To illustrate further how Controller components work in AngularJS, let's create a little app with the
|
||||
@@ -156,7 +157,7 @@ string "very". Depending on which button is clicked, the `spice` model is set to
|
||||
|
||||
Things to notice in the example above:
|
||||
|
||||
- The `ng-controller` directive is used to (implicitly) create a scope for our template, and the
|
||||
- The `ngController` directive is used to (implicitly) create a scope for our template, and the
|
||||
scope is augmented (managed) by the `SpicyController` Controller.
|
||||
- `SpicyController` is just a plain JavaScript function. As an (optional) naming convention the name
|
||||
starts with capital letter and ends with "Controller".
|
||||
|
||||
@@ -279,20 +279,15 @@ construction and lookup of dependencies.
|
||||
|
||||
Here is an example of using the injector service:
|
||||
|
||||
First create an AngularJS module that will hold the service definition. (The empty array passed as
|
||||
the second parameter means that this module does not depend on any other modules.)
|
||||
|
||||
```js
|
||||
// Create a module to hold the service definition
|
||||
// Provide the wiring information in a module
|
||||
var myModule = angular.module('myModule', []);
|
||||
```
|
||||
|
||||
Teach the injector how to build a `greeter` service, which is just an object that contains a `greet`
|
||||
method. Notice that `greeter` is dependent on the `$window` service, which will be provided
|
||||
(injected into `greeter`) by the injector.
|
||||
Teach the injector how to build a `greeter` service. Notice that `greeter` is dependent on the
|
||||
`$window` service. The `greeter` service is an object that contains a `greet` method.
|
||||
|
||||
```js
|
||||
// Define the `greeter` service
|
||||
myModule.factory('greeter', function($window) {
|
||||
return {
|
||||
greet: function(text) {
|
||||
|
||||
@@ -125,8 +125,8 @@ and comments (M).
|
||||
|
||||
The built-in AngularJS directives show in their documentation page which type of matching they support.
|
||||
|
||||
The following demonstrates the various ways a directive (`myDir` in this case) that matches all
|
||||
4 types can be referenced from within a template.
|
||||
The following demonstrates the various ways a directive that matches all 4 types
|
||||
(`myDir` in this case) can be referenced from within a template.
|
||||
|
||||
```html
|
||||
<my-dir></my-dir>
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
|
||||
# E2E Testing
|
||||
|
||||
<div class="alert alert-danger">
|
||||
**Note:** In the past, end-to-end testing could be done with a deprecated tool called
|
||||
[AngularJS Scenario Runner](http://code.angularjs.org/1.2.16/docs/guide/e2e-testing). That tool
|
||||
is now in maintenance mode, and will be removed in version 1.7.0.
|
||||
</div>
|
||||
|
||||
As applications grow in size and complexity, it becomes unrealistic to rely on manual testing to
|
||||
verify the correctness of new features, catch bugs and notice regressions. Unit tests
|
||||
are the first line of defense for catching bugs, but sometimes issues come up with integration
|
||||
|
||||
@@ -37,8 +37,8 @@ AngularJS expressions are like JavaScript expressions with the following differe
|
||||
even inside `ng-init` directive.
|
||||
|
||||
* **No RegExp Creation With Literal Notation:** You cannot create regular expressions
|
||||
in an AngularJS expression. An exception to this rule is {@link ngPattern `ng-pattern`} which accepts valid
|
||||
RegExp.
|
||||
in an AngularJS expression. An exception to this rule is {@link ngPattern `ng-pattern`} which
|
||||
accepts valid RegExp.
|
||||
|
||||
* **No Object Creation With New Operator:** You cannot use `new` operator in an AngularJS expression.
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@ attributes and tags. Read this document if you are planning on deploying your An
|
||||
on IE.
|
||||
|
||||
The project currently supports and will attempt to fix bugs for IE9 and above. The continuous
|
||||
integration server runs all unit tests against IE9, IE10, and IE11. See
|
||||
[CircleCI](https://circleci.com/gh/angular/workflows/angular.js/tree/master).
|
||||
integration server runs all the tests against IE9, IE10, and IE11. See
|
||||
[Travis CI](https://travis-ci.org/angular/angular.js) and
|
||||
[ci.angularjs.org](https://ci.angularjs.org).
|
||||
|
||||
We do not run tests on IE8 and below. A subset of the AngularJS functionality may work on these
|
||||
browsers, but it is up to you to test and decide whether it works for your particular app.
|
||||
|
||||
@@ -43,7 +43,7 @@ In AngularJS applications, you move the job of filling page templates with data
|
||||
|
||||
* **Animation:** {@link guide/animations Core concepts}, {@link ngAnimate ngAnimate API}
|
||||
* **Security:** {@link guide/security Security Docs}, {@link ng.$sce Strict Contextual Escaping}, {@link ng.directive:ngCsp Content Security Policy}, {@link ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
|
||||
* **Internationalization and Localization:** {@link guide/i18n AngularJS Guide to i18n and l10n}, {@link ng.filter:date date filter}, {@link ng.filter:currency currency filter}, [Creating multilingual support](https://blog.novanet.no/creating-multilingual-support-using-angularjs/)
|
||||
* **Internationalization and Localization:** {@link guide/i18n AngularJS Guide to i18n and l10n}, {@link ng.filter:date date filter}, {@link ng.filter:currency currency filter}, [Creating multilingual support](http://www.novanet.no/blog/hallstein-brotan/dates/2013/10/creating-multilingual-support-using-angularjs/)
|
||||
* **Touch events:** {@link ngTouch Touch events}
|
||||
* **Accessibility:** {@link guide/accessibility ngAria}
|
||||
|
||||
@@ -75,7 +75,7 @@ Official announcements, news and releases are posted to our blog, G+ and Twitter
|
||||
|
||||
* [AngularJS Blog](http://blog.angularjs.org/)
|
||||
* [Google+](https://plus.google.com/u/0/+AngularJS)
|
||||
* [Twitter](https://twitter.com/angular)
|
||||
* [Twitter](https://twitter.com/angularjs)
|
||||
* [AngularJS on YouTube](http://youtube.com/angularjs)
|
||||
|
||||
## Contributing to AngularJS
|
||||
|
||||
@@ -15,835 +15,6 @@ which drives many of these changes.
|
||||
* Several new features, especially animations, would not be possible without a few changes.
|
||||
* Finally, some outstanding bugs were best fixed by changing an existing API.
|
||||
|
||||
## Migrating from 1.7 to 1.8
|
||||
|
||||
Generally updating to 1.8.0 from 1.7.x should be a straightforward process and is highly recommended.
|
||||
AngularJS 1.8 is a breaking change release from 1.7 to mitigate a security issue.
|
||||
|
||||
JqLite no longer turns XHTML-like strings like `<div /><span />` to sibling elements when not in XHTML
|
||||
mode: `<div></div><span></span>`.
|
||||
Instead it will leave the elements alone. In non-XHTML mode the browser will convert these to nested
|
||||
elements: `<div><span></span></div>`.
|
||||
|
||||
This is a security fix to avoid an XSS vulnerability if a new jqLite element is created from a
|
||||
user-controlled HTML string. If you must have this functionality and understand the risk involved
|
||||
then it is posible to restore the original behavior by calling
|
||||
|
||||
```js
|
||||
angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement();
|
||||
```
|
||||
|
||||
But you should adjust your code for this change and remove your use of this function as soon as
|
||||
possible.
|
||||
|
||||
Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the
|
||||
[jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details about the workarounds.
|
||||
|
||||
|
||||
## Migrating from 1.6 to 1.7
|
||||
|
||||
AngularJS 1.7 contains bug fixes and features to AngularJS core and its external modules, some of
|
||||
which contain breaking changes. However, most of these address internal behavior and not APIs, and
|
||||
should not affect many applications.
|
||||
Additionally, we have removed some long-deprecated modules and APIs.
|
||||
|
||||
The most notable changes are:
|
||||
|
||||
- `$resource` has now support for request and requestError interceptors
|
||||
|
||||
- Several deprecated features have been removed:
|
||||
- the `$controllerProvider.allowGlobals()` flag
|
||||
- the `$compileProvider.preAssignBindingsEnabled()` flag
|
||||
- the `angular.lowercase` and `angular.uppercase` methods
|
||||
- the `$cookieStore` service from the `ngCookies` module
|
||||
- the `ngClick` override directive and corresponding services from the `ngTouch` module
|
||||
- the complete `ngScenario` module
|
||||
|
||||
Please note that feature development (without breaking changes) has happened in parallel on the
|
||||
1.6.x branch, so 1.7 doesn't contain many new features, but you may still benefit from those
|
||||
features that were added (with possible BCs), bugfixes, and a few smaller performance improvements.
|
||||
|
||||
|
||||
<br />
|
||||
Below is the full list of breaking changes:
|
||||
|
||||
|
||||
<br />
|
||||
<a name="migrate1.6to1.7-ng-directives"></a>
|
||||
### Core: _Directives_
|
||||
|
||||
|
||||
#### **form**
|
||||
|
||||
**Due to [223de5](https://github.com/angular/angular.js/commit/223de59e988dc0cc8b4ec3a045b7c0735eba1c77)**,
|
||||
forms will now set `$submitted` on child forms when they are submitted.
|
||||
For example:
|
||||
```
|
||||
<form name="parentform" ng-submit="$ctrl.submit()">
|
||||
<ng-form name="childform">
|
||||
<input type="text" name="input" ng-model="my.model" />
|
||||
</ng-form>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
```
|
||||
|
||||
Submitting this form will set `$submitted` on "parentform" and "childform".
|
||||
Previously, it was only set on "parentform".
|
||||
|
||||
This change was introduced because mixing `form` and `ngForm` does not create
|
||||
logically separate forms, but rather something like input groups.
|
||||
Therefore, child forms should inherit the submission state from their parent form.
|
||||
|
||||
|
||||
#### **input[radio]** and **input[checkbox]**
|
||||
|
||||
**Due to [656c8f](https://github.com/angular/angular.js/commit/656c8fa8f23b1277cc5c214c4d0237f3393afa1e)**,
|
||||
`input[radio]` and `input[checkbox]` now listen to the "change" event instead of the "click" event.
|
||||
Most apps should not be affected, as "change" is automatically fired by browsers after "click"
|
||||
happens.
|
||||
|
||||
Two scenarios might need migration:
|
||||
|
||||
- Custom click events:
|
||||
|
||||
Before this change, custom click event listeners on radio / checkbox would be called after the
|
||||
input element and `ngModel` had been updated, unless they were specifically registered before
|
||||
the built-in click handlers.
|
||||
After this change, they are called before the input is updated, and can call
|
||||
`event.preventDefault()` to prevent the input from updating.
|
||||
|
||||
If an app uses a click event listener that expects `ngModel` to be updated when it is called, it now
|
||||
needs to register a change event listener instead.
|
||||
|
||||
- Triggering click events:
|
||||
|
||||
Conventional trigger functions:
|
||||
|
||||
The change event might not be fired when the input element is not attached to the document. This
|
||||
can happen in **tests** that compile input elements and trigger click events on them. Depending on
|
||||
the browser (Chrome and Safari) and the trigger method, the change event will not be fired when the
|
||||
input isn't attached to the document.
|
||||
|
||||
Before:
|
||||
|
||||
```js
|
||||
it('should update the model', inject(function($compile, $rootScope) {
|
||||
var inputElm = $compile('<input type="checkbox" ng-model="checkbox" />')($rootScope);
|
||||
|
||||
inputElm[0].click(); // Or different trigger mechanisms, such as jQuery.trigger()
|
||||
expect($rootScope.checkbox).toBe(true);
|
||||
});
|
||||
```
|
||||
|
||||
With this patch, `$rootScope.checkbox` might not be true, because the click event hasn't triggered
|
||||
the change event. To make the test, work append `inputElm` to the app's `$rootElement`, and the
|
||||
`$rootElement` to the `$document`.
|
||||
|
||||
After:
|
||||
|
||||
```js
|
||||
it('should update the model', inject(function($compile, $rootScope, $rootElement, $document) {
|
||||
var inputElm = $compile('<input type="checkbox" ng-model="checkbox" />')($rootScope);
|
||||
|
||||
$rootElement.append(inputElm);
|
||||
$document.append($rootElement);
|
||||
|
||||
inputElm[0].click(); // Or different trigger mechanisms, such as jQuery.trigger()
|
||||
expect($rootScope.checkbox).toBe(true);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### **input\[number\]**
|
||||
|
||||
**Due to [aa3f95](https://github.com/angular/angular.js/commit/aa3f951330ec7b10b43ea884d9b5754e296770ec)**,
|
||||
`input[type=number]` with `ngModel` now validates the input for the `max`/`min` restriction against
|
||||
the `ngModelController.$viewValue` instead of against the `ngModelController.$modelValue`.
|
||||
|
||||
This affects apps that use `$parsers` or `$formatters` to transform the input / model value.
|
||||
|
||||
If you rely on the `$modelValue` validation, you can overwrite the `min`/`max` validator from a
|
||||
custom directive, as seen in the following example directive definition object:
|
||||
|
||||
```js
|
||||
{
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attrs, ctrl) {
|
||||
var maxValidator = ctrl.$validators.max;
|
||||
|
||||
ctrl.$validators.max = function(modelValue, viewValue) {
|
||||
return maxValidator(modelValue, modelValue);
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### **ngModel, input**
|
||||
|
||||
**Due to [74b04c](https://github.com/angular/angular.js/commit/74b04c9403af4fc7df5b6420f22c9f45a3e84140)**,
|
||||
*Custom* parsers that fail to parse on input types "email", "url", "number", "date", "month",
|
||||
"time", "datetime-local", "week", no longer set `ngModelController.$error[inputType]`, and
|
||||
the `ng-invalid-[inputType]` class. Also, custom parsers on input type "range" no longer set `ngModelController.$error.number` and the `ng-invalid-number` class.
|
||||
|
||||
Instead, any custom parsers on these inputs set `ngModelController.$error.parse` and
|
||||
`ng-invalid-parse`. This change was made to make distinguishing errors from built-in parsers
|
||||
and custom parsers easier.
|
||||
|
||||
|
||||
#### **ngModelOptions**
|
||||
|
||||
**Due to [55ba44](https://github.com/angular/angular.js/commit/55ba44913e02650b56410aa9ab5eeea5d3492b68)**,
|
||||
the 'default' key in 'debounce' now only debounces the default event, i.e. the event that is added
|
||||
as an update trigger by the different input directives automatically.
|
||||
|
||||
Previously, it also applied to other update triggers defined in 'updateOn' that
|
||||
did not have a corresponding key in the 'debounce'.
|
||||
|
||||
This behavior is now supported via a special wildcard / catch-all key: '*'.
|
||||
|
||||
See the following example:
|
||||
|
||||
Pre-1.7:
|
||||
'mouseup' is also debounced by 500 milliseconds because 'default' is applied:
|
||||
```html
|
||||
ng-model-options="{
|
||||
updateOn: 'default blur mouseup',
|
||||
debounce: { 'default': 500, 'blur': 0 }
|
||||
}"
|
||||
```
|
||||
|
||||
1.7:
|
||||
The pre-1.7 behavior can be re-created by setting '*' as a catch-all debounce value:
|
||||
```html
|
||||
ng-model-options="{
|
||||
updateOn: 'default blur mouseup',
|
||||
debounce: { '*': 500, 'blur': 0 }
|
||||
}"
|
||||
```
|
||||
|
||||
In contrast, when only 'default' is used, 'blur' and 'mouseup' are not debounced:
|
||||
```html
|
||||
ng-model-options="{
|
||||
updateOn: 'default blur mouseup',
|
||||
debounce: { 'default': 500 }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### **ngStyle**
|
||||
|
||||
**Due to [15bbd3](https://github.com/angular/angular.js/commit/15bbd3e18cd89b91f7206a06c73d40e54a8a48a0)**,
|
||||
the use of deep-watching in `ngStyle` has changed. Previously, `ngStyle` would trigger styles to be
|
||||
re-applied whenever nested state changed. Now, only changes to direct properties of the watched
|
||||
object will trigger changes.
|
||||
|
||||
|
||||
<a name="migrate1.6to1.7-ng-services"></a>
|
||||
### Core: _Services_
|
||||
|
||||
|
||||
#### **$compile**
|
||||
|
||||
**Due to [38f8c9](https://github.com/angular/angular.js/commit/38f8c97af74649ce224b6dd45f433cc665acfbfb)**,
|
||||
directive bindings are no longer available in the constructor.
|
||||
|
||||
Previously, the `$compileProvider.preAssignBindingsEnabled` flag was supported.
|
||||
The flag controlled whether bindings were available inside the controller
|
||||
constructor or only in the `$onInit` hook. The bindings are now no longer
|
||||
available in the constructor.
|
||||
|
||||
To migrate your code:
|
||||
|
||||
1. If you haven't invoked `$compileProvider.preAssignBindingsEnabled()` you
|
||||
don't have to do anything to migrate.
|
||||
|
||||
2. If you specified `$compileProvider.preAssignBindingsEnabled(false)`, you
|
||||
can remove that statement - since AngularJS 1.6.0 this is the default so your
|
||||
app should still work even in AngularJS 1.6 after such removal. Afterwards,
|
||||
migrating to AngularJS 1.7.0 shouldn't require any further action.
|
||||
|
||||
3. If you specified `$compileProvider.preAssignBindingsEnabled(true)` you need
|
||||
to first migrate your code so that the flag can be flipped to `false`. The
|
||||
instructions on how to do that are available in the "Migrating from 1.5 to 1.6"
|
||||
guide: https://docs.angularjs.org/guide/migration#migrating-from-1-5-to-1-6
|
||||
Afterwards, remove the `$compileProvider.preAssignBindingsEnabled(true)`
|
||||
statement.
|
||||
|
||||
<hr />
|
||||
|
||||
**Due to [6ccbfa](https://github.com/angular/angular.js/commit/6ccbfa65d60a3dc396d0cf6da21b993ad74653fd)**,
|
||||
the `xlink:href` security context for SVG's `a` and `image` elements has been lowered.
|
||||
|
||||
In the unlikely case that an app relied on `RESOURCE_URL` trusted list for the
|
||||
purpose of binding to the `xlink:href` property of SVG's `<a>` or `<image>`
|
||||
elements and if the values do not pass the regular URL sanitization, they will
|
||||
break.
|
||||
|
||||
To fix this you need to ensure that the values used for binding to the affected
|
||||
`xlink:href` contexts are considered safe URLs, e.g. by trusting them in
|
||||
`$compileProvider`'s `aHrefSanitizationWhitelist` (called `aHrefSanitizationTrustedUrlList` form
|
||||
1.8.1 onwards) (for `<a>` elements) or `imgSrcSanitizationWhitelist` (called
|
||||
`imgSrcSanitizationTrustedUrlList` from 1.8.1 onwards) (for `<image>` elements).
|
||||
|
||||
<hr />
|
||||
|
||||
**Due to [fd4f01](https://github.com/angular/angular.js/commit/fd4f0111188b62773b99ab6eab38b4d2b5d8d727)**,
|
||||
deep-watching is no longer used in literal one-way bindings.
|
||||
|
||||
Previously, when a literal value was passed into a directive/component via
|
||||
one-way binding it would be watched with a deep watcher.
|
||||
|
||||
For example, for `<my-component input="[a]">`, a new instance of the array
|
||||
would be passed into the directive/component (and trigger `$onChanges`) not
|
||||
only if `a` changed but also if any sub property of `a` changed such as
|
||||
`a.b` or `a.b.c.d.e` etc.
|
||||
|
||||
This also means a new but equal value for `a` would NOT trigger such a
|
||||
change.
|
||||
|
||||
Now, literal values use an input-based watch similar to other directive/component
|
||||
one-way bindings. In this context inputs are the non-constant parts of the
|
||||
literal. In the example above, the input would be `a`. Changes are only
|
||||
triggered, when the inputs to the literal change.
|
||||
|
||||
<hr />
|
||||
|
||||
**Due to [1cf728](https://github.com/angular/angular.js/commit/1cf728e209a9e0016068fac2769827e8f747760e)**,
|
||||
`base[href]` was added to the list of `RESOURCE_URL` context attributes.
|
||||
|
||||
Previously, `<base href="{{ $ctrl.baseUrl }}" />` would not require `baseUrl` to
|
||||
be trusted as a `RESOURCE_URL`. Now, `baseUrl` will be sent to `$sce`'s
|
||||
`RESOURCE_URL` checks. By default, it will break unless `baseUrl` is of the same
|
||||
origin as the application document.
|
||||
|
||||
Refer to the
|
||||
[`$sce` API docs](https://code.angularjs.org/snapshot/docs/api/ng/service/$sce)
|
||||
for more info on how to trust a value in a `RESOURCE_URL` context.
|
||||
|
||||
Also, concatenation in trusted contexts is not allowed, which means that the
|
||||
following won't work: `<base href="/something/{{ $ctrl.partialPath }}" />`.
|
||||
|
||||
Either construct complex values in a controller (recommended):
|
||||
|
||||
```js
|
||||
this.baseUrl = '/something/' + this.partialPath;
|
||||
```
|
||||
```html
|
||||
<base href="{{ $ctrl.baseUrl }}" />
|
||||
```
|
||||
|
||||
Or use string concatenation in the interpolation expression (not recommended
|
||||
except for the simplest of cases):
|
||||
|
||||
```html
|
||||
<base href="{{ '/something/' + $ctrl.partialPath }}" />
|
||||
```
|
||||
|
||||
|
||||
#### **$rootScope**
|
||||
|
||||
**Due to ([c2b8fa](https://github.com/angular/angular.js/commit/c2b8fab0a480204374d561d6b9b3d47347ac5570))**,
|
||||
the arguments of `$watchGroup` callbacks have changed.
|
||||
|
||||
Previously, when using `$watchGroup`, the entries in `newValues` and
|
||||
`oldValues` represented the *most recent change of each entry*.
|
||||
|
||||
Now, the entries in `oldValues` will always equal the `newValues` of the previous
|
||||
call of the listener. This means comparing the entries in `newValues` and
|
||||
`oldValues` can be used to determine which individual expressions changed.
|
||||
|
||||
For example `$scope.$watchGroup(['a', 'b'], fn)` would previously:
|
||||
|
||||
| Action | newValue | oldValue |
|
||||
|----------|------------|------------|
|
||||
| (init) | [undefined, undefined] | [undefined, undefined] |
|
||||
| `a=1` | [1, undefined] | [undefined, undefined] |
|
||||
| `a=2` | [2, undefined] | [1, undefined] |
|
||||
| `b=3` | [2, 3] | [1, undefined] |
|
||||
|
||||
|
||||
Now the `oldValue` will always equal the previous `newValue`:
|
||||
|
||||
| Action | newValue | oldValue |
|
||||
|----------|------------|------------|
|
||||
| (init) | [undefined, undefined] | [undefined, undefined] |
|
||||
| `a=1` | [1, undefined] | [undefined, undefined] |
|
||||
| `a=2` | [2, undefined] | [1, undefined] |
|
||||
| `b=3` | [2, 3] | [2, undefined] |
|
||||
|
||||
Note the last call now shows `a === 2` in the `oldValues` array.
|
||||
|
||||
This also makes the `oldValue` of one-time watchers more clear. Previously,
|
||||
the `oldValue` of a one-time watcher would remain `undefined` forever. For
|
||||
example `$scope.$watchGroup(['a', '::b'], fn)` would previously:
|
||||
|
||||
| Action | newValue | oldValue |
|
||||
|----------|------------|------------|
|
||||
| (init) | [undefined, undefined] | [undefined, undefined] |
|
||||
| `a=1` | [1, undefined] | [undefined, undefined] |
|
||||
| `b=2` | [1, 2] | [undefined, undefined] |
|
||||
| `a=b=3` | [3, 2] | [1, undefined] |
|
||||
|
||||
Where now the `oldValue` will always equal the previous `newValue`:
|
||||
|
||||
| Action | newValue | oldValue |
|
||||
|----------|------------|------------|
|
||||
| (init) | [undefined, undefined] | [undefined, undefined] |
|
||||
| `a=1` | [1, undefined] | [undefined, undefined] |
|
||||
| `b=2` | [1, 2] | [1, undefined] |
|
||||
| `a=b=3` | [3, 2] | [1, 2] |
|
||||
|
||||
|
||||
#### **$interval**
|
||||
|
||||
**Due to [a8bef9](https://github.com/angular/angular.js/commit/a8bef95127775d83d80daa4617c33227c4b443d4)**,
|
||||
`$interval.cancel()` will throw an error if called with a promise that was not generated by
|
||||
`$interval()`. Previously, it would silently do nothing.
|
||||
|
||||
Before:
|
||||
```js
|
||||
var promise = $interval(doSomething, 1000, 5).then(doSomethingElse);
|
||||
$interval.cancel(promise); // No error; interval NOT canceled.
|
||||
```
|
||||
|
||||
After:
|
||||
```js
|
||||
var promise = $interval(doSomething, 1000, 5).then(doSomethingElse);
|
||||
$interval.cancel(promise); // Throws error.
|
||||
```
|
||||
|
||||
Correct usage:
|
||||
```js
|
||||
var promise = $interval(doSomething, 1000, 5);
|
||||
var newPromise = promise.then(doSomethingElse);
|
||||
$interval.cancel(promise); // Interval canceled.
|
||||
```
|
||||
|
||||
|
||||
#### **$timeout**
|
||||
|
||||
**Due to [336525](https://github.com/angular/angular.js/commit/3365256502344970f86355d3ace1cb4251ae9828)**,
|
||||
`$timeout.cancel()` will throw an error if called with a promise that was not generated by
|
||||
`$timeout()`. Previously, it would silently do nothing.
|
||||
|
||||
Before:
|
||||
```js
|
||||
var promise = $timeout(doSomething, 1000).then(doSomethingElse);
|
||||
$timeout.cancel(promise); // No error; timeout NOT canceled.
|
||||
```
|
||||
|
||||
After:
|
||||
```js
|
||||
var promise = $timeout(doSomething, 1000).then(doSomethingElse);
|
||||
$timeout.cancel(promise); // Throws error.
|
||||
```
|
||||
|
||||
Correct usage:
|
||||
```js
|
||||
var promise = $timeout(doSomething, 1000);
|
||||
var newPromise = promise.then(doSomethingElse);
|
||||
$timeout.cancel(promise); // Timeout canceled.
|
||||
```
|
||||
|
||||
|
||||
#### **$cookies**
|
||||
|
||||
**Due to [73c646](https://github.com/angular/angular.js/commit/73c6467f1468353215dc689c019ed83aa4993c77)**,
|
||||
the `$cookieStore`service has been removed. Migrate to the `$cookies` service. Note that
|
||||
for object values you need to use the `putObject` & `getObject` methods, as
|
||||
`get`/`put` will not correctly save/retrieve the object values.
|
||||
|
||||
Before:
|
||||
```js
|
||||
$cookieStore.put('name', {key: 'value'});
|
||||
$cookieStore.get('name'); // {key: 'value'}
|
||||
$cookieStore.remove('name');
|
||||
```
|
||||
|
||||
|
||||
#### **$templateRequest**
|
||||
|
||||
**Due to [c617d6](https://github.com/angular/angular.js/commit/c617d6dceee5b000bfceda44ced22fc16b48b18b)**,
|
||||
the `tpload` error namespace has changed. Previously, the `tpload` error was namespaced to
|
||||
`$compile`. If you have code that matches errors of the form `[$compile:tpload]` it will no longer
|
||||
run. You should change the code to match `[$templateRequest:tpload]`.
|
||||
|
||||
<hr />
|
||||
|
||||
**Due to ([fb0099](https://github.com/angular/angular.js/commit/fb00991460cf69ae8bc7f1f826363d09c73c0d5e)**,
|
||||
`$templateRequest()` now returns the result of `$templateCache.put()` when making a server request
|
||||
for a template. Previously, it would return the content of the response directly.
|
||||
|
||||
This means that if you are decorating `$templateCache.put()` to manipulate the template, you will
|
||||
now get this manipulated result also on the first `$templateRequest()` call rather than only on
|
||||
subsequent calls (when the template is retrieved from the cache).
|
||||
|
||||
In practice, this should not affect any apps, as it is unlikely that they rely on the template being
|
||||
different in the first and subsequent calls.
|
||||
|
||||
|
||||
#### **$animate**
|
||||
|
||||
**Due to [16b82c](https://github.com/angular/angular.js/commit/16b82c6afe0ab916fef1d6ca78053b00bf5ada83)**,
|
||||
`$animate.cancel(runner)` now rejects the underlying promise and calls the `catch()` handler on the
|
||||
runner returned by `$animate` functions (`enter`, `leave`, `move`, `addClass`, `removeClass`,
|
||||
`setClass`, `animate`).
|
||||
Previously, it would resolve the promise as if the animation had ended successfully.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
var runner = $animate.addClass('red');
|
||||
runner.then(function() { console.log('success')});
|
||||
runner.catch(function() { console.log('cancelled')});
|
||||
|
||||
runner.cancel();
|
||||
```
|
||||
|
||||
Pre-1.7.0, this logs 'success', 1.7.0 and later it logs 'cancelled'.
|
||||
To migrate, add a `catch()` handler to your animation runners.
|
||||
|
||||
|
||||
#### **$controller**
|
||||
|
||||
**Due to [e269c1](https://github.com/angular/angular.js/commit/e269c14425a3209040f65c022658770e00a36f16)**,
|
||||
the option to instantiate controllers from constructors on the global `window` object
|
||||
has been removed. Likewise, the deprecated `$controllerProvider.allowGlobals()`
|
||||
method that could enable this behavior, has been removed.
|
||||
|
||||
This behavior had been deprecated since AngularJS v1.3.0, because polluting the global scope
|
||||
is considered bad practice. To migrate, remove the call to `$controllerProvider.allowGlobals()` in
|
||||
the config, and register your controller via the Module API or the `$controllerProvider`, e.g.:
|
||||
|
||||
```js
|
||||
angular.module('myModule', []).controller('myController', function() {...});
|
||||
|
||||
// or
|
||||
|
||||
angular.module('myModule', []).config(function($controllerProvider) {
|
||||
$controllerProvider.register('myController', function() {...});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### **$sce**
|
||||
|
||||
**Due to [1e9ead](https://github.com/angular/angular.js/commit/1e9eadcd72dbbd5c67dae8328a63e535cfa91ff9)**,
|
||||
if you use `attrs.$set` for URL attributes (`a[href]` and `img[src]`) there will no
|
||||
longer be any automated sanitization of the value. This is in line with other
|
||||
programmatic operations, such as writing to the `innerHTML` of an element.
|
||||
|
||||
If you are programmatically writing URL values to attributes from untrusted
|
||||
input, then you must sanitize it yourself. You could write your own sanitizer or copy
|
||||
the private `$$sanitizeUri` service.
|
||||
|
||||
Note that values that have been passed through the `$interpolate` service within the
|
||||
`URL` or `MEDIA_URL` will have already been sanitized, so you would not need to sanitize
|
||||
these values again.
|
||||
|
||||
<hr/>
|
||||
|
||||
**Due to [1e9ead](https://github.com/angular/angular.js/commit/1e9eadcd72dbbd5c67dae8328a63e535cfa91ff9)**,
|
||||
binding {@link ng.$sce#trustAs trustAs()} and the short versions
|
||||
({@link ng.$sce#trustAsResourceUrl trustAsResourceUrl()} et al.) to {@link ng.ngSrc},
|
||||
{@link ng.ngSrcset}, and {@link ng.ngHref} will now raise an infinite digest error:
|
||||
|
||||
```js
|
||||
$scope.imgThumbFn = function(id) {
|
||||
return $sce.trustAsResourceUrl(someService.someUrl(id));
|
||||
};
|
||||
```
|
||||
|
||||
```html
|
||||
<img ng-src="{{ imgThumbFn(imgId) }}" />
|
||||
```
|
||||
|
||||
This is because {@link ng.$interpolate} is now responsible for sanitizing
|
||||
the attribute value, and its watcher receives a new object from `trustAs()`
|
||||
on every digest.
|
||||
To migrate, compute the trusted value only when the input value changes:
|
||||
|
||||
```js
|
||||
$scope.$watch('imgId', function(id) {
|
||||
$scope.imgThumb = $sce.trustAsResourceUrl(someService.someUrl(id));
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
<img ng-src="{{ imgThumb }}" />
|
||||
```
|
||||
|
||||
|
||||
<a name="migrate1.6to1.7-ng-filters"></a>
|
||||
### Core: _Filters_
|
||||
|
||||
|
||||
#### **orderBy**
|
||||
|
||||
**Due to [1d8046](https://github.com/angular/angular.js/commit/1d804645f7656d592c90216a0355b4948807f6b8)**,
|
||||
when using `orderBy` to sort arrays containing `null` values, the `null` values
|
||||
will be considered "greater than" all other values, except for `undefined`.
|
||||
Previously, they were sorted as strings. This will result in different (but more
|
||||
intuitive) sorting order.
|
||||
|
||||
Before:
|
||||
```js
|
||||
orderByFilter(['a', undefined, 'o', null, 'z']);
|
||||
//--> 'a', null, 'o', 'z', undefined
|
||||
```
|
||||
|
||||
After:
|
||||
```js
|
||||
orderByFilter(['a', undefined, 'o', null, 'z']);
|
||||
//--> 'a', 'o', 'z', null, undefined
|
||||
```
|
||||
|
||||
|
||||
<a name="migrate1.6to1.7-ng-misc"></a>
|
||||
### Core: _Miscellaneous_
|
||||
|
||||
|
||||
#### **jqLite**
|
||||
|
||||
**Due to [b7d396](https://github.com/angular/angular.js/commit/b7d396b8b6e8f27a1f4556d58fc903321e8d532a)**,
|
||||
`removeData()` no longer removes event handlers.
|
||||
|
||||
Before this commit `removeData()` invoked on an element removed its event
|
||||
handlers as well. If you want to trigger a full cleanup of an element, change:
|
||||
|
||||
```js
|
||||
elem.removeData();
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```js
|
||||
angular.element.cleanData(elem);
|
||||
```
|
||||
|
||||
In most cases, though, cleaning up after an element is supposed to be done
|
||||
only when it's removed from the DOM as well; in such cases the following:
|
||||
|
||||
```js
|
||||
elem.remove();
|
||||
```
|
||||
|
||||
will remove event handlers as well.
|
||||
|
||||
|
||||
#### **Helpers**
|
||||
|
||||
**Due to [1daa4f](https://github.com/angular/angular.js/commit/1daa4f2231a89ee88345689f001805ffffa9e7de)**,
|
||||
the helper functions `angular.lowercase` and `angular.uppercase` have been removed.
|
||||
|
||||
These functions have been deprecated since 1.5.0. They are internally
|
||||
used, but should not be exposed as they contain special locale handling
|
||||
(for Turkish) to maintain internal consistency regardless of user-set locale.
|
||||
|
||||
Developers should generally use the built-in methods `toLowerCase` and `toUpperCase`
|
||||
or `toLocaleLowerCase` and `toLocaleUpperCase` for special cases.
|
||||
|
||||
<hr />
|
||||
|
||||
**Due to [e3ece2](https://github.com/angular/angular.js/commit/e3ece2fad9e1e6d47b5f06815ff186d7e6f44948)**,
|
||||
`angular.isArray()` now supports Array subclasses.
|
||||
|
||||
Previously, `angular.isArray()` was an alias for `Array.isArray()`.
|
||||
Therefore, objects that prototypally inherit from `Array` where not
|
||||
considered arrays. Now such objects are considered arrays too.
|
||||
|
||||
This change affects several other methods that use `angular.isArray()`
|
||||
under the hood, such as `angular.copy()`, `angular.equals()`,
|
||||
`angular.forEach()`, and `angular.merge()`.
|
||||
|
||||
This in turn affects how dirty checking treats objects that prototypally
|
||||
inherit from `Array` (e.g. MobX observable arrays). AngularJS will now
|
||||
be able to handle these objects better when copying or watching.
|
||||
|
||||
|
||||
<a name="migrate1.6to1.7-ngAria"></a>
|
||||
### ngAria
|
||||
|
||||
**Due to [6d5ef3](https://github.com/angular/angular.js/commit/6d5ef34fc6a974cde73157ba94f9706723dd8f5b)**,
|
||||
`ngAria` no longer sets `aria-*` attributes on `input[type="hidden"]` with `ngModel`.
|
||||
This can affect apps that test for the presence of ARIA attributes on hidden inputs.
|
||||
To migrate, remove these assertions.
|
||||
In actual apps, this should not have a user-facing effect, as the previous behavior
|
||||
was incorrect, and the new behavior is correct for accessibility.
|
||||
|
||||
|
||||
<a name="migrate1.6to1.7-ngResource"></a>
|
||||
### ngResource
|
||||
|
||||
|
||||
#### **$resource**
|
||||
|
||||
**Due to [ea0585](https://github.com/angular/angular.js/commit/ea0585773bb93fd891576e2271254a17e15f1ddd)**,
|
||||
the behavior of interceptors and success/error callbacks has changed.
|
||||
|
||||
If you are not using `success` or `error` callbacks with `$resource`,
|
||||
your app should not be affected by this change.
|
||||
|
||||
If you are using `success` or `error` callbacks (with or without
|
||||
response interceptors), one (subtle) difference is that throwing an
|
||||
error inside the callbacks will not propagate to the returned
|
||||
`$promise`. Therefore, you should try to use the promises whenever
|
||||
possible. E.g.:
|
||||
|
||||
```js
|
||||
// Avoid
|
||||
User.query(function onSuccess(users) { throw new Error(); }).
|
||||
$promise.
|
||||
catch(function onError() { /* Will not be called. */ });
|
||||
|
||||
// Prefer
|
||||
User.query().
|
||||
$promise.
|
||||
then(function onSuccess(users) { throw new Error(); }).
|
||||
catch(function onError() { /* Will be called. */ });
|
||||
```
|
||||
|
||||
Finally, if you are using `success` or `error` callbacks with response
|
||||
interceptors, the callbacks will now always run _after_ the interceptors
|
||||
(and wait for them to resolve in case they return a promise).
|
||||
Previously, the `error` callback was called before the `responseError`
|
||||
interceptor and the `success` callback was synchronously called after
|
||||
the `response` interceptor. E.g.:
|
||||
|
||||
```js
|
||||
var User = $resource('/api/users/:id', {id: '@id'}, {
|
||||
get: {
|
||||
method: 'get',
|
||||
interceptor: {
|
||||
response: function(response) {
|
||||
console.log('responseInterceptor-1');
|
||||
return $timeout(1000).then(function() {
|
||||
console.log('responseInterceptor-2');
|
||||
return response.resource;
|
||||
});
|
||||
},
|
||||
responseError: function(response) {
|
||||
console.log('responseErrorInterceptor-1');
|
||||
return $timeout(1000).then(function() {
|
||||
console.log('responseErrorInterceptor-2');
|
||||
return $q.reject('Ooops!');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
var onSuccess = function(value) { console.log('successCallback', value); };
|
||||
var onError = function(error) { console.log('errorCallback', error); };
|
||||
|
||||
// Assuming the following call is successful...
|
||||
User.get({id: 1}, onSuccess, onError);
|
||||
// Old behavior:
|
||||
// responseInterceptor-1
|
||||
// successCallback, {/* Promise object */}
|
||||
// responseInterceptor-2
|
||||
// New behavior:
|
||||
// responseInterceptor-1
|
||||
// responseInterceptor-2
|
||||
// successCallback, {/* User object */}
|
||||
|
||||
// Assuming the following call returns an error...
|
||||
User.get({id: 2}, onSuccess, onError);
|
||||
// Old behavior:
|
||||
// errorCallback, {/* Response object */}
|
||||
// responseErrorInterceptor-1
|
||||
// responseErrorInterceptor-2
|
||||
// New behavior:
|
||||
// responseErrorInterceptor-1
|
||||
// responseErrorInterceptor-2
|
||||
// errorCallback, Ooops!
|
||||
```
|
||||
|
||||
<hr />
|
||||
|
||||
**Due to [240a3d](https://github.com/angular/angular.js/commit/240a3ddbf12a9bb79754031be95dae4b6bd2dded)**,
|
||||
`$http` will be called asynchronously from `$resource` methods
|
||||
(regardless if a `request`/`requestError` interceptor has been defined).
|
||||
|
||||
Previously, calling a `$resource` method would synchronously call
|
||||
`$http`.
|
||||
|
||||
This is not expected to affect applications at runtime, since the
|
||||
overall operation is asynchronous already, but may affect assertions in
|
||||
tests. For example, if you want to assert that `$http` has been called
|
||||
with specific arguments as a result of a `$resource` call, you now need
|
||||
to run a `$digest` first, to ensure the (possibly empty) request
|
||||
interceptor promise has been resolved.
|
||||
|
||||
Before:
|
||||
```js
|
||||
it('...', function() {
|
||||
$httpBackend.expectGET('/api/things').respond(...);
|
||||
var Things = $resource('/api/things');
|
||||
Things.query();
|
||||
|
||||
expect($http).toHaveBeenCalledWith(...);
|
||||
});
|
||||
```
|
||||
|
||||
After:
|
||||
```js
|
||||
it('...', function() {
|
||||
$httpBackend.expectGET('/api/things').respond(...);
|
||||
var Things = $resource('/api/things');
|
||||
Things.query();
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($http).toHaveBeenCalledWith(...);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
<a name="migrate1.6to1.7-ngScenario"></a>
|
||||
### ngScenario
|
||||
|
||||
**Due to[0cd392](https://github.com/angular/angular.js/commit/0cd39217828b0ad53eaf731576af17d66c18ff60)**,
|
||||
the angular scenario runner end-to-end test framework has been
|
||||
removed from the project and will no longer be available on npm
|
||||
or bower starting with 1.7.0.
|
||||
It has been deprecated and removed from the documentation since 2014.
|
||||
Applications that still use it should migrate to
|
||||
[Protractor](http://www.protractortest.org).
|
||||
Technically, it should also be possible to continue using an
|
||||
older version of the scenario runner, as the underlying APIs have
|
||||
not changed. However, we do not guarantee future compatibility.
|
||||
|
||||
|
||||
<a name="migrate1.6to1.7-ngTouch"></a>
|
||||
### ngTouch
|
||||
|
||||
**Due to [11d9ad](https://github.com/angular/angular.js/commit/11d9ad1eb25eaf5967195e424108207427835d50)**,
|
||||
the `ngClick` directive of the `ngTouch` module has been removed, and with it the
|
||||
corresponding `$touchProvider` and `$touch` service.
|
||||
|
||||
If you have included `ngTouch` v1.5.0 or higher in your application, and have not
|
||||
changed the value of `$touchProvider.ngClickOverrideEnabled()`, or injected and used the `$touch`
|
||||
service, then there are no migration steps for your code. Otherwise you must remove references to
|
||||
the provider and service.
|
||||
|
||||
The `ngClick` override directive had been deprecated and by default disabled since v1.5.0,
|
||||
because of buggy behavior in edge cases, and a general trend to avoid special touch based
|
||||
overrides of click events. In modern browsers, it should not be necessary to use a touch override
|
||||
library:
|
||||
|
||||
- Chrome, Firefox, Edge, and Safari remove the 300ms delay when
|
||||
`<meta name="viewport" content="width=device-width">` is set.
|
||||
- Internet Explorer 10+, Edge, Safari, and Chrome remove the delay on elements that have the
|
||||
`touch-action` css property is set to `manipulation`.
|
||||
|
||||
You can find out more in these articles:
|
||||
https://developers.google.com/web/updates/2013/12/300ms-tap-delay-gone-away
|
||||
https://developer.apple.com/library/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_9_1.html#//apple_ref/doc/uid/TP40014305-CH10-SW8
|
||||
https://blogs.msdn.microsoft.com/ie/2015/02/24/pointer-events-w3c-recommendation-interoperable-touch-and-removing-the-dreaded-300ms-tap-delay/
|
||||
|
||||
|
||||
|
||||
## Migrating from 1.5 to 1.6
|
||||
|
||||
AngularJS 1.6 fixes numerous bugs and adds new features, both in core and in external modules.
|
||||
@@ -1310,7 +481,7 @@ running at `https://docs.angularjs.org` then the following will fail:
|
||||
|
||||
By default, only URLs with the same domain and protocol as the application document are considered
|
||||
safe in the `RESOURCE_URL` context. To use URLs from other domains and/or protocols, you may either
|
||||
add them to the trusted source URL list or wrap them into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
|
||||
whitelist them or wrap them into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
|
||||
|
||||
<hr />
|
||||
<minor />
|
||||
@@ -1388,7 +559,7 @@ $http.json('other/trusted/url', {jsonpCallbackParam: 'cb'});
|
||||
all JSONP requests now require the URL to be trusted as a resource URL. There are two approaches to
|
||||
trust a URL:
|
||||
|
||||
1. **Setting trusted resource URLs with the `$sceDelegateProvider.resourceUrlWhitelist()` (called `trustedResourceUrlList()` from 1.8.1 onwards) method.**
|
||||
1. **Whitelisting with the `$sceDelegateProvider.resourceUrlWhitelist()` method.**
|
||||
You configure this list in a module configuration block:
|
||||
|
||||
```js
|
||||
@@ -2101,7 +1272,7 @@ Due to [b71d7c3f](https://github.com/angular/angular.js/commit/b71d7c3f3c04e65b0
|
||||
falsy values (`''`, `0`, `false` and `null`) are properly recognized as option group identifiers for
|
||||
options passed to `ngOptions`. Previously, all of these values were ignored and the option was not
|
||||
assigned to any group. `undefined` is still interpreted as "no group".
|
||||
If you have options with falsy group identifiers that should still not be assigned to any group,
|
||||
If you have options with falsy group indentifiers that should still not be assigned to any group,
|
||||
then you must filter the values before passing them to `ngOptions`, converting falsy values to
|
||||
`undefined`.
|
||||
|
||||
@@ -2208,7 +1379,7 @@ service does not have access to the resource in order to sanitize it.
|
||||
Similarly, due to [234053fc](https://github.com/angular/angular.js/commit/234053fc9ad90e0d05be7e8359c6af66be94c094),
|
||||
the `$sanitize` service will now also remove instances of the `usemap` attribute from any elements
|
||||
passed to it. This attribute is used to reference another element by `name` or `id`. Since the
|
||||
`name` and `id` attributes are already banned, a sanitized `usemap` attribute could only
|
||||
`name` and `id` attributes are already blacklisted, a sanitized `usemap` attribute could only
|
||||
reference unsanitized content, which is a security risk.
|
||||
|
||||
Due to [98c2db7f](https://github.com/angular/angular.js/commit/98c2db7f9c2d078a408576e722407d518c7ee10a),
|
||||
@@ -2260,8 +1431,8 @@ For more info on the topic, you can take a look at this
|
||||
## Migrating from 1.3 to 1.4
|
||||
|
||||
AngularJS 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
|
||||
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions`, `ngPattern`, `pattern` and some fixes to core filters:
|
||||
`limitTo` and `filter`.
|
||||
are changes to `ngMessages`, `$compile`, `ngRepeat`, `ngOptions`, `ngPattern`, `pattern`, and
|
||||
some fixes to core filters: `limitTo` and `filter`.
|
||||
|
||||
The reason for the ngAnimate refactor was to fix timing issues and to expose new APIs to allow
|
||||
for developers to construct more versatile animations. We now have access to `$animateCss`
|
||||
@@ -2648,8 +1819,8 @@ $scope.findTemplate = function(templateName) {
|
||||
};
|
||||
```
|
||||
|
||||
To migrate, either cache the result of `trustAsResourceUrl()`, or put the template url in the trusted resource
|
||||
URL list in the `config()` function:
|
||||
To migrate, either cache the result of `trustAsResourceUrl()`, or put the template url in the resource
|
||||
whitelist in the `config()` function:
|
||||
|
||||
After:
|
||||
|
||||
@@ -2663,8 +1834,7 @@ $scope.findTemplate = function(templateName) {
|
||||
return templateCache[templateName];
|
||||
};
|
||||
|
||||
// Alternatively, use `$sceDelegateProvider.resourceUrlWhitelist()` (called
|
||||
// `trustedResourceUrlList()` from 1.8.1 onwards), which means you don't
|
||||
// Alternatively, use `$sceDelegateProvider.resourceUrlWhitelist()`, which means you don't
|
||||
// have to use `$sce.trustAsResourceUrl()` at all:
|
||||
|
||||
angular.module('myApp', []).config(function($sceDelegateProvider) {
|
||||
@@ -3355,7 +2525,7 @@ below should still apply, but you may want to consult the
|
||||
<li>{@link guide/migration#directive-priority Directive priority}</li>
|
||||
<li>{@link guide/migration#ngscenario ngScenario}</li>
|
||||
<li>{@link guide/migration#nginclude-and-ngview-replace-its-entire-element-on-update ngInclude and ngView replace its entire element on update}</li>
|
||||
<li>{@link guide/migration#urls-are-now-sanitized-against-a-trusted-uri-matcher URLs are now sanitized against a trusted URI matcher}</li>
|
||||
<li>{@link guide/migration#urls-are-now-sanitized-against-a-whitelist URLs are now sanitized against a whitelist}</li>
|
||||
<li>{@link guide/migration#isolate-scope-only-exposed-to-directives-with-scope-property Isolate scope only exposed to directives with <code>scope</code> property}</li>
|
||||
<li>{@link guide/migration#change-to-interpolation-priority Change to interpolation priority}</li>
|
||||
<li>{@link guide/migration#underscore-prefixed-suffixed-properties-are-non-bindable Underscore-prefixed/suffixed properties are non-bindable}</li>
|
||||
@@ -3845,10 +3015,10 @@ See [7d69d52a](https://github.com/angular/angular.js/commit/7d69d52acff8578e0f7d
|
||||
[aa2133ad](https://github.com/angular/angular.js/commit/aa2133ad818d2e5c27cbd3933061797096356c8a).
|
||||
|
||||
|
||||
### URLs are now sanitized against a trusted URI matcher
|
||||
### URLs are now sanitized against a whitelist
|
||||
|
||||
A trusted URI matcher configured via `$compileProvider` can be used to configure what URLs are considered safe.
|
||||
By default all common protocol prefixes are trusted including `data:` URIs with mime types `image/*`.
|
||||
A whitelist configured via `$compileProvider` can be used to configure what URLs are considered safe.
|
||||
By default all common protocol prefixes are whitelisted including `data:` URIs with mime types `image/*`.
|
||||
This change shouldn't impact apps that don't contain malicious image links.
|
||||
|
||||
See [1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d61286840177607edd552a9df97),
|
||||
|
||||
@@ -188,6 +188,11 @@ myApp.service('unicornLauncher', ["apiToken", UnicornLauncher]);
|
||||
|
||||
Much simpler!
|
||||
|
||||
Note: Yes, we have called one of our service recipes 'Service'. We regret this and know that we'll
|
||||
be somehow punished for our misdeed. It's like we named one of our offspring 'Child'. Boy,
|
||||
that would mess with the teachers.
|
||||
|
||||
|
||||
## Provider Recipe
|
||||
|
||||
As already mentioned in the intro, the Provider recipe is the core recipe type and
|
||||
|
||||
@@ -109,14 +109,12 @@ to test the behavior without being distracted by the rendering details.
|
||||
## Scope Hierarchies
|
||||
|
||||
Each AngularJS application has exactly one {@link ng.$rootScope root scope}, but
|
||||
may have any number of child scopes.
|
||||
may have several child scopes.
|
||||
|
||||
The application can have multiple scopes, because {@link guide/directive directives} can create new
|
||||
child scopes. When new scopes are created, they are added as children of their parent scope. This
|
||||
creates a tree structure which parallels the DOM where they're attached.
|
||||
|
||||
The section {@link guide/scope#directives-that-create-scopes Directives that Create Scopes} has more
|
||||
info about which directives create scopes.
|
||||
The application can have multiple scopes, because some {@link guide/directive directives} create
|
||||
new child scopes (refer to directive documentation to see which directives create new scopes).
|
||||
When new scopes are created, they are added as children of their parent scope. This creates a tree
|
||||
structure which parallels the DOM where they're attached.
|
||||
|
||||
When AngularJS evaluates `{{name}}`, it first looks at the scope associated with the given
|
||||
element for the `name` property. If no such property is found, it searches the parent scope
|
||||
@@ -185,11 +183,8 @@ To examine the scope in the debugger:
|
||||
2. The debugger allows you to access the currently selected element in the console as `$0`
|
||||
variable.
|
||||
|
||||
3. To retrieve the associated scope in console execute: `angular.element($0).scope()`
|
||||
3. To retrieve the associated scope in console execute: `angular.element($0).scope()` or just type $scope
|
||||
|
||||
<div class="alert alert-warning">
|
||||
The `scope()` function is only available when {@link ng.$compileProvider#debugInfoEnabled `$compileProvider.debugInfoEnabled()`} is true (which is the default).
|
||||
</div>
|
||||
|
||||
## Scope Events Propagation
|
||||
|
||||
@@ -314,16 +309,12 @@ correctly.
|
||||
|
||||
In most cases, {@link ng.$compileProvider#directive directives} and scopes interact
|
||||
but do not create new instances of scope. However, some directives, such as {@link
|
||||
ng.directive:ngController ng-controller} and {@link ng.directive:ngRepeat ng-repeat},
|
||||
create new child scopes and attach the child scope to the corresponding DOM element.
|
||||
|
||||
A special type of scope is the `isolate` scope, which does not inherit prototypically from the parent scope.
|
||||
This type of scope is useful for component directives that should be isolated from their parent scope.
|
||||
See the {@link guide/directive#isolating-the-scope-of-a-directive directives guide} for
|
||||
more information about isolate scopes in custom directives.
|
||||
|
||||
Note also that component directives, which are created with the
|
||||
{@link api/ng/type/angular.Module#component .component()} helper always create an isolate scope.
|
||||
ng.directive:ngController ng-controller} and {@link
|
||||
ng.directive:ngRepeat ng-repeat}, create new child scopes
|
||||
and attach the child scope to the corresponding DOM element. You can retrieve a scope for any DOM
|
||||
element by using an `angular.element(aDomElement).scope()` method call.
|
||||
See the {@link guide/directive#isolating-the-scope-of-a-directive
|
||||
directives guide} for more information about isolate scopes.
|
||||
|
||||
### Controllers and Scopes
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ For more information please visit {@link $http#json-vulnerability-protection JSO
|
||||
|
||||
Bear in mind that calling `$http.jsonp` gives the remote server (and, if the request is not secured, any Man-in-the-Middle attackers)
|
||||
instant remote code execution in your application: the result of these requests is handed off
|
||||
to the browser as a regular `<script>` tag.
|
||||
to the browser as regular `<script>` tag.
|
||||
|
||||
## Strict Contextual Escaping
|
||||
|
||||
|
||||
@@ -149,17 +149,16 @@ for instantiating controllers.
|
||||
describe('PasswordController', function() {
|
||||
beforeEach(module('app'));
|
||||
|
||||
var $controller, $rootScope;
|
||||
var $controller;
|
||||
|
||||
beforeEach(inject(function(_$controller_, _$rootScope_){
|
||||
beforeEach(inject(function(_$controller_){
|
||||
// The injector unwraps the underscores (_) from around the parameter names when matching
|
||||
$controller = _$controller_;
|
||||
$rootScope = _$rootScope_;
|
||||
}));
|
||||
|
||||
describe('$scope.grade', function() {
|
||||
it('sets the strength to "strong" if the password length is >8 chars', function() {
|
||||
var $scope = $rootScope.$new();
|
||||
var $scope = {};
|
||||
var controller = $controller('PasswordController', { $scope: $scope });
|
||||
$scope.password = 'longerthaneightchars';
|
||||
$scope.grade();
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
@description
|
||||
|
||||
# Including AngularJS scripts from the Google CDN
|
||||
The quickest way to get started is to point your html `<script>` tag to a Google CDN URL.
|
||||
The quickest way to get started is to point your html `<script>` tag to a
|
||||
[Google CDN](https://developers.google.com/speed/libraries/#angularjs) URL.
|
||||
This way, you don't have to download anything or maintain a local copy.
|
||||
|
||||
There are two types of AngularJS script URLs you can point to, one for development and one for
|
||||
@@ -110,7 +111,7 @@ The set of files included in each version directory are:
|
||||
* __`angular-route.js`__ — Routing and deep-linking services and directives for AngularJS apps.
|
||||
({@link module:ngRoute API docs})
|
||||
* __`angular-sanitize.js`__ — Functionality to sanitize HTML. ({@link module:ngSanitize API docs})
|
||||
* __`angular-touch.js`__ — Touch events for touch-enabled devices.
|
||||
* __`angular-touch.js`__ — Touch events and other helpers for touch-enabled devices.
|
||||
({@link module:ngTouch API docs})
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
### Why is this project called "AngularJS"? Why is the namespace called "ng"?
|
||||
|
||||
Because HTML has angular brackets and "ng" sounds like "AngularJS".
|
||||
Because HTML has AngularJS brackets and "ng" sounds like "AngularJS".
|
||||
|
||||
|
||||
### Is AngularJS a library, framework, plugin or a browser extension?
|
||||
@@ -39,7 +39,7 @@ When we are making a release we generate updates to the changelog directly from
|
||||
generated update contains a highlighted section that contains all the breaking changes that have been
|
||||
extracted from the commits. We can quickly see in the new changelog exactly what commits contain breaking
|
||||
changes and so can application developers when they are deciding whether to update to a new version of
|
||||
AngularJS.
|
||||
Angular.
|
||||
|
||||
Features with non-breaking changes can also appear in the "patch" version, e.g. in version 1.6.3 there might
|
||||
be a feature that is not available in 1.6.2.
|
||||
@@ -94,7 +94,8 @@ When adding new code to AngularJS, we have a very stringent commit policy:
|
||||
- Commit messages must be written in a specific manner that allows us to parse them and extract the changes
|
||||
for release notes ([see the contributing guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md))
|
||||
|
||||
The AngularJS code base has a very large set of unit tests and end-to-end tests. This means that a breaking change will require one or more tests to be changed to allow the
|
||||
The AngularJS code base has a very large set of unit tests and end-to-end tests. This means that
|
||||
a breaking change will require one or more tests to be changed to allow the
|
||||
tests to pass. So when a commit includes tests that are being removed or modified, this is a flag that the
|
||||
code might include a breaking change. When reviewing the commit we can then decide whether there really is
|
||||
a breaking change and if it is appropriate for the branch to which it is being merged. If so, then we
|
||||
@@ -174,9 +175,8 @@ Yes, AngularJS can use [jQuery](http://jquery.com/) if it's present in your app
|
||||
application is being bootstrapped. If jQuery is not present in your script path, AngularJS falls back
|
||||
to its own implementation of the subset of jQuery that we call {@link angular.element jQLite}.
|
||||
|
||||
For AngularJS 1.8 we support jQuery 2.1+ but we suggest jQuery 3.5.1 or above to avoid a potential
|
||||
security issue. Earlier versions of jQuery might work correctly with AngularJS but we don't guarantee
|
||||
that.
|
||||
AngularJS 1.3 only supports jQuery 2.1 or above. jQuery 1.7 and newer might work correctly with AngularJS
|
||||
but we don't guarantee that.
|
||||
|
||||
|
||||
### What is testability like in AngularJS?
|
||||
|
||||
@@ -4,25 +4,51 @@
|
||||
|
||||
# Version Support Status
|
||||
|
||||
**AngularJS support has officially ended as of January 2022.**
|
||||
This page describes the support status of the significant versions of AngularJS.
|
||||
|
||||
Visit [angular.io](https://angular.io) for the actively supported Angular.
|
||||
<div class="alert alert-info">
|
||||
AngularJS is planning one more significant release, version 1.7, and on July 1, 2018 it will enter a 3 year Long Term Support period.
|
||||
</div>
|
||||
|
||||
## What does end of support mean?
|
||||
### Until July 1st 2018
|
||||
|
||||
The code will remain accessible on [GitHub](https://github.com/angular/angular.js),
|
||||
[npm](https://www.npmjs.com/package/angular),
|
||||
[Bower](https://github.com/angular/bower-angular), and
|
||||
[Release archive](https://code.angularjs.org/1.8.2).
|
||||
This website will remain here indefinitely.
|
||||
Any version branch not shown in the following table (e.g. 1.5.x) is no longer being developed.
|
||||
|
||||
The GitHub repository will be in an archived state, meaning that no new issues or pull requests
|
||||
can be submitted.
|
||||
<table class="dev-status table table-bordered">
|
||||
<thead>
|
||||
<tr><th>Version</th><th>Status</th><th>Comments</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="security"><td><span>1.2.x</span></td><td>Security patches only</td><td>Last version to provide IE 8 support</td></tr>
|
||||
<tr class="stable"><td><span>1.6.x</span></td><td>Patch Releases</td><td>Minor features, bug fixes, security patches - no breaking changes</td></tr>
|
||||
<tr class="current"><td><span>1.7.x</span></td><td>Active Development</td><td>1.7.0 (not yet released) will be the last release of AngularJS to contain breaking changes</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
See https://goo.gle/angularjs-end-of-life for the full details.
|
||||
### After July 1st 2018
|
||||
|
||||
### Extended Long Term Support
|
||||
Any version branch not shown in the following table (e.g. 1.6.x) is no longer being developed.
|
||||
|
||||
If you need extended support for AngularJS, you should consider:
|
||||
<table class="dev-status table table-bordered">
|
||||
<thead>
|
||||
<tr><th>Version</th><th>Status</th><th>Comments</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="security"><td><span>1.2.x</span></td><td>Long Term Support</td><td>Last version to provide IE 8 support</td></tr>
|
||||
<tr class="stable"><td><span>1.7.x</span></td><td>Long Term Support</td><td>See [Long Term Support](#long-term-support) section below.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
* [HeroDevs](https://www.herodevs.com/support/nes-angularjs)
|
||||
### Long Term Support
|
||||
|
||||
On July 1st 2018, we will enter a Long Term Support period for AngularJS.
|
||||
|
||||
At this time we will focus exclusively on providing fixes to bugs that satisfy at least one of the following criteria:
|
||||
|
||||
* A security flaw is detected in the 1.7.x branch of the framework
|
||||
* One of the major browsers releases a version that will cause current production applications using AngularJS 1.7.x to stop working
|
||||
* The jQuery library releases a version that will cause current production applications using AngularJS 1.7.x to stop working.
|
||||
|
||||
### Blog Post
|
||||
|
||||
You can read more about these plans in our [blog post announcement](https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c).
|
||||
@@ -64,7 +64,7 @@ a few git commands.
|
||||
|
||||
### Install Git
|
||||
|
||||
You can download and install Git from https://git-scm.com/download. Once installed, you should have
|
||||
You can download and install Git from http://git-scm.com/download. Once installed, you should have
|
||||
access to the `git` command line tool. The main commands that you will need to use are:
|
||||
|
||||
* `git clone ...`: Clone a remote repository onto your local machine.
|
||||
@@ -99,8 +99,8 @@ The tutorial instructions, from now on, assume you are running all commands from
|
||||
|
||||
### Install Node.js
|
||||
|
||||
In order to install dependencies (such as the test tools and AngularJS itself) and run the
|
||||
preconfigured local web server, you will also need [Node.js v6+][node].
|
||||
If you want to run the preconfigured local web server and the test tools then you will also need
|
||||
[Node.js v4+][node].
|
||||
|
||||
You can download a Node.js installer for your operating system from https://nodejs.org/en/download/.
|
||||
|
||||
@@ -125,25 +125,22 @@ npm --version
|
||||
[Node Version Manager (nvm)][nvm] or [Node Version Manager (nvm) for Windows][nvm-windows].
|
||||
</div>
|
||||
|
||||
By installing Node.js, you also get [npm][npm], which is a command line executable for downloading
|
||||
and managing Node.js packages. We use it to download the AngularJS framework as well as development
|
||||
and testing tools.
|
||||
|
||||
Once you have Node.js installed on your machine, you can download these dependencies by running:
|
||||
Once you have Node.js installed on your machine, you can download the tool dependencies by running:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
This command reads angular-phonecat's `package.json` file and downloads the following dependencies
|
||||
into the `node_modules` directory:
|
||||
This command reads angular-phonecat's `package.json` file and downloads the following tools into the
|
||||
`node_modules` directory:
|
||||
|
||||
* [Bower][bower] - client-side code package manager
|
||||
* [Http-Server][http-server] - simple local static web server
|
||||
* [Karma][karma] - unit test runner
|
||||
* [Protractor][protractor] - end-to-end (E2E) test runner
|
||||
|
||||
Running `npm install` will also automatically copy the AngularJS framework and other dependencies
|
||||
necessary for our app to work into the `app/lib/` directory.
|
||||
Running `npm install` will also automatically use bower to download the AngularJS framework into the
|
||||
`app/bower_components` directory.
|
||||
|
||||
<div class="alert alert-info">
|
||||
Note the angular-phonecat project is setup to install and run these utilities via npm scripts.
|
||||
@@ -163,23 +160,23 @@ tasks that you will need while developing:
|
||||
|
||||
### Install Helper Tools (optional)
|
||||
|
||||
The Http-Server, Karma and Protractor modules are also executables, which can be installed globally
|
||||
and run directly from a terminal/command prompt. You don't need to do this to follow the tutorial,
|
||||
but if you decide you do want to run them directly, you can install these modules globally using,
|
||||
`sudo npm install --global ...`.
|
||||
The Bower, Http-Server, Karma and Protractor modules are also executables, which can be installed
|
||||
globally and run directly from a terminal/command prompt. You don't need to do this to follow the
|
||||
tutorial, but if you decide you do want to run them directly, you can install these modules globally
|
||||
using, `sudo npm install -g ...`.
|
||||
|
||||
For instance, to install the `http-server` command line executable you would do:
|
||||
For instance, to install the Bower command line executable you would do:
|
||||
|
||||
```
|
||||
sudo npm install --global http-server
|
||||
sudo npm install -g bower
|
||||
```
|
||||
|
||||
_(Omit the sudo if running on Windows.)_
|
||||
_(Omit the sudo if running on Windows)_
|
||||
|
||||
Then you can run the `http-server` tool directly, such as:
|
||||
Then you can run the bower tool directly, such as:
|
||||
|
||||
```
|
||||
http-server ./app
|
||||
bower install
|
||||
```
|
||||
|
||||
|
||||
@@ -281,45 +278,6 @@ It is good to run the E2E tests whenever you make changes to the HTML views or w
|
||||
the application as a whole is executing correctly. It is very common to run E2E tests before pushing
|
||||
a new commit of changes to a remote repository.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<p>
|
||||
Each version of Protractor is compatible with specific browser versions. If you are reading this
|
||||
some time in the future, it is possible that the specified Protractor version is no longer
|
||||
compatible with the latest version of Chrome that you are using.
|
||||
</p>
|
||||
<p>
|
||||
If that is the case, you can try upgrading Protractor to newer version. For instructions on how
|
||||
to upgrade dependencies see [Updating dependencies](tutorial/#updating-dependencies).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
### Updating dependencies
|
||||
|
||||
In order to avoid surprises, all dependencies listed in `package.json` are pinned to specific
|
||||
versions (this is what the [package-lock.json][package-lock] file is about). This ensures that the
|
||||
same version of a dependency is installed every time.
|
||||
|
||||
Since all dependencies are acquired via npm, you can use the same tool to easily update them as
|
||||
well (although you probably don't need to for the purpose of this tutorial). Simply run the
|
||||
preconfigured script:
|
||||
|
||||
```
|
||||
npm run update-deps
|
||||
```
|
||||
|
||||
This will update all packages to the latest version that satisfy their version ranges (as specified
|
||||
in `package.json`) and also copy the necessary files into `app/lib/`. For example, if `package.json`
|
||||
contains `"some-package": "1.2.x"`, it will be updated to the latest 1.2.x version (e.g. 1.2.99),
|
||||
but not to 1.3.x (e.g. 1.3.0).
|
||||
|
||||
If you want to update a dependency to a version newer than what the specificed range would permit,
|
||||
you can change the version range in `package.json` and then run `npm run update-deps` as usual.
|
||||
|
||||
<div class="alert alert-info">
|
||||
See [here][semver-ranges] for more info on the various version range formats.
|
||||
</div>
|
||||
|
||||
|
||||
### Common Issues
|
||||
|
||||
@@ -366,16 +324,14 @@ Now that you have set up your local machine, let's get started with the tutorial
|
||||
|
||||
|
||||
[angular-phonecat]: https://github.com/angular/angular-phonecat
|
||||
[git]: https://git-scm.com/
|
||||
[bower]: http://bower.io/
|
||||
[git]: http://git-scm.com/
|
||||
[http-server]: https://github.com/nodeapps/http-server
|
||||
[jdk]: https://en.wikipedia.org/wiki/Java_Development_Kit
|
||||
[jdk-download]: https://www.oracle.com/technetwork/java/javase/downloads/index.html
|
||||
[jdk-download]: http://www.oracle.com/technetwork/java/javase/downloads/index.html
|
||||
[karma]: https://karma-runner.github.io/
|
||||
[node]: https://nodejs.org/
|
||||
[npm]: https://www.npmjs.com/
|
||||
[node]: http://nodejs.org/
|
||||
[nvm]: https://github.com/creationix/nvm
|
||||
[nvm-windows]: https://github.com/coreybutler/nvm-windows
|
||||
[package-lock]: https://docs.npmjs.com/files/package-lock.json
|
||||
[protractor]: https://github.com/angular/protractor
|
||||
[selenium]: https://docs.seleniumhq.org/
|
||||
[semver-ranges]: https://docs.npmjs.com/misc/semver#ranges
|
||||
[selenium]: http://docs.seleniumhq.org/
|
||||
|
||||
@@ -51,8 +51,8 @@ The code contains some key AngularJS elements that we will need as we progress.
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>My HTML File</title>
|
||||
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.css" />
|
||||
<script src="lib/angular/angular.js"></script>
|
||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
|
||||
<script src="bower_components/angular/angular.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -84,7 +84,7 @@ For more info on `ngApp`, check out the {@link ngApp API Reference}.
|
||||
**`angular.js` script tag:**
|
||||
|
||||
```html
|
||||
<script src="lib/angular/angular.js"></script>
|
||||
<script src="bower_components/angular/angular.js"></script>
|
||||
```
|
||||
|
||||
This code downloads the `angular.js` script which registers a callback that will be executed by the
|
||||
@@ -154,8 +154,8 @@ and one static binding, and our model is empty. That will soon change!
|
||||
|
||||
Most of the files in your working directory come from the [angular-seed project][angular-seed],
|
||||
which is typically used to bootstrap new AngularJS projects. The seed project is pre-configured to
|
||||
install the AngularJS framework (via `npm` into the `app/lib/` directory) and tools for developing
|
||||
and testing a typical web application (via `npm`).
|
||||
install the AngularJS framework (via `bower` into the `app/bower_components/` directory) and tools
|
||||
for developing and testing a typical web application (via `npm`).
|
||||
|
||||
For the purposes of this tutorial, we modified the angular-seed with the following changes:
|
||||
|
||||
@@ -163,7 +163,7 @@ For the purposes of this tutorial, we modified the angular-seed with the followi
|
||||
* Removed unused dependencies.
|
||||
* Added phone images to `app/img/phones/`.
|
||||
* Added phone data files (JSON) to `app/phones/`.
|
||||
* Added a dependency on [Bootstrap][bootstrap-3.3] in the `package.json` file.
|
||||
* Added a dependency on [Bootstrap](http://getbootstrap.com) in the `bower.json` file.
|
||||
|
||||
|
||||
## Experiments
|
||||
@@ -186,4 +186,3 @@ Now let's go to {@link step_01 step 1} and add some content to the web app.
|
||||
|
||||
|
||||
[angular-seed]: https://github.com/angular/angular-seed
|
||||
[bootstrap-3.3]: https://getbootstrap.com/docs/3.3
|
||||
|
||||
@@ -33,7 +33,7 @@ The view is constructed by AngularJS from this template.
|
||||
<html ng-app="phonecatApp">
|
||||
<head>
|
||||
...
|
||||
<script src="lib/angular/angular.js"></script>
|
||||
<script src="bower_components/angular/angular.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</head>
|
||||
<body ng-controller="PhoneListController">
|
||||
@@ -151,20 +151,38 @@ To learn more about AngularJS scopes, see the {@link ng.$rootScope.Scope Angular
|
||||
|
||||
### Testing Controllers
|
||||
|
||||
The "AngularJS way" of separating the controller from the view makes it easy to test code as it is being
|
||||
developed. In the section "Model and Controller" we have registered our controller via a constructor
|
||||
function on the `phonecatApp` module.
|
||||
The "AngularJS way" of separating controller from the view, makes it easy to test code as it is being
|
||||
developed. If our controller were available on the global namespace, we could simply instantiate it
|
||||
with a mock scope object:
|
||||
|
||||
In tests, we use an AngularJS service, `$controller`, which will retrieve a controller by name. It
|
||||
also takes a second argument - a map of dependencies that should be injected.
|
||||
<br />
|
||||
```js
|
||||
describe('PhoneListController', function() {
|
||||
|
||||
The following test instantiates `PhoneListController` with a mock scope object,
|
||||
and verifies that the phones array property on the scope contains three records.
|
||||
it('should create a `phones` model with 3 phones', function() {
|
||||
var scope = {};
|
||||
var ctrl = new PhoneListController(scope);
|
||||
|
||||
This example demonstrates how easy it is to create a unit test for
|
||||
expect(scope.phones.length).toBe(3);
|
||||
});
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
The test instantiates `PhoneListController` and verifies that the phones array property on the
|
||||
scope contains three records. This example demonstrates how easy it is to create a unit test for
|
||||
code in AngularJS. Since testing is such a critical part of software development, we make it easy to
|
||||
create tests in AngularJS so that developers are encouraged to write them.
|
||||
|
||||
|
||||
### Testing non-global Controllers
|
||||
|
||||
In practice, you will not want to have your controller functions in the global namespace. Instead,
|
||||
you can see that we have registered it via a constructor function on the `phonecatApp` module.
|
||||
|
||||
In this case AngularJS provides a service, `$controller`, which will retrieve your controller by name.
|
||||
Here is the same test using `$controller`:
|
||||
|
||||
<br />
|
||||
**`app/app.spec.js`:**
|
||||
|
||||
@@ -317,7 +335,7 @@ by utilizing components.
|
||||
<ul doc-tutorial-nav="2"></ul>
|
||||
|
||||
|
||||
[jasmine-docs]: https://jasmine.github.io/api/3.3/global
|
||||
[jasmine-home]: https://jasmine.github.io/
|
||||
[jasmine-docs]: http://jasmine.github.io/2.4/introduction.html
|
||||
[jasmine-home]: http://jasmine.github.io/
|
||||
[karma]: https://karma-runner.github.io/
|
||||
[mvc-pattern]: https://en.wikipedia.org/wiki/Model–View–Controller
|
||||
[mvc-pattern]: http://en.wikipedia.org/wiki/Model–View–Controller
|
||||
|
||||
@@ -88,13 +88,6 @@ Let's see an example:
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
<body>
|
||||
<!-- The following line is how to use the `greetUser` component above in your html doc. -->
|
||||
<greet-user></greet-user>
|
||||
</body>
|
||||
```
|
||||
|
||||
Now, every time we include `<greet-user></greet-user>` in our view, AngularJS will expand it into a
|
||||
DOM sub-tree constructed using the provided `template` and managed by an instance of the specified
|
||||
controller.
|
||||
@@ -127,14 +120,14 @@ acquired skill.
|
||||
<html ng-app="phonecatApp">
|
||||
<head>
|
||||
...
|
||||
<script src="lib/angular/angular.js"></script>
|
||||
<script src="bower_components/angular/angular.js"></script>
|
||||
<script src="app.js"></script>
|
||||
<script src="phone-list.component.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Use a custom component to render a list of phones -->
|
||||
<phone-list></phone-list> <!-- This tells AngularJS to instantiate a `phoneList` component here. -->
|
||||
<phone-list></phone-list>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -155,7 +148,7 @@ angular.module('phonecatApp', []);
|
||||
// Register `phoneList` component, along with its associated controller and template
|
||||
angular.
|
||||
module('phonecatApp').
|
||||
component('phoneList', { // This name is what AngularJS uses to match to the `<phone-list>` element.
|
||||
component('phoneList', {
|
||||
template:
|
||||
'<ul>' +
|
||||
'<li ng-repeat="phone in $ctrl.phones">' +
|
||||
@@ -284,7 +277,7 @@ files, so it remains easy to locate as our application grows.
|
||||
|
||||
|
||||
[case-styles]: https://en.wikipedia.org/wiki/Letter_case#Special_case_styles
|
||||
[jasmine-docs]: https://jasmine.github.io/api/3.3/global
|
||||
[jasmine-home]: https://jasmine.github.io/
|
||||
[jasmine-docs]: http://jasmine.github.io/2.4/introduction.html
|
||||
[jasmine-home]: http://jasmine.github.io/
|
||||
[karma]: https://karma-runner.github.io/
|
||||
[mvc-pattern]: https://en.wikipedia.org/wiki/Model–View–Controller
|
||||
[mvc-pattern]: http://en.wikipedia.org/wiki/Model–View–Controller
|
||||
|
||||
@@ -230,8 +230,6 @@ You can now rerun `npm run protractor` to see the tests run.
|
||||
|
||||
* Reverse the sort order by adding a `-` symbol before the sorting value:
|
||||
`<option value="-age">Oldest</option>`
|
||||
After making this change, you'll notice that the drop-down list has a blank option selected and does not default to age anymore.
|
||||
Fix this by updating the `orderProp` value in `phone-list.component.js` to match the new value on the `<option>` element.
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset
|
||||
from our server using one of AngularJS's built-in {@link guide/services services} called
|
||||
{@link ng.$http $http}. We will use AngularJS's {@link guide/di dependency injection (DI)} to
|
||||
provide the service to the `phoneList` component's controller.
|
||||
{@link ng.$http $http}. We will use AngularJS's {@link guide/di dependency injection (DI)} to provide
|
||||
the service to the `phoneList` component's controller.
|
||||
|
||||
* There is now a list of 20 phones, loaded from the server.
|
||||
|
||||
|
||||
@@ -47,10 +47,10 @@ URLs point to the `app/img/phones/` directory.
|
||||
...
|
||||
<ul class="phones">
|
||||
<li ng-repeat="phone in $ctrl.phones | filter:$ctrl.query | orderBy:$ctrl.orderProp" class="thumbnail">
|
||||
<a href="#!/phones/{{phone.id}}" class="thumb">
|
||||
<a href="#/phones/{{phone.id}}" class="thumb">
|
||||
<img ng-src="{{phone.imageUrl}}" alt="{{phone.name}}" />
|
||||
</a>
|
||||
<a href="#!/phones/{{phone.id}}">{{phone.name}}</a>
|
||||
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
|
||||
<p>{{phone.snippet}}</p>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -83,7 +83,7 @@ HTTP request to an invalid location.
|
||||
query.sendKeys('nexus');
|
||||
|
||||
element.all(by.css('.phones li a')).first().click();
|
||||
expect(browser.getCurrentUrl()).toContain('index.html#!/phones/nexus-s');
|
||||
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
|
||||
});
|
||||
|
||||
...
|
||||
@@ -110,9 +110,8 @@ You can now rerun `npm run protractor` to see the tests run.
|
||||
|
||||
## Summary
|
||||
|
||||
Now that you have added phone images and links, go to {@link step_09 step 9} to learn about
|
||||
AngularJS layout templates and how AngularJS makes it easy to create applications that have
|
||||
multiple views.
|
||||
Now that you have added phone images and links, go to {@link step_09 step 9} to learn about AngularJS
|
||||
layout templates and how AngularJS makes it easy to create applications that have multiple views.
|
||||
|
||||
|
||||
<ul doc-tutorial-nav="8"></ul>
|
||||
|
||||
@@ -23,33 +23,49 @@ has multiple views by adding routing, using an AngularJS module called {@link ng
|
||||
The routing functionality added in this step is provided by AngularJS in the `ngRoute` module, which
|
||||
is distributed separately from the core AngularJS framework.
|
||||
|
||||
Since we are using [npm][npm] to install client-side dependencies, this step updates the
|
||||
`package.json` configuration file to include the new dependency:
|
||||
Since we are using [Bower][bower] to install client-side dependencies, this step updates the
|
||||
`bower.json` configuration file to include the new dependency:
|
||||
|
||||
<br />
|
||||
**`package.json`:**
|
||||
**`bower.json`:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "angular-phonecat",
|
||||
...
|
||||
"description": "A starter project for AngularJS",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/angular/angular-phonecat",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"angular": "1.8.x",
|
||||
"angular-route": "1.8.x",
|
||||
"angular": "1.5.x",
|
||||
"angular-mocks": "1.5.x",
|
||||
"angular-route": "1.5.x",
|
||||
"bootstrap": "3.3.x"
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The new dependency `"angular-route": "1.8.x"` tells npm to install a version of the angular-route
|
||||
module that is compatible with version 1.8.x of AngularJS. We must tell npm to download and install
|
||||
The new dependency `"angular-route": "1.5.x"` tells bower to install a version of the angular-route
|
||||
module that is compatible with version 1.5.x of AngularJS. We must tell bower to download and install
|
||||
this dependency.
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Note:** If you have bower installed globally, you can run `bower install`, but for this project
|
||||
we have preconfigured `npm install` to run bower for us.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Warning:** If a new version of AngularJS has been released since you last ran `npm install`, then
|
||||
you may have a problem with the `bower install` due to a conflict between the versions of
|
||||
angular.js that need to be installed. If you run into this issue, simply delete your
|
||||
`app/bower_components` directory and then run `npm install`.
|
||||
</div>
|
||||
|
||||
|
||||
## Multiple Views, Routing and Layout Templates
|
||||
|
||||
@@ -111,8 +127,8 @@ service, the `$routeProvider` exposes APIs that allow you to define routes for y
|
||||
</div>
|
||||
|
||||
AngularJS modules solve the problem of removing global variables from the application and provide a
|
||||
way of configuring the injector. As opposed to AMD or require.js modules, AngularJS modules don't
|
||||
try to solve the problem of script load ordering or lazy script fetching. These goals are totally
|
||||
way of configuring the injector. As opposed to AMD or require.js modules, AngularJS modules don't try
|
||||
to solve the problem of script load ordering or lazy script fetching. These goals are totally
|
||||
independent and both module systems can live side-by-side and fulfill their goals.
|
||||
|
||||
To deepen your understanding on AngularJS's DI, see [Understanding Dependency Injection][wiki-di].
|
||||
@@ -130,8 +146,8 @@ into the layout template. This makes it a perfect fit for our `index.html` templ
|
||||
```html
|
||||
<head>
|
||||
...
|
||||
<script src="lib/angular/angular.js"></script>
|
||||
<script src="lib/angular-route/angular-route.js"></script>
|
||||
<script src="bower_components/angular/angular.js"></script>
|
||||
<script src="bower_components/angular-route/angular-route.js"></script>
|
||||
<script src="app.module.js"></script>
|
||||
<script src="app.config.js"></script>
|
||||
...
|
||||
@@ -187,8 +203,10 @@ code, we put it into a separate file and used the `.config` suffix.
|
||||
```js
|
||||
angular.
|
||||
module('phonecatApp').
|
||||
config(['$routeProvider',
|
||||
function config($routeProvider) {
|
||||
config(['$locationProvider', '$routeProvider',
|
||||
function config($locationProvider, $routeProvider) {
|
||||
$locationProvider.hashPrefix('!');
|
||||
|
||||
$routeProvider.
|
||||
when('/phones', {
|
||||
template: '<phone-list></phone-list>'
|
||||
@@ -208,6 +226,18 @@ the corresponding services. Here, we use the
|
||||
{@link ngRoute.$routeProvider#otherwise $routeProvider.otherwise()} methods to define our
|
||||
application routes.
|
||||
|
||||
<div class="alert alert-success">
|
||||
<p>
|
||||
We also used {@link $locationProvider#hashPrefix $locationProvider.hashPrefix()} to set the
|
||||
hash-prefix to `!`. This prefix will appear in the links to our client-side routes, right after
|
||||
the hash (`#`) symbol and before the actual path (e.g. `index.html#!/some/path`).
|
||||
</p>
|
||||
<p>
|
||||
Setting a prefix is not necessary, but it is considered a good practice (for reasons that are
|
||||
outside the scope of this tutorial). `!` is the most commonly used prefix.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
Our routes are defined as follows:
|
||||
|
||||
* `when('/phones')`: Determines the view that will be shown, when the URL hash fragment is
|
||||
@@ -231,25 +261,6 @@ the route declaration — `'/phones/:phoneId'` — as a template that is matched
|
||||
URL. All variables defined with the `:` prefix are extracted into the (injectable)
|
||||
{@link ngRoute.$routeParams $routeParams} object.
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p>
|
||||
You may have noticed, that — while the configured route paths start with `/` (e.g.
|
||||
`/phones`) — the URLs used in templates start with `#!/` (e.g. `#!/phones`).
|
||||
</p>
|
||||
<p>
|
||||
Without getting into much detail, AngularJS (by default) uses the hash part of the URL (i.e.
|
||||
what comes after the hash (`#`) symbol) to determine the current route. In addition to that, you
|
||||
can also specify a {@link $locationProvider#hashPrefix hash-prefix} (`!` by default) that needs
|
||||
to appear after the hash symbol in order for AngularJS to consider the value an "AngularJS path"
|
||||
and process it (for example, try to match it to a route).
|
||||
</p>
|
||||
<p>
|
||||
You can find out more about how all this works in the [Using $location](guide/$location) section
|
||||
of the Developer Guide. But all you need to know for now, is that the URLs to our various routes
|
||||
should be prefixed with `#!`.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
## The `phoneDetail` Component
|
||||
|
||||
@@ -334,8 +345,8 @@ any modification.
|
||||
|
||||
```js
|
||||
files: [
|
||||
'lib/angular/angular.js',
|
||||
'lib/angular-route/angular-route.js',
|
||||
'bower_components/angular/angular.js',
|
||||
'bower_components/angular-route/angular-route.js',
|
||||
...
|
||||
],
|
||||
```
|
||||
@@ -352,7 +363,7 @@ various URLs and verifying that the correct view was rendered.
|
||||
|
||||
it('should redirect `index.html` to `index.html#!/phones', function() {
|
||||
browser.get('index.html');
|
||||
expect(browser.getCurrentUrl()).toContain('index.html#!/phones');
|
||||
expect(browser.getLocationAbsUrl()).toBe('/phones');
|
||||
});
|
||||
|
||||
...
|
||||
@@ -413,6 +424,6 @@ With the routing set up and the phone list view implemented, we are ready to go
|
||||
<ul doc-tutorial-nav="9"></ul>
|
||||
|
||||
|
||||
[bower]: http://bower.io
|
||||
[deep-linking]: https://en.wikipedia.org/wiki/Deep_linking
|
||||
[npm]: https://www.npmjs.com/
|
||||
[wiki-di]: https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection
|
||||
|
||||
@@ -21,34 +21,50 @@ In this step, we will change the way our application fetches data.
|
||||
The RESTful functionality is provided by AngularJS in the {@link ngResource ngResource} module, which
|
||||
is distributed separately from the core AngularJS framework.
|
||||
|
||||
Since we are using [npm][npm] to install client-side dependencies, this step updates the
|
||||
`package.json` configuration file to include the new dependency:
|
||||
Since we are using [Bower][bower] to install client-side dependencies, this step updates the
|
||||
`bower.json` configuration file to include the new dependency:
|
||||
|
||||
<br />
|
||||
**`package.json`:**
|
||||
**`bower.json`:**
|
||||
|
||||
```json
|
||||
```
|
||||
{
|
||||
"name": "angular-phonecat",
|
||||
...
|
||||
"description": "A starter project for AngularJS",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/angular/angular-phonecat",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"angular": "1.8.x",
|
||||
"angular-resource": "1.8.x",
|
||||
"angular-route": "1.8.x",
|
||||
"angular": "1.5.x",
|
||||
"angular-mocks": "1.5.x",
|
||||
"angular-resource": "1.5.x",
|
||||
"angular-route": "1.5.x",
|
||||
"bootstrap": "3.3.x"
|
||||
},
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The new dependency `"angular-resource": "1.8.x"` tells npm to install a version of the
|
||||
angular-resource module that is compatible with version 1.8.x of AngularJS. We must tell npm to
|
||||
The new dependency `"angular-resource": "1.5.x"` tells bower to install a version of the
|
||||
angular-resource module that is compatible with version 1.5.x of AngularJS. We must tell bower to
|
||||
download and install this dependency.
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Note:** If you have bower installed globally, you can run `bower install`, but for this project
|
||||
we have preconfigured `npm install` to run bower for us.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Warning:** If a new version of AngularJS has been released since you last ran `npm install`, then
|
||||
you may have a problem with the `bower install` due to a conflict between the versions of
|
||||
angular.js that need to be installed. If you run into this issue, simply delete your
|
||||
`app/bower_components` directory and then run `npm install`.
|
||||
</div>
|
||||
|
||||
|
||||
## Service
|
||||
|
||||
@@ -113,7 +129,7 @@ need to load the `angular-resource.js` file, which contains the `ngResource` mod
|
||||
```html
|
||||
<head>
|
||||
...
|
||||
<script src="lib/angular-resource/angular-resource.js"></script>
|
||||
<script src="bower_components/angular-resource/angular-resource.js"></script>
|
||||
...
|
||||
<script src="core/phone/phone.module.js"></script>
|
||||
<script src="core/phone/phone.service.js"></script>
|
||||
@@ -125,10 +141,9 @@ need to load the `angular-resource.js` file, which contains the `ngResource` mod
|
||||
## Component Controllers
|
||||
|
||||
We can now simplify our component controllers (`PhoneListController` and `PhoneDetailController`) by
|
||||
factoring out the lower-level `$http` service, replacing it with the new `Phone` service.
|
||||
AngularJS's `$resource` service is easier to use than `$http` for interacting with data sources
|
||||
exposed as RESTful resources. It is also easier now to understand what the code in our controllers
|
||||
is doing.
|
||||
factoring out the lower-level `$http` service, replacing it with the new `Phone` service. AngularJS's
|
||||
`$resource` service is easier to use than `$http` for interacting with data sources exposed as
|
||||
RESTful resources. It is also easier now to understand what the code in our controllers is doing.
|
||||
|
||||
<br />
|
||||
**`app/phone-list/phone-list.module.js`:**
|
||||
@@ -225,8 +240,8 @@ Karma configuration file with angular-resource.
|
||||
|
||||
```js
|
||||
files: [
|
||||
'lib/angular/angular.js',
|
||||
'lib/angular-resource/angular-resource.js',
|
||||
'bower_components/angular/angular.js',
|
||||
'bower_components/angular-resource/angular-resource.js',
|
||||
...
|
||||
],
|
||||
```
|
||||
@@ -304,6 +319,6 @@ Now that we have seen how to build a custom service as a RESTful client, we are
|
||||
<ul doc-tutorial-nav="13"></ul>
|
||||
|
||||
|
||||
[bower]: http://bower.io/
|
||||
[jasmine-equality]: https://jasmine.github.io/2.4/custom_equality.html
|
||||
[npm]: https://www.npmjs.com/
|
||||
[restful]: https://en.wikipedia.org/wiki/Representational_State_Transfer
|
||||
|
||||
@@ -22,43 +22,59 @@ the template code we created earlier.
|
||||
## Dependencies
|
||||
|
||||
The animation functionality is provided by AngularJS in the `ngAnimate` module, which is distributed
|
||||
separately from the core AngularJS framework. In addition we will use [jQuery][jquery] in this
|
||||
project to do extra JavaScript animations.
|
||||
separately from the core AngularJS framework. In addition we will use [jQuery][jquery] in this project
|
||||
to do extra JavaScript animations.
|
||||
|
||||
Since we are using [npm][npm] to install client-side dependencies, this step updates the
|
||||
`package.json` configuration file to include the new dependencies:
|
||||
Since we are using [Bower][bower] to install client-side dependencies, this step updates the
|
||||
`bower.json` configuration file to include the new dependencies:
|
||||
|
||||
<br />
|
||||
**`package.json`:**
|
||||
**`bower.json`:**
|
||||
|
||||
```json
|
||||
```
|
||||
{
|
||||
"name": "angular-phonecat",
|
||||
...
|
||||
"description": "A starter project for AngularJS",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/angular/angular-phonecat",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"angular": "1.8.x",
|
||||
"angular-animate": "1.8.x",
|
||||
"angular-resource": "1.8.x",
|
||||
"angular-route": "1.8.x",
|
||||
"angular": "1.5.x",
|
||||
"angular-animate": "1.5.x",
|
||||
"angular-mocks": "1.5.x",
|
||||
"angular-resource": "1.5.x",
|
||||
"angular-route": "1.5.x",
|
||||
"bootstrap": "3.3.x",
|
||||
"jquery": "^3.5.1"
|
||||
},
|
||||
...
|
||||
"jquery": "3.2.x"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* `"angular-animate": "1.8.x"` tells npm to install a version of the angular-animate module that
|
||||
is compatible with version 1.8.x of AngularJS.
|
||||
* `"jquery": "^3.5.1"` tells npm to install a version of jQuery that is compatible with 3.5.x and at least 3.5.1.
|
||||
Note that this is not an AngularJS library; it is the standard jQuery library. We can use npm to
|
||||
* `"angular-animate": "1.5.x"` tells bower to install a version of the angular-animate module that
|
||||
is compatible with version 1.5.x of AngularJS.
|
||||
* `"jquery": "3.2.x"` tells bower to install the latest patch release of the 3.2 version of jQuery.
|
||||
Note that this is not an AngularJS library; it is the standard jQuery library. We can use bower to
|
||||
install a wide range of 3rd party libraries.
|
||||
|
||||
Now, we must tell npm to download and install these dependencies.
|
||||
Now, we must tell bower to download and install these dependencies.
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Note:** If you have bower installed globally, you can run `bower install`, but for this project
|
||||
we have preconfigured `npm install` to run bower for us.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Warning:** If a new version of AngularJS has been released since you last ran `npm install`, then
|
||||
you may have a problem with the `bower install` due to a conflict between the versions of
|
||||
angular.js that need to be installed. If you run into this issue, simply delete your
|
||||
`app/bower_components` directory and then run `npm install`.
|
||||
</div>
|
||||
|
||||
|
||||
## How Animations work with `ngAnimate`
|
||||
|
||||
@@ -85,12 +101,12 @@ code necessary to make your application "animation aware".
|
||||
...
|
||||
|
||||
<!-- Used for JavaScript animations (include this before angular.js) -->
|
||||
<script src="lib/jquery/dist/jquery.js"></script>
|
||||
<script src="bower_components/jquery/dist/jquery.js"></script>
|
||||
|
||||
...
|
||||
|
||||
<!-- Adds animation support in AngularJS -->
|
||||
<script src="lib/angular-animate/angular-animate.js"></script>
|
||||
<script src="bower_components/angular-animate/angular-animate.js"></script>
|
||||
|
||||
<!-- Defines JavaScript animations -->
|
||||
<script src="app.animations.js"></script>
|
||||
@@ -99,8 +115,8 @@ code necessary to make your application "animation aware".
|
||||
```
|
||||
|
||||
<div class="alert alert-error">
|
||||
**Important:** Be sure to use jQuery version 2.1 or newer, when using AngularJS 1.5 or newer;
|
||||
jQuery 1.x is not officially supported.
|
||||
**Important:** Be sure to use jQuery version 2.1 or newer, when using AngularJS 1.5 or newer; jQuery 1.x is
|
||||
not officially supported.
|
||||
In order for AngularJS to detect jQuery and take advantage of it, make sure to include `jquery.js`
|
||||
before `angular.js`.
|
||||
</div>
|
||||
@@ -540,9 +556,9 @@ There you have it! We have created a web application in a relatively short amoun
|
||||
<ul doc-tutorial-nav="14"></ul>
|
||||
|
||||
|
||||
[caniuse-css-animation]: https://caniuse.com/#feat=css-animation
|
||||
[caniuse-css-transitions]: https://caniuse.com/#feat=css-transitions
|
||||
[bower]: http://bower.io/
|
||||
[caniuse-css-animation]: http://caniuse.com/#feat=css-animation
|
||||
[caniuse-css-transitions]: http://caniuse.com/#feat=css-transitions
|
||||
[jquery]: https://jquery.com/
|
||||
[jquery-animate]: https://api.jquery.com/animate
|
||||
[jquery-animate]: https://api.jquery.com/animate/
|
||||
[mdn-animations]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations
|
||||
[npm]: https://www.npmjs.com/
|
||||
|
||||
@@ -22,5 +22,5 @@ If you have questions or feedback or just want to say "hi", please post a messag
|
||||
|
||||
[angular-seed]: https://github.com/angular/angular-seed
|
||||
[gitter]: https://gitter.im/angular/angular.js
|
||||
[irc]: https://webchat.freenode.net/?channels=angularjs&uio=d4
|
||||
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
|
||||
[mailing-list]: https://groups.google.com/forum/#!forum/angular
|
||||
|
||||
@@ -20,7 +20,7 @@ function main() {
|
||||
} catch (e) {
|
||||
fs.mkdirSync(__dirname + '/../../../src/ngParseExt');
|
||||
}
|
||||
fs.writeFileSync(__dirname + '/../../../src/ngParseExt/ucd.js', code);
|
||||
fs.writeFile(__dirname + '/../../../src/ngParseExt/ucd.js', code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var angularFiles = require('./angularFiles');
|
||||
var sharedConfig = require('./karma-shared.conf');
|
||||
|
||||
module.exports = function(config) {
|
||||
sharedConfig(config, {testName: 'AngularJS: isolated module tests (ngAnimate)', logFile: 'karma-ngAnimate-isolated.log'});
|
||||
|
||||
config.set({
|
||||
files: angularFiles.mergeFilesFor('karmaModules-ngAnimate')
|
||||
});
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var angularFiles = require('./angularFiles');
|
||||
var sharedConfig = require('./karma-shared.conf');
|
||||
|
||||
module.exports = function(config) {
|
||||
sharedConfig(config, {testName: 'AngularJS: isolated module tests (ngMock)', logFile: 'karma-ngMock-isolated.log'});
|
||||
|
||||
config.set({
|
||||
files: angularFiles.mergeFilesFor('karmaModules-ngMock')
|
||||
});
|
||||
};
|
||||
+8
-11
@@ -1,20 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
var angularFiles = require('./angularFiles');
|
||||
var sharedConfig = require('./karma-shared.conf');
|
||||
|
||||
module.exports = function(config) {
|
||||
sharedConfig(config, {testName: 'AngularJS: isolated module tests', logFile: 'karma-modules-isolated.log'});
|
||||
sharedConfig(config, {testName: 'AngularJS: modules', logFile: 'karma-modules.log'});
|
||||
|
||||
config.set({
|
||||
files: [
|
||||
'build/angular.js',
|
||||
'build/angular-mocks.js',
|
||||
'test/modules/no_bootstrap.js',
|
||||
'test/helpers/matchers.js',
|
||||
'test/helpers/privateMocks.js',
|
||||
'test/helpers/support.js',
|
||||
'test/helpers/testabilityPatch.js',
|
||||
'build/test-bundles/angular-*.js'
|
||||
]
|
||||
files: angularFiles.mergeFilesFor('karmaModules'),
|
||||
|
||||
junitReporter: {
|
||||
outputFile: 'test_out/modules.xml',
|
||||
suite: 'modules'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
+48
-11
@@ -23,7 +23,12 @@ module.exports = function(config, specificOptions) {
|
||||
// SauceLabs config for local development.
|
||||
sauceLabs: {
|
||||
testName: specificOptions.testName || 'AngularJS',
|
||||
startConnect: true
|
||||
startConnect: true,
|
||||
options: {
|
||||
// We need selenium version +2.46 for Firefox 39 and the last selenium version for OS X is 2.45.
|
||||
// TODO: Uncomment when there is a selenium 2.46 available for OS X.
|
||||
// 'selenium-version': '2.46.0'
|
||||
}
|
||||
},
|
||||
|
||||
// BrowserStack config for local development.
|
||||
@@ -60,11 +65,13 @@ module.exports = function(config, specificOptions) {
|
||||
'SL_Safari-1': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.12',
|
||||
version: 'latest-1'
|
||||
},
|
||||
'SL_Safari': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.12',
|
||||
version: 'latest'
|
||||
},
|
||||
'SL_IE_9': {
|
||||
@@ -97,34 +104,34 @@ module.exports = function(config, specificOptions) {
|
||||
platform: 'Windows 10',
|
||||
version: 'latest-1'
|
||||
},
|
||||
'SL_iOS': {
|
||||
'SL_iOS_10': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'iphone',
|
||||
version: 'latest'
|
||||
version: '10.3'
|
||||
},
|
||||
'SL_iOS-1': {
|
||||
'SL_iOS_11': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'iphone',
|
||||
version: 'latest-1'
|
||||
version: '11'
|
||||
},
|
||||
|
||||
'BS_Chrome': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'chrome',
|
||||
os: 'OS X',
|
||||
os_version: 'Sierra'
|
||||
os_version: 'Yosemite'
|
||||
},
|
||||
'BS_Safari': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'safari',
|
||||
os: 'OS X',
|
||||
os_version: 'Sierra'
|
||||
os_version: 'Yosemite'
|
||||
},
|
||||
'BS_Firefox': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'firefox',
|
||||
os: 'Windows',
|
||||
os_version: '10'
|
||||
os_version: '8'
|
||||
},
|
||||
'BS_IE_9': {
|
||||
base: 'BrowserStack',
|
||||
@@ -169,9 +176,39 @@ module.exports = function(config, specificOptions) {
|
||||
});
|
||||
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
var buildLabel = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
|
||||
|
||||
// Karma (with socket.io 1.x) buffers by 50 and 50 tests can take a long time on IEs;-)
|
||||
config.browserNoActivityTimeout = 120000;
|
||||
|
||||
config.browserStack.build = buildLabel;
|
||||
config.browserStack.startTunnel = false;
|
||||
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
|
||||
config.sauceLabs.build = buildLabel;
|
||||
config.sauceLabs.startConnect = false;
|
||||
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
config.sauceLabs.recordScreenshots = true;
|
||||
|
||||
// Debug logging into a file, that we print out at the end of the build.
|
||||
config.loggers.push({
|
||||
type: 'file',
|
||||
filename: process.env.LOGS_DIR + '/' + (specificOptions.logFile || 'karma.log')
|
||||
});
|
||||
|
||||
if (process.env.BROWSER_PROVIDER === 'saucelabs' || !process.env.BROWSER_PROVIDER) {
|
||||
// Allocating a browser can take pretty long (eg. if we are out of capacity and need to wait
|
||||
// for another build to finish) and so the `captureTimeout` typically kills
|
||||
// an in-queue-pending request, which makes no sense.
|
||||
config.captureTimeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Terrible hack to workaround inflexibility of log4js:
|
||||
// - ignore web-server's 404 warnings,
|
||||
// - ignore DEBUG logs (on CI), we log them into a file instead.
|
||||
// - ignore DEBUG logs (on Travis), we log them into a file instead.
|
||||
var IGNORED_404 = [
|
||||
'/favicon.ico',
|
||||
'/%7B%7BtestUrl%7D%7D',
|
||||
@@ -197,8 +234,8 @@ module.exports = function(config, specificOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
// on CI, ignore DEBUG statements
|
||||
if (process.env.CI && log.level.levelStr === config.LOG_DEBUG) {
|
||||
// on Travis, ignore DEBUG statements
|
||||
if (process.env.TRAVIS && log.level.levelStr === config.LOG_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var http = require('http');
|
||||
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
|
||||
|
||||
var HOSTNAME = 'localhost';
|
||||
var PORTS = [9876, 8000];
|
||||
var ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY;
|
||||
var READY_FILE = process.env.BROWSER_PROVIDER_READY_FILE;
|
||||
var TUNNEL_IDENTIFIER = process.env.TRAVIS_JOB_NUMBER;
|
||||
|
||||
// We need to start fake servers, otherwise the tunnel does not start.
|
||||
var fakeServers = [];
|
||||
var hosts = [];
|
||||
|
||||
PORTS.forEach(function(port) {
|
||||
fakeServers.push(http.createServer(function() {}).listen(port));
|
||||
hosts.push({
|
||||
name: HOSTNAME,
|
||||
port: port,
|
||||
sslFlag: 0
|
||||
});
|
||||
});
|
||||
|
||||
var tunnel = new BrowserStackTunnel({
|
||||
key: ACCESS_KEY,
|
||||
localIdentifier: TUNNEL_IDENTIFIER,
|
||||
hosts: hosts
|
||||
});
|
||||
|
||||
console.log('Starting tunnel on ports', PORTS.join(', '));
|
||||
tunnel.start(function(error) {
|
||||
if (error) {
|
||||
console.error('Can not establish the tunnel', error);
|
||||
} else {
|
||||
console.log('Tunnel established.');
|
||||
fakeServers.forEach(function(server) {
|
||||
server.close();
|
||||
});
|
||||
|
||||
if (READY_FILE) {
|
||||
fs.writeFile(READY_FILE, '');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tunnel.on('error', function(error) {
|
||||
console.error(error);
|
||||
});
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
|
||||
|
||||
node ./lib/browserstack/start_tunnel.js &
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user