Compare commits
290 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8f77817eb | |||
| 47bf11ee94 | |||
| b5aa42586e | |||
| cf16b241e1 | |||
| 757d56ea9c | |||
| f3624374e4 | |||
| fb04e424bb | |||
| 6a52c4f90c | |||
| ed30c4d0ea | |||
| 4032655100 | |||
| 47f8c65aca | |||
| 56b0ee3275 | |||
| 58cd897420 | |||
| c3769a6b5b | |||
| c140d89583 | |||
| 1a5b0517d0 | |||
| e29900c78f | |||
| 02545a8bab | |||
| 9bff2ce8fb | |||
| d463206d0a | |||
| ae8e903edf | |||
| 89c7794b21 | |||
| 8a941b8ea9 | |||
| 30a4424da2 | |||
| a6fa1ce76e | |||
| 63d613fccf | |||
| ed7d506b7d | |||
| 12df4d6a00 | |||
| 4267ad65a5 | |||
| 66ada20d1b | |||
| c7d68fa044 | |||
| 667ff87ab5 | |||
| b481a16576 | |||
| 6e052a4243 | |||
| 2e72ea13fa | |||
| 9b3b6f7f79 | |||
| e41f018959 | |||
| 71d19f120a | |||
| 8aa3389ed6 | |||
| bb480064b9 | |||
| 6b86a888cb | |||
| f17c7d8f66 | |||
| e7c105c592 | |||
| d0e7dc14bb | |||
| 0a746a2521 | |||
| 2f73f6a8c0 | |||
| e1ecd184c5 | |||
| abff650016 | |||
| b96a1de842 | |||
| b42ab51ad9 | |||
| 3dd42cea68 | |||
| 767381020d | |||
| c953af6b8c | |||
| a206e2675c | |||
| 9679e58ec4 | |||
| 26e13e5797 | |||
| 4428dd0c0f | |||
| a6a6c16195 | |||
| 744862ac31 | |||
| 3e62832680 | |||
| 83f084e5db | |||
| 046887048a | |||
| f9b5cbfcf7 | |||
| 0d14993d75 | |||
| 5541828ff4 | |||
| 4099279426 | |||
| 01ed44efd6 | |||
| 49655fac26 | |||
| 42abc8270a | |||
| d6ae0ee772 | |||
| 94dc1d0e6d | |||
| 2fab3d4e00 | |||
| 72fbd48f2a | |||
| e55d352e94 | |||
| 78ab691072 | |||
| 59b5651d82 | |||
| c8b7c16b78 | |||
| 05cf60677b | |||
| 2df43c0777 | |||
| 295213df95 | |||
| a31c207bf1 | |||
| 2518966153 | |||
| 7de25c8e41 | |||
| 566a552645 | |||
| 3c75a89906 | |||
| d9e68b157b | |||
| a0488b30a7 | |||
| 974700af7c | |||
| 9c810ebb2c | |||
| c4b79d59b4 | |||
| 43c3e5b11b | |||
| 8e941f42e4 | |||
| 418355f1cf | |||
| 94c288b125 | |||
| 123c5a0a3e | |||
| f6986f8e52 | |||
| ff963de73a | |||
| 2b28c540ad | |||
| 68701efb9e | |||
| c8a6e8450f | |||
| 0cd592f49f | |||
| a4daf1f767 | |||
| be6a6d80e0 | |||
| 36f17c9262 | |||
| ff5f782b20 | |||
| 27460db1db | |||
| add78e6200 | |||
| 060bcdeeb9 | |||
| 881167d7bd | |||
| 1147f0e213 | |||
| 825e25b095 | |||
| 10d1b19737 | |||
| c8d985a0f3 | |||
| 55075b840c | |||
| c8980099dc | |||
| e629fe4a78 | |||
| 6959bc297f | |||
| a1d15649ed | |||
| cbf35f04f3 | |||
| f768023698 | |||
| 587843bca0 | |||
| 94582f0def | |||
| fffe7d1979 | |||
| 005dd97255 | |||
| 9f7144b035 | |||
| 65f800e19e | |||
| 63796d3f98 | |||
| 2d8b34670b | |||
| fbc83f00c7 | |||
| 0633d8f2b0 | |||
| 7825772925 | |||
| c7671edbfd | |||
| 8b973e04ca | |||
| be45d3c208 | |||
| 53ff4487e7 | |||
| 7944b0c98f | |||
| 195756b45c | |||
| 940c1abf86 | |||
| 4584f0c37d | |||
| 7448d8748c | |||
| 915939396a | |||
| 1e8a3de15d | |||
| 2580bde8ac | |||
| 98d9143f0d | |||
| 9ae51d751b | |||
| 264819a308 | |||
| 5f1cf11e23 | |||
| 04ae4e5b47 | |||
| e7e8dad3b3 | |||
| 09f013ae92 | |||
| de0aad8984 | |||
| 3ea8c2b880 | |||
| a0c4e25a01 | |||
| fa8fe1f739 | |||
| 0637a2124c | |||
| d855b74095 | |||
| 0cdff42737 | |||
| a5a98d36c0 | |||
| 15d4dd3cca | |||
| ab36c4b487 | |||
| e77a74472a | |||
| 4a3ae43407 | |||
| dc90cbf6db | |||
| 622d32e805 | |||
| 2dfb6b4af6 | |||
| 318e6ceea3 | |||
| 4f2b2b61c5 | |||
| 67263f2bd0 | |||
| a48c47fec0 | |||
| b77f058505 | |||
| 1a14b58c6e | |||
| 362dd1786f | |||
| 736e299ef3 | |||
| 06d154f91c | |||
| ba4d903586 | |||
| 7240f31824 | |||
| c3f6123de9 | |||
| 4e372d9314 | |||
| 3df4ee421c | |||
| 258713a77d | |||
| 6e3bbfc744 | |||
| 09751be9bc | |||
| b4e409bf6c | |||
| 3e380325d8 | |||
| fd28edfc50 | |||
| 393072081c | |||
| 52ad819d2f | |||
| d86f6be57b | |||
| 100cf7245e | |||
| 0a5e58dacb | |||
| bb5a7e39ba | |||
| 33f801e7c2 | |||
| 26ddc5f830 | |||
| eb0ccc625f | |||
| e25f84296f | |||
| 8082d5eae0 | |||
| c42cadd4ed | |||
| 44cc823092 | |||
| f010d6c00f | |||
| a5537359c5 | |||
| 99ad41fa3f | |||
| 132344c867 | |||
| 321ee99647 | |||
| 9824c59dca | |||
| 506fe73a4a | |||
| 510404e5b3 | |||
| 937fb891fa | |||
| aecd551bde | |||
| 837e519acc | |||
| ad7ea95386 | |||
| fd4a284c85 | |||
| 79ca0f1e91 | |||
| 848c9b51f1 | |||
| 16b0692885 | |||
| af3b71ef46 | |||
| dedb10c0b8 | |||
| 88a12f8623 | |||
| ebeb1c9491 | |||
| 864c7f00c4 | |||
| 2907798ca5 | |||
| 8562a62197 | |||
| fdfba097da | |||
| a07191727d | |||
| c133ef8360 | |||
| aa7d45e804 | |||
| 6b915ad9db | |||
| a42f8a0d5b | |||
| 6b0193e4d9 | |||
| e500fb6ddb | |||
| 204f9ffebe | |||
| 7eee0c2c13 | |||
| 2dc83b2f04 | |||
| 3154111bb4 | |||
| 2f6f1a7d70 | |||
| ff60b3f47a | |||
| c2d0783ca9 | |||
| 6706353a71 | |||
| 24eeab0ebd | |||
| b14f67f4ae | |||
| 411e35472b | |||
| af59a0a00b | |||
| 1c380b7671 | |||
| 84fb041a89 | |||
| aee7d53a6b | |||
| bfdc9170f2 | |||
| 494277e3d3 | |||
| e4339bc512 | |||
| 0e26197623 | |||
| 74726b4f79 | |||
| 3ad07eadef | |||
| 7920f7140f | |||
| 66fdf2a8a7 | |||
| 26a5779cdd | |||
| a90d0cbbba | |||
| 9307ccf6ee | |||
| 2c7aa68ca8 | |||
| 840b5f0a76 | |||
| 6c224a2a60 | |||
| af1e6a38b7 | |||
| 5b11145473 | |||
| d7d64cc363 | |||
| 998d8b4b55 | |||
| 2472d621d7 | |||
| 83f7980e2f | |||
| c9a92fcad5 | |||
| f7b2fffa51 | |||
| 9a065c0fa9 | |||
| 42e622b751 | |||
| ad0ba99d8a | |||
| 05170bf371 | |||
| db584f7835 | |||
| 83d1229c87 | |||
| 60069e67ae | |||
| 84d80be2b4 | |||
| 03a4782a35 | |||
| 0ed36430da | |||
| aa6adc77ae | |||
| a7de87d3e8 | |||
| 1bb9aa0523 | |||
| 586b6e8b73 | |||
| 459997b482 | |||
| 8e104ee508 | |||
| 78b9f61366 | |||
| b9f19ad0d4 | |||
| 0b1adbb2e7 | |||
| 6a1d7dd7dc | |||
| 5262039096 | |||
| 96c4cb6694 | |||
| 9fe596422f | |||
| e22c5d3dba |
@@ -0,0 +1,509 @@
|
||||
# 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
|
||||
@@ -0,0 +1,73 @@
|
||||
####################################################################################################
|
||||
# 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;
|
||||
}
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/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
@@ -15,7 +15,7 @@
|
||||
// Stylistic issues
|
||||
"block-spacing": ["error", "always"],
|
||||
"comma-spacing": "error",
|
||||
"id-blacklist": ["error", "event"],
|
||||
"id-denylist": ["error", "event"],
|
||||
"indent": ["error", 2],
|
||||
"key-spacing": ["error", { "beforeColon": false, "afterColon": true, "mode": "minimum" }],
|
||||
"object-curly-spacing": ["error", "never"],
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
# 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
|
||||
-->
|
||||
@@ -9,8 +13,9 @@ IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOU
|
||||
|
||||
**I'm submitting a ...**
|
||||
<!-- (check one with "x") -->
|
||||
- [ ] bug report
|
||||
- [ ] feature request
|
||||
- [ ] regression from 1.7.0
|
||||
- [ ] security issue
|
||||
- [ ] issue caused by a new browser version
|
||||
- [ ] other <!--(Please do not submit support requests here - see above)-->
|
||||
|
||||
**Current behavior:**
|
||||
@@ -26,7 +31,7 @@ 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.x.y
|
||||
**AngularJS version:** 1.8.x
|
||||
<!-- Check whether this is still an issue in the most recent stable or in the snapshot AngularJS
|
||||
version (https://code.angularjs.org/snapshot/) -->
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<!-- General PR submission guidelines https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#submit-pr -->
|
||||
**What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)**
|
||||
# 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/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)**
|
||||
|
||||
+4
-1
@@ -1,5 +1,4 @@
|
||||
/build/
|
||||
/deploy/
|
||||
/benchpress-build/
|
||||
.DS_Store
|
||||
gen_docs.disable
|
||||
@@ -12,6 +11,7 @@ performance/temp*.html
|
||||
angular.js.tmproj
|
||||
node_modules/
|
||||
angular.xcodeproj
|
||||
.firebase/
|
||||
.idea
|
||||
*.iml
|
||||
.agignore
|
||||
@@ -22,3 +22,6 @@ 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
@@ -1,104 +0,0 @@
|
||||
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=unit-modules 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.10.1
|
||||
- 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"
|
||||
|
||||
@@ -1,3 +1,102 @@
|
||||
**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.**
|
||||
|
||||
<a name="1.8.3"></a>
|
||||
# 1.8.3 ultimate-farewell (2022-04-07)
|
||||
|
||||
One final release of AngularJS in order to update package README files on npm.
|
||||
|
||||
<a name="1.8.2"></a>
|
||||
# 1.8.2 meteoric-mining (2020-10-21)
|
||||
|
||||
## Bug Fixes
|
||||
- **$sceDelegate:** ensure that `resourceUrlWhitelist()` is identical to `trustedResourceUrlList()`
|
||||
([e41f01](https://github.com/angular/angular.js/commit/e41f018959934bfbf982ba996cd654b1fce88d43),
|
||||
[#17090](https://github.com/angular/angular.js/issues/17090))
|
||||
|
||||
|
||||
<a name="1.8.1"></a>
|
||||
# 1.8.1 mutually-supporting (2020-09-30)
|
||||
|
||||
## Bug Fixes
|
||||
- **$sanitize:** do not trigger CSP alert/report in Firefox and Chrome
|
||||
([2fab3d](https://github.com/angular/angular.js/commit/2fab3d4e00f4fe35bfa3cf255160cb97404baf24))
|
||||
|
||||
## Refactorings
|
||||
|
||||
- **SanitizeUriProvider:** remove usages of whitelist
|
||||
([76738102](https://github.com/angular/angular.js/commit/767381020d88bda2855ac87ca6f00748907e14ff))
|
||||
- **httpProvider:** remove usages of whitelist and blacklist
|
||||
([c953af6b](https://github.com/angular/angular.js/commit/c953af6b8cfeefe4acc0ca358550eed5da8cfe00))
|
||||
- **sceDelegateProvider:** remove usages of whitelist and blacklist
|
||||
([a206e267](https://github.com/angular/angular.js/commit/a206e2675c351c3cdcde3402978126774c1c5df9))
|
||||
|
||||
## Deprecation Notices
|
||||
|
||||
- Deprecated ~~`$compileProvider.aHrefSanitizationWhitelist`~~.
|
||||
It is now [`aHrefSanitizationTrustedUrlList`](https://docs.angularjs.org/api/ng/provider/$compileProvider#aHrefSanitizationTrustedUrlList).
|
||||
- Deprecated ~~`$compileProvider.imgSrcSanitizationWhitelist`~~.
|
||||
It is now [`imgSrcSanitizationTrustedUrlList`](https://docs.angularjs.org/api/ng/provider/$compileProvider#imgSrcSanitizationTrustedUrlList).
|
||||
- Deprecated ~~`$httpProvider.xsrfWhitelistedOrigins`~~.
|
||||
It is now [`xsrfTrustedOrigins`](https://docs.angularjs.org/api/ng/provider/$httpProvider#xsrfTrustedOrigins).
|
||||
- Deprecated ~~`$sceDelegateProvider.resourceUrlWhitelist`~~.
|
||||
It is now [`trustedResourceUrlList`](https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider#trustedResourceUrlList).
|
||||
- Deprecated ~~`$sceDelegateProvider.resourceUrlBlacklist`~~.
|
||||
It is now [`bannedResourceUrlList`](https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider#bannedResourceUrlList).
|
||||
|
||||
For the purposes of backward compatibility, the previous symbols are aliased to their new symbol.
|
||||
|
||||
|
||||
<a name="1.8.0"></a>
|
||||
# 1.8.0 nested-vaccination (2020-06-01)
|
||||
|
||||
_This release contains a breaking change to resolve a security issue which was discovered by
|
||||
Krzysztof Kotowicz(@koto); and independently by Esben Sparre Andreasen (@esbena) while
|
||||
performing a Variant Analysis of [CVE-2020-11022](https://github.com/advisories/GHSA-gxr4-xjj5-5px2)
|
||||
which itself was found and reported by Masato Kinugawa (@masatokinugawa)._
|
||||
|
||||
## Bug Fixes
|
||||
- **jqLite:**
|
||||
- prevent possible XSS due to regex-based HTML replacement
|
||||
([2df43c](https://github.com/angular/angular.js/commit/2df43c07779137d1bddf7f3b282a1287a8634acd))
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
### **jqLite** due to:
|
||||
- **[2df43c](https://github.com/angular/angular.js/commit/2df43c07779137d1bddf7f3b282a1287a8634acd)**: prevent possible XSS due to regex-based HTML replacement
|
||||
|
||||
JqLite no longer turns XHTML-like strings like `<div /><span />` to sibling elements `<div></div><span></span>`
|
||||
when not in XHTML mode. Instead it will leave them as-is. The browser, in non-XHTML mode, will convert these to:
|
||||
`<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.
|
||||
|
||||
|
||||
<a name="1.7.9"></a>
|
||||
# 1.7.9 pollution-eradication (2019-11-19)
|
||||
|
||||
## Bug Fixes
|
||||
- **angular.merge:** do not merge __proto__ property
|
||||
([726f49](https://github.com/angular/angular.js/commit/726f49dcf6c23106ddaf5cfd5e2e592841db743a))
|
||||
<br>(Thanks to the [Snyk Security Research Team](https://snyk.io/blog/snyk-research-team-discovers-severe-prototype-pollution-security-vulnerabilities-affecting-all-versions-of-lodash/) for identifyng this issue.)
|
||||
- **ngStyle:** correctly remove old style when new style value is invalid
|
||||
([5edd25](https://github.com/angular/angular.js/commit/5edd25364f617083363dc2bd61f9230b38267578),
|
||||
[#16860](https://github.com/angular/angular.js/issues/16860),
|
||||
[#16868](https://github.com/angular/angular.js/issues/16868))
|
||||
|
||||
|
||||
<a name="1.7.8"></a>
|
||||
# 1.7.8 enthusiastic-oblation (2019-03-11)
|
||||
|
||||
|
||||
+5
-5
@@ -125,8 +125,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 Travis integration will
|
||||
run the tests on all supported browsers.
|
||||
pass. It is generally sufficient to run the tests only on Chrome, as our continuous integration test will
|
||||
run the tests on additional 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 +151,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 Travis integration.
|
||||
[Contributor License Agreement](#cla) and the continuous integration tests.
|
||||
|
||||
* If you find that the Travis integration has failed, look into the logs on Travis to find out
|
||||
* If you find that the continuous integration tests have failed, look into the logs 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.
|
||||
@@ -172,7 +172,7 @@ restarted.
|
||||
git push origin my-fix-branch -f
|
||||
```
|
||||
|
||||
This is generally easier to follow, but seperate commits are useful if the Pull Request contains
|
||||
This is generally easier to follow, but separate 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!
|
||||
|
||||
+2
-3
@@ -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 100 characters! This allows the message to be easier
|
||||
Any line of the commit message cannot be longer than 100 characters! This allows the message to be easier
|
||||
to read on GitHub as well as in various git tools.
|
||||
|
||||
### Revert
|
||||
@@ -257,7 +257,6 @@ 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:
|
||||
@@ -429,7 +428,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
|
||||
automated Travis tests.
|
||||
continuous integration 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,
|
||||
|
||||
+18
-39
@@ -14,7 +14,8 @@ var semver = require('semver');
|
||||
var exec = require('shelljs').exec;
|
||||
var pkg = require(__dirname + '/package.json');
|
||||
|
||||
var docsScriptFolder = 'scripts/docs.angularjs.org-firebase';
|
||||
var codeScriptFolder = util.codeScriptFolder;
|
||||
var docsScriptFolder = util.docsScriptFolder;
|
||||
|
||||
// Node.js version checks
|
||||
if (!semver.satisfies(process.version, pkg.engines.node)) {
|
||||
@@ -45,7 +46,7 @@ if (!match) {
|
||||
}
|
||||
|
||||
// Ensure Node.js dependencies have been installed
|
||||
if (!process.env.TRAVIS && !process.env.JENKINS_HOME) {
|
||||
if (!process.env.CI) {
|
||||
var yarnOutput = exec('yarn install');
|
||||
if (yarnOutput.code !== 0) {
|
||||
throw new Error('Yarn install failed: ' + yarnOutput.stderr);
|
||||
@@ -109,16 +110,14 @@ module.exports = function(grunt) {
|
||||
},
|
||||
testserver: {
|
||||
options: {
|
||||
// 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
|
||||
// We start the webserver as a separate process from the E2E tests
|
||||
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 on travis
|
||||
// cache GET requests to speed up tests
|
||||
if (req.method === 'GET') {
|
||||
resp.setHeader('Cache-control', 'public, max-age=3600');
|
||||
}
|
||||
@@ -160,8 +159,7 @@ module.exports = function(grunt) {
|
||||
|
||||
protractor: {
|
||||
normal: 'protractor-conf.js',
|
||||
travis: 'protractor-travis-conf.js',
|
||||
jenkins: 'protractor-jenkins-conf.js'
|
||||
circleci: 'protractor-circleci-conf.js'
|
||||
},
|
||||
|
||||
|
||||
@@ -169,9 +167,9 @@ module.exports = function(grunt) {
|
||||
build: ['build'],
|
||||
tmp: ['tmp'],
|
||||
deploy: [
|
||||
'deploy/docs',
|
||||
'deploy/code',
|
||||
docsScriptFolder + '/functions/html'
|
||||
codeScriptFolder + '/deploy',
|
||||
docsScriptFolder + '/deploy',
|
||||
docsScriptFolder + '/functions/content'
|
||||
]
|
||||
},
|
||||
|
||||
@@ -372,11 +370,10 @@ module.exports = function(grunt) {
|
||||
},
|
||||
deployFirebaseCode: {
|
||||
files: [
|
||||
// copy files that are not handled by compress
|
||||
{
|
||||
cwd: 'build',
|
||||
src: '**/*.{zip,jpg,jpeg,png}',
|
||||
dest: 'deploy/code/' + deployVersion + '/',
|
||||
src: '**',
|
||||
dest: codeScriptFolder + '/deploy/' + deployVersion + '/',
|
||||
expand: true
|
||||
}
|
||||
]
|
||||
@@ -386,19 +383,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: 'deploy/docs/',
|
||||
dest: docsScriptFolder + '/deploy/',
|
||||
expand: true,
|
||||
flatten: true
|
||||
},
|
||||
{
|
||||
cwd: 'build/docs',
|
||||
src: ['**', '!ptore2e/**', '!index*.html'],
|
||||
dest: 'deploy/docs/',
|
||||
dest: docsScriptFolder + '/deploy/',
|
||||
expand: true
|
||||
},
|
||||
{
|
||||
src: 'build/docs/index-production.html',
|
||||
dest: 'deploy/docs/index.html'
|
||||
dest: docsScriptFolder + '/deploy/index.html'
|
||||
},
|
||||
{
|
||||
src: 'build/docs/index-production.html',
|
||||
@@ -407,7 +404,7 @@ module.exports = function(grunt) {
|
||||
{
|
||||
cwd: 'build/docs',
|
||||
src: 'partials/**',
|
||||
dest: docsScriptFolder + '/functions/content',
|
||||
dest: docsScriptFolder + '/functions/content/',
|
||||
expand: true
|
||||
}
|
||||
]
|
||||
@@ -423,16 +420,6 @@ 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 + '/'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -498,14 +485,9 @@ module.exports = function(grunt) {
|
||||
'connect:testserver',
|
||||
'protractor:normal'
|
||||
]);
|
||||
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', [
|
||||
grunt.registerTask('test:circleci-protractor', 'Run the end to end tests with Protractor for CircleCI builds', [
|
||||
'connect:testserver',
|
||||
'protractor:travis'
|
||||
]);
|
||||
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', [
|
||||
'webdriver',
|
||||
'connect:testserver',
|
||||
'protractor:jenkins'
|
||||
'protractor:circleci'
|
||||
]);
|
||||
grunt.registerTask('test:e2e', 'Alias for test:protractor', ['test:protractor']);
|
||||
grunt.registerTask('test:promises-aplus',[
|
||||
@@ -535,10 +517,7 @@ module.exports = function(grunt) {
|
||||
'eslint'
|
||||
]);
|
||||
grunt.registerTask('prepareDeploy', [
|
||||
'package',
|
||||
'compress:deployFirebaseCode',
|
||||
'copy:deployFirebaseCode',
|
||||
'firebaseDocsJsonForTravis',
|
||||
'copy:deployFirebaseDocs'
|
||||
]);
|
||||
grunt.registerTask('default', ['package']);
|
||||
@@ -546,7 +525,7 @@ module.exports = function(grunt) {
|
||||
|
||||
|
||||
function reportOrFail(message) {
|
||||
if (process.env.TRAVIS || process.env.JENKINS_HOME) {
|
||||
if (process.env.CI) {
|
||||
throw new Error(message);
|
||||
} else {
|
||||
console.log('===============================================================================');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2010-2018 Google, Inc. http://angularjs.org
|
||||
Copyright (c) 2010-2020 Google LLC. 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://travis-ci.org/angular/angular.js)
|
||||
AngularJS [](https://circleci.com/gh/angular/workflows/angular.js/tree/master)
|
||||
=========
|
||||
|
||||
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
|
||||
@@ -14,9 +14,11 @@ piece of cake. Best of all? It makes development fun!
|
||||
|
||||
--------------------
|
||||
|
||||
**On July 1, 2018 AngularJS entered a 3 year Long Term Support period:** [Find out more](https://docs.angularjs.org/misc/version-support-status)
|
||||
**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).**
|
||||
|
||||
**Looking for the new Angular? Go here:** https://github.com/angular/angular
|
||||
**Visit [angular.io](https://angular.io) for the actively supported Angular.**
|
||||
|
||||
--------------------
|
||||
|
||||
@@ -55,11 +57,12 @@ 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, 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](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
|
||||
_Whatever_ is AngularJS's way of telling that you may create any kind of linking between the Model
|
||||
and the View here.
|
||||
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@ Usually this will be the commit containing the release notes, but it may also be
|
||||
## Run "release" script
|
||||
|
||||
```bash
|
||||
scripts/jenkins/release.sh --git-push-dryrun=false --commit-sha=8822a4f --version-number=1.7.6 --version-name=gravity-manipulation
|
||||
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).
|
||||
@@ -67,10 +67,10 @@ If we want to make our files available, we need submit our CLs before this time
|
||||
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 Travis job)
|
||||
## 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 Travis deploy stage: https://github.com/angular/angularjs.org/blob/a4d25c5abcd39e8ce19d31cb1c78073d13c4c974/.travis.yml#L26
|
||||
(You may need to explicitly trigger the Travis job. e.g. re-running the last 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)
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# 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 | |
|
||||
@@ -478,10 +478,10 @@ iframe.example {
|
||||
#navbar-sub {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
background: rgba(245,245,245,0.88);
|
||||
background: rgba(245,245,245,1);
|
||||
box-shadow: 0 0 2px #999;
|
||||
z-index: 1028;
|
||||
top: 83px;
|
||||
top: 57px;
|
||||
}
|
||||
|
||||
.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: 17px;
|
||||
top: 0;
|
||||
margin-top: 80px;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
|
||||
@@ -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 choses to bypass pop-up blocker one time and click the link, they will arrive at
|
||||
* If a user chooses 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 Inc. All Rights Reserved.\n'
|
||||
var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google LLC. 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*/';
|
||||
|
||||
@@ -47,13 +47,13 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
|
||||
}
|
||||
|
||||
areasToSearch = _.indexBy(this.areasToSearch);
|
||||
propertiesToIgnore = _.indexBy(this.propertiesToIgnore);
|
||||
areasToSearch = _.keyBy(this.areasToSearch);
|
||||
propertiesToIgnore = _.keyBy(this.propertiesToIgnore);
|
||||
log.debug('Properties to ignore', propertiesToIgnore);
|
||||
docTypesToIgnore = _.indexBy(this.docTypesToIgnore);
|
||||
docTypesToIgnore = _.keyBy(this.docTypesToIgnore);
|
||||
log.debug('Doc types to ignore', docTypesToIgnore);
|
||||
|
||||
var ignoreWordsMap = _.indexBy(wordsToIgnore);
|
||||
var ignoreWordsMap = _.keyBy(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']);
|
||||
})
|
||||
.indexBy('path')
|
||||
.keyBy('path')
|
||||
.value();
|
||||
|
||||
docs.push({
|
||||
|
||||
@@ -13,11 +13,11 @@ module.exports = function generateVersionDocProcessor(gitData) {
|
||||
return {
|
||||
$runAfter: ['generatePagesDataProcessor'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
// 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'],
|
||||
// Remove rogue builds that are in the npm repository but not on code.angularjs.org
|
||||
ignoredBuilds: ['1.3.4-build.3588'],
|
||||
$process: function(docs) {
|
||||
|
||||
var blacklist = this.blacklist;
|
||||
var ignoredBuilds = this.ignoredBuilds;
|
||||
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 blacklist.indexOf(versionStr) === -1;
|
||||
return ignoredBuilds.indexOf(versionStr) === -1;
|
||||
})
|
||||
.map(function(versionStr) {
|
||||
return semver.parse(versionStr);
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
{# 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>
|
||||
@@ -24,50 +33,27 @@
|
||||
})();
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// 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.
|
||||
// Dynamically add `<base>` tag.
|
||||
(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],
|
||||
sync = true;
|
||||
baseEl = document.createElement('base');
|
||||
|
||||
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);
|
||||
}
|
||||
baseEl.setAttribute('href', baseUrl);
|
||||
headEl.appendChild(baseEl);
|
||||
})();
|
||||
</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']);
|
||||
@@ -156,21 +142,18 @@
|
||||
</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>
|
||||
@@ -222,7 +205,7 @@
|
||||
<p class="pull-right"><a back-to-top>Back to top</a></p>
|
||||
|
||||
<p>
|
||||
Super-powered by Google ©2010-2018
|
||||
Super-powered by Google ©2010-2020
|
||||
(<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">
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
@description
|
||||
|
||||
# AngularJS API Docs
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**On July 1, 2018 AngularJS entered a 3 year Long Term Support period:** [Find out more](misc/version-support-status).
|
||||
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>
|
||||
|
||||
## Welcome to the AngularJS API docs page.
|
||||
|
||||
@@ -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 assigment is not a valid reference to a variable
|
||||
This can happen if the left side of an assignment 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#resourceUrlWhitelist
|
||||
$sceDelegateProvider.resourceUrlWhitelist} and {@link
|
||||
$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} for the
|
||||
Please see {@link $sceDelegateProvider#trustedResourceUrlList
|
||||
$sceDelegateProvider.trustedResourceUrlList} and {@link
|
||||
$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList} 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#resourceUrlWhitelist whitelist}/ {@link
|
||||
ng.$sceDelegateProvider#resourceUrlBlacklist blacklist} or wrap the URL with a call to {@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.$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#resourceUrlWhitelist
|
||||
$sceDelegateProvider.resourceUrlWhitelist} and {@link
|
||||
$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} may not
|
||||
The strings in {@link $sceDelegateProvider#trustedResourceUrlList
|
||||
$sceDelegateProvider.trustedResourceUrlList} and {@link
|
||||
$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList} may not
|
||||
contain the undefined sequence `***`. Only `*` and `**` wildcard patterns are defined.
|
||||
|
||||
@@ -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
|
||||
a node blacklist:
|
||||
the list of built in aria nodes:
|
||||
|
||||
* Button
|
||||
* Anchor
|
||||
@@ -337,7 +337,8 @@ a node blacklist:
|
||||
* 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 the node blacklist.
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -17,9 +17,8 @@ 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 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).
|
||||
integration server runs all unit tests against IE9, IE10, and IE11. See
|
||||
[CircleCI](https://circleci.com/gh/angular/workflows/angular.js/tree/master).
|
||||
|
||||
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.
|
||||
|
||||
@@ -15,6 +15,30 @@ 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
|
||||
|
||||
@@ -252,15 +276,16 @@ statement.
|
||||
**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` whitelisting for the
|
||||
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 whitelisting them in
|
||||
`$compileProvider`'s `aHrefSanitizationWhitelist` (for `<a>` elements) or
|
||||
`imgSrcSanitizationWhitelist` (for `<image>` elements).
|
||||
`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 />
|
||||
|
||||
@@ -577,7 +602,7 @@ orderByFilter(['a', undefined, 'o', null, 'z']);
|
||||
|
||||
|
||||
<a name="migrate1.6to1.7-ng-misc"></a>
|
||||
### Core: _Misceallenous_
|
||||
### Core: _Miscellaneous_
|
||||
|
||||
|
||||
#### **jqLite**
|
||||
@@ -1285,7 +1310,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
|
||||
whitelist them or wrap them into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
|
||||
add them to the trusted source URL list or wrap them into a trusted value by calling `$sce.trustAsResourceUrl(url)`.
|
||||
|
||||
<hr />
|
||||
<minor />
|
||||
@@ -1363,7 +1388,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. **Whitelisting with the `$sceDelegateProvider.resourceUrlWhitelist()` method.**
|
||||
1. **Setting trusted resource URLs with the `$sceDelegateProvider.resourceUrlWhitelist()` (called `trustedResourceUrlList()` from 1.8.1 onwards) method.**
|
||||
You configure this list in a module configuration block:
|
||||
|
||||
```js
|
||||
@@ -2183,7 +2208,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 blacklisted, a sanitized `usemap` attribute could only
|
||||
`name` and `id` attributes are already banned, 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),
|
||||
@@ -2623,8 +2648,8 @@ $scope.findTemplate = function(templateName) {
|
||||
};
|
||||
```
|
||||
|
||||
To migrate, either cache the result of `trustAsResourceUrl()`, or put the template url in the resource
|
||||
whitelist in the `config()` function:
|
||||
To migrate, either cache the result of `trustAsResourceUrl()`, or put the template url in the trusted resource
|
||||
URL list in the `config()` function:
|
||||
|
||||
After:
|
||||
|
||||
@@ -2638,7 +2663,8 @@ $scope.findTemplate = function(templateName) {
|
||||
return templateCache[templateName];
|
||||
};
|
||||
|
||||
// Alternatively, use `$sceDelegateProvider.resourceUrlWhitelist()`, which means you don't
|
||||
// Alternatively, use `$sceDelegateProvider.resourceUrlWhitelist()` (called
|
||||
// `trustedResourceUrlList()` from 1.8.1 onwards), which means you don't
|
||||
// have to use `$sce.trustAsResourceUrl()` at all:
|
||||
|
||||
angular.module('myApp', []).config(function($sceDelegateProvider) {
|
||||
@@ -3329,7 +3355,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-whitelist URLs are now sanitized against a whitelist}</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#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>
|
||||
@@ -3819,10 +3845,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 whitelist
|
||||
### URLs are now sanitized against a trusted URI matcher
|
||||
|
||||
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/*`.
|
||||
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/*`.
|
||||
This change shouldn't impact apps that don't contain malicious image links.
|
||||
|
||||
See [1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d61286840177607edd552a9df97),
|
||||
|
||||
@@ -174,8 +174,9 @@ 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}.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
### What is testability like in AngularJS?
|
||||
|
||||
@@ -4,44 +4,25 @@
|
||||
|
||||
# Version Support Status
|
||||
|
||||
This page describes the support status of the significant versions of AngularJS.
|
||||
**AngularJS support has officially ended as of January 2022.**
|
||||
|
||||
<div class="alert alert-info">
|
||||
On July 1, 2018 AngularJS entered a 3 year Long Term Support period.
|
||||
</div>
|
||||
Visit [angular.io](https://angular.io) for the actively supported Angular.
|
||||
|
||||
Any version branch not shown in the following table (e.g. 1.6.x) is no longer being developed.
|
||||
## What does end of support mean?
|
||||
|
||||
<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.7.x</span></td>
|
||||
<td>Long Term Support</td>
|
||||
<td>See {@link version-support-status#long-term-support Long Term Support} section below.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
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.
|
||||
|
||||
### Long Term Support
|
||||
The GitHub repository will be in an archived state, meaning that no new issues or pull requests
|
||||
can be submitted.
|
||||
|
||||
On July 1st 2018, AngularJS entered a Long Term Support period for AngularJS.
|
||||
See https://goo.gle/angularjs-end-of-life for the full details.
|
||||
|
||||
We now focus exclusively on providing fixes to bugs that satisfy at least one of the following criteria:
|
||||
### Extended Long Term Support
|
||||
|
||||
* 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.
|
||||
If you need extended support for AngularJS, you should consider:
|
||||
|
||||
AngularJS 1.2.x will get a new version if and only if a new severe security issue is discovered.
|
||||
|
||||
### 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).
|
||||
* [HeroDevs](https://www.herodevs.com/support/nes-angularjs)
|
||||
|
||||
@@ -34,16 +34,16 @@ Since we are using [npm][npm] to install client-side dependencies, this step upd
|
||||
"name": "angular-phonecat",
|
||||
...
|
||||
"dependencies": {
|
||||
"angular": "1.7.x",
|
||||
"angular-route": "1.7.x",
|
||||
"angular": "1.8.x",
|
||||
"angular-route": "1.8.x",
|
||||
"bootstrap": "3.3.x"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The new dependency `"angular-route": "1.7.x"` tells npm to install a version of the angular-route
|
||||
module that is compatible with version 1.7.x of AngularJS. We must tell npm to download and install
|
||||
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
|
||||
this dependency.
|
||||
|
||||
```
|
||||
|
||||
@@ -32,17 +32,17 @@ Since we are using [npm][npm] to install client-side dependencies, this step upd
|
||||
"name": "angular-phonecat",
|
||||
...
|
||||
"dependencies": {
|
||||
"angular": "1.7.x",
|
||||
"angular-resource": "1.7.x",
|
||||
"angular-route": "1.7.x",
|
||||
"angular": "1.8.x",
|
||||
"angular-resource": "1.8.x",
|
||||
"angular-route": "1.8.x",
|
||||
"bootstrap": "3.3.x"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The new dependency `"angular-resource": "1.7.x"` tells npm to install a version of the
|
||||
angular-resource module that is compatible with version 1.7.x of AngularJS. We must tell npm to
|
||||
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
|
||||
download and install this dependency.
|
||||
|
||||
```
|
||||
|
||||
@@ -36,20 +36,20 @@ Since we are using [npm][npm] to install client-side dependencies, this step upd
|
||||
"name": "angular-phonecat",
|
||||
...
|
||||
"dependencies": {
|
||||
"angular": "1.7.x",
|
||||
"angular-animate": "1.7.x",
|
||||
"angular-resource": "1.7.x",
|
||||
"angular-route": "1.7.x",
|
||||
"angular": "1.8.x",
|
||||
"angular-animate": "1.8.x",
|
||||
"angular-resource": "1.8.x",
|
||||
"angular-route": "1.8.x",
|
||||
"bootstrap": "3.3.x",
|
||||
"jquery": "3.3.x"
|
||||
"jquery": "^3.5.1"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
* `"angular-animate": "1.7.x"` tells npm to install a version of the angular-animate module that
|
||||
is compatible with version 1.7.x of AngularJS.
|
||||
* `"jquery": "3.3.x"` tells npm to install the latest patch release of the 3.3 version of jQuery.
|
||||
* `"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
|
||||
install a wide range of 3rd party libraries.
|
||||
|
||||
|
||||
+3
-36
@@ -169,42 +169,9 @@ 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;
|
||||
|
||||
// Try 'websocket' for a faster transmission first. Fallback to 'polling' if necessary.
|
||||
config.transports = ['websocket', 'polling'];
|
||||
|
||||
// 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 Travis), we log them into a file instead.
|
||||
// - ignore DEBUG logs (on CI), we log them into a file instead.
|
||||
var IGNORED_404 = [
|
||||
'/favicon.ico',
|
||||
'/%7B%7BtestUrl%7D%7D',
|
||||
@@ -230,8 +197,8 @@ module.exports = function(config, specificOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
// on Travis, ignore DEBUG statements
|
||||
if (process.env.TRAVIS && log.level.levelStr === config.LOG_DEBUG) {
|
||||
// on CI, ignore DEBUG statements
|
||||
if (process.env.CI && log.level.levelStr === config.LOG_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
'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);
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
|
||||
|
||||
node ./lib/browserstack/start_tunnel.js &
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
|
||||
echo "Shutting down Browserstack tunnel"
|
||||
echo "TODO: implement me"
|
||||
exit 1
|
||||
@@ -63,8 +63,8 @@ module.exports = function(grunt) {
|
||||
util.collectErrors();
|
||||
});
|
||||
|
||||
grunt.registerTask('firebaseDocsJsonForTravis', function() {
|
||||
util.firebaseDocsJsonForTravis();
|
||||
grunt.registerTask('firebaseDocsJsonForCI', function() {
|
||||
util.firebaseDocsJsonForCI();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
+8
-18
@@ -7,9 +7,12 @@ var spawn = require('npm-run').spawn;
|
||||
|
||||
var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP mode. */\n\n';
|
||||
|
||||
|
||||
module.exports = {
|
||||
|
||||
codeScriptFolder: 'scripts/code.angularjs.org-firebase',
|
||||
|
||||
docsScriptFolder: 'scripts/docs.angularjs.org-firebase',
|
||||
|
||||
startKarma: function(config, singleRun, done) {
|
||||
var browsers = grunt.option('browsers');
|
||||
var reporters = grunt.option('reporters');
|
||||
@@ -32,8 +35,8 @@ module.exports = {
|
||||
|
||||
|
||||
updateWebdriver: function(done) {
|
||||
if (process.env.TRAVIS) {
|
||||
// Skip the webdriver-manager update on Travis, since the browsers will
|
||||
if (process.env.CI) {
|
||||
// Skip the webdriver-manager update on CI, since the browsers will
|
||||
// be provided remotely.
|
||||
done();
|
||||
return;
|
||||
@@ -110,7 +113,7 @@ module.exports = {
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/'/g, '\\\'')
|
||||
.replace(/\r?\n/g, '\\n');
|
||||
js = '!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend(\'<style type="text/css">' + css + '</style>\');';
|
||||
js = '!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend(window.angular.element(\'<style>\').text(\'' + css + '\'));';
|
||||
state.js.push(js);
|
||||
|
||||
return state;
|
||||
@@ -300,19 +303,6 @@ module.exports = {
|
||||
}
|
||||
next();
|
||||
};
|
||||
},
|
||||
|
||||
// Our Firebase projects are in subfolders, but Travis expects them in the root,
|
||||
// so we need to modify the upload folder path and copy the file into the root
|
||||
firebaseDocsJsonForTravis: function() {
|
||||
var docsScriptFolder = 'scripts/docs.angularjs.org-firebase';
|
||||
|
||||
var fileName = docsScriptFolder + '/firebase.json';
|
||||
var json = grunt.file.readJSON(fileName);
|
||||
|
||||
(json.hosting || (json.hosting = {})).public = 'deploy/docs';
|
||||
(json.functions || (json.functions = {})).source = docsScriptFolder + '/functions';
|
||||
|
||||
grunt.file.write('firebase.json', JSON.stringify(json));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Executable
+459
@@ -0,0 +1,459 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -u -e -o pipefail
|
||||
|
||||
####################################################################################################
|
||||
# Some helper funtions
|
||||
|
||||
@echo() {
|
||||
echo "# $*"
|
||||
}
|
||||
|
||||
@warn() {
|
||||
@echo "Warning: $*" >&2
|
||||
}
|
||||
|
||||
@fail() {
|
||||
@echo "Error! $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
@remove() {
|
||||
local f="$1"
|
||||
if [[ -f ${f} ]]; then
|
||||
@echo "Removing ${f}"
|
||||
rm -f "${f}" || @fail "Can not delete ${f} file"
|
||||
fi
|
||||
}
|
||||
|
||||
@kill() {
|
||||
for p in $1; do
|
||||
if kill -0 ${p} >/dev/null 2>&1; then
|
||||
kill ${p}
|
||||
sleep 2
|
||||
if kill -0 ${p} >/dev/null 2>&1; then
|
||||
kill -9 ${p}
|
||||
sleep 2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@wait_for() {
|
||||
local m="$1"
|
||||
local f="$2"
|
||||
if [[ ! -f "${f}" ]]; then
|
||||
printf "# ${m} (${f})"
|
||||
while [[ ! -f "${f}" ]]; do
|
||||
printf "."
|
||||
sleep 0.5
|
||||
done
|
||||
printf "\n"
|
||||
fi
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
# Sauce service functions
|
||||
|
||||
readonly SCRIPT_DIR=$(cd $(dirname $0); pwd)
|
||||
readonly TMP_DIR="/tmp/angular/sauce-service"
|
||||
mkdir -p ${TMP_DIR}
|
||||
|
||||
# Location for the saucelabs log file.
|
||||
readonly SAUCE_LOG_FILE="${TMP_DIR}/sauce-connect.log"
|
||||
|
||||
# Location for the saucelabs ready to connection process id lock file.
|
||||
readonly SAUCE_PID_FILE="${TMP_DIR}/sauce-connect.pid"
|
||||
|
||||
# Location for the saucelabs ready to connect lock file.
|
||||
readonly SAUCE_READY_FILE="${TMP_DIR}/sauce-connect.lock"
|
||||
|
||||
# Location for the saucelabs params file for use by test runner.
|
||||
readonly SAUCE_PARAMS_JSON_FILE="${TMP_DIR}/sauce-connect-params.json"
|
||||
|
||||
# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not
|
||||
# acquire CircleCI instances for too long if sauceconnect fails, we need a connect timeout.
|
||||
readonly SAUCE_READY_FILE_TIMEOUT=120
|
||||
|
||||
readonly SERVICE_LOCK_FILE="${TMP_DIR}/service.lock"
|
||||
readonly SERVICE_START_FILE="${TMP_DIR}/service.start"
|
||||
readonly SERVICE_PID_FILE="${TMP_DIR}/service.pid"
|
||||
readonly SERVICE_LOG_FILE="${TMP_DIR}/service.log"
|
||||
|
||||
service-setup-command() {
|
||||
if [[ -z "${SAUCE_USERNAME:-}" ]]; then
|
||||
@fail "SAUCE_USERNAME environment variable required"
|
||||
fi
|
||||
|
||||
if [[ -z "${SAUCE_ACCESS_KEY:-}" ]]; then
|
||||
@fail "SAUCE_ACCESS_KEY environment variable required"
|
||||
fi
|
||||
|
||||
if [[ -z "${SAUCE_TUNNEL_IDENTIFIER:-}" ]]; then
|
||||
@fail "SAUCE_TUNNEL_IDENTIFIER environment variable required"
|
||||
fi
|
||||
|
||||
local unameOut="$(uname -s)"
|
||||
case "${unameOut}" in
|
||||
Linux*) local machine=linux ;;
|
||||
Darwin*) local machine=darwin ;;
|
||||
CYGWIN*) local machine=windows ;;
|
||||
MINGW*) local machine=windows ;;
|
||||
MSYS_NT*) local machine=windows ;;
|
||||
*) local machine=linux
|
||||
printf "\nUnrecongized uname '${unameOut}'; defaulting to use node for linux.\n" >&2
|
||||
printf "Please file an issue to https://github.com/bazelbuild/rules_nodejs/issues if \n" >&2
|
||||
printf "you would like to add your platform to the supported rules_nodejs node platforms.\n\n" >&2
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${machine}" in
|
||||
# Path to sauce connect executable
|
||||
linux)
|
||||
if [[ -z "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then
|
||||
# Started manually
|
||||
SAUCE_CONNECT="${SCRIPT_DIR}/../../node_modules/sauce-connect/bin/sc"
|
||||
else
|
||||
# Started via `bazel run`
|
||||
SAUCE_CONNECT="${BUILD_WORKSPACE_DIRECTORY}/node_modules/sauce-connect/bin/sc"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if [[ -z "${SAUCE_CONNECT:-}" ]]; then
|
||||
@fail "SAUCE_CONNECT environment variable is required on non-linux environments"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ ! -f ${SAUCE_CONNECT} ]]; then
|
||||
@fail "sc binary not found at ${SAUCE_CONNECT}"
|
||||
fi
|
||||
|
||||
echo "{ \"SAUCE_USERNAME\": \"${SAUCE_USERNAME}\", \"SAUCE_ACCESS_KEY\": \"${SAUCE_ACCESS_KEY}\", \"SAUCE_TUNNEL_IDENTIFIER\": \"${SAUCE_TUNNEL_IDENTIFIER}\", \"SAUCE_LOCALHOST_ALIAS_DOMAIN\": \"${SAUCE_LOCALHOST_ALIAS_DOMAIN:-}\" }" > ${SAUCE_PARAMS_JSON_FILE}
|
||||
|
||||
# Command arguments that will be passed to sauce-connect.
|
||||
# By default we disable SSL bumping for all requests. This is because SSL bumping is
|
||||
# not needed for our test setup and in order to perform the SSL bumping, Saucelabs
|
||||
# intercepts all HTTP requests in the tunnel VM and modifies them. This can cause
|
||||
# flakiness as it makes all requests dependent on the SSL bumping middleware.
|
||||
# See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping
|
||||
local sauce_args=(
|
||||
"--no-ssl-bump-domains all"
|
||||
"--logfile ${SAUCE_LOG_FILE}"
|
||||
"--pidfile ${SAUCE_PID_FILE}"
|
||||
"--readyfile ${SAUCE_READY_FILE}"
|
||||
"--tunnel-identifier ${SAUCE_TUNNEL_IDENTIFIER}"
|
||||
"--user ${SAUCE_USERNAME}"
|
||||
# Don't add the --api-key here so we don't echo it out in service-pre-start
|
||||
)
|
||||
|
||||
if [[ -n "${SAUCE_LOCALHOST_ALIAS_DOMAIN:-}" ]]; then
|
||||
# Ensures that requests to the localhost alias domain are always resolved through the tunnel.
|
||||
# This environment variable is usually configured on CI, and refers to a domain that has been
|
||||
# locally configured in the current machine's hosts file (e.g. `/etc/hosts`). The domain should
|
||||
# resolve to the current machine in Saucelabs VMs, so we need to ensure that it is resolved
|
||||
# through the tunnel we going to create.
|
||||
sauce_args+=("--tunnel-domains ${SAUCE_LOCALHOST_ALIAS_DOMAIN}")
|
||||
fi
|
||||
|
||||
@echo "Sauce connect will be started with:"
|
||||
echo " ${SAUCE_CONNECT} ${sauce_args[@]}"
|
||||
SERVICE_COMMAND="${SAUCE_CONNECT} ${sauce_args[@]} --api-key ${SAUCE_ACCESS_KEY}"
|
||||
}
|
||||
|
||||
# Called by pre-start & post-stop
|
||||
service-cleanup() {
|
||||
if [[ -f "${SAUCE_PID_FILE}" ]]; then
|
||||
local p=$(cat "${SAUCE_PID_FILE}")
|
||||
@echo "Stopping Sauce Connect (pid $p)..."
|
||||
@kill $p
|
||||
fi
|
||||
@remove "${SAUCE_PID_FILE}"
|
||||
@remove "${SAUCE_READY_FILE}"
|
||||
@remove "${SAUCE_PARAMS_JSON_FILE}"
|
||||
}
|
||||
|
||||
# Called before service is setup
|
||||
service-pre-setup() {
|
||||
service-cleanup
|
||||
}
|
||||
|
||||
# Called after service is setup
|
||||
service-post-setup() {
|
||||
@echo " sauce params : ${SAUCE_PARAMS_JSON_FILE}"
|
||||
}
|
||||
|
||||
# Called before service is started
|
||||
service-pre-start() {
|
||||
return
|
||||
}
|
||||
|
||||
# Called after service is started
|
||||
service-post-start() {
|
||||
if [[ ! -f "${SAUCE_PID_FILE}" ]]; then
|
||||
printf "# Waiting for Sauce Connect Proxy process (${SAUCE_PID_FILE})"
|
||||
while [[ ! -f "${SAUCE_PID_FILE}" ]]; do
|
||||
if ! @serviceStatus >/dev/null 2>&1; then
|
||||
printf "\n"
|
||||
@serviceStop
|
||||
@echo "Service failed to start!"
|
||||
service-failed-setup
|
||||
exit 1
|
||||
fi
|
||||
printf "."
|
||||
sleep 0.5
|
||||
done
|
||||
printf "\n"
|
||||
fi
|
||||
@echo "Sauce Connect Proxy started (pid $(cat "${SAUCE_PID_FILE}"))"
|
||||
}
|
||||
|
||||
# Called if service fails to start
|
||||
service-failed-setup() {
|
||||
if [[ -f "${SERVICE_LOG_FILE}" ]]; then
|
||||
@echo "tail ${SERVICE_LOG_FILE}:"
|
||||
echo "--------------------------------------------------------------------------------"
|
||||
tail "${SERVICE_LOG_FILE}"
|
||||
echo "--------------------------------------------------------------------------------"
|
||||
echo "^^^^^ ${SERVICE_LOG_FILE} ^^^^^"
|
||||
fi
|
||||
}
|
||||
|
||||
# Called by ready-wait action
|
||||
service-ready-wait() {
|
||||
if [[ ! -f "${SAUCE_PID_FILE}" ]]; then
|
||||
@fail "Sauce Connect not running"
|
||||
fi
|
||||
if [[ ! -f "${SAUCE_READY_FILE}" ]]; then
|
||||
# Wait for saucelabs tunnel to connect
|
||||
printf "# Waiting for saucelabs tunnel to connect (${SAUCE_READY_FILE})"
|
||||
counter=0
|
||||
while [[ ! -f "${SAUCE_READY_FILE}" ]]; do
|
||||
counter=$((counter + 1))
|
||||
|
||||
# Counter needs to be multiplied by two because the while loop only sleeps a half second.
|
||||
# This has been made in favor of better progress logging (printing dots every half second)
|
||||
if [ $counter -gt $[${SAUCE_READY_FILE_TIMEOUT} * 2] ]; then
|
||||
@echo "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file."
|
||||
if [[ -f "${SAUCE_LOG_FILE}" ]]; then
|
||||
echo "================================================================================"
|
||||
echo "${SAUCE_LOG_FILE}:"
|
||||
cat "${SAUCE_LOG_FILE}"
|
||||
fi
|
||||
exit 5
|
||||
fi
|
||||
|
||||
printf "."
|
||||
sleep 0.5
|
||||
done
|
||||
printf "\n"
|
||||
@echo "Saucelabs tunnel connected"
|
||||
else
|
||||
@echo "Saucelabs tunnel already connected"
|
||||
fi
|
||||
}
|
||||
|
||||
# Called before service is stopped
|
||||
service-pre-stop() {
|
||||
return
|
||||
}
|
||||
|
||||
# Called after service is stopped
|
||||
service-post-stop() {
|
||||
service-cleanup
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
# Generic service functions
|
||||
# This uses functions setup above but nothing below should be specific to saucelabs
|
||||
|
||||
@serviceLock() {
|
||||
# Check is Lock File exists, if not create it and set trap on exit
|
||||
printf "# Waiting for service action lock (${SERVICE_LOCK_FILE})"
|
||||
while true; do
|
||||
if { set -C; 2>/dev/null >"${SERVICE_LOCK_FILE}"; }; then
|
||||
trap "rm -f \"${SERVICE_LOCK_FILE}\"" EXIT
|
||||
printf "\n"
|
||||
break
|
||||
fi
|
||||
printf "."
|
||||
sleep 0.5
|
||||
done
|
||||
@echo "Acquired service action lock"
|
||||
}
|
||||
|
||||
@serviceStatus() {
|
||||
if [ -f "${SERVICE_PID_FILE}" ] && [ ! -z "$(cat "${SERVICE_PID_FILE}")" ]; then
|
||||
local p=$(cat "${SERVICE_PID_FILE}")
|
||||
|
||||
if kill -0 $p >/dev/null 2>&1; then
|
||||
@echo "Service is running (pid $p)"
|
||||
return 0
|
||||
else
|
||||
@echo "Service is not running (process PID $p not exists)"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
@echo "Service is not running"
|
||||
return 2
|
||||
fi
|
||||
}
|
||||
|
||||
@serviceSetup() {
|
||||
if @serviceStatus >/dev/null 2>&1; then
|
||||
@echo "Service already running (pid $(cat "${SERVICE_PID_FILE}"))"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@echo "Setting up service..."
|
||||
@remove "${SERVICE_PID_FILE}"
|
||||
@remove "${SERVICE_START_FILE}"
|
||||
touch "${SERVICE_LOG_FILE}" >/dev/null 2>&1 || @fail "Can not create ${SERVICE_LOG_FILE} file"
|
||||
@echo " service pid : ${SERVICE_PID_FILE}"
|
||||
@echo " service logs : ${SERVICE_LOG_FILE}"
|
||||
service-pre-setup
|
||||
service-setup-command
|
||||
|
||||
(
|
||||
(
|
||||
if [[ -z "${SERVICE_COMMAND:-}" ]]; then
|
||||
@fail "No SERVICE_COMMAND is set"
|
||||
fi
|
||||
@wait_for "Waiting for start file" "${SERVICE_START_FILE}"
|
||||
${SERVICE_COMMAND}
|
||||
) >>"${SERVICE_LOG_FILE}" 2>&1
|
||||
) &
|
||||
echo $! >"${SERVICE_PID_FILE}"
|
||||
|
||||
if @serviceStatus >/dev/null 2>&1; then
|
||||
@echo "Service setup (pid $(cat "${SERVICE_PID_FILE}"))"
|
||||
service-post-setup
|
||||
else
|
||||
@echo "Error setting up Service!"
|
||||
service-failed-setup
|
||||
exit 1
|
||||
fi
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
@serviceStart() {
|
||||
if @serviceStatus >/dev/null 2>&1; then
|
||||
@echo "Service already setup (pid $(cat "${SERVICE_PID_FILE}"))"
|
||||
else
|
||||
@serviceSetup
|
||||
fi
|
||||
if [[ -f "${SERVICE_START_FILE}" ]]; then
|
||||
@echo "Service already started"
|
||||
else
|
||||
@echo "Starting service..."
|
||||
service-pre-start
|
||||
touch "${SERVICE_START_FILE}" >/dev/null 2>&1 || @err "Can not create ${SERVICE_START_FILE} file"
|
||||
service-post-start
|
||||
@echo "Service started"
|
||||
fi
|
||||
}
|
||||
|
||||
@serviceStop() {
|
||||
if @serviceStatus >/dev/null 2>&1; then
|
||||
touch "${SERVICE_PID_FILE}" >/dev/null 2>&1 || @fail "Can not touch ${SERVICE_PID_FILE} file"
|
||||
|
||||
service-pre-stop
|
||||
@echo "Stopping sevice (pid $(cat "${SERVICE_PID_FILE}"))..."
|
||||
@kill $(cat "${SERVICE_PID_FILE}")
|
||||
|
||||
if @serviceStatus >/dev/null 2>&1; then
|
||||
@fail "Error stopping Service! Service already running with PID $(cat "${SERVICE_PID_FILE}")"
|
||||
else
|
||||
@echo "Service stopped"
|
||||
@remove "${SERVICE_PID_FILE}"
|
||||
@remove "${SERVICE_START_FILE}"
|
||||
service-post-stop
|
||||
fi
|
||||
|
||||
return 0
|
||||
else
|
||||
@warn "Service is not running"
|
||||
@remove "${SERVICE_PID_FILE}"
|
||||
@remove "${SERVICE_START_FILE}"
|
||||
service-post-stop
|
||||
fi
|
||||
}
|
||||
|
||||
@serviceStartReadyWait() {
|
||||
@serviceStart
|
||||
@serviceReadyWait
|
||||
}
|
||||
|
||||
@serviceReadyWait() {
|
||||
service-ready-wait
|
||||
}
|
||||
|
||||
@serviceRestart() {
|
||||
@serviceStop
|
||||
@serviceStart
|
||||
}
|
||||
|
||||
@serviceTail() {
|
||||
@echo "tail ${SERVICE_LOG_FILE}:"
|
||||
tail -f "${SERVICE_LOG_FILE}"
|
||||
}
|
||||
|
||||
@serviceLog() {
|
||||
@echo "cat ${SERVICE_LOG_FILE}:"
|
||||
echo "--------------------------------------------------------------------------------"
|
||||
cat "${SERVICE_LOG_FILE}"
|
||||
echo "--------------------------------------------------------------------------------"
|
||||
echo "^^^^^ ${SERVICE_LOG_FILE} ^^^^^"
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
setup)
|
||||
@serviceLock
|
||||
@serviceSetup
|
||||
;;
|
||||
start)
|
||||
@serviceLock
|
||||
@serviceStart
|
||||
;;
|
||||
start-ready-wait)
|
||||
@serviceLock
|
||||
@serviceStartReadyWait
|
||||
;;
|
||||
ready-wait)
|
||||
@serviceLock
|
||||
@serviceReadyWait
|
||||
;;
|
||||
stop)
|
||||
@serviceLock
|
||||
@serviceStop
|
||||
;;
|
||||
restart)
|
||||
@serviceLock
|
||||
@serviceRestart
|
||||
;;
|
||||
status)
|
||||
@serviceLock
|
||||
@serviceStatus
|
||||
;;
|
||||
run)
|
||||
(
|
||||
service-setup-command
|
||||
if [[ -z "${SERVICE_COMMAND:-}" ]]; then
|
||||
@fail "No SERVICE_COMMAND is set"
|
||||
fi
|
||||
${SERVICE_COMMAND}
|
||||
)
|
||||
;;
|
||||
log)
|
||||
@serviceLog
|
||||
;;
|
||||
tail)
|
||||
@serviceTail
|
||||
;;
|
||||
*)
|
||||
@echo "Actions: [setup|start|start-read-wait|ready-wait|stop|restart|status|run|tail]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Setup and start Sauce Connect for your TravisCI build
|
||||
# This script requires your .travis.yml to include the following two private env variables:
|
||||
# SAUCE_USERNAME
|
||||
# SAUCE_ACCESS_KEY
|
||||
# Follow the steps at https://saucelabs.com/opensource/travis to set that up.
|
||||
#
|
||||
# Curl and run this script as part of your .travis.yml before_script section:
|
||||
# before_script:
|
||||
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
|
||||
SC_VERSION="4.5.2"
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-$SC_VERSION-linux.tar.gz"
|
||||
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
|
||||
CONNECT_DOWNLOAD="sc-$SC_VERSION-linux.tar.gz"
|
||||
|
||||
# We don't want to create a log file because sauceconnect always logs in verbose mode. This seems
|
||||
# to be overwhelming Travis and causing flakes when we are cat-ing the log in "print_logs.sh"
|
||||
CONNECT_LOG="/dev/null"
|
||||
|
||||
# Get Connect and start it
|
||||
mkdir -p $CONNECT_DIR
|
||||
cd $CONNECT_DIR
|
||||
curl $CONNECT_URL -o $CONNECT_DOWNLOAD 2> /dev/null 1> /dev/null
|
||||
mkdir sauce-connect
|
||||
tar --extract --file=$CONNECT_DOWNLOAD --strip-components=1 --directory=sauce-connect > /dev/null
|
||||
rm $CONNECT_DOWNLOAD
|
||||
|
||||
SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
|
||||
|
||||
ARGS=""
|
||||
|
||||
# Set tunnel-id only on Travis, to make local testing easier.
|
||||
if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then
|
||||
ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_NUMBER"
|
||||
fi
|
||||
if [ ! -z "$BROWSER_PROVIDER_READY_FILE" ]; then
|
||||
ARGS="$ARGS --readyfile $BROWSER_PROVIDER_READY_FILE"
|
||||
fi
|
||||
|
||||
|
||||
echo "Starting Sauce Connect in the background"
|
||||
sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS \
|
||||
--logfile $CONNECT_LOG &
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
|
||||
echo "Shutting down Sauce Connect tunnel"
|
||||
|
||||
killall sc
|
||||
|
||||
while [[ -n `ps -ef | grep "sauce-connect-" | grep -v "grep"` ]]; do
|
||||
printf "."
|
||||
sleep .5
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Sauce Connect tunnel has been shut down"
|
||||
@@ -65,7 +65,7 @@ var getCodeName = function(tagName) {
|
||||
|
||||
|
||||
/**
|
||||
* Compute a build segment for the version, from the Jenkins build number and current commit SHA
|
||||
* Compute a build segment for the version, from the CI build number and current commit SHA
|
||||
* @return {String} The build segment of the version
|
||||
*/
|
||||
function getBuild() {
|
||||
@@ -189,7 +189,7 @@ var getSnapshotVersion = function() {
|
||||
// We need to clone to ensure that we are not modifying another version
|
||||
version = semver(version.raw);
|
||||
|
||||
var jenkinsBuild = process.env.TRAVIS_BUILD_NUMBER || process.env.BUILD_NUMBER;
|
||||
var ciBuild = process.env.CIRCLE_BUILD_NUM || process.env.BUILD_NUMBER;
|
||||
if (!version.prerelease || !version.prerelease.length) {
|
||||
// last release was a non beta release. Increment the patch level to
|
||||
// indicate the next release that we will be doing.
|
||||
@@ -203,7 +203,7 @@ var getSnapshotVersion = function() {
|
||||
// as this is bigger than 1.3.0-beta.2 according to semver
|
||||
version.patch++;
|
||||
}
|
||||
version.prerelease = jenkinsBuild ? ['build', jenkinsBuild] : ['local'];
|
||||
version.prerelease = ciBuild ? ['build', ciBuild] : ['local'];
|
||||
version.build = getBuild();
|
||||
version.codeName = 'snapshot';
|
||||
version.isSnapshot = true;
|
||||
|
||||
+29
-25
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "angular",
|
||||
"license": "MIT",
|
||||
"branchVersion": "^1.7.0",
|
||||
"branchPattern": "1.7.*",
|
||||
"distTag": "latest",
|
||||
"branchVersion": "^1.8.0",
|
||||
"branchPattern": "1.8.*",
|
||||
"distTag": "next",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.12.0",
|
||||
"yarn": ">=1.10.1",
|
||||
"node": ">=12.14.1",
|
||||
"yarn": ">=1.21.1",
|
||||
"grunt-cli": "^1.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -22,12 +22,12 @@
|
||||
"angular-benchpress": "0.x.x",
|
||||
"benchmark": "1.x.x",
|
||||
"bootstrap": "3.1.1",
|
||||
"browserstacktunnel-wrapper": "2.0.0",
|
||||
"browserstacktunnel-wrapper": "2.0.4",
|
||||
"canonical-path": "0.0.2",
|
||||
"changez": "^2.1.1",
|
||||
"changez-angular": "^2.1.2",
|
||||
"cheerio": "^0.17.0",
|
||||
"commitizen": "^2.3.0",
|
||||
"commitizen": "^4.2.4",
|
||||
"commitplease": "^2.7.10",
|
||||
"cross-spawn": "^4.0.0",
|
||||
"cz-conventional-changelog": "1.1.4",
|
||||
@@ -35,9 +35,10 @@
|
||||
"dgeni-packages": "^0.26.5",
|
||||
"eslint-plugin-promise": "^3.6.0",
|
||||
"event-stream": "~3.1.0",
|
||||
"firebase-tools": "^9.3.0",
|
||||
"glob": "^6.0.1",
|
||||
"google-code-prettify": "1.0.1",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt": "^1.4.1",
|
||||
"grunt-bump": "^0.8.0",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-contrib-clean": "^1.0.0",
|
||||
@@ -54,28 +55,28 @@
|
||||
"gulp-foreach": "0.0.1",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"gulp-sourcemaps": "^1.2.2",
|
||||
"gulp-uglify": "^1.0.1",
|
||||
"gulp-uglify": "^3.0.2",
|
||||
"gulp-util": "^3.0.1",
|
||||
"jasmine-core": "^2.8.0",
|
||||
"jasmine-node": "^2.0.0",
|
||||
"jasmine-reporters": "^2.2.0",
|
||||
"jquery": "3.2.1",
|
||||
"jquery": "3.5.1",
|
||||
"jquery-2.1": "npm:jquery@2.1.4",
|
||||
"jquery-2.2": "npm:jquery@2.2.4",
|
||||
"karma": "^3.1.4",
|
||||
"karma-browserstack-launcher": "^1.3.0",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-edge-launcher": "^0.4.2",
|
||||
"karma-firefox-launcher": "^1.1.0",
|
||||
"karma-ie-launcher": "^1.0.0",
|
||||
"karma": "4.4.1",
|
||||
"karma-browserstack-launcher": "1.5.1",
|
||||
"karma-chrome-launcher": "3.1.0",
|
||||
"karma-edge-launcher": "0.4.2",
|
||||
"karma-firefox-launcher": "1.2.0",
|
||||
"karma-ie-launcher": "1.0.0",
|
||||
"karma-jasmine": "^1.1.2",
|
||||
"karma-junit-reporter": "^1.2.0",
|
||||
"karma-safari-launcher": "^1.0.0",
|
||||
"karma-sauce-launcher": "^2.0.2",
|
||||
"karma-script-launcher": "^1.0.0",
|
||||
"karma-spec-reporter": "^0.0.32",
|
||||
"karma-junit-reporter": "2.0.1",
|
||||
"karma-safari-launcher": "1.0.0",
|
||||
"karma-sauce-launcher": "2.0.2",
|
||||
"karma-script-launcher": "1.0.0",
|
||||
"karma-spec-reporter": "0.0.32",
|
||||
"load-grunt-tasks": "^3.5.0",
|
||||
"lodash": "~2.4.1",
|
||||
"lodash": "~4.17.21",
|
||||
"log4js": "^0.6.27",
|
||||
"lunr": "^0.7.2",
|
||||
"marked": "~0.3.0",
|
||||
@@ -83,11 +84,12 @@
|
||||
"npm-run": "^4.1.0",
|
||||
"open-sans-fontface": "^1.4.0",
|
||||
"promises-aplus-tests": "~2.1.0",
|
||||
"protractor": "^5.4.1",
|
||||
"protractor": "^7.0.0",
|
||||
"q": "~1.0.0",
|
||||
"q-io": "^1.10.9",
|
||||
"qq": "^0.3.5",
|
||||
"rewire": "~2.1.0",
|
||||
"sauce-connect": "https://saucelabs.com/downloads/sc-4.6.2-linux.tar.gz",
|
||||
"sax": "^1.1.1",
|
||||
"selenium-webdriver": "^4.0.0-alpha.1",
|
||||
"semver": "^5.4.1",
|
||||
@@ -101,8 +103,10 @@
|
||||
"dependencies": {},
|
||||
"resolutions": {
|
||||
"//1": "`natives@1.1.0` does not work with Node.js 10.x on Windows 10",
|
||||
"//2": "(E.g. see https://github.com/gulpjs/gulp/issues/2162.)",
|
||||
"natives": "1.1.3"
|
||||
"//2": "(E.g. see https://github.com/gulpjs/gulp/issues/2162 and https://github.com/nodejs/node/issues/25132.)",
|
||||
"natives": "1.1.6",
|
||||
"//3": "`graceful-fs` needs to be pinned to support gulp 3, on Node v12+",
|
||||
"graceful-fs": "^4.2.3"
|
||||
},
|
||||
"commitplease": {
|
||||
"style": "angular",
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('./protractor-shared-conf').config;
|
||||
|
||||
|
||||
// Using SauceLabs.
|
||||
config.capabilities = undefined;
|
||||
config.sauceUser = process.env.SAUCE_USERNAME;
|
||||
config.sauceKey = process.env.SAUCE_ACCESS_KEY;
|
||||
config.multiCapabilities = [
|
||||
capabilitiesForSauceLabs({
|
||||
browserName: 'chrome',
|
||||
platform: 'OS X 10.15',
|
||||
version: '91'
|
||||
}),
|
||||
capabilitiesForSauceLabs({
|
||||
browserName: 'firefox',
|
||||
platform: 'OS X 10.15',
|
||||
version: '85'
|
||||
})
|
||||
];
|
||||
|
||||
|
||||
config.allScriptsTimeout = 30000;
|
||||
config.getPageTimeout = 30000;
|
||||
|
||||
exports.config = config;
|
||||
|
||||
|
||||
function capabilitiesForSauceLabs(capabilities) {
|
||||
return {
|
||||
'tunnel-identifier': process.env.SAUCE_TUNNEL_IDENTIFIER,
|
||||
|
||||
'name': 'AngularJS E2E',
|
||||
'build': `${process.env.CIRCLE_BUILD_NUM}-${process.env.CIRCLE_NODE_INDEX}`,
|
||||
|
||||
'browserName': capabilities.browserName,
|
||||
'platform': capabilities.platform,
|
||||
'version': capabilities.version,
|
||||
'elementScrollBehavior': 1,
|
||||
// Allow e2e test sessions to run for a maximum of 40 minutes, instead of the default 30 minutes.
|
||||
'maxDuration': 2400
|
||||
};
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
|
||||
specs: [
|
||||
'test/e2e/tests/**/*.js',
|
||||
'build/docs/ptore2e/**/*.js',
|
||||
'docs/app/e2e/*.scenario.js'
|
||||
],
|
||||
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
|
||||
baseUrl: 'http://localhost:8000/',
|
||||
|
||||
framework: 'jasmine2',
|
||||
|
||||
onPrepare: function() {
|
||||
/* global angular: false, browser: false, jasmine: false */
|
||||
|
||||
// Disable animations so e2e tests run more quickly
|
||||
var disableNgAnimate = function() {
|
||||
angular.module('disableNgAnimate', []).run(['$animate', function($animate) {
|
||||
$animate.enabled(false);
|
||||
}]);
|
||||
};
|
||||
|
||||
browser.addMockModule('disableNgAnimate', disableNgAnimate);
|
||||
|
||||
var reporters = require('jasmine-reporters');
|
||||
jasmine.getEnv().addReporter(new reporters.JUnitXmlReporter({
|
||||
savePath: 'test_out/docs-e2e-' + exports.config.capabilities.browserName + '-'
|
||||
}));
|
||||
},
|
||||
|
||||
jasmineNodeOpts: {
|
||||
defaultTimeoutInterval: 30000,
|
||||
showColors: false
|
||||
}
|
||||
};
|
||||
@@ -1,86 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('./protractor-shared-conf').config;
|
||||
|
||||
if (process.env.BROWSER_PROVIDER === 'browserstack') {
|
||||
// Using BrowserStack.
|
||||
config.seleniumAddress = 'http://hub.browserstack.com/wd/hub';
|
||||
config.multiCapabilities = [
|
||||
capabilitiesForBrowserStack({
|
||||
browserName: 'chrome',
|
||||
platform: 'MAC',
|
||||
version: '49'
|
||||
}),
|
||||
capabilitiesForBrowserStack({
|
||||
browserName: 'firefox',
|
||||
version: '47'
|
||||
}),
|
||||
capabilitiesForBrowserStack({
|
||||
browserName: 'safari',
|
||||
platform: 'MAC',
|
||||
version: '9'
|
||||
})
|
||||
];
|
||||
} else {
|
||||
// Using SauceLabs.
|
||||
config.sauceUser = process.env.SAUCE_USERNAME;
|
||||
config.sauceKey = process.env.SAUCE_ACCESS_KEY;
|
||||
config.multiCapabilities = [
|
||||
capabilitiesForSauceLabs({
|
||||
browserName: 'chrome',
|
||||
platform: 'OS X 10.11',
|
||||
version: '48'
|
||||
}),
|
||||
capabilitiesForSauceLabs({
|
||||
browserName: 'firefox',
|
||||
version: '47'
|
||||
}),
|
||||
capabilitiesForSauceLabs({
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.11',
|
||||
version: '9'
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
config.allScriptsTimeout = 30000;
|
||||
config.getPageTimeout = 30000;
|
||||
|
||||
exports.config = config;
|
||||
|
||||
|
||||
function capabilitiesForBrowserStack(capabilities) {
|
||||
return {
|
||||
'browserstack.user': process.env.BROWSER_STACK_USERNAME,
|
||||
'browserstack.key': process.env.BROWSER_STACK_ACCESS_KEY,
|
||||
'browserstack.local': 'true',
|
||||
'browserstack.debug': 'true',
|
||||
'browserstack.tunnelIdentifier': process.env.TRAVIS_JOB_NUMBER,
|
||||
'tunnelIdentifier': process.env.TRAVIS_JOB_NUMBER,
|
||||
|
||||
'name': 'AngularJS E2E',
|
||||
'build': process.env.TRAVIS_BUILD_NUMBER,
|
||||
|
||||
'browserName': capabilities.browserName,
|
||||
'platform': capabilities.platform,
|
||||
'version': capabilities.version,
|
||||
'elementScrollBehavior': 1
|
||||
};
|
||||
}
|
||||
|
||||
function capabilitiesForSauceLabs(capabilities) {
|
||||
return {
|
||||
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
|
||||
|
||||
'name': 'AngularJS E2E',
|
||||
'build': process.env.TRAVIS_BUILD_NUMBER,
|
||||
|
||||
'browserName': capabilities.browserName,
|
||||
'platform': capabilities.platform,
|
||||
'version': capabilities.version,
|
||||
'elementScrollBehavior': 1,
|
||||
// Allow e2e test sessions to run for a maximum of 35 minutes, instead of the default 30 minutes.
|
||||
'maxDuration': 2100
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Tags a release
|
||||
# so that travis can do the actual release.
|
||||
|
||||
echo "#################################"
|
||||
echo "## Tag angular.js for a release #"
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const functions = require('firebase-functions');
|
||||
const gcs = require('@google-cloud/storage')();
|
||||
const path = require('path');
|
||||
const {Storage} = require('@google-cloud/storage');
|
||||
|
||||
const storage = new Storage();
|
||||
const gcsBucketId = `${process.env.GCLOUD_PROJECT}.appspot.com`;
|
||||
|
||||
const BROWSER_CACHE_DURATION = 60 * 10;
|
||||
const CDN_CACHE_DURATION = 60 * 60 * 12;
|
||||
|
||||
function sendStoredFile(request, response) {
|
||||
const requestPath = request.path || '/';
|
||||
// Request paths will be URI-encoded, so we need to decode them to match the file names in the
|
||||
// storage bucket. Failing to do so will result in a 404 error from the bucket and `index.html`
|
||||
// will be returned instead.
|
||||
// Example of path requiring decoding: `.../input%5Btext%5D.html` --> `.../input[text].html`
|
||||
const requestPath = decodeURI(request.path || '/');
|
||||
let filePathSegments = requestPath.split('/').filter((segment) => {
|
||||
// Remove empty leading or trailing path parts
|
||||
return segment !== '';
|
||||
@@ -19,7 +23,7 @@ function sendStoredFile(request, response) {
|
||||
const version = filePathSegments[0];
|
||||
const isDocsPath = filePathSegments[1] === 'docs';
|
||||
const lastSegment = filePathSegments[filePathSegments.length - 1];
|
||||
const bucket = gcs.bucket(gcsBucketId);
|
||||
const bucket = storage.bucket(gcsBucketId);
|
||||
|
||||
let downloadSource;
|
||||
let fileName;
|
||||
@@ -36,13 +40,13 @@ function sendStoredFile(request, response) {
|
||||
return getDirectoryListing('/').catch(sendErrorResponse);
|
||||
}
|
||||
|
||||
downloadSource = path.join.apply(null, filePathSegments);
|
||||
downloadSource = filePathSegments.join('/');
|
||||
|
||||
downloadAndSend(downloadSource).catch(error => {
|
||||
if (isDocsPath && error.code === 404) {
|
||||
fileName = 'index.html';
|
||||
filePathSegments = [version, 'docs', fileName];
|
||||
downloadSource = path.join.apply(null, filePathSegments);
|
||||
downloadSource = filePathSegments.join('/');
|
||||
|
||||
return downloadAndSend(downloadSource);
|
||||
}
|
||||
@@ -195,12 +199,12 @@ const snapshotRegex = /^snapshot(-stable)?\//;
|
||||
* When a new zip file is uploaded into snapshot or snapshot-stable,
|
||||
* delete the previous zip file.
|
||||
*/
|
||||
function deleteOldSnapshotZip(object, context) {
|
||||
function deleteOldSnapshotZip(object) {
|
||||
const bucketId = object.bucket;
|
||||
const filePath = object.name;
|
||||
const contentType = object.contentType;
|
||||
|
||||
const bucket = gcs.bucket(bucketId);
|
||||
const bucket = storage.bucket(bucketId);
|
||||
|
||||
const snapshotFolderMatch = filePath.match(snapshotRegex);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,13 @@
|
||||
{
|
||||
"name": "functions-firebase-code.angularjs.org",
|
||||
"description": "Cloud Functions to serve files from gcs to code.angularjs.org",
|
||||
"engines": {
|
||||
"node": "14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google-cloud/storage": "^1.1.1",
|
||||
"firebase-admin": "^5.11.0",
|
||||
"firebase-functions": "^1.0.4"
|
||||
"@google-cloud/storage": "^5.8.5",
|
||||
"firebase-admin": "^9.9.0",
|
||||
"firebase-functions": "^3.14.1"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,15 @@
|
||||
Firebase for code.angularjs.org
|
||||
===============================
|
||||
|
||||
This folder contains the Google Firebase scripts for the code.angularjs.org setup.
|
||||
This folder contains the Google Firebase scripts for the `code.angularjs.org` setup.
|
||||
|
||||
firebase.json contains the rewrite rules that route every subdirectory request to the cloud function
|
||||
in functions/index.js that serves the docs from the Firebase Google Cloud Storage bucket.
|
||||
`firebase.json` contains the rewrite rules that route every subdirectory request to the cloud function in `functions/index.js` that serves the docs from the Firebase Google Cloud Storage bucket.
|
||||
|
||||
functions/index.js also contains a rule that deletes outdated build zip files
|
||||
from the snapshot and snapshot-stable folders when new zip files are uploaded.
|
||||
`functions/index.js` also contains a rule that deletes outdated build zip files from the snapshot and snapshot-stable folders when new zip files are uploaded.
|
||||
|
||||
The deployment to the Google Cloud Storage bucket happens automatically via Travis. See the travis.yml
|
||||
file in the repository root.
|
||||
See `/scripts/docs.angularjs.org-firebase/readme.firebase.code.md` for the Firebase deployment to `docs.angularjs.org`.
|
||||
|
||||
See /readme.firebase.docs.md for the firebase deployment to docs.angularjs.org
|
||||
# Continuous integration
|
||||
|
||||
The code is deployed to Google Firebase hosting and functions as well as to the Google Cloud Storage bucket automatically via CI.
|
||||
See `.circleci/config.yml` for the complete deployment config and build steps.
|
||||
|
||||
@@ -63,7 +63,7 @@ function _update_code() {
|
||||
|
||||
function publish {
|
||||
# publish updates the code.angularjs.org Github repository
|
||||
# the deployment to Firebase happens via Travis
|
||||
# the deployment to Firebase happens via CI
|
||||
_update_code
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"hosting": {
|
||||
"public": "../../deploy/docs",
|
||||
"public": "deploy",
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/error/:namespace\\::error*",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,24 @@
|
||||
{
|
||||
"name": "functions",
|
||||
"description": "Cloud Functions for Firebase",
|
||||
"engines": {
|
||||
"node": "14"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"serve": "firebase serve --only functions",
|
||||
"shell": "firebase experimental:functions:shell",
|
||||
"serve": "firebase emulators:start --only functions",
|
||||
"shell": "firebase functions:shell",
|
||||
"start": "npm run shell",
|
||||
"deploy": "firebase deploy --only functions",
|
||||
"logs": "firebase functions:log"
|
||||
},
|
||||
"dependencies": {
|
||||
"firebase-admin": "~5.8.1",
|
||||
"firebase-functions": "^0.8.1"
|
||||
"firebase-admin": "^9.9.0",
|
||||
"firebase-functions": "^3.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^4.12.0",
|
||||
"eslint-plugin-promise": "^3.6.0"
|
||||
"eslint": "^7.28.0",
|
||||
"eslint-plugin-promise": "^5.1.0"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,26 @@
|
||||
Firebase for docs.angularjs.org
|
||||
===============================
|
||||
|
||||
This folder contains the Google Firebase scripts for the `docs.angularjs.org` setup.
|
||||
|
||||
See `/scripts/code.angularjs.org-firebase/readme.firebase.code.md` for the Firebase deployment to `code.angularjs.org`.
|
||||
|
||||
# Continuous integration
|
||||
|
||||
The docs are deployed to Google Firebase hosting via Travis deployment config, which expects
|
||||
firebase.json in the repository root, which is done by a Grunt task (firebaseDocsJsonForTravis)
|
||||
that modifies the paths in the firebase.json and copies it into the repository root.
|
||||
The docs are deployed to Google Firebase hosting and functions automatically via CI.
|
||||
|
||||
See travis.yml for the complete deployment config, and scripts/travis/build.sh for the full deployment
|
||||
build steps.
|
||||
See `.circleci/config.yml` for the complete deployment config and build steps.
|
||||
|
||||
# Serving locally:
|
||||
|
||||
- Run `grunt:prepareDeploy`.
|
||||
This copies docs content files into deploy/docs and the partials for Search Engine AJAX
|
||||
Crawling into ./functions/content.
|
||||
- Run `cd scripts/docs.angularjs.org-firebase`.
|
||||
This changes the current working directory.
|
||||
|
||||
- Run `firebase serve --only functions,hosting`
|
||||
Creates a server at localhost:5000 that serves from deploy/docs and uses the local function
|
||||
- Run `yarn grunt package`.
|
||||
This builds the files that will be deployed.
|
||||
|
||||
See /scripts/code.angularjs.org-firebase/readme.firebase.code.md for the firebase deployment to
|
||||
code.angularjs.org
|
||||
- Run `yarn grunt prepareDeploy`.
|
||||
This copies docs content files into `./deploy` and the partials for Search Engine AJAX Crawling into `./functions/content`.
|
||||
|
||||
- Run `$(yarn bin)/firebase emulators:start` (or `..\..\node_modules\.bin\firebase emulators:start` on Windows).
|
||||
Creates a server at http://localhost:5000 that serves from `./deploy` and uses the local function.
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
|
||||
source scripts/jenkins/init-node.sh
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
# This is the default set of browsers to use on the CI server unless overridden via env variable
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
BROWSERS="Chrome"
|
||||
fi
|
||||
|
||||
# CLEAN #
|
||||
rm -f angular.min.js.gzip.size
|
||||
rm -f angular.js.size
|
||||
|
||||
|
||||
# BUILD #
|
||||
yarn grunt ci-checks package --no-color
|
||||
|
||||
mkdir -p test_out
|
||||
|
||||
# UNIT TESTS #
|
||||
yarn grunt test:unit --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
# END TO END TESTS #
|
||||
yarn grunt test:ci-protractor
|
||||
|
||||
# DOCS APP TESTS #
|
||||
yarn grunt test:docs --browsers="$BROWSERS" --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
# Promises/A+ TESTS #
|
||||
yarn grunt test:promises-aplus --no-color
|
||||
|
||||
|
||||
# CHECK SIZE #
|
||||
gzip -c < build/angular.min.js > build/angular.min.js.gzip
|
||||
echo "YVALUE=`ls -l build/angular.min.js | cut -d" " -f 8`" > angular.min.js.size
|
||||
echo "YVALUE=`ls -l build/angular.min.js.gzip | cut -d" " -f 8`" > angular.min.js.gzip.size
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install nvm for this shell
|
||||
source ~/.nvm/nvm.sh
|
||||
|
||||
# Use version of node.js found in .nvmrc
|
||||
nvm install
|
||||
|
||||
# clean out and install yarn
|
||||
rm -rf ~/.yarn
|
||||
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.10.1
|
||||
export PATH="$HOME/.yarn/bin:$PATH"
|
||||
|
||||
# Ensure that we have the local dependencies installed
|
||||
yarn install
|
||||
|
||||
echo testing grunt version
|
||||
yarn grunt --version
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update master ##############"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=()
|
||||
|
||||
function init {
|
||||
if [[ ! $VERBOSE ]]; then
|
||||
VERBOSE=false
|
||||
fi
|
||||
VERBOSE_ARG="--verbose=$VERBOSE"
|
||||
}
|
||||
|
||||
function build {
|
||||
cd ../..
|
||||
scripts/jenkins/build.sh
|
||||
cd $SCRIPT_DIR
|
||||
}
|
||||
|
||||
function phase {
|
||||
ACTION_ARG="--action=$1"
|
||||
../code.angularjs.org/publish.sh $ACTION_ARG $VERBOSE_ARG
|
||||
../bower/publish.sh $ACTION_ARG $VERBOSE_ARG
|
||||
}
|
||||
|
||||
function run {
|
||||
build
|
||||
|
||||
# First prepare all scripts (build, test, commit, tag, ...),
|
||||
# so we are sure everything is all right
|
||||
phase prepare
|
||||
# only then publish to github
|
||||
phase publish
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
@@ -36,7 +36,6 @@ function init {
|
||||
|
||||
function build {
|
||||
cd ../..
|
||||
source scripts/jenkins/init-node.sh
|
||||
yarn grunt ci-checks package --no-color
|
||||
|
||||
cd $SCRIPT_DIR
|
||||
@@ -65,4 +64,4 @@ function run {
|
||||
phase publish
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
source $(dirname $0)/../utils.inc
|
||||
@@ -38,4 +38,4 @@ function run {
|
||||
phase publish
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
source $(dirname $0)/../utils.inc
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p "$LOGS_DIR"
|
||||
|
||||
if [ "$JOB" != "ci-checks" ]; then
|
||||
echo "start_browser_provider"
|
||||
./scripts/travis/start_browser_provider.sh
|
||||
fi
|
||||
|
||||
# ci-checks and unit tests do not run against the packaged code
|
||||
if [[ "$JOB" != "ci-checks" ]] && [[ "$JOB" != unit-* ]]; then
|
||||
yarn grunt package
|
||||
fi
|
||||
|
||||
# unit runs the docs tests too which need a built version of the code
|
||||
if [[ "$JOB" = unit-* ]]; then
|
||||
yarn grunt validate-angular-files
|
||||
yarn grunt build
|
||||
fi
|
||||
|
||||
# check this after the package, because at this point the browser_provider
|
||||
# has probably arrived
|
||||
if [ "$JOB" != "ci-checks" ]; then
|
||||
echo "wait_for_browser_provider"
|
||||
./scripts/travis/wait_for_browser_provider.sh
|
||||
fi
|
||||
@@ -1,113 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
readonly THIS_DIR=$(cd $(dirname ${BASH_SOURCE[0]}); pwd)
|
||||
readonly ROOT_DIR="$THIS_DIR/../.."
|
||||
|
||||
export BROWSER_STACK_ACCESS_KEY
|
||||
export SAUCE_ACCESS_KEY
|
||||
|
||||
BROWSER_STACK_ACCESS_KEY=$(echo "$BROWSER_STACK_ACCESS_KEY" | rev)
|
||||
SAUCE_ACCESS_KEY=$(echo "$SAUCE_ACCESS_KEY" | rev)
|
||||
|
||||
# The currently latest version of Safari on Saucelabs (v12) is unstable and disconnects frequently.
|
||||
# TODO: Add `SL_Safari` back, once/if it becomes more stable again.
|
||||
BROWSERS="SL_Chrome,SL_Chrome-1,\
|
||||
SL_Firefox,SL_Firefox-1,\
|
||||
SL_Safari-1,\
|
||||
SL_iOS,SL_iOS-1,\
|
||||
SL_IE_9,SL_IE_10,SL_IE_11,\
|
||||
SL_EDGE,SL_EDGE-1"
|
||||
|
||||
case "$JOB" in
|
||||
"ci-checks")
|
||||
grunt ci-checks
|
||||
|
||||
if [[ $TRAVIS_PULL_REQUEST != 'false' ]]; then
|
||||
# validate commit messages of all commits in the PR
|
||||
# convert commit range to 2 dots, as commitplease uses `git log`.
|
||||
# See https://github.com/travis-ci/travis-ci/issues/4596 for more info
|
||||
echo "Validate commit messages in PR:"
|
||||
yarn run commitplease "${TRAVIS_COMMIT_RANGE/.../..}"
|
||||
fi
|
||||
;;
|
||||
"unit-core")
|
||||
grunt test:promises-aplus
|
||||
grunt test:jqlite --browsers="$BROWSERS" --reporters=spec
|
||||
;;
|
||||
"unit-jquery")
|
||||
grunt test:jquery --browsers="$BROWSERS" --reporters=spec
|
||||
grunt test:jquery-2.2 --browsers="$BROWSERS" --reporters=spec
|
||||
grunt test:jquery-2.1 --browsers="$BROWSERS" --reporters=spec
|
||||
;;
|
||||
"unit-modules")
|
||||
grunt test:modules --browsers="$BROWSERS" --reporters=spec
|
||||
;;
|
||||
"docs-app")
|
||||
grunt tests:docs --browsers="$BROWSERS" --reporters=spec
|
||||
grunt test:travis-protractor --specs="docs/app/e2e/**/*.scenario.js"
|
||||
;;
|
||||
"e2e")
|
||||
if [[ $TEST_TARGET == jquery* ]]; then
|
||||
export USE_JQUERY=1
|
||||
fi
|
||||
|
||||
if [[ "$TEST_TARGET" == jquery* ]]; then
|
||||
TARGET_SPECS="build/docs/ptore2e/**/jquery_test.js"
|
||||
else
|
||||
TARGET_SPECS="build/docs/ptore2e/**/default_test.js"
|
||||
fi
|
||||
|
||||
TARGET_SPECS="test/e2e/tests/**/*.js,$TARGET_SPECS"
|
||||
grunt test:travis-protractor --specs="$TARGET_SPECS"
|
||||
;;
|
||||
"deploy")
|
||||
export DEPLOY_DOCS
|
||||
export DEPLOY_CODE
|
||||
|
||||
DIST_TAG=$( jq ".distTag" "package.json" | tr -d "\"[:space:]" )
|
||||
|
||||
# upload docs if the branch distTag from package.json is "latest" (i.e. stable branch)
|
||||
if [[ "$DIST_TAG" == latest ]]; then
|
||||
DEPLOY_DOCS=true
|
||||
else
|
||||
DEPLOY_DOCS=false
|
||||
fi
|
||||
|
||||
# upload the build (code + docs) if ...
|
||||
# the commit is tagged
|
||||
# - or the branch is "master"
|
||||
# - or the branch distTag from package.json is "latest" (i.e. stable branch)
|
||||
if [[ "$TRAVIS_TAG" != '' || "$TRAVIS_BRANCH" == master || "$DIST_TAG" == latest ]]; then
|
||||
DEPLOY_CODE=true
|
||||
else
|
||||
DEPLOY_CODE=false
|
||||
fi
|
||||
|
||||
if [[ "$DEPLOY_DOCS" == true || "$DEPLOY_CODE" == true ]]; then
|
||||
grunt prepareDeploy
|
||||
|
||||
if [[ "$DEPLOY_DOCS" == true ]]; then
|
||||
# Install npm dependencies for Firebase functions.
|
||||
(
|
||||
cd "$ROOT_DIR/scripts/docs.angularjs.org-firebase/functions"
|
||||
npm install
|
||||
)
|
||||
fi
|
||||
else
|
||||
echo "Skipping deployment build because conditions have not been met."
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown job type. Please set JOB to one of\
|
||||
'ci-checks',\
|
||||
'unit-core',\
|
||||
'unit-jquery',\
|
||||
'unit-modules',\
|
||||
'docs-app',\
|
||||
'e2e',\
|
||||
or\
|
||||
'deploy'."
|
||||
;;
|
||||
esac
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
LOG_FILES=$LOGS_DIR/*
|
||||
|
||||
for FILE in $LOG_FILES; do
|
||||
echo -e "\n\n\n"
|
||||
echo "================================================================================"
|
||||
echo " $FILE"
|
||||
echo "================================================================================"
|
||||
cat $FILE || true
|
||||
done
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Has to be run from project root directory.
|
||||
|
||||
|
||||
if [ "$BROWSER_PROVIDER" == "browserstack" ]; then
|
||||
echo "Using BrowserStack"
|
||||
elif [ "$BROWSER_PROVIDER" == "saucelabs" ]; then
|
||||
echo "Using SauceLabs"
|
||||
else
|
||||
echo "Invalid BROWSER_PROVIDER. Please set env var BROWSER_PROVIDER to 'saucelabs' or 'browserstack'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
./lib/${BROWSER_PROVIDER}/start_tunnel.sh
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Has to be run from project root directory.
|
||||
|
||||
./lib/${BROWSER_PROVIDER}/teardown_tunnel.sh
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
# Wait for Connect to be ready before exiting
|
||||
# Time out if we wait for more than 2 minutes, so that we can print logs.
|
||||
let "counter=0"
|
||||
|
||||
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
|
||||
let "counter++"
|
||||
if [ $counter -gt 240 ]; then
|
||||
echo "Timed out after 2 minutes waiting for browser provider ready file"
|
||||
# We must manually print logs here because travis will not run
|
||||
# after_script commands if the failure occurs before the script
|
||||
# phase.
|
||||
./scripts/travis/print_logs.sh
|
||||
exit 5
|
||||
fi
|
||||
sleep .5
|
||||
done
|
||||
@@ -100,6 +100,7 @@
|
||||
"VALIDITY_STATE_PROPERTY": false,
|
||||
"reloadWithDebugInfo": false,
|
||||
"stringify": false,
|
||||
"UNSAFE_restoreLegacyJqLiteXHTMLReplacement": false,
|
||||
|
||||
"NODE_TYPE_ELEMENT": false,
|
||||
"NODE_TYPE_ATTRIBUTE": false,
|
||||
|
||||
+28
-5
@@ -93,6 +93,7 @@
|
||||
hasOwnProperty,
|
||||
createMap,
|
||||
stringify,
|
||||
UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
|
||||
|
||||
NODE_TYPE_ELEMENT,
|
||||
NODE_TYPE_ATTRIBUTE,
|
||||
@@ -342,8 +343,10 @@ function baseExtend(dst, objs, deep) {
|
||||
} else if (isElement(src)) {
|
||||
dst[key] = src.clone();
|
||||
} else {
|
||||
if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
|
||||
baseExtend(dst[key], [src], true);
|
||||
if (key !== '__proto__') {
|
||||
if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
|
||||
baseExtend(dst[key], [src], true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dst[key] = src;
|
||||
@@ -818,8 +821,8 @@ function arrayRemove(array, value) {
|
||||
* - [`MediaStream`](https://developer.mozilla.org/docs/Web/API/MediaStream)
|
||||
* - [`Set`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Set)
|
||||
* - [`WeakMap`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)
|
||||
* - ['getter'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/
|
||||
* [`setter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set)`
|
||||
* - [`getter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/
|
||||
* [`setter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set)
|
||||
*
|
||||
* @param {*} source The source that will be used to make a copy. Can be any type, including
|
||||
* primitives, `null`, and `undefined`.
|
||||
@@ -1529,7 +1532,7 @@ function allowAutoBootstrap(document) {
|
||||
link.href = src.value;
|
||||
|
||||
if (document.location.origin === link.origin) {
|
||||
// Same-origin resources are always allowed, even for non-whitelisted schemes.
|
||||
// Same-origin resources are always allowed, even for banned URL schemes.
|
||||
return true;
|
||||
}
|
||||
// Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
|
||||
@@ -1947,6 +1950,26 @@ function bindJQuery() {
|
||||
bindJQueryFired = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Restores the pre-1.8 behavior of jqLite that turns XHTML-like strings like
|
||||
* `<div /><span />` to `<div></div><span></span>` instead of `<div><span></span></div>`.
|
||||
* The new behavior is a security fix. Thus, if you need to call this function, please try to 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.
|
||||
*/
|
||||
function UNSAFE_restoreLegacyJqLiteXHTMLReplacement() {
|
||||
JQLite.legacyXHTMLReplacement = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* throw error if the argument is falsy.
|
||||
*/
|
||||
|
||||
@@ -156,6 +156,7 @@ function publishExternalAPI(angular) {
|
||||
'callbacks': {$$counter: 0},
|
||||
'getTestability': getTestability,
|
||||
'reloadWithDebugInfo': reloadWithDebugInfo,
|
||||
'UNSAFE_restoreLegacyJqLiteXHTMLReplacement': UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
|
||||
'$$minErr': minErr,
|
||||
'$$csp': csp,
|
||||
'$$encodeUriSegment': encodeUriSegment,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2018 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2020 Google LLC. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window) {
|
||||
|
||||
+58
-15
@@ -90,6 +90,16 @@
|
||||
* - [`val()`](http://api.jquery.com/val/)
|
||||
* - [`wrap()`](http://api.jquery.com/wrap/)
|
||||
*
|
||||
* jqLite also provides a method restoring pre-1.8 insecure treatment of XHTML-like tags.
|
||||
* This legacy behavior turns input like `<div /><span />` to `<div></div><span></span>`
|
||||
* instead of `<div><span></span></div>` like version 1.8 & newer do. To restore it, invoke:
|
||||
* ```js
|
||||
* angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement();
|
||||
* ```
|
||||
* 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.
|
||||
*
|
||||
* ## jQuery/jqLite Extras
|
||||
* AngularJS also provides the following additional methods and events to both jQuery and jqLite:
|
||||
*
|
||||
@@ -169,20 +179,36 @@ var HTML_REGEXP = /<|&#?\w+;/;
|
||||
var TAG_NAME_REGEXP = /<([\w:-]+)/;
|
||||
var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
|
||||
|
||||
// Table parts need to be wrapped with `<table>` or they're
|
||||
// stripped to their contents when put in a div.
|
||||
// XHTML parsers do not magically insert elements in the
|
||||
// same way that tag soup parsers do, so we cannot shorten
|
||||
// this by omitting <tbody> or other required elements.
|
||||
var wrapMap = {
|
||||
'option': [1, '<select multiple="multiple">', '</select>'],
|
||||
|
||||
'thead': [1, '<table>', '</table>'],
|
||||
'col': [2, '<table><colgroup>', '</colgroup></table>'],
|
||||
'tr': [2, '<table><tbody>', '</tbody></table>'],
|
||||
'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
|
||||
'_default': [0, '', '']
|
||||
thead: ['table'],
|
||||
col: ['colgroup', 'table'],
|
||||
tr: ['tbody', 'table'],
|
||||
td: ['tr', 'tbody', 'table']
|
||||
};
|
||||
|
||||
wrapMap.optgroup = wrapMap.option;
|
||||
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
|
||||
wrapMap.th = wrapMap.td;
|
||||
|
||||
// Support: IE <10 only
|
||||
// IE 9 requires an option wrapper & it needs to have the whole table structure
|
||||
// set up in advance; assigning `"<td></td>"` to `tr.innerHTML` doesn't work, etc.
|
||||
var wrapMapIE9 = {
|
||||
option: [1, '<select multiple="multiple">', '</select>'],
|
||||
_default: [0, '', '']
|
||||
};
|
||||
|
||||
for (var key in wrapMap) {
|
||||
var wrapMapValueClosing = wrapMap[key];
|
||||
var wrapMapValue = wrapMapValueClosing.slice().reverse();
|
||||
wrapMapIE9[key] = [wrapMapValue.length, '<' + wrapMapValue.join('><') + '>', '</' + wrapMapValueClosing.join('></') + '>'];
|
||||
}
|
||||
|
||||
wrapMapIE9.optgroup = wrapMapIE9.option;
|
||||
|
||||
function jqLiteIsTextNode(html) {
|
||||
return !HTML_REGEXP.test(html);
|
||||
@@ -203,7 +229,7 @@ function jqLiteHasData(node) {
|
||||
}
|
||||
|
||||
function jqLiteBuildFragment(html, context) {
|
||||
var tmp, tag, wrap,
|
||||
var tmp, tag, wrap, finalHtml,
|
||||
fragment = context.createDocumentFragment(),
|
||||
nodes = [], i;
|
||||
|
||||
@@ -214,13 +240,30 @@ function jqLiteBuildFragment(html, context) {
|
||||
// Convert html into DOM nodes
|
||||
tmp = fragment.appendChild(context.createElement('div'));
|
||||
tag = (TAG_NAME_REGEXP.exec(html) || ['', ''])[1].toLowerCase();
|
||||
wrap = wrapMap[tag] || wrapMap._default;
|
||||
tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, '<$1></$2>') + wrap[2];
|
||||
finalHtml = JQLite.legacyXHTMLReplacement ?
|
||||
html.replace(XHTML_TAG_REGEXP, '<$1></$2>') :
|
||||
html;
|
||||
|
||||
// Descend through wrappers to the right content
|
||||
i = wrap[0];
|
||||
while (i--) {
|
||||
tmp = tmp.lastChild;
|
||||
if (msie < 10) {
|
||||
wrap = wrapMapIE9[tag] || wrapMapIE9._default;
|
||||
tmp.innerHTML = wrap[1] + finalHtml + wrap[2];
|
||||
|
||||
// Descend through wrappers to the right content
|
||||
i = wrap[0];
|
||||
while (i--) {
|
||||
tmp = tmp.firstChild;
|
||||
}
|
||||
} else {
|
||||
wrap = wrapMap[tag] || [];
|
||||
|
||||
// Create wrappers & descend into them
|
||||
i = wrap.length;
|
||||
while (--i > -1) {
|
||||
tmp.appendChild(window.document.createElement(wrap[i]));
|
||||
tmp = tmp.firstChild;
|
||||
}
|
||||
|
||||
tmp.innerHTML = finalHtml;
|
||||
}
|
||||
|
||||
nodes = concat(nodes, tmp.childNodes);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2018 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2020 Google LLC. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ var minErrConfig = {
|
||||
* non-positive or non-numeric value, removes the max depth limit.
|
||||
* Default: 5
|
||||
*
|
||||
* * `urlErrorParamsEnabled` **{Boolean}** - Specifies wether the generated error url will
|
||||
* * `urlErrorParamsEnabled` **{Boolean}** - Specifies whether the generated error url will
|
||||
* contain the parameters of the thrown error. Disabling the parameters can be useful if the
|
||||
* generated error url is very long.
|
||||
*
|
||||
@@ -82,7 +82,7 @@ function isValidObjectMaxDepth(maxDepth) {
|
||||
* Since data will be parsed statically during a build step, some restrictions
|
||||
* are applied with respect to how minErr instances are created and called.
|
||||
* Instances should have names of the form namespaceMinErr for a minErr created
|
||||
* using minErr('namespace') . Error codes, namespaces and template strings
|
||||
* using minErr('namespace'). Error codes, namespaces and template strings
|
||||
* should all be static strings, not variables or general expressions.
|
||||
*
|
||||
* @param {string} module The namespace to use for the new minErr instance.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2018 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2020 Google LLC. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular) {
|
||||
|
||||
+106
-63
@@ -205,7 +205,7 @@
|
||||
*
|
||||
* This example show how you might use `$doCheck` to trigger changes in your component's inputs even if the
|
||||
* actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large
|
||||
* arrays or objects can have a negative impact on your application performance)
|
||||
* arrays or objects can have a negative impact on your application performance.)
|
||||
*
|
||||
* <example name="doCheckArrayExample" module="do-check-module">
|
||||
* <file name="index.html">
|
||||
@@ -528,7 +528,7 @@
|
||||
* would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
|
||||
* case when only one deeply nested directive has `templateUrl`.
|
||||
*
|
||||
* Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
|
||||
* Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}.
|
||||
*
|
||||
* You can specify `templateUrl` as a string representing the URL or as a function which takes two
|
||||
* arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
|
||||
@@ -589,7 +589,7 @@
|
||||
* own templates or compile functions. Compiling these directives results in an infinite loop and
|
||||
* stack overflow errors.
|
||||
*
|
||||
* This can be avoided by manually using $compile in the postLink function to imperatively compile
|
||||
* This can be avoided by manually using `$compile` in the postLink function to imperatively compile
|
||||
* a directive's template instead of relying on automatic template compilation via `template` or
|
||||
* `templateUrl` declaration or manual compilation inside the compile function.
|
||||
* </div>
|
||||
@@ -693,17 +693,17 @@
|
||||
*
|
||||
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
|
||||
* * `'element'` - transclude the whole of the directive's element including any directives on this
|
||||
* element that defined at a lower priority than this directive. When used, the `template`
|
||||
* element that are defined at a lower priority than this directive. When used, the `template`
|
||||
* property is ignored.
|
||||
* * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
|
||||
*
|
||||
* **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
|
||||
* **Multi-slot transclusion** is declared by providing an object for the `transclude` property.
|
||||
*
|
||||
* This object is a map where the keys are the name of the slot to fill and the value is an element selector
|
||||
* used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
|
||||
* and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
|
||||
*
|
||||
* For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
|
||||
* For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}.
|
||||
*
|
||||
* If the element selector is prefixed with a `?` then that slot is optional.
|
||||
*
|
||||
@@ -728,7 +728,7 @@
|
||||
* </div>
|
||||
*
|
||||
* If you want to manually control the insertion and removal of the transcluded content in your directive
|
||||
* then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
|
||||
* then you must use this transclude function. When you call a transclude function it returns a jqLite/JQuery
|
||||
* object that contains the compiled DOM, which is linked to the correct transclusion scope.
|
||||
*
|
||||
* When you call a transclusion function you can pass in a **clone attach function**. This function accepts
|
||||
@@ -813,8 +813,8 @@
|
||||
* The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
|
||||
* `link()` or `compile()` functions. It has a variety of uses.
|
||||
*
|
||||
* * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
|
||||
* 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
|
||||
* * *Accessing normalized attribute names:* Directives like `ngBind` can be expressed in many ways:
|
||||
* `ng:bind`, `data-ng-bind`, or `x-ng-bind`. The attributes object allows for normalized access
|
||||
* to the attributes.
|
||||
*
|
||||
* * *Directive inter-communication:* All directives share the same instance of the attributes
|
||||
@@ -855,25 +855,24 @@
|
||||
<file name="index.html">
|
||||
<script>
|
||||
angular.module('compileExample', [], function($compileProvider) {
|
||||
// configure new 'compile' directive by passing a directive
|
||||
// factory function. The factory function injects the '$compile'
|
||||
// Configure new 'compile' directive by passing a directive
|
||||
// factory function. The factory function injects '$compile'.
|
||||
$compileProvider.directive('compile', function($compile) {
|
||||
// directive factory creates a link function
|
||||
// The directive factory creates a link function.
|
||||
return function(scope, element, attrs) {
|
||||
scope.$watch(
|
||||
function(scope) {
|
||||
// watch the 'compile' expression for changes
|
||||
// Watch the 'compile' expression for changes.
|
||||
return scope.$eval(attrs.compile);
|
||||
},
|
||||
function(value) {
|
||||
// when the 'compile' expression changes
|
||||
// assign it into the current DOM
|
||||
// When the 'compile' expression changes
|
||||
// assign it into the current DOM.
|
||||
element.html(value);
|
||||
|
||||
// compile the new DOM and link it to the current
|
||||
// scope.
|
||||
// NOTE: we only compile .childNodes so that
|
||||
// we don't get into infinite loop compiling ourselves
|
||||
// Compile the new DOM and link it to the current scope.
|
||||
// NOTE: we only compile '.childNodes' so that we
|
||||
// don't get into an infinite loop compiling ourselves.
|
||||
$compile(element.contents())(scope);
|
||||
}
|
||||
);
|
||||
@@ -946,13 +945,13 @@
|
||||
* }
|
||||
* ```
|
||||
* * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
|
||||
* the cloned elements; only needed for transcludes that are allowed to contain non html
|
||||
* elements (e.g. SVG elements). See also the directive.controller property.
|
||||
* the cloned elements; only needed for transcludes that are allowed to contain non HTML
|
||||
* elements (e.g. SVG elements). See also the `directive.controller` property.
|
||||
*
|
||||
* Calling the linking function returns the element of the template. It is either the original
|
||||
* element passed in, or the clone of the element if the `cloneAttachFn` is provided.
|
||||
*
|
||||
* After linking the view is not updated until after a call to $digest which typically is done by
|
||||
* After linking the view is not updated until after a call to `$digest`, which typically is done by
|
||||
* AngularJS automatically.
|
||||
*
|
||||
* If you need access to the bound view, there are two ways to do it:
|
||||
@@ -960,21 +959,23 @@
|
||||
* - If you are not asking the linking function to clone the template, create the DOM element(s)
|
||||
* before you send them to the compiler and keep this reference around.
|
||||
* ```js
|
||||
* var element = $compile('<p>{{total}}</p>')(scope);
|
||||
* var element = angular.element('<p>{{total}}</p>');
|
||||
* $compile(element)(scope);
|
||||
* ```
|
||||
*
|
||||
* - if on the other hand, you need the element to be cloned, the view reference from the original
|
||||
* example would not point to the clone, but rather to the original template that was cloned. In
|
||||
* this case, you can access the clone via the cloneAttachFn:
|
||||
* this case, you can access the clone either via the `cloneAttachFn` or the value returned by the
|
||||
* linking function:
|
||||
* ```js
|
||||
* var templateElement = angular.element('<p>{{total}}</p>'),
|
||||
* scope = ....;
|
||||
*
|
||||
* var templateElement = angular.element('<p>{{total}}</p>');
|
||||
* var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
|
||||
* //attach the clone to DOM document at the right place
|
||||
* // Attach the clone to DOM document at the right place.
|
||||
* });
|
||||
*
|
||||
* //now we have reference to the cloned DOM via `clonedElement`
|
||||
* // Now we have reference to the cloned DOM via `clonedElement`.
|
||||
* // NOTE: The `clonedElement` returned by the linking function is the same as the
|
||||
* // `clonedElement` passed to `cloneAttachFn`.
|
||||
* ```
|
||||
*
|
||||
*
|
||||
@@ -1025,7 +1026,7 @@
|
||||
*
|
||||
* When the original node and the replace template declare the same directive(s), they will be
|
||||
* {@link guide/compiler#double-compilation-and-how-to-avoid-it compiled twice} because the compiler
|
||||
* does not deduplicate them. In many cases, this is not noticable, but e.g. {@link ngModel} will
|
||||
* does not deduplicate them. In many cases, this is not noticeable, but e.g. {@link ngModel} will
|
||||
* attach `$formatters` and `$parsers` twice.
|
||||
*
|
||||
* See issue [#2573](https://github.com/angular/angular.js/issues/2573).
|
||||
@@ -1105,8 +1106,8 @@
|
||||
*
|
||||
* Based on the context, other options may exist to mark a value as trusted / configure the behavior
|
||||
* of {@link ng.$sce}. For example, to restrict the `RESOURCE_URL` context to specific origins, use
|
||||
* the {@link $sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist()}
|
||||
* and {@link $sceDelegateProvider#resourceUrlBlacklist resourceUrlBlacklist()}.
|
||||
* the {@link $sceDelegateProvider#trustedResourceUrlList trustedResourceUrlList()}
|
||||
* and {@link $sceDelegateProvider#bannedResourceUrlList bannedResourceUrlList()}.
|
||||
*
|
||||
* {@link ng.$sce#what-trusted-context-types-are-supported- Find out more about the different context types}.
|
||||
*
|
||||
@@ -1115,7 +1116,7 @@
|
||||
* By default, `$sce` will throw an error if it detects untrusted HTML content, and will not bind the
|
||||
* content.
|
||||
* However, if you include the {@link ngSanitize ngSanitize module}, it will try to sanitize the
|
||||
* potentially dangerous HTML, e.g. strip non-whitelisted tags and attributes when binding to
|
||||
* potentially dangerous HTML, e.g. strip non-trusted tags and attributes when binding to
|
||||
* `innerHTML`.
|
||||
*
|
||||
* @example
|
||||
@@ -1500,9 +1501,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
* @description
|
||||
* Register a new directive with the compiler.
|
||||
*
|
||||
* @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
|
||||
* will match as <code>ng-bind</code>), or an object map of directives where the keys are the
|
||||
* names and the values are the factories.
|
||||
* @param {string|Object} name Name of the directive in camel-case (i.e. `ngBind` which will match
|
||||
* as `ng-bind`), or an object map of directives where the keys are the names and the values
|
||||
* are the factories.
|
||||
* @param {Function|Array} directiveFactory An injectable directive factory function. See the
|
||||
* {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
|
||||
* @returns {ng.$compileProvider} Self for chaining.
|
||||
@@ -1697,30 +1698,81 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $compileProvider#aHrefSanitizationWhitelist
|
||||
* @name $compileProvider#aHrefSanitizationTrustedUrlList
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
||||
* Retrieves or overrides the default regular expression that is used for determining trusted safe
|
||||
* urls during a[href] sanitization.
|
||||
*
|
||||
* The sanitization is a security measure aimed at preventing XSS attacks via html links.
|
||||
*
|
||||
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into
|
||||
* an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
|
||||
* an absolute url. Afterwards, the url is matched against the `aHrefSanitizationTrustedUrlList`
|
||||
* regular expression. If a match is found, the original url is written into the dom. Otherwise,
|
||||
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
|
||||
*
|
||||
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
||||
* @param {RegExp=} regexp New regexp to trust urls with.
|
||||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
||||
* chaining otherwise.
|
||||
*/
|
||||
this.aHrefSanitizationWhitelist = function(regexp) {
|
||||
this.aHrefSanitizationTrustedUrlList = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
$$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
|
||||
$$sanitizeUriProvider.aHrefSanitizationTrustedUrlList(regexp);
|
||||
return this;
|
||||
} else {
|
||||
return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
|
||||
return $$sanitizeUriProvider.aHrefSanitizationTrustedUrlList();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $compileProvider#aHrefSanitizationWhitelist
|
||||
* @kind function
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.8.1"
|
||||
*
|
||||
* This method is deprecated. Use {@link $compileProvider#aHrefSanitizationTrustedUrlList
|
||||
* aHrefSanitizationTrustedUrlList} instead.
|
||||
*/
|
||||
Object.defineProperty(this, 'aHrefSanitizationWhitelist', {
|
||||
get: function() {
|
||||
return this.aHrefSanitizationTrustedUrlList;
|
||||
},
|
||||
set: function(value) {
|
||||
this.aHrefSanitizationTrustedUrlList = value;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $compileProvider#imgSrcSanitizationTrustedUrlList
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Retrieves or overrides the default regular expression that is used for determining trusted safe
|
||||
* urls during img[src] sanitization.
|
||||
*
|
||||
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
|
||||
*
|
||||
* Any url about to be assigned to img[src] via data-binding is first normalized and turned into
|
||||
* an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationTrustedUrlList`
|
||||
* regular expression. If a match is found, the original url is written into the dom. Otherwise,
|
||||
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
|
||||
*
|
||||
* @param {RegExp=} regexp New regexp to trust urls with.
|
||||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
||||
* chaining otherwise.
|
||||
*/
|
||||
this.imgSrcSanitizationTrustedUrlList = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
$$sanitizeUriProvider.imgSrcSanitizationTrustedUrlList(regexp);
|
||||
return this;
|
||||
} else {
|
||||
return $$sanitizeUriProvider.imgSrcSanitizationTrustedUrlList();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1730,29 +1782,20 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
* @name $compileProvider#imgSrcSanitizationWhitelist
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
||||
* urls during img[src] sanitization.
|
||||
* @deprecated
|
||||
* sinceVersion="1.8.1"
|
||||
*
|
||||
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
|
||||
*
|
||||
* Any url about to be assigned to img[src] via data-binding is first normalized and turned into
|
||||
* an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
|
||||
* regular expression. If a match is found, the original url is written into the dom. Otherwise,
|
||||
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
|
||||
*
|
||||
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
||||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
||||
* chaining otherwise.
|
||||
* This method is deprecated. Use {@link $compileProvider#imgSrcSanitizationTrustedUrlList
|
||||
* imgSrcSanitizationTrustedUrlList} instead.
|
||||
*/
|
||||
this.imgSrcSanitizationWhitelist = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
$$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
|
||||
return this;
|
||||
} else {
|
||||
return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
|
||||
Object.defineProperty(this, 'imgSrcSanitizationWhitelist', {
|
||||
get: function() {
|
||||
return this.imgSrcSanitizationTrustedUrlList;
|
||||
},
|
||||
set: function(value) {
|
||||
this.imgSrcSanitizationTrustedUrlList = value;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
* By default, the template URL is restricted to the same domain and protocol as the
|
||||
* application document. This is done by calling {@link $sce#getTrustedResourceUrl
|
||||
* $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
|
||||
* you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
|
||||
* {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to AngularJS's {@link
|
||||
* ng.$sce Strict Contextual Escaping}.
|
||||
* you may either add them to your {@link ng.$sceDelegateProvider#trustedResourceUrlList trusted
|
||||
* resource URL list} or {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to
|
||||
* AngularJS's {@link ng.$sce Strict Contextual Escaping}.
|
||||
*
|
||||
* In addition, the browser's
|
||||
* [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
|
||||
|
||||
@@ -332,7 +332,7 @@
|
||||
* For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
|
||||
* the items have been processed through the filter.
|
||||
*
|
||||
* Please note that `as [variable name] is not an operator but rather a part of ngRepeat
|
||||
* Please note that `as [variable name]` is not an operator but rather a part of ngRepeat
|
||||
* micro-syntax so it can be used only after all filters (and not as operator, inside an expression).
|
||||
*
|
||||
* For example: `item in items | filter : x | orderBy : order | limitTo : limit as results track by item.id` .
|
||||
|
||||
@@ -42,11 +42,11 @@
|
||||
var colorSpan = element(by.css('span'));
|
||||
|
||||
it('should check ng-style', function() {
|
||||
expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
|
||||
expect(colorSpan.getCssValue('color')).toMatch(/rgba\(0, 0, 0, 1\)|rgb\(0, 0, 0\)/);
|
||||
element(by.css('input[value=\'set color\']')).click();
|
||||
expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
|
||||
expect(colorSpan.getCssValue('color')).toMatch(/rgba\(255, 0, 0, 1\)|rgb\(255, 0, 0\)/);
|
||||
element(by.css('input[value=clear]')).click();
|
||||
expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
|
||||
expect(colorSpan.getCssValue('color')).toMatch(/rgba\(0, 0, 0, 1\)|rgb\(0, 0, 0\)/);
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
@@ -54,14 +54,7 @@
|
||||
var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
||||
scope.$watchCollection(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
|
||||
if (oldStyles && (newStyles !== oldStyles)) {
|
||||
if (!newStyles) {
|
||||
newStyles = {};
|
||||
}
|
||||
forEach(oldStyles, function(val, style) {
|
||||
if (newStyles[style] == null) {
|
||||
newStyles[style] = '';
|
||||
}
|
||||
});
|
||||
forEach(oldStyles, function(val, style) { element.css(style, ''); });
|
||||
}
|
||||
if (newStyles) element.css(newStyles);
|
||||
});
|
||||
|
||||
+34
-14
@@ -388,7 +388,7 @@ function $HttpProvider() {
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $httpProvider#xsrfWhitelistedOrigins
|
||||
* @name $httpProvider#xsrfTrustedOrigins
|
||||
* @description
|
||||
*
|
||||
* Array containing URLs whose origins are trusted to receive the XSRF token. See the
|
||||
@@ -402,7 +402,7 @@ function $HttpProvider() {
|
||||
* Examples: `http://example.com`, `https://api.example.com:9876`
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* It is not possible to whitelist specific URLs/paths. The `path`, `query` and `fragment` parts
|
||||
* It is not possible to trust specific URLs/paths. The `path`, `query` and `fragment` parts
|
||||
* of a URL will be ignored. For example, `https://foo.com/path/bar?query=baz#fragment` will be
|
||||
* treated as `https://foo.com`, meaning that **all** requests to URLs starting with
|
||||
* `https://foo.com/` will include the XSRF token.
|
||||
@@ -413,9 +413,9 @@ function $HttpProvider() {
|
||||
* ```js
|
||||
* // App served from `https://example.com/`.
|
||||
* angular.
|
||||
* module('xsrfWhitelistedOriginsExample', []).
|
||||
* module('xsrfTrustedOriginsExample', []).
|
||||
* config(['$httpProvider', function($httpProvider) {
|
||||
* $httpProvider.xsrfWhitelistedOrigins.push('https://api.example.com');
|
||||
* $httpProvider.xsrfTrustedOrigins.push('https://api.example.com');
|
||||
* }]).
|
||||
* run(['$http', function($http) {
|
||||
* // The XSRF token will be sent.
|
||||
@@ -426,7 +426,27 @@ function $HttpProvider() {
|
||||
* }]);
|
||||
* ```
|
||||
*/
|
||||
var xsrfWhitelistedOrigins = this.xsrfWhitelistedOrigins = [];
|
||||
var xsrfTrustedOrigins = this.xsrfTrustedOrigins = [];
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $httpProvider#xsrfWhitelistedOrigins
|
||||
* @description
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.8.1"
|
||||
*
|
||||
* This property is deprecated. Use {@link $httpProvider#xsrfTrustedOrigins xsrfTrustedOrigins}
|
||||
* instead.
|
||||
*/
|
||||
Object.defineProperty(this, 'xsrfWhitelistedOrigins', {
|
||||
get: function() {
|
||||
return this.xsrfTrustedOrigins;
|
||||
},
|
||||
set: function(origins) {
|
||||
this.xsrfTrustedOrigins = origins;
|
||||
}
|
||||
});
|
||||
|
||||
this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', '$sce',
|
||||
function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector, $sce) {
|
||||
@@ -454,7 +474,7 @@ function $HttpProvider() {
|
||||
/**
|
||||
* A function to check request URLs against a list of allowed origins.
|
||||
*/
|
||||
var urlIsAllowedOrigin = urlIsAllowedOriginFactory(xsrfWhitelistedOrigins);
|
||||
var urlIsAllowedOrigin = urlIsAllowedOriginFactory(xsrfTrustedOrigins);
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
@@ -828,16 +848,16 @@ function $HttpProvider() {
|
||||
* The header will — by default — **not** be set for cross-domain requests. This
|
||||
* prevents unauthorized servers (e.g. malicious or compromised 3rd-party APIs) from gaining
|
||||
* access to your users' XSRF tokens and exposing them to Cross Site Request Forgery. If you
|
||||
* want to, you can whitelist additional origins to also receive the XSRF token, by adding them
|
||||
* to {@link ng.$httpProvider#xsrfWhitelistedOrigins xsrfWhitelistedOrigins}. This might be
|
||||
* want to, you can trust additional origins to also receive the XSRF token, by adding them
|
||||
* to {@link ng.$httpProvider#xsrfTrustedOrigins xsrfTrustedOrigins}. This might be
|
||||
* useful, for example, if your application, served from `example.com`, needs to access your API
|
||||
* at `api.example.com`.
|
||||
* See {@link ng.$httpProvider#xsrfWhitelistedOrigins $httpProvider.xsrfWhitelistedOrigins} for
|
||||
* See {@link ng.$httpProvider#xsrfTrustedOrigins $httpProvider.xsrfTrustedOrigins} for
|
||||
* more details.
|
||||
*
|
||||
* <div class="alert alert-danger">
|
||||
* **Warning**<br />
|
||||
* Only whitelist origins that you have control over and make sure you understand the
|
||||
* Only trusted origins that you have control over and make sure you understand the
|
||||
* implications of doing so.
|
||||
* </div>
|
||||
*
|
||||
@@ -964,8 +984,8 @@ function $HttpProvider() {
|
||||
<file name="script.js">
|
||||
angular.module('httpExample', [])
|
||||
.config(['$sceDelegateProvider', function($sceDelegateProvider) {
|
||||
// We must whitelist the JSONP endpoint that we are using to show that we trust it
|
||||
$sceDelegateProvider.resourceUrlWhitelist([
|
||||
// We must add the JSONP endpoint that we are using to the trusted list to show that we trust it
|
||||
$sceDelegateProvider.trustedResourceUrlList([
|
||||
'self',
|
||||
'https://angularjs.org/**'
|
||||
]);
|
||||
@@ -1222,8 +1242,8 @@ function $HttpProvider() {
|
||||
*
|
||||
* Note that, since JSONP requests are sensitive because the response is given full access to the browser,
|
||||
* the url must be declared, via {@link $sce} as a trusted resource URL.
|
||||
* You can trust a URL by adding it to the whitelist via
|
||||
* {@link $sceDelegateProvider#resourceUrlWhitelist `$sceDelegateProvider.resourceUrlWhitelist`} or
|
||||
* You can trust a URL by adding it to the trusted resource URL list via
|
||||
* {@link $sceDelegateProvider#trustedResourceUrlList `$sceDelegateProvider.trustedResourceUrlList`} or
|
||||
* by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}.
|
||||
*
|
||||
* You should avoid generating the URL for the JSONP request from user provided data.
|
||||
|
||||
+2
-2
@@ -1900,7 +1900,7 @@ function $ParseProvider() {
|
||||
|
||||
var useInputs = parsedExpression.inputs && !exp.inputs;
|
||||
|
||||
// Propogate the literal/inputs/constant attributes
|
||||
// Propagate the literal/inputs/constant attributes
|
||||
// ... but not oneTime since we are handling it
|
||||
oneTimeWatch.literal = parsedExpression.literal;
|
||||
oneTimeWatch.constant = parsedExpression.constant;
|
||||
@@ -1987,7 +1987,7 @@ function $ParseProvider() {
|
||||
fn.$$intercepted = parsedExpression;
|
||||
fn.$$interceptor = interceptorFn;
|
||||
|
||||
// Propogate the literal/oneTime/constant attributes
|
||||
// Propagate the literal/oneTime/constant attributes
|
||||
fn.literal = parsedExpression.literal;
|
||||
fn.oneTime = parsedExpression.oneTime;
|
||||
fn.constant = parsedExpression.constant;
|
||||
|
||||
+16
-15
@@ -7,12 +7,12 @@
|
||||
*/
|
||||
function $$SanitizeUriProvider() {
|
||||
|
||||
var aHrefSanitizationWhitelist = /^\s*(https?|s?ftp|mailto|tel|file):/,
|
||||
imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
|
||||
var aHrefSanitizationTrustedUrlList = /^\s*(https?|s?ftp|mailto|tel|file):/,
|
||||
imgSrcSanitizationTrustedUrlList = /^\s*((https?|ftp|file|blob):|data:image\/)/;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
||||
* Retrieves or overrides the default regular expression that is used for determining trusted safe
|
||||
* urls during a[href] sanitization.
|
||||
*
|
||||
* The sanitization is a security measure aimed at prevent XSS attacks via HTML anchor links.
|
||||
@@ -21,27 +21,27 @@ function $$SanitizeUriProvider() {
|
||||
* the $sce.URL security context. When interpolation occurs a call is made to `$sce.trustAsUrl(url)`
|
||||
* which in turn may call `$$sanitizeUri(url, isMedia)` to sanitize the potentially malicious URL.
|
||||
*
|
||||
* If the URL matches the `aHrefSanitizationWhitelist` regular expression, it is returned unchanged.
|
||||
* If the URL matches the `aHrefSanitizationTrustedUrlList` regular expression, it is returned unchanged.
|
||||
*
|
||||
* If there is no match the URL is returned prefixed with `'unsafe:'` to ensure that when it is written
|
||||
* to the DOM it is inactive and potentially malicious code will not be executed.
|
||||
*
|
||||
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
||||
* @param {RegExp=} regexp New regexp to trust urls with.
|
||||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
||||
* chaining otherwise.
|
||||
*/
|
||||
this.aHrefSanitizationWhitelist = function(regexp) {
|
||||
this.aHrefSanitizationTrustedUrlList = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
aHrefSanitizationWhitelist = regexp;
|
||||
aHrefSanitizationTrustedUrlList = regexp;
|
||||
return this;
|
||||
}
|
||||
return aHrefSanitizationWhitelist;
|
||||
return aHrefSanitizationTrustedUrlList;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
||||
* Retrieves or overrides the default regular expression that is used for determining trusted safe
|
||||
* urls during img[src] sanitization.
|
||||
*
|
||||
* The sanitization is a security measure aimed at prevent XSS attacks via HTML image src links.
|
||||
@@ -51,27 +51,28 @@ function $$SanitizeUriProvider() {
|
||||
* `$sce.trustAsMediaUrl(url)` which in turn may call `$$sanitizeUri(url, isMedia)` to sanitize
|
||||
* the potentially malicious URL.
|
||||
*
|
||||
* If the URL matches the `aImgSanitizationWhitelist` regular expression, it is returned unchanged.
|
||||
* If the URL matches the `imgSrcSanitizationTrustedUrlList` regular expression, it is returned
|
||||
* unchanged.
|
||||
*
|
||||
* If there is no match the URL is returned prefixed with `'unsafe:'` to ensure that when it is written
|
||||
* to the DOM it is inactive and potentially malicious code will not be executed.
|
||||
*
|
||||
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
||||
* @param {RegExp=} regexp New regexp to trust urls with.
|
||||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
||||
* chaining otherwise.
|
||||
*/
|
||||
this.imgSrcSanitizationWhitelist = function(regexp) {
|
||||
this.imgSrcSanitizationTrustedUrlList = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
imgSrcSanitizationWhitelist = regexp;
|
||||
imgSrcSanitizationTrustedUrlList = regexp;
|
||||
return this;
|
||||
}
|
||||
return imgSrcSanitizationWhitelist;
|
||||
return imgSrcSanitizationTrustedUrlList;
|
||||
};
|
||||
|
||||
this.$get = function() {
|
||||
return function sanitizeUri(uri, isMediaUrl) {
|
||||
// if (!uri) return uri;
|
||||
var regex = isMediaUrl ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
|
||||
var regex = isMediaUrl ? imgSrcSanitizationTrustedUrlList : aHrefSanitizationTrustedUrlList;
|
||||
var normalizedVal = urlResolve(uri && uri.trim()).href;
|
||||
if (normalizedVal !== '' && !normalizedVal.match(regex)) {
|
||||
return 'unsafe:' + normalizedVal;
|
||||
|
||||
+118
-77
@@ -118,10 +118,10 @@ function adjustMatchers(matchers) {
|
||||
* The default instance of `$sceDelegate` should work out of the box with little pain. While you
|
||||
* can override it completely to change the behavior of `$sce`, the common case would
|
||||
* involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
|
||||
* your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
|
||||
* templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
|
||||
* $sceDelegateProvider.resourceUrlWhitelist} and {@link
|
||||
* ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
|
||||
* your own trusted and banned resource lists for trusting URLs used for loading AngularJS resources
|
||||
* such as templates. Refer {@link ng.$sceDelegateProvider#trustedResourceUrlList
|
||||
* $sceDelegateProvider.trustedResourceUrlList} and {@link
|
||||
* ng.$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList}
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -134,12 +134,12 @@ function adjustMatchers(matchers) {
|
||||
* The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
|
||||
* $sceDelegate service}, used as a delegate for {@link ng.$sce Strict Contextual Escaping (SCE)}.
|
||||
*
|
||||
* The `$sceDelegateProvider` allows one to get/set the whitelists and blacklists used to ensure
|
||||
* that the URLs used for sourcing AngularJS templates and other script-running URLs are safe (all
|
||||
* places that use the `$sce.RESOURCE_URL` context). See
|
||||
* {@link ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist}
|
||||
* and
|
||||
* {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist},
|
||||
* The `$sceDelegateProvider` allows one to get/set the `trustedResourceUrlList` and
|
||||
* `bannedResourceUrlList` used to ensure that the URLs used for sourcing AngularJS templates and
|
||||
* other script-running URLs are safe (all places that use the `$sce.RESOURCE_URL` context). See
|
||||
* {@link ng.$sceDelegateProvider#trustedResourceUrlList
|
||||
* $sceDelegateProvider.trustedResourceUrlList} and
|
||||
* {@link ng.$sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider.bannedResourceUrlList},
|
||||
*
|
||||
* For the general details about this service in AngularJS, read the main page for {@link ng.$sce
|
||||
* Strict Contextual Escaping (SCE)}.
|
||||
@@ -155,64 +155,117 @@ function adjustMatchers(matchers) {
|
||||
*
|
||||
* ```
|
||||
* angular.module('myApp', []).config(function($sceDelegateProvider) {
|
||||
* $sceDelegateProvider.resourceUrlWhitelist([
|
||||
* $sceDelegateProvider.trustedResourceUrlList([
|
||||
* // Allow same origin resource loads.
|
||||
* 'self',
|
||||
* // Allow loading from our assets domain. Notice the difference between * and **.
|
||||
* 'http://srv*.assets.example.com/**'
|
||||
* ]);
|
||||
*
|
||||
* // The blacklist overrides the whitelist so the open redirect here is blocked.
|
||||
* $sceDelegateProvider.resourceUrlBlacklist([
|
||||
* // The banned resource URL list overrides the trusted resource URL list so the open redirect
|
||||
* // here is blocked.
|
||||
* $sceDelegateProvider.bannedResourceUrlList([
|
||||
* 'http://myapp.example.com/clickThru**'
|
||||
* ]);
|
||||
* });
|
||||
* ```
|
||||
* Note that an empty whitelist will block every resource URL from being loaded, and will require
|
||||
* Note that an empty trusted resource URL list will block every resource URL from being loaded, and will require
|
||||
* you to manually mark each one as trusted with `$sce.trustAsResourceUrl`. However, templates
|
||||
* requested by {@link ng.$templateRequest $templateRequest} that are present in
|
||||
* {@link ng.$templateCache $templateCache} will not go through this check. If you have a mechanism
|
||||
* to populate your templates in that cache at config time, then it is a good idea to remove 'self'
|
||||
* from that whitelist. This helps to mitigate the security impact of certain types of issues, like
|
||||
* for instance attacker-controlled `ng-includes`.
|
||||
* from the trusted resource URL lsit. This helps to mitigate the security impact of certain types
|
||||
* of issues, like for instance attacker-controlled `ng-includes`.
|
||||
*/
|
||||
|
||||
function $SceDelegateProvider() {
|
||||
this.SCE_CONTEXTS = SCE_CONTEXTS;
|
||||
|
||||
// Resource URLs can also be trusted by policy.
|
||||
var resourceUrlWhitelist = ['self'],
|
||||
resourceUrlBlacklist = [];
|
||||
var trustedResourceUrlList = ['self'],
|
||||
bannedResourceUrlList = [];
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $sceDelegateProvider#trustedResourceUrlList
|
||||
* @kind function
|
||||
*
|
||||
* @param {Array=} trustedResourceUrlList When provided, replaces the trustedResourceUrlList with
|
||||
* the value provided. This must be an array or null. A snapshot of this array is used so
|
||||
* further changes to the array are ignored.
|
||||
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
||||
* allowed in this array.
|
||||
*
|
||||
* @return {Array} The currently set trusted resource URL array.
|
||||
*
|
||||
* @description
|
||||
* Sets/Gets the list trusted of resource URLs.
|
||||
*
|
||||
* The **default value** when no `trustedResourceUrlList` has been explicitly set is `['self']`
|
||||
* allowing only same origin resource requests.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** the default `trustedResourceUrlList` of 'self' is not recommended if your app shares
|
||||
* its origin with other apps! It is a good idea to limit it to only your application's directory.
|
||||
* </div>
|
||||
*/
|
||||
this.trustedResourceUrlList = function(value) {
|
||||
if (arguments.length) {
|
||||
trustedResourceUrlList = adjustMatchers(value);
|
||||
}
|
||||
return trustedResourceUrlList;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $sceDelegateProvider#resourceUrlWhitelist
|
||||
* @kind function
|
||||
*
|
||||
* @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
|
||||
* provided. This must be an array or null. A snapshot of this array is used so further
|
||||
* changes to the array are ignored.
|
||||
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
||||
* allowed in this array.
|
||||
* @deprecated
|
||||
* sinceVersion="1.8.1"
|
||||
*
|
||||
* @return {Array} The currently set whitelist array.
|
||||
* This method is deprecated. Use {@link $sceDelegateProvider#trustedResourceUrlList
|
||||
* trustedResourceUrlList} instead.
|
||||
*/
|
||||
Object.defineProperty(this, 'resourceUrlWhitelist', {
|
||||
get: function() {
|
||||
return this.trustedResourceUrlList;
|
||||
},
|
||||
set: function(value) {
|
||||
this.trustedResourceUrlList = value;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $sceDelegateProvider#bannedResourceUrlList
|
||||
* @kind function
|
||||
*
|
||||
* @param {Array=} bannedResourceUrlList When provided, replaces the `bannedResourceUrlList` with
|
||||
* the value provided. This must be an array or null. A snapshot of this array is used so
|
||||
* further changes to the array are ignored.</p><p>
|
||||
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
||||
* allowed in this array.</p><p>
|
||||
* The typical usage for the `bannedResourceUrlList` is to **block
|
||||
* [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
|
||||
* these would otherwise be trusted but actually return content from the redirected domain.
|
||||
* </p><p>
|
||||
* Finally, **the banned resource URL list overrides the trusted resource URL list** and has
|
||||
* the final say.
|
||||
*
|
||||
* @return {Array} The currently set `bannedResourceUrlList` array.
|
||||
*
|
||||
* @description
|
||||
* Sets/Gets the whitelist of trusted resource URLs.
|
||||
* Sets/Gets the `bannedResourceUrlList` of trusted resource URLs.
|
||||
*
|
||||
* The **default value** when no whitelist has been explicitly set is `['self']` allowing only
|
||||
* same origin resource requests.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** the default whitelist of 'self' is not recommended if your app shares its origin
|
||||
* with other apps! It is a good idea to limit it to only your application's directory.
|
||||
* </div>
|
||||
* The **default value** when no trusted resource URL list has been explicitly set is the empty
|
||||
* array (i.e. there is no `bannedResourceUrlList`.)
|
||||
*/
|
||||
this.resourceUrlWhitelist = function(value) {
|
||||
this.bannedResourceUrlList = function(value) {
|
||||
if (arguments.length) {
|
||||
resourceUrlWhitelist = adjustMatchers(value);
|
||||
bannedResourceUrlList = adjustMatchers(value);
|
||||
}
|
||||
return resourceUrlWhitelist;
|
||||
return bannedResourceUrlList;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -220,32 +273,20 @@ function $SceDelegateProvider() {
|
||||
* @name $sceDelegateProvider#resourceUrlBlacklist
|
||||
* @kind function
|
||||
*
|
||||
* @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
|
||||
* provided. This must be an array or null. A snapshot of this array is used so further
|
||||
* changes to the array are ignored.</p><p>
|
||||
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
||||
* allowed in this array.</p><p>
|
||||
* The typical usage for the blacklist is to **block
|
||||
* [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
|
||||
* these would otherwise be trusted but actually return content from the redirected domain.
|
||||
* </p><p>
|
||||
* Finally, **the blacklist overrides the whitelist** and has the final say.
|
||||
* @deprecated
|
||||
* sinceVersion="1.8.1"
|
||||
*
|
||||
* @return {Array} The currently set blacklist array.
|
||||
*
|
||||
* @description
|
||||
* Sets/Gets the blacklist of trusted resource URLs.
|
||||
*
|
||||
* The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
|
||||
* is no blacklist.)
|
||||
* This method is deprecated. Use {@link $sceDelegateProvider#bannedResourceUrlList
|
||||
* bannedResourceUrlList} instead.
|
||||
*/
|
||||
|
||||
this.resourceUrlBlacklist = function(value) {
|
||||
if (arguments.length) {
|
||||
resourceUrlBlacklist = adjustMatchers(value);
|
||||
Object.defineProperty(this, 'resourceUrlBlacklist', {
|
||||
get: function() {
|
||||
return this.bannedResourceUrlList;
|
||||
},
|
||||
set: function(value) {
|
||||
this.bannedResourceUrlList = value;
|
||||
}
|
||||
return resourceUrlBlacklist;
|
||||
};
|
||||
});
|
||||
|
||||
this.$get = ['$injector', '$$sanitizeUri', function($injector, $$sanitizeUri) {
|
||||
|
||||
@@ -270,17 +311,17 @@ function $SceDelegateProvider() {
|
||||
function isResourceUrlAllowedByPolicy(url) {
|
||||
var parsedUrl = urlResolve(url.toString());
|
||||
var i, n, allowed = false;
|
||||
// Ensure that at least one item from the whitelist allows this url.
|
||||
for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
|
||||
if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
|
||||
// Ensure that at least one item from the trusted resource URL list allows this url.
|
||||
for (i = 0, n = trustedResourceUrlList.length; i < n; i++) {
|
||||
if (matchUrl(trustedResourceUrlList[i], parsedUrl)) {
|
||||
allowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allowed) {
|
||||
// Ensure that no item from the blacklist blocked this url.
|
||||
for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
|
||||
if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
|
||||
// Ensure that no item from the banned resource URL list has blocked this url.
|
||||
for (i = 0, n = bannedResourceUrlList.length; i < n; i++) {
|
||||
if (matchUrl(bannedResourceUrlList[i], parsedUrl)) {
|
||||
allowed = false;
|
||||
break;
|
||||
}
|
||||
@@ -401,9 +442,9 @@ function $SceDelegateProvider() {
|
||||
* The contexts that can be sanitized are $sce.MEDIA_URL, $sce.URL and $sce.HTML. The first two are available
|
||||
* by default, and the third one relies on the `$sanitize` service (which may be loaded through
|
||||
* the `ngSanitize` module). Furthermore, for $sce.RESOURCE_URL context, a plain string may be
|
||||
* accepted if the resource url policy defined by {@link ng.$sceDelegateProvider#resourceUrlWhitelist
|
||||
* `$sceDelegateProvider.resourceUrlWhitelist`} and {@link ng.$sceDelegateProvider#resourceUrlBlacklist
|
||||
* `$sceDelegateProvider.resourceUrlBlacklist`} accepts that resource.
|
||||
* accepted if the resource url policy defined by {@link ng.$sceDelegateProvider#trustedResourceUrlList
|
||||
* `$sceDelegateProvider.trustedResourceUrlList`} and {@link ng.$sceDelegateProvider#bannedResourceUrlList
|
||||
* `$sceDelegateProvider.bannedResourceUrlList`} accepts that resource.
|
||||
*
|
||||
* This function will throw if the safe type isn't appropriate for this context, or if the
|
||||
* value given cannot be accepted in the context (which might be caused by sanitization not
|
||||
@@ -497,9 +538,9 @@ function $SceDelegateProvider() {
|
||||
*
|
||||
* To systematically block XSS security bugs, AngularJS treats all values as untrusted by default in
|
||||
* HTML or sensitive URL bindings. When binding untrusted values, AngularJS will automatically
|
||||
* run security checks on them (sanitizations, whitelists, depending on context), or throw when it
|
||||
* cannot guarantee the security of the result. That behavior depends strongly on contexts: HTML
|
||||
* can be sanitized, but template URLs cannot, for instance.
|
||||
* run security checks on them (sanitizations, trusted URL resource, depending on context), or throw
|
||||
* when it cannot guarantee the security of the result. That behavior depends strongly on contexts:
|
||||
* HTML can be sanitized, but template URLs cannot, for instance.
|
||||
*
|
||||
* To illustrate this, consider the `ng-bind-html` directive. It renders its value directly as HTML:
|
||||
* we call that the *context*. When given an untrusted input, AngularJS will attempt to sanitize it
|
||||
@@ -578,8 +619,8 @@ function $SceDelegateProvider() {
|
||||
* By default, AngularJS only loads templates from the same domain and protocol as the application
|
||||
* document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
|
||||
* $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or
|
||||
* protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
|
||||
* them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
|
||||
* protocols, you may either add them to the {@link ng.$sceDelegateProvider#trustedResourceUrlList
|
||||
* trustedResourceUrlList} or {@link ng.$sce#trustAsResourceUrl wrap them} into trusted values.
|
||||
*
|
||||
* *Please note*:
|
||||
* The browser's
|
||||
@@ -607,8 +648,8 @@ function $SceDelegateProvider() {
|
||||
* templates in `ng-include` from your application's domain without having to even know about SCE.
|
||||
* It blocks loading templates from other domains or loading templates over http from an https
|
||||
* served document. You can change these by setting your own custom {@link
|
||||
* ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
|
||||
* ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
|
||||
* ng.$sceDelegateProvider#trustedResourceUrlList trusted resource URL list} and {@link
|
||||
* ng.$sceDelegateProvider#bannedResourceUrlList banned resource URL list} for matching such URLs.
|
||||
*
|
||||
* This significantly reduces the overhead. It is far easier to pay the small overhead and have an
|
||||
* application that's secure and can be audited to verify that with much more ease than bolting
|
||||
@@ -623,7 +664,7 @@ function $SceDelegateProvider() {
|
||||
* | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. |
|
||||
* | `$sce.MEDIA_URL` | For URLs that are safe to render as media. Is automatically converted from string by sanitizing when needed. |
|
||||
* | `$sce.URL` | For URLs that are safe to follow as links. Is automatically converted from string by sanitizing when needed. Note that `$sce.URL` makes a stronger statement about the URL than `$sce.MEDIA_URL` does and therefore contexts requiring values trusted for `$sce.URL` can be used anywhere that values trusted for `$sce.MEDIA_URL` are required.|
|
||||
* | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` or `$sce.MEDIA_URL` do and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` or `$sce.MEDIA_URL` are required. <br><br> The {@link $sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider#resourceUrlWhitelist()} and {@link $sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider#resourceUrlBlacklist()} can be used to restrict trusted origins for `RESOURCE_URL` |
|
||||
* | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` or `$sce.MEDIA_URL` do and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` or `$sce.MEDIA_URL` are required. <br><br> The {@link $sceDelegateProvider#trustedResourceUrlList $sceDelegateProvider#trustedResourceUrlList()} and {@link $sceDelegateProvider#bannedResourceUrlList $sceDelegateProvider#bannedResourceUrlList()} can be used to restrict trusted origins for `RESOURCE_URL` |
|
||||
* | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. |
|
||||
*
|
||||
*
|
||||
@@ -641,7 +682,7 @@ function $SceDelegateProvider() {
|
||||
* There are no CSS or JS context bindings in AngularJS currently, so their corresponding `$sce.trustAs`
|
||||
* functions aren't useful yet. This might evolve.
|
||||
*
|
||||
* ### Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
|
||||
* ### Format of items in {@link ng.$sceDelegateProvider#trustedResourceUrlList trustedResourceUrlList}/{@link ng.$sceDelegateProvider#bannedResourceUrlList bannedResourceUrlList} <a name="resourceUrlPatternItem"></a>
|
||||
*
|
||||
* Each element in these arrays must be one of the following:
|
||||
*
|
||||
@@ -655,7 +696,7 @@ function $SceDelegateProvider() {
|
||||
* match themselves.
|
||||
* - `*`: matches zero or more occurrences of any character other than one of the following 6
|
||||
* characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'. It's a useful wildcard for use
|
||||
* in a whitelist.
|
||||
* for matching resource URL lists.
|
||||
* - `**`: matches zero or more occurrences of *any* character. As such, it's not
|
||||
* appropriate for use in a scheme, domain, etc. as it would match too much. (e.g.
|
||||
* http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
|
||||
|
||||
@@ -73,10 +73,10 @@ function $TemplateRequestProvider() {
|
||||
handleRequestFn.totalPendingRequests++;
|
||||
|
||||
// We consider the template cache holds only trusted templates, so
|
||||
// there's no need to go through whitelisting again for keys that already
|
||||
// are included in there. This also makes AngularJS accept any script
|
||||
// directive, no matter its name. However, we still need to unwrap trusted
|
||||
// types.
|
||||
// there's no need to go through adding the template again to the trusted
|
||||
// resources for keys that already are included in there. This also makes
|
||||
// AngularJS accept any script directive, no matter its name. However, we
|
||||
// still need to unwrap trusted types.
|
||||
if (!isString(tpl) || isUndefined($templateCache.get(tpl))) {
|
||||
tpl = $sce.getTrustedResourceUrl(tpl);
|
||||
}
|
||||
|
||||
+5
-5
@@ -125,20 +125,20 @@ function urlIsSameOriginAsBaseUrl(requestUrl) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a function that can check a URL's origin against a list of allowed/whitelisted origins.
|
||||
* Create a function that can check a URL's origin against a list of allowed/trusted origins.
|
||||
* The current location's origin is implicitly trusted.
|
||||
*
|
||||
* @param {string[]} whitelistedOriginUrls - A list of URLs (strings), whose origins are trusted.
|
||||
* @param {string[]} trustedOriginUrls - A list of URLs (strings), whose origins are trusted.
|
||||
*
|
||||
* @returns {Function} - A function that receives a URL (string or parsed URL object) and returns
|
||||
* whether it is of an allowed origin.
|
||||
*/
|
||||
function urlIsAllowedOriginFactory(whitelistedOriginUrls) {
|
||||
var parsedAllowedOriginUrls = [originUrl].concat(whitelistedOriginUrls.map(urlResolve));
|
||||
function urlIsAllowedOriginFactory(trustedOriginUrls) {
|
||||
var parsedAllowedOriginUrls = [originUrl].concat(trustedOriginUrls.map(urlResolve));
|
||||
|
||||
/**
|
||||
* Check whether the specified URL (string or parsed URL object) has an origin that is allowed
|
||||
* based on a list of whitelisted-origin URLs. The current location's origin is implicitly
|
||||
* based on a list of trusted-origin URLs. The current location's origin is implicitly
|
||||
* trusted.
|
||||
*
|
||||
* @param {string|Object} requestUrl - The URL to be checked (provided as a string that will be
|
||||
|
||||
+16
-17
@@ -64,7 +64,7 @@ var ngAriaModule = angular.module('ngAria', ['ng']).
|
||||
/**
|
||||
* Internal Utilities
|
||||
*/
|
||||
var nodeBlackList = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY'];
|
||||
var nativeAriaNodeNames = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY'];
|
||||
|
||||
var isNodeOneOf = function(elem, nodeTypeArray) {
|
||||
if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) {
|
||||
@@ -136,12 +136,12 @@ function $AriaProvider() {
|
||||
config = angular.extend(config, newConfig);
|
||||
};
|
||||
|
||||
function watchExpr(attrName, ariaAttr, nodeBlackList, negate) {
|
||||
function watchExpr(attrName, ariaAttr, nativeAriaNodeNames, negate) {
|
||||
return function(scope, elem, attr) {
|
||||
if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
|
||||
|
||||
var ariaCamelName = attr.$normalize(ariaAttr);
|
||||
if (config[ariaCamelName] && !isNodeOneOf(elem, nodeBlackList) && !attr[ariaCamelName]) {
|
||||
if (config[ariaCamelName] && !isNodeOneOf(elem, nativeAriaNodeNames) && !attr[ariaCamelName]) {
|
||||
scope.$watch(attr[attrName], function(boolVal) {
|
||||
// ensure boolean value
|
||||
boolVal = negate ? !boolVal : !!boolVal;
|
||||
@@ -155,7 +155,6 @@ function $AriaProvider() {
|
||||
* @name $aria
|
||||
*
|
||||
* @description
|
||||
* @priority 200
|
||||
*
|
||||
* The $aria service contains helper methods for applying common
|
||||
* [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
|
||||
@@ -166,7 +165,7 @@ function $AriaProvider() {
|
||||
*
|
||||
*```js
|
||||
* ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
|
||||
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
|
||||
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nativeAriaNodeNames, false);
|
||||
* }])
|
||||
*```
|
||||
* Shown above, the ngAria module creates a directive with the same signature as the
|
||||
@@ -218,31 +217,31 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false);
|
||||
}])
|
||||
.directive('ngValue', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngValue', 'aria-checked', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngValue', 'aria-checked', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngChecked', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngChecked', 'aria-checked', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngChecked', 'aria-checked', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngReadonly', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngRequired', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngRequired', 'aria-required', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngRequired', 'aria-required', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngModel', ['$aria', function($aria) {
|
||||
|
||||
function shouldAttachAttr(attr, normalizedAttr, elem, allowBlacklistEls) {
|
||||
function shouldAttachAttr(attr, normalizedAttr, elem, allowNonAriaNodes) {
|
||||
return $aria.config(normalizedAttr) &&
|
||||
!elem.attr(attr) &&
|
||||
(allowBlacklistEls || !isNodeOneOf(elem, nodeBlackList)) &&
|
||||
(allowNonAriaNodes || !isNodeOneOf(elem, nativeAriaNodeNames)) &&
|
||||
(elem.attr('type') !== 'hidden' || elem[0].nodeName !== 'INPUT');
|
||||
}
|
||||
|
||||
function shouldAttachRole(role, elem) {
|
||||
// if element does not have role attribute
|
||||
// AND element type is equal to role (if custom element has a type equaling shape) <-- remove?
|
||||
// AND element is not in nodeBlackList
|
||||
return !elem.attr('role') && (elem.attr('type') === role) && !isNodeOneOf(elem, nodeBlackList);
|
||||
// AND element is not in nativeAriaNodeNames
|
||||
return !elem.attr('role') && (elem.attr('type') === role) && !isNodeOneOf(elem, nativeAriaNodeNames);
|
||||
}
|
||||
|
||||
function getShape(attr, elem) {
|
||||
@@ -350,7 +349,7 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
};
|
||||
}])
|
||||
.directive('ngDisabled', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
|
||||
return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nativeAriaNodeNames, false);
|
||||
}])
|
||||
.directive('ngMessages', function() {
|
||||
return {
|
||||
@@ -374,7 +373,7 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
var fn = $parse(attr.ngClick);
|
||||
return function(scope, elem, attr) {
|
||||
|
||||
if (!isNodeOneOf(elem, nodeBlackList)) {
|
||||
if (!isNodeOneOf(elem, nativeAriaNodeNames)) {
|
||||
|
||||
if ($aria.config('bindRoleForClick') && !elem.attr('role')) {
|
||||
elem.attr('role', 'button');
|
||||
@@ -390,7 +389,7 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
|
||||
if (keyCode === 13 || keyCode === 32) {
|
||||
// If the event is triggered on a non-interactive element ...
|
||||
if (nodeBlackList.indexOf(event.target.nodeName) === -1 && !event.target.isContentEditable) {
|
||||
if (nativeAriaNodeNames.indexOf(event.target.nodeName) === -1 && !event.target.isContentEditable) {
|
||||
// ... prevent the default browser behavior (e.g. scrolling when pressing spacebar)
|
||||
// See https://github.com/angular/angular.js/issues/16664
|
||||
event.preventDefault();
|
||||
@@ -412,7 +411,7 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
return function(scope, elem, attr) {
|
||||
if (attr.hasOwnProperty(ARIA_DISABLE_ATTR)) return;
|
||||
|
||||
if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nodeBlackList)) {
|
||||
if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nativeAriaNodeNames)) {
|
||||
elem.attr('tabindex', 0);
|
||||
}
|
||||
};
|
||||
|
||||
+18
-40
@@ -41,12 +41,12 @@ var htmlSanitizeWriter;
|
||||
* @description
|
||||
* Sanitizes an html string by stripping all potentially dangerous tokens.
|
||||
*
|
||||
* The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are
|
||||
* The input is sanitized by parsing the HTML into tokens. All safe tokens (from a trusted URI list) are
|
||||
* then serialized back to a properly escaped HTML string. This means that no unsafe input can make
|
||||
* it into the returned string.
|
||||
*
|
||||
* The whitelist for URL sanitization of attribute values is configured using the functions
|
||||
* `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link $compileProvider}.
|
||||
* The trusted URIs for URL sanitization of attribute values is configured using the functions
|
||||
* `aHrefSanitizationTrustedUrlList` and `imgSrcSanitizationTrustedUrlList` of {@link $compileProvider}.
|
||||
*
|
||||
* The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
|
||||
*
|
||||
@@ -277,8 +277,8 @@ function $SanitizeProvider() {
|
||||
* **Note**:
|
||||
* The new attributes will not be treated as URI attributes, which means their values will not be
|
||||
* sanitized as URIs using `$compileProvider`'s
|
||||
* {@link ng.$compileProvider#aHrefSanitizationWhitelist aHrefSanitizationWhitelist} and
|
||||
* {@link ng.$compileProvider#imgSrcSanitizationWhitelist imgSrcSanitizationWhitelist}.
|
||||
* {@link ng.$compileProvider#aHrefSanitizationTrustedUrlList aHrefSanitizationTrustedUrlList} and
|
||||
* {@link ng.$compileProvider#imgSrcSanitizationTrustedUrlList imgSrcSanitizationTrustedUrlList}.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* This method must be called during the {@link angular.Module#config config} phase. Once the
|
||||
@@ -421,50 +421,28 @@ function $SanitizeProvider() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an inert document that contains the dirty HTML that needs sanitizing
|
||||
* Depending upon browser support we use one of three strategies for doing this.
|
||||
* Support: Safari 10.x -> XHR strategy
|
||||
* Support: Firefox -> DomParser strategy
|
||||
* Create an inert document that contains the dirty HTML that needs sanitizing.
|
||||
* We use the DOMParser API by default and fall back to createHTMLDocument if DOMParser is not
|
||||
* available.
|
||||
*/
|
||||
var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) {
|
||||
var inertDocument;
|
||||
if (document && document.implementation) {
|
||||
inertDocument = document.implementation.createHTMLDocument('inert');
|
||||
} else {
|
||||
if (isDOMParserAvailable()) {
|
||||
return getInertBodyElement_DOMParser;
|
||||
}
|
||||
|
||||
if (!document || !document.implementation) {
|
||||
throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document');
|
||||
}
|
||||
var inertDocument = document.implementation.createHTMLDocument('inert');
|
||||
var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body');
|
||||
return getInertBodyElement_InertDocument;
|
||||
|
||||
// Check for the Safari 10.1 bug - which allows JS to run inside the SVG G element
|
||||
inertBodyElement.innerHTML = '<svg><g onload="this.parentNode.remove()"></g></svg>';
|
||||
if (!inertBodyElement.querySelector('svg')) {
|
||||
return getInertBodyElement_XHR;
|
||||
} else {
|
||||
// Check for the Firefox bug - which prevents the inner img JS from being sanitized
|
||||
inertBodyElement.innerHTML = '<svg><p><style><img src="</style><img src=x onerror=alert(1)//">';
|
||||
if (inertBodyElement.querySelector('svg img')) {
|
||||
return getInertBodyElement_DOMParser;
|
||||
} else {
|
||||
return getInertBodyElement_InertDocument;
|
||||
}
|
||||
}
|
||||
|
||||
function getInertBodyElement_XHR(html) {
|
||||
// We add this dummy element to ensure that the rest of the content is parsed as expected
|
||||
// e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag.
|
||||
html = '<remove></remove>' + html;
|
||||
function isDOMParserAvailable() {
|
||||
try {
|
||||
html = encodeURI(html);
|
||||
return !!getInertBodyElement_DOMParser('');
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
return false;
|
||||
}
|
||||
var xhr = new window.XMLHttpRequest();
|
||||
xhr.responseType = 'document';
|
||||
xhr.open('GET', 'data:text/html;charset=utf-8,' + html, false);
|
||||
xhr.send(null);
|
||||
var body = xhr.response.body;
|
||||
body.firstChild.remove();
|
||||
return body;
|
||||
}
|
||||
|
||||
function getInertBodyElement_DOMParser(html) {
|
||||
|
||||
+19
-1
@@ -814,6 +814,19 @@ describe('angular', function() {
|
||||
expect(isElement(dst.jqObject)).toBeTruthy();
|
||||
expect(dst.jqObject.nodeName).toBeUndefined(); // i.e it is a jqLite/jQuery object
|
||||
});
|
||||
|
||||
it('should not merge the __proto__ property', function() {
|
||||
var src = JSON.parse('{ "__proto__": { "xxx": "polluted" } }');
|
||||
var dst = {};
|
||||
|
||||
merge(dst, src);
|
||||
|
||||
if (typeof dst.__proto__ !== 'undefined') { // eslint-disable-line
|
||||
// Should not overwrite the __proto__ property or pollute the Object prototype
|
||||
expect(dst.__proto__).toBe(Object.prototype); // eslint-disable-line
|
||||
}
|
||||
expect(({}).xxx).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1780,7 +1793,12 @@ describe('angular', function() {
|
||||
} else if (/Chrome\//.test(userAgent)) {
|
||||
protocol = 'chrome-extension:';
|
||||
} else if (/Safari\//.test(userAgent)) {
|
||||
protocol = 'safari-extension:';
|
||||
// On iOS, Safari versions <15 recognize `safari-extension:`, while versions >=15 only
|
||||
// recognize `chrome-extension:`.
|
||||
// (On macOS, Safari v15 recognizes both protocols, so it is fine to use either.)
|
||||
var majorVersionMatch = /Version\/(\d+)/.exec(userAgent);
|
||||
var majorVersion = majorVersionMatch ? parseInt(majorVersionMatch[1], 10) : 0;
|
||||
protocol = (majorVersion < 15) ? 'safari-extension:' : 'chrome-extension:';
|
||||
} else {
|
||||
protocol = 'browserext:'; // Upcoming standard scheme.
|
||||
}
|
||||
|
||||
@@ -123,6 +123,8 @@ describe('$anchorScroll', function() {
|
||||
var lastAnchor = anchors.last();
|
||||
var lastAnchorId = 'anchor-5';
|
||||
|
||||
if (browser.params.browser === 'firefox') return;
|
||||
|
||||
// Make sure there is not enough room to scroll the last anchor to the top
|
||||
lastAnchor.getSize().then(function(size) {
|
||||
var tempHeight = size.height + (yOffset / 2);
|
||||
|
||||
@@ -9,14 +9,12 @@ describe('ngRoute promises', function() {
|
||||
expect(element.all(by.tagName('li')).count()).toBe(5);
|
||||
});
|
||||
|
||||
it('should time out if the promise takes long enough', function() {
|
||||
it('should time out if the promise takes long enough', function(done) {
|
||||
// Don't try this at home kids, I'm a protractor dev
|
||||
browser.manage().timeouts().setScriptTimeout(1000);
|
||||
browser.waitForAngular().then(function() {
|
||||
fail('waitForAngular() should have timed out, but didn\'t');
|
||||
}, function(error) {
|
||||
expect(error.message).toContain('Timed out waiting for asynchronous Angular tasks to finish');
|
||||
});
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should wait for route promises when navigating to another route', function() {
|
||||
|
||||
@@ -9,4 +9,13 @@ describe('Sample', function() {
|
||||
it('should have the interpolated text', function() {
|
||||
expect(element(by.binding('text')).getText()).toBe('Hello, world!');
|
||||
});
|
||||
|
||||
it('should insert the ng-cloak styles', function() {
|
||||
browser.executeScript(`
|
||||
var span = document.createElement('span');
|
||||
span.className = 'ng-cloak foo';
|
||||
document.body.appendChild(span);
|
||||
`);
|
||||
expect(element(by.className('foo')).isDisplayed()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -147,6 +147,13 @@ describe('jqLite', function() {
|
||||
expect(nodes[0].nodeName.toLowerCase()).toBe('option');
|
||||
});
|
||||
|
||||
it('should allow construction of multiple <option> elements', function() {
|
||||
var nodes = jqLite('<option></option><option></option>');
|
||||
expect(nodes.length).toBe(2);
|
||||
expect(nodes[0].nodeName.toLowerCase()).toBe('option');
|
||||
expect(nodes[1].nodeName.toLowerCase()).toBe('option');
|
||||
});
|
||||
|
||||
|
||||
// Special tests for the construction of elements which are restricted (in the HTML5 spec) to
|
||||
// being children of specific nodes.
|
||||
@@ -169,6 +176,95 @@ describe('jqLite', function() {
|
||||
expect(nodes[0].nodeName.toLowerCase()).toBe(name);
|
||||
});
|
||||
});
|
||||
|
||||
describe('security', function() {
|
||||
it('shouldn\'t crash at attempts to close the table wrapper', function() {
|
||||
// jQuery doesn't pass this test yet.
|
||||
if (!_jqLiteMode) return;
|
||||
|
||||
// Support: IE <10
|
||||
// In IE 9 we still need to use the old-style innerHTML assignment
|
||||
// as that's the only one that works.
|
||||
if (msie < 10) return;
|
||||
|
||||
expect(function() {
|
||||
// This test case attempts to close the tags which wrap input
|
||||
// based on matching done in wrapMap, escaping the wrapper & thus
|
||||
// triggering an error when descending.
|
||||
var el = jqLite('<td></td></tr></tbody></table><td></td>');
|
||||
expect(el.length).toBe(2);
|
||||
expect(el[0].nodeName.toLowerCase()).toBe('td');
|
||||
expect(el[1].nodeName.toLowerCase()).toBe('td');
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('shouldn\'t unsanitize sanitized code', function(done) {
|
||||
// jQuery <3.5.0 fail those tests.
|
||||
if (isJQuery2x()) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
var counter = 0,
|
||||
assertCount = 13,
|
||||
container = jqLite('<div></div>');
|
||||
|
||||
function donePartial() {
|
||||
counter++;
|
||||
if (counter === assertCount) {
|
||||
container.remove();
|
||||
delete window.xss;
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
jqLite(document.body).append(container);
|
||||
window.xss = jasmine.createSpy('xss');
|
||||
|
||||
// Thanks to Masato Kinugawa from Cure53 for providing the following test cases.
|
||||
// Note: below test cases need to invoke the xss function with consecutive
|
||||
// decimal parameters for the assertions to be correct.
|
||||
forEach([
|
||||
'<img alt="<x" title="/><img src=url404 onerror=xss(0)>">',
|
||||
'<img alt="\n<x" title="/>\n<img src=url404 onerror=xss(1)>">',
|
||||
'<style><style/><img src=url404 onerror=xss(2)>',
|
||||
'<xmp><xmp/><img src=url404 onerror=xss(3)>',
|
||||
'<title><title /><img src=url404 onerror=xss(4)>',
|
||||
'<iframe><iframe/><img src=url404 onerror=xss(5)>',
|
||||
'<noframes><noframes/><img src=url404 onerror=xss(6)>',
|
||||
'<noscript><noscript/><img src=url404 onerror=xss(7)>',
|
||||
'<foo" alt="" title="/><img src=url404 onerror=xss(8)>">',
|
||||
'<img alt="<x" title="" src="/><img src=url404 onerror=xss(9)>">',
|
||||
'<noscript/><img src=url404 onerror=xss(10)>',
|
||||
'<noembed><noembed/><img src=url404 onerror=xss(11)>',
|
||||
|
||||
'<option><style></option></select><img src=url404 onerror=xss(12)></style>'
|
||||
], function(htmlString, index) {
|
||||
var element = jqLite('<div></div>');
|
||||
|
||||
container.append(element);
|
||||
element.append(jqLite(htmlString));
|
||||
|
||||
window.setTimeout(function() {
|
||||
expect(window.xss).not.toHaveBeenCalledWith(index);
|
||||
donePartial();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow to restore legacy insecure behavior', function() {
|
||||
// jQuery doesn't have this API.
|
||||
if (!_jqLiteMode) return;
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement();
|
||||
|
||||
var elem = jqLite('<div/><span/>');
|
||||
expect(elem.length).toBe(2);
|
||||
expect(elem[0].nodeName.toLowerCase()).toBe('div');
|
||||
expect(elem[1].nodeName.toLowerCase()).toBe('span');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('_data', function() {
|
||||
|
||||
+25
-25
@@ -151,30 +151,30 @@ describe('$compile', function() {
|
||||
|
||||
describe('configuration', function() {
|
||||
|
||||
it('should use $$sanitizeUriProvider for reconfiguration of the `aHrefSanitizationWhitelist`', function() {
|
||||
it('should use $$sanitizeUriProvider for reconfiguration of the `aHrefSanitizationTrustedUrlList`', function() {
|
||||
module(function($compileProvider, $$sanitizeUriProvider) {
|
||||
var newRe = /safe:/, returnVal;
|
||||
|
||||
expect($compileProvider.aHrefSanitizationWhitelist()).toBe($$sanitizeUriProvider.aHrefSanitizationWhitelist());
|
||||
returnVal = $compileProvider.aHrefSanitizationWhitelist(newRe);
|
||||
expect($compileProvider.aHrefSanitizationTrustedUrlList()).toBe($$sanitizeUriProvider.aHrefSanitizationTrustedUrlList());
|
||||
returnVal = $compileProvider.aHrefSanitizationTrustedUrlList(newRe);
|
||||
expect(returnVal).toBe($compileProvider);
|
||||
expect($$sanitizeUriProvider.aHrefSanitizationWhitelist()).toBe(newRe);
|
||||
expect($compileProvider.aHrefSanitizationWhitelist()).toBe(newRe);
|
||||
expect($$sanitizeUriProvider.aHrefSanitizationTrustedUrlList()).toBe(newRe);
|
||||
expect($compileProvider.aHrefSanitizationTrustedUrlList()).toBe(newRe);
|
||||
});
|
||||
inject(function() {
|
||||
// needed to the module definition above is run...
|
||||
});
|
||||
});
|
||||
|
||||
it('should use $$sanitizeUriProvider for reconfiguration of the `imgSrcSanitizationWhitelist`', function() {
|
||||
it('should use $$sanitizeUriProvider for reconfiguration of the `imgSrcSanitizationTrustedUrlList`', function() {
|
||||
module(function($compileProvider, $$sanitizeUriProvider) {
|
||||
var newRe = /safe:/, returnVal;
|
||||
|
||||
expect($compileProvider.imgSrcSanitizationWhitelist()).toBe($$sanitizeUriProvider.imgSrcSanitizationWhitelist());
|
||||
returnVal = $compileProvider.imgSrcSanitizationWhitelist(newRe);
|
||||
expect($compileProvider.imgSrcSanitizationTrustedUrlList()).toBe($$sanitizeUriProvider.imgSrcSanitizationTrustedUrlList());
|
||||
returnVal = $compileProvider.imgSrcSanitizationTrustedUrlList(newRe);
|
||||
expect(returnVal).toBe($compileProvider);
|
||||
expect($$sanitizeUriProvider.imgSrcSanitizationWhitelist()).toBe(newRe);
|
||||
expect($compileProvider.imgSrcSanitizationWhitelist()).toBe(newRe);
|
||||
expect($$sanitizeUriProvider.imgSrcSanitizationTrustedUrlList()).toBe(newRe);
|
||||
expect($compileProvider.imgSrcSanitizationTrustedUrlList()).toBe(newRe);
|
||||
});
|
||||
inject(function() {
|
||||
// needed to the module definition above is run...
|
||||
@@ -11334,9 +11334,9 @@ describe('$compile', function() {
|
||||
// IE9 rejects the `video` / `audio` tags with "Error: Not implemented"
|
||||
if (msie !== 9 || tag === 'img') {
|
||||
describe(tag + '[src] context requirement', function() {
|
||||
it('should NOT require trusted values for whitelisted URIs', inject(function($rootScope, $compile) {
|
||||
it('should NOT require trusted values for trusted URIs', inject(function($rootScope, $compile) {
|
||||
element = $compile('<' + tag + ' src="{{testUrl}}"></' + tag + '>')($rootScope);
|
||||
$rootScope.testUrl = 'http://example.com/image.mp4'; // `http` is whitelisted
|
||||
$rootScope.testUrl = 'http://example.com/image.mp4'; // `http` is trusted
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('src')).toEqual('http://example.com/image.mp4');
|
||||
}));
|
||||
@@ -11372,9 +11372,9 @@ describe('$compile', function() {
|
||||
if (msie !== 9) {
|
||||
['source', 'track'].forEach(function(tag) {
|
||||
describe(tag + '[src]', function() {
|
||||
it('should NOT require trusted values for whitelisted URIs', inject(function($rootScope, $compile) {
|
||||
it('should NOT require trusted values for trusted URIs', inject(function($rootScope, $compile) {
|
||||
element = $compile('<video><' + tag + ' src="{{testUrl}}"></' + tag + '></video>')($rootScope);
|
||||
$rootScope.testUrl = 'http://example.com/image.mp4'; // `http` is whitelisted
|
||||
$rootScope.testUrl = 'http://example.com/image.mp4'; // `http` is trusted
|
||||
$rootScope.$digest();
|
||||
expect(element.find(tag).attr('src')).toEqual('http://example.com/image.mp4');
|
||||
}));
|
||||
@@ -11509,14 +11509,14 @@ describe('$compile', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should NOT require trusted values for whitelisted values', inject(function($rootScope, $compile, $sce) {
|
||||
it('should NOT require trusted values for trusted URI values', inject(function($rootScope, $compile, $sce) {
|
||||
element = $compile('<img srcset="{{testUrl}}"></img>')($rootScope);
|
||||
$rootScope.testUrl = 'http://example.com/image.png'; // `http` is whitelisted
|
||||
$rootScope.testUrl = 'http://example.com/image.png'; // `http` is trusted
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('srcset')).toEqual('http://example.com/image.png');
|
||||
}));
|
||||
|
||||
it('should accept trusted values, if they are also whitelisted', inject(function($rootScope, $compile, $sce) {
|
||||
it('should accept trusted values, if they are also trusted URIs', inject(function($rootScope, $compile, $sce) {
|
||||
element = $compile('<img srcset="{{testUrl}}"></img>')($rootScope);
|
||||
$rootScope.testUrl = $sce.trustAsUrl('http://example.com');
|
||||
$rootScope.$digest();
|
||||
@@ -11602,8 +11602,8 @@ describe('$compile', function() {
|
||||
});
|
||||
|
||||
describe('a[href] sanitization', function() {
|
||||
it('should NOT require trusted values for whitelisted values', inject(function($rootScope, $compile) {
|
||||
$rootScope.testUrl = 'http://example.com/image.png'; // `http` is whitelisted
|
||||
it('should NOT require trusted values for trusted URI values', inject(function($rootScope, $compile) {
|
||||
$rootScope.testUrl = 'http://example.com/image.png'; // `http` is trusted
|
||||
element = $compile('<a href="{{testUrl}}"></a>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('href')).toEqual('http://example.com/image.png');
|
||||
@@ -11613,8 +11613,8 @@ describe('$compile', function() {
|
||||
expect(element.attr('ng-href')).toEqual('http://example.com/image.png');
|
||||
}));
|
||||
|
||||
it('should accept trusted values for non-whitelisted values', inject(function($rootScope, $compile, $sce) {
|
||||
$rootScope.testUrl = $sce.trustAsUrl('javascript:foo()'); // `javascript` is not whitelisted
|
||||
it('should accept trusted values for non-trusted URI values', inject(function($rootScope, $compile, $sce) {
|
||||
$rootScope.testUrl = $sce.trustAsUrl('javascript:foo()'); // `javascript` is not trusted
|
||||
element = $compile('<a href="{{testUrl}}"></a>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('href')).toEqual('javascript:foo()');
|
||||
@@ -11624,8 +11624,8 @@ describe('$compile', function() {
|
||||
expect(element.attr('ng-href')).toEqual('javascript:foo()');
|
||||
}));
|
||||
|
||||
it('should sanitize non-whitelisted values', inject(function($rootScope, $compile) {
|
||||
$rootScope.testUrl = 'javascript:foo()'; // `javascript` is not whitelisted
|
||||
it('should sanitize non-trusted values', inject(function($rootScope, $compile) {
|
||||
$rootScope.testUrl = 'javascript:foo()'; // `javascript` is not trusted
|
||||
element = $compile('<a href="{{testUrl}}"></a>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('href')).toEqual('unsafe:javascript:foo()');
|
||||
@@ -11678,7 +11678,7 @@ describe('$compile', function() {
|
||||
$provide.value('$$sanitizeUri', $$sanitizeUri);
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
// This URL would fail the RESOURCE_URL whitelist, but that test shouldn't be run
|
||||
// This URL would fail the RESOURCE_URL trusted list, but that test shouldn't be run
|
||||
// because these interpolations will be resolved against the URL context instead
|
||||
$rootScope.testUrl = 'https://bad.example.org';
|
||||
|
||||
@@ -11700,7 +11700,7 @@ describe('$compile', function() {
|
||||
$provide.value('$$sanitizeUri', $$sanitizeUri);
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
// This URL would fail the RESOURCE_URL whitelist, but that test shouldn't be run
|
||||
// This URL would fail the RESOURCE_URL trusted list, but that test shouldn't be run
|
||||
// because these interpolations will be resolved against the URL context instead
|
||||
$rootScope.testUrl = 'https://bad.example.org';
|
||||
|
||||
|
||||
@@ -1271,10 +1271,10 @@ describe('input', function() {
|
||||
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="breakMe"/>');
|
||||
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.breakMe = new Date(2009, 0, 6, 16, 25, 0);
|
||||
$rootScope.breakMe = new Date(2009, 0, 6, 16, 25, 1, 337);
|
||||
});
|
||||
|
||||
expect(inputElm.val()).toBe('2009-01-06T16:25:00.000');
|
||||
expect(inputElm.val()).toBe('2009-01-06T16:25:01.337');
|
||||
|
||||
//set to text for browsers with datetime-local validation.
|
||||
inputElm[0].setAttribute('type', 'text');
|
||||
@@ -1324,32 +1324,32 @@ describe('input', function() {
|
||||
it('should use UTC if specified in the options', function() {
|
||||
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
|
||||
|
||||
helper.changeInputValueTo('2000-01-01T01:02');
|
||||
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
|
||||
helper.changeInputValueTo('2000-01-01T01:02:03.456');
|
||||
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 3, 456));
|
||||
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 0));
|
||||
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 3, 456));
|
||||
});
|
||||
expect(inputElm.val()).toBe('2001-01-01T01:02:00.000');
|
||||
expect(inputElm.val()).toBe('2001-01-01T01:02:03.456');
|
||||
});
|
||||
|
||||
|
||||
it('should be possible to override the timezone', function() {
|
||||
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
|
||||
|
||||
helper.changeInputValueTo('2000-01-01T01:02');
|
||||
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
|
||||
helper.changeInputValueTo('2000-01-01T01:02:03.456');
|
||||
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 3, 456));
|
||||
|
||||
inputElm.controller('ngModel').$overrideModelOptions({timezone: '+0500'});
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 0));
|
||||
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 3, 456));
|
||||
});
|
||||
expect(inputElm.val()).toBe('2001-01-01T06:02:00.000');
|
||||
expect(inputElm.val()).toBe('2001-01-01T06:02:03.456');
|
||||
|
||||
inputElm.controller('ngModel').$overrideModelOptions({timezone: 'UTC'});
|
||||
|
||||
helper.changeInputValueTo('2000-01-01T01:02');
|
||||
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
|
||||
helper.changeInputValueTo('2000-01-01T01:02:03.456');
|
||||
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 3, 456));
|
||||
});
|
||||
|
||||
|
||||
@@ -1360,13 +1360,13 @@ describe('input', function() {
|
||||
var inputElm = helper.compileInput(
|
||||
'<input type="datetime-local" ng-model="value" ng-model-options="' + ngModelOptions + '" />');
|
||||
|
||||
helper.changeInputValueTo('2000-01-01T06:02');
|
||||
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 0));
|
||||
helper.changeInputValueTo('2000-01-01T06:02:03.456');
|
||||
expect(+$rootScope.value).toBe(Date.UTC(2000, 0, 1, 1, 2, 3, 456));
|
||||
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 0));
|
||||
$rootScope.value = new Date(Date.UTC(2001, 0, 1, 1, 2, 3, 456));
|
||||
});
|
||||
expect(inputElm.val()).toBe('2001-01-01T06:02:00.000');
|
||||
expect(inputElm.val()).toBe('2001-01-01T06:02:03.456');
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1401,13 +1401,13 @@ describe('input', function() {
|
||||
it('should allow to specify the seconds', function() {
|
||||
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value"" />');
|
||||
|
||||
helper.changeInputValueTo('2000-01-01T01:02:03');
|
||||
expect(+$rootScope.value).toBe(+new Date(2000, 0, 1, 1, 2, 3));
|
||||
helper.changeInputValueTo('2000-01-01T01:02:03.456');
|
||||
expect(+$rootScope.value).toBe(+new Date(2000, 0, 1, 1, 2, 3, 456));
|
||||
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.value = new Date(2001, 0, 1, 1, 2, 3);
|
||||
$rootScope.value = new Date(2001, 0, 1, 1, 2, 3, 456);
|
||||
});
|
||||
expect(inputElm.val()).toBe('2001-01-01T01:02:03.000');
|
||||
expect(inputElm.val()).toBe('2001-01-01T01:02:03.456');
|
||||
});
|
||||
|
||||
|
||||
@@ -1425,13 +1425,13 @@ describe('input', function() {
|
||||
it('should allow four or more digits in year', function() {
|
||||
var inputElm = helper.compileInput('<input type="datetime-local" ng-model="value" />');
|
||||
|
||||
helper.changeInputValueTo('10123-01-01T01:02');
|
||||
expect(+$rootScope.value).toBe(+new Date(10123, 0, 1, 1, 2, 0));
|
||||
helper.changeInputValueTo('10123-01-01T01:02:03.456');
|
||||
expect(+$rootScope.value).toBe(+new Date(10123, 0, 1, 1, 2, 3, 456));
|
||||
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.value = new Date(20456, 1, 1, 1, 2, 0);
|
||||
$rootScope.value = new Date(20456, 1, 1, 1, 2, 3, 456);
|
||||
});
|
||||
expect(inputElm.val()).toBe('20456-02-01T01:02:00.000');
|
||||
expect(inputElm.val()).toBe('20456-02-01T01:02:03.456');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user