Compare commits
318 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b879223cf3 | |||
| bba6004147 | |||
| d386b7ae4b | |||
| ebc5a477db | |||
| 21c935a303 | |||
| 7e5ef766da | |||
| 1cb96303e9 | |||
| d2058d92bd | |||
| 053f4e26ae | |||
| 45ca45a29a | |||
| e2bf5726ab | |||
| bf706f2f52 | |||
| d2fe381ea8 | |||
| 63c83ffa43 | |||
| 7fa13c3da2 | |||
| 4b91042559 | |||
| a9ecde1e33 | |||
| ada25a9266 | |||
| 0f956b2893 | |||
| 17eb3d717f | |||
| c9ccc801b9 | |||
| 420490aa1b | |||
| 2a65c3deb7 | |||
| ef0c333776 | |||
| bce1d8ecad | |||
| 5a1bc6eb32 | |||
| 1f7a0b2b72 | |||
| a665550933 | |||
| d434f3db53 | |||
| 7e08975b67 | |||
| 82c481bb23 | |||
| b1f46bb1b2 | |||
| 3a6bf0d5bc | |||
| e201f9040f | |||
| 40e9bcd1b4 | |||
| f98e038418 | |||
| ec98c94ccb | |||
| f13055a0a5 | |||
| 623ce1ad2c | |||
| 34cf141838 | |||
| 274e93537e | |||
| f7622dcc0d | |||
| 2c03a35743 | |||
| 6b72598b87 | |||
| 51e24d75c3 | |||
| 64a142b58e | |||
| 0026ebf2de | |||
| a4f73c9f99 | |||
| bd5c4e5f0e | |||
| 9742565d61 | |||
| 6f33dfa8cc | |||
| 96f0c8df17 | |||
| 53fb534889 | |||
| 6271ac064c | |||
| 2d71b5b053 | |||
| a547dff09b | |||
| 3f9517ea5b | |||
| 8b4ffdde7a | |||
| e57240d87d | |||
| a51b4e6dc4 | |||
| 215be0b0ab | |||
| 7c5880f998 | |||
| 0d941a986a | |||
| 8714cabdb7 | |||
| cbab2923ef | |||
| dba7e20e96 | |||
| 24dd9ea649 | |||
| 8bd59a593b | |||
| 9a1349d2e0 | |||
| 7e6155a6f1 | |||
| 0f034444c3 | |||
| 74ecea9f2d | |||
| 8d5c08c6b8 | |||
| 0bb57d538f | |||
| 61a3fb676a | |||
| f486ebe80b | |||
| 03190fd896 | |||
| 340e4da2eb | |||
| 46e4fa87fb | |||
| 45d43b9234 | |||
| 6b28aef1c5 | |||
| 5a1b4a06f4 | |||
| 12f08c5e14 | |||
| 706a93ab69 | |||
| c4ae7d261a | |||
| 0adc036426 | |||
| 1ee58612a2 | |||
| ddc7f85493 | |||
| 90621a6c89 | |||
| 0c59599a45 | |||
| 4a4db1e7e6 | |||
| 10d8b010d3 | |||
| 3881831906 | |||
| 9e3f82bbaf | |||
| 05156143c8 | |||
| 39b078bad4 | |||
| 9055b4e041 | |||
| 6224a3eefb | |||
| a45a34c261 | |||
| ceeeb6b4b1 | |||
| cbc5f1c114 | |||
| 4dfb80d96f | |||
| 368039b881 | |||
| 647f3f55eb | |||
| c8de0e425f | |||
| 9717c8fe1f | |||
| fee437f9cf | |||
| 861b1a3d9d | |||
| 72ff49f40f | |||
| 7a529992c8 | |||
| e89d6829bc | |||
| 1b343e7bb6 | |||
| b3c022d672 | |||
| 9dd0fe35d1 | |||
| 7560a8d2d6 | |||
| c68357dbf8 | |||
| eaf6981499 | |||
| 1cc24f3c4f | |||
| 9e3e26328e | |||
| 82b2961868 | |||
| 3cb10edca0 | |||
| b64519fea7 | |||
| 830c81d0f1 | |||
| 66650bfb36 | |||
| 900b3a416c | |||
| f40252205e | |||
| 40441f6dfc | |||
| 1f65087126 | |||
| d5c99ea42b | |||
| bbc5fdde50 | |||
| b5685e23f0 | |||
| 5b26521de2 | |||
| abfbfd6c1c | |||
| a0e91c4ef7 | |||
| 3353fb84aa | |||
| 3a22c6461d | |||
| 54f5d82d4f | |||
| e80434c93f | |||
| 7dd5d7a523 | |||
| 6198c0d9c0 | |||
| 1acde764d5 | |||
| 3bdb39f667 | |||
| f231dda29d | |||
| 03f858ea5c | |||
| 4a26249946 | |||
| 06364c8cdc | |||
| 1c282af5ab | |||
| 45f006f6fb | |||
| 731e1f6534 | |||
| 634e467172 | |||
| 2ca34a0cd3 | |||
| 181e5ebc3f | |||
| 874392464b | |||
| 7e7244402d | |||
| 4b94b9e34f | |||
| a2e7f54320 | |||
| 9b2e11b6fa | |||
| 2114a50c9a | |||
| 38f92c3a27 | |||
| 7dbf1ef2d1 | |||
| e13aae1ed0 | |||
| 36eacb172a | |||
| f2683f956f | |||
| 1a670aa466 | |||
| 578425303f | |||
| 528cf09e3f | |||
| c849098fbf | |||
| 145d397988 | |||
| 26d4d0dc22 | |||
| 64a9faaf8e | |||
| b7aba16839 | |||
| a72e1c4767 | |||
| 6545212d24 | |||
| 3fabbdb804 | |||
| ce8be9c47f | |||
| b3878a36d9 | |||
| ebd84e8008 | |||
| e721169738 | |||
| cdfbe25c00 | |||
| 0d4b15a4c9 | |||
| 0dd061c239 | |||
| 7288be25a7 | |||
| 2b279dd8a1 | |||
| 63b9956faf | |||
| 92767c098f | |||
| 2fe9b1dd9e | |||
| b9ad91cf1e | |||
| 40752a520a | |||
| 21369943fa | |||
| 190ea883c5 | |||
| 3a093123ef | |||
| b8e8f9af78 | |||
| 01161a0e9f | |||
| 75abbd525f | |||
| 01a725a769 | |||
| f5781dbb60 | |||
| 59205d7809 | |||
| 0cf170df16 | |||
| 05a3b088fd | |||
| 65df5da07a | |||
| 0689c3697f | |||
| 0f53c29954 | |||
| 11bfe85598 | |||
| 93c503fa16 | |||
| 9d4e948e82 | |||
| 26f19d0399 | |||
| 5cd2e2291b | |||
| 69bbbe675e | |||
| 825de1cdf2 | |||
| e5318c61ee | |||
| 67b40a19fb | |||
| 5fbac749c9 | |||
| 0daadeb3d3 | |||
| 6b7625a095 | |||
| ab7e0cd100 | |||
| dee5f7fea5 | |||
| 140d149cee | |||
| 4d65ddddf8 | |||
| abfce5327c | |||
| 944c150e6c | |||
| d8dc53d215 | |||
| 0ec206f5a6 | |||
| ce49d4d61b | |||
| 69ee593fd2 | |||
| 39ddef6829 | |||
| 11aedbd741 | |||
| e4d1e12f7f | |||
| 9c2b32d6f3 | |||
| 4b3a590b00 | |||
| 7f50e97628 | |||
| e5ee6123fc | |||
| 923b6aba0d | |||
| 955e20eb61 | |||
| 286a40751c | |||
| eca0535457 | |||
| 7ace77a5d7 | |||
| 7f362af153 | |||
| 35dee2abac | |||
| 29c926201d | |||
| 9b6852a8c9 | |||
| 53efc8d5d0 | |||
| 0b8461c9cb | |||
| abd8e2a9eb | |||
| bc4dadc894 | |||
| ec53089bb1 | |||
| 7bb50e2823 | |||
| 632b2ddd34 | |||
| 7caad2205a | |||
| 9bf5f89659 | |||
| f41ca4a53e | |||
| 0bcd0872d8 | |||
| 6ec5946094 | |||
| 784ea8e160 | |||
| 6ec53bdfd3 | |||
| d1b6480dcf | |||
| ef6fed3ef8 | |||
| 473dee5786 | |||
| 779e3f6b5f | |||
| 71bca00651 | |||
| 9a9fce0abc | |||
| 939ca37cfe | |||
| 4ae8a2a4b6 | |||
| 113d3954b9 | |||
| 7cb5983750 | |||
| 2b149ca6d4 | |||
| e77866c18c | |||
| 0dc6418d20 | |||
| 837a077578 | |||
| adf91fe6ee | |||
| dea1c0d34c | |||
| f533acc9aa | |||
| d01cae2a0d | |||
| d015c8a80b | |||
| 8d2717146b | |||
| 3d598dae64 | |||
| 0a58986f52 | |||
| 6e69b85f9a | |||
| 7a9e336028 | |||
| 9b8df52aa9 | |||
| 7fab29fbe1 | |||
| 1a47fcbb8b | |||
| ffd4dab611 | |||
| 13edaa95c7 | |||
| 47b1f54bba | |||
| cdc7280dd3 | |||
| 0bb282bc6d | |||
| fdb09ef858 | |||
| 5e69cb2f9f | |||
| 5c2da38e3f | |||
| 3a799df0f1 | |||
| 511c765a44 | |||
| bf55d76d27 | |||
| c9efc80cd0 | |||
| fa15f2a6df | |||
| c023a0bfbb | |||
| b470e005e8 | |||
| c959191882 | |||
| e4adebd07a | |||
| ac94f6125f | |||
| c5686c5271 | |||
| 7fdb54d12b | |||
| 869008140a | |||
| 26ee32ec79 | |||
| a06193f97b | |||
| ba9dee170c | |||
| d4b60ada1e | |||
| b839f73ad0 | |||
| aee32931fd | |||
| 7ee5f46bbc | |||
| 2b97854bf4 | |||
| 316ee8f7ca | |||
| 2e18f44fcd | |||
| c85d064ecf | |||
| 7b9b82281a | |||
| aab632b330 | |||
| 4c8d8ad508 | |||
| 3a8f3dc9ea | |||
| c139e68d99 |
@@ -1,15 +0,0 @@
|
||||
// This is an incomplete TODO list of checks we want to start enforcing
|
||||
//
|
||||
// The goal is to enable these checks one by one by moving them to .jscs.json along with commits
|
||||
// that correct the existing code base issues and make the new check pass.
|
||||
|
||||
{
|
||||
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
|
||||
"disallowImplicitTypeConversion": ["string"],
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
"validateJSDoc": {
|
||||
"checkParamNames": true,
|
||||
"requireParamTypes": true
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"excludeFiles": ["src/ngLocale/**"],
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleLineStrings": true,
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
@@ -11,6 +12,7 @@
|
||||
"disallowSpacesInAnonymousFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInCallExpression": true,
|
||||
"disallowSpacesInFunctionDeclaration": {
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
@@ -18,6 +20,11 @@
|
||||
"beforeOpeningRoundBrace": true
|
||||
},
|
||||
"disallowSpacesInsideArrayBrackets": true,
|
||||
"requireSpaceBeforeKeywords": [
|
||||
"else",
|
||||
"while",
|
||||
"catch"
|
||||
],
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
"disallowTrailingComma": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
@@ -33,9 +40,9 @@
|
||||
"afterConsequent": true,
|
||||
"beforeAlternate": true
|
||||
},
|
||||
"requireSpacesInForStatement": true,
|
||||
"requireSpacesInFunction": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"validateLineBreaks": "LF",
|
||||
"validateParameterSeparator": ", "
|
||||
"validateLineBreaks": "LF"
|
||||
}
|
||||
+27
-13
@@ -1,6 +1,13 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '0.10'
|
||||
- '4.2'
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- bower_components
|
||||
- docs/bower_components
|
||||
|
||||
branches:
|
||||
except:
|
||||
@@ -8,40 +15,47 @@ branches:
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- JOB=ci-checks
|
||||
- JOB=unit BROWSER_PROVIDER=saucelabs
|
||||
- JOB=docs-e2e BROWSER_PROVIDER=saucelabs
|
||||
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=saucelabs
|
||||
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=saucelabs
|
||||
- JOB=unit BROWSER_PROVIDER=browserstack
|
||||
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=browserstack
|
||||
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=browserstack
|
||||
global:
|
||||
- CXX=g++-4.8 # node 4 likes the G++ v4.8 compiler
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
- BROWSER_STACK_USERNAME=VojtaJina
|
||||
- BROWSER_STACK_ACCESS_KEY=QCQJ1ZpWXpBkSwEdD8ev
|
||||
- LOGS_DIR=/tmp/angular-build/logs
|
||||
- BROWSER_PROVIDER_READY_FILE=/tmp/browsersprovider-tunnel-ready
|
||||
|
||||
# node 4 likes the G++ v4.8 compiler
|
||||
# see https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
|
||||
install:
|
||||
# Check the size of caches
|
||||
- du -sh ./node_modules ./bower_components/ ./docs/bower_components/ || true
|
||||
# - npm config set registry http://23.251.144.68
|
||||
# Disable the spinner, it looks bad on Travis
|
||||
- npm config set spin false
|
||||
# Log HTTP requests
|
||||
- npm config set loglevel http
|
||||
- time ./scripts/travis/npm-bundle-deps.sh
|
||||
- time npm install
|
||||
#- npm install -g npm@2.5
|
||||
# Install npm dependencies and ensure that npm cache is not stale
|
||||
- npm install
|
||||
|
||||
before_script:
|
||||
- mkdir -p $LOGS_DIR
|
||||
- ./scripts/travis/start_browser_provider.sh
|
||||
- npm install -g grunt-cli
|
||||
- grunt package
|
||||
- ./scripts/travis/wait_for_browser_provider.sh
|
||||
- ./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:
|
||||
|
||||
+1155
-2
File diff suppressed because it is too large
Load Diff
+13
-7
@@ -1,4 +1,4 @@
|
||||
#Contributing to AngularJS
|
||||
# Contributing to AngularJS
|
||||
|
||||
We'd love for you to contribute to our source code and to make AngularJS even better than it is
|
||||
today! Here are the guidelines we'd like you to follow:
|
||||
@@ -54,7 +54,7 @@ For large fixes, please build and test the documentation before submitting the P
|
||||
accidentally introduced any layout or formatting issues. You should also make sure that your commit message
|
||||
is labeled "docs:" and follows the **Git Commit Guidelines** outlined below.
|
||||
|
||||
If you're just making a small change, don't worry about filing an issue first. Use the friendly blue "Improve this doc" button at the top right of the doc page to fork the repository in-place and make a quick change on the fly. When naming the commit, it is advised to still label it according to the commit guidelines below, by starting the commit message with **docs** and referencing the filename. Since this is not obvious and some changes are made on the fly, this is not strictly necessary and we will understand if this isn't done the first few times.
|
||||
If you're just making a small change, don't worry about filing an issue first. Use the friendly blue "Improve this doc" button at the top right of the doc page to fork the repository in-place and make a quick change on the fly. When naming the commit, it is advised to still label it according to the commit guidelines below, by starting the commit message with **docs** and referencing the filename. Since this is not obvious and some changes are made on the fly, this is not strictly necessary and we will understand if this isn't done the first few times.
|
||||
|
||||
## <a name="submit"></a> Submission Guidelines
|
||||
|
||||
@@ -87,7 +87,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
* Please sign our [Contributor License Agreement (CLA)](#cla) before sending pull
|
||||
requests. We cannot accept code without this.
|
||||
* Make your changes in a new git branch
|
||||
* Make your changes in a new git branch:
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
@@ -107,7 +107,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
```
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
|
||||
* Build your changes locally to ensure all the tests pass
|
||||
* Build your changes locally to ensure all the tests pass:
|
||||
|
||||
```shell
|
||||
grunt test
|
||||
@@ -120,7 +120,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
```
|
||||
|
||||
* In GitHub, send a pull request to `angular:master`.
|
||||
* If we suggest changes then
|
||||
* If we suggest changes then:
|
||||
* Make the required updates.
|
||||
* Re-run the Angular test suite to ensure tests are still passing.
|
||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
@@ -199,9 +199,14 @@ format that includes a **type**, a **scope** and a **subject**:
|
||||
<footer>
|
||||
```
|
||||
|
||||
The **header** is mandatory and the **scope** of the header is optional.
|
||||
|
||||
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
|
||||
to read on github as well as in various git tools.
|
||||
|
||||
### Revert
|
||||
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header 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.
|
||||
|
||||
### Type
|
||||
Must be one of the following:
|
||||
|
||||
@@ -227,14 +232,15 @@ The subject contains succinct description of the change:
|
||||
* don't capitalize first letter
|
||||
* no dot (.) at the end
|
||||
|
||||
###Body
|
||||
### Body
|
||||
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes"
|
||||
The body should include the motivation for the change and contrast this with previous behavior.
|
||||
|
||||
###Footer
|
||||
### Footer
|
||||
The footer should contain any information about **Breaking Changes** and is also the place to
|
||||
reference GitHub issues that this commit **Closes**.
|
||||
|
||||
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
|
||||
|
||||
A detailed explanation can be found in this [document][commit-message-format].
|
||||
|
||||
|
||||
+35
-18
@@ -17,10 +17,6 @@ module.exports = function(grunt) {
|
||||
NG_VERSION.cdn = versionInfo.cdnVersion;
|
||||
var dist = 'angular-'+ NG_VERSION.full;
|
||||
|
||||
//global beforeEach
|
||||
util.init();
|
||||
|
||||
|
||||
//config
|
||||
grunt.initConfig({
|
||||
NG_VERSION: NG_VERSION,
|
||||
@@ -159,7 +155,7 @@ module.exports = function(grunt) {
|
||||
jscs: {
|
||||
src: ['src/**/*.js', 'test/**/*.js'],
|
||||
options: {
|
||||
config: ".jscs.json"
|
||||
config: '.jscsrc'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -224,9 +220,9 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-aria.js',
|
||||
src: util.wrap(files['angularModules']['ngAria'], 'module')
|
||||
},
|
||||
"promises-aplus-adapter": {
|
||||
'promises-aplus-adapter': {
|
||||
dest:'tmp/promises-aplus-adapter++.js',
|
||||
src:['src/ng/q.js','lib/promises-aplus/promises-aplus-test-adapter.js']
|
||||
src:['src/ng/q.js', 'lib/promises-aplus/promises-aplus-test-adapter.js']
|
||||
}
|
||||
},
|
||||
|
||||
@@ -245,17 +241,28 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
|
||||
"ddescribe-iit": {
|
||||
'ddescribe-iit': {
|
||||
files: [
|
||||
'src/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/ngScenario/DescribeSpec.js',
|
||||
'!src/ng/directive/attrs.js', // legitimate xit here
|
||||
'!src/ngScenario/**/*.js'
|
||||
]
|
||||
'!src/ngScenario/**/*.js',
|
||||
'!test/helpers/privateMocks*.js'
|
||||
],
|
||||
options: {
|
||||
disallowed: [
|
||||
'iit',
|
||||
'xit',
|
||||
'tthey',
|
||||
'xthey',
|
||||
'ddescribe',
|
||||
'xdescribe'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"merge-conflict": {
|
||||
'merge-conflict': {
|
||||
files: [
|
||||
'src/**/*',
|
||||
'test/**/*',
|
||||
@@ -285,7 +292,11 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
shell: {
|
||||
"promises-aplus-tests": {
|
||||
'npm-install': {
|
||||
command: 'node scripts/npm/check-node-modules.js'
|
||||
},
|
||||
|
||||
'promises-aplus-tests': {
|
||||
options: {
|
||||
stdout: false,
|
||||
stderr: true,
|
||||
@@ -311,23 +322,29 @@ module.exports = function(grunt) {
|
||||
}
|
||||
});
|
||||
|
||||
// global beforeEach task
|
||||
if (!process.env.TRAVIS) {
|
||||
grunt.task.run('shell:npm-install');
|
||||
}
|
||||
|
||||
|
||||
|
||||
//alias tasks
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:protractor']);
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package', 'test:unit', 'test:promises-aplus', 'tests:docs', 'test:protractor']);
|
||||
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
|
||||
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['build', 'tests:modules']);
|
||||
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
|
||||
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
|
||||
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['test:jqlite', 'test:jquery', 'test:modules']);
|
||||
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:normal']);
|
||||
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI 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']);
|
||||
grunt.registerTask('test:e2e', 'Alias for test:protractor', ['test:protractor']);
|
||||
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']);
|
||||
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter', 'shell:promises-aplus-tests']);
|
||||
|
||||
grunt.registerTask('minify', ['bower','clean', 'build', 'minall']);
|
||||
grunt.registerTask('minify', ['bower', 'clean', 'build', 'minall']);
|
||||
grunt.registerTask('webserver', ['connect:devserver']);
|
||||
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('package', ['bower', 'validate-angular-files', 'clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'jscs']);
|
||||
grunt.registerTask('default', ['package']);
|
||||
};
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
Using AngularJS with the Closure Compiler
|
||||
=========================================
|
||||
|
||||
The Closure Compiler project contains externs definitions for AngularJS
|
||||
JavaScript in its `contrib/externs` directory.
|
||||
The Closure Compiler project contains definitions for the AngularJS JavaScript
|
||||
in its `contrib/externs` directory.
|
||||
|
||||
The definitions contain externs for use with the Closure compiler (aka
|
||||
JSCompiler). Passing these files to the --externs parameter of a compiler
|
||||
|
||||
@@ -10,7 +10,7 @@ the browser how to do dependency injection and inversion of control.
|
||||
|
||||
Oh yeah and it helps with server-side communication, taming async callbacks with promises and
|
||||
deferreds. It also makes client-side navigation and deeplinking with hashbang urls or HTML5 pushState a
|
||||
piece of cake. The best of all: it makes development fun!
|
||||
piece of cake. Best of all?? It makes development fun!
|
||||
|
||||
* Web site: http://angularjs.org
|
||||
* Tutorial: http://docs.angularjs.org/tutorial
|
||||
|
||||
+5
-1
@@ -55,7 +55,11 @@ This process based on the idea of minimizing user pain
|
||||
* inconvenience - causes ugly/boilerplate code in apps
|
||||
1. Label `component: *`
|
||||
* In rare cases, it's ok to have multiple components.
|
||||
1. Label `PRs plz!` - These issues are good targets for PRs from the open source community. Apply to issues where the problem and solution are well defined in the comments, and it's not too complex.
|
||||
1. Label `PRs plz!` - These issues are good targets for PRs from the open source community. In addition to applying this label, you must:
|
||||
* Leave a comment explaining the problem and solution so someone can easily finish it.
|
||||
* Assign the issue to yourself.
|
||||
* Give feedback on PRs addressing this issue.
|
||||
* You are responsible for mentoring contributors helping with this issue.
|
||||
1. Label `origin: google` for issues from Google
|
||||
1. Assign a milestone:
|
||||
* Backlog - triaged fixes and features, should be the default choice
|
||||
|
||||
Vendored
+7
-2
@@ -32,6 +32,7 @@ var angularFiles = {
|
||||
'src/ng/q.js',
|
||||
'src/ng/raf.js',
|
||||
'src/ng/rootScope.js',
|
||||
'src/ng/rootElement.js',
|
||||
'src/ng/sanitizeUri.js',
|
||||
'src/ng/sce.js',
|
||||
'src/ng/sniffer.js',
|
||||
@@ -53,6 +54,7 @@ var angularFiles = {
|
||||
'src/ng/directive/form.js',
|
||||
'src/ng/directive/input.js',
|
||||
'src/ng/directive/ngBind.js',
|
||||
'src/ng/directive/ngChange.js',
|
||||
'src/ng/directive/ngClass.js',
|
||||
'src/ng/directive/ngCloak.js',
|
||||
'src/ng/directive/ngController.js',
|
||||
@@ -61,6 +63,8 @@ var angularFiles = {
|
||||
'src/ng/directive/ngIf.js',
|
||||
'src/ng/directive/ngInclude.js',
|
||||
'src/ng/directive/ngInit.js',
|
||||
'src/ng/directive/ngList.js',
|
||||
'src/ng/directive/ngModel.js',
|
||||
'src/ng/directive/ngNonBindable.js',
|
||||
'src/ng/directive/ngPluralize.js',
|
||||
'src/ng/directive/ngRepeat.js',
|
||||
@@ -70,11 +74,12 @@ var angularFiles = {
|
||||
'src/ng/directive/ngTransclude.js',
|
||||
'src/ng/directive/script.js',
|
||||
'src/ng/directive/select.js',
|
||||
'src/ng/directive/style.js'
|
||||
'src/ng/directive/style.js',
|
||||
'src/ng/directive/validators.js'
|
||||
],
|
||||
|
||||
'angularLoader': [
|
||||
'stringify.js',
|
||||
'src/stringify.js',
|
||||
'src/minErr.js',
|
||||
'src/loader.js'
|
||||
],
|
||||
|
||||
@@ -546,10 +546,10 @@ h4 {
|
||||
margin-left:10px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
color:black!important;
|
||||
.btn:hover, .btn:focus {
|
||||
color: black!important;
|
||||
border: 1px solid #ddd!important;
|
||||
background:white!important;
|
||||
background: white!important;
|
||||
}
|
||||
|
||||
.view-source, .improve-docs {
|
||||
@@ -583,6 +583,12 @@ ul.events > li {
|
||||
margin-bottom:40px;
|
||||
}
|
||||
|
||||
.definition-table td {
|
||||
padding: 8px;
|
||||
border: 1px solid #eee;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 769px) and (max-width: 991px) {
|
||||
.main-body-grid {
|
||||
margin-top: 160px;
|
||||
@@ -631,6 +637,7 @@ ul.events > li {
|
||||
}
|
||||
.main-body-grid .side-navigation {
|
||||
display:block!important;
|
||||
padding-bottom:50px;
|
||||
}
|
||||
.main-body-grid .side-navigation.ng-hide {
|
||||
display:none!important;
|
||||
@@ -656,14 +663,14 @@ ul.events > li {
|
||||
}
|
||||
.toc-close {
|
||||
position: absolute;
|
||||
bottom: -50px;
|
||||
bottom: 5px;
|
||||
left: 50%;
|
||||
margin-left: -50%;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
background: #eee;
|
||||
border-radius: 5px;
|
||||
width: 90%;
|
||||
width: 100%;
|
||||
border:1px solid #ddd;
|
||||
box-shadow:0 0 10px #bbb;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
angular.module('examples', [])
|
||||
|
||||
.factory('formPostData', ['$document', function($document) {
|
||||
return function(url, fields) {
|
||||
return function(url, newWindow, fields) {
|
||||
/**
|
||||
* Form previously posted to target="_blank", but pop-up blockers were causing this to not work.
|
||||
* If a user chose to bypass pop-up blocker one time and click the link, they would arrive at
|
||||
* a new default plnkr, not a plnkr with the desired template.
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
var form = angular.element('<form style="display: none;" method="post" action="' + url + '"></form>');
|
||||
var target = newWindow ? '_blank' : '_self';
|
||||
var form = angular.element('<form style="display: none;" method="post" action="' + url + '" target="' + target + '"></form>');
|
||||
angular.forEach(fields, function(value, name) {
|
||||
var input = angular.element('<input type="hidden" name="' + name + '">');
|
||||
input.attr('value', value);
|
||||
@@ -21,9 +24,10 @@ angular.module('examples', [])
|
||||
|
||||
|
||||
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
|
||||
return function(exampleFolder) {
|
||||
return function(exampleFolder, clickEvent) {
|
||||
|
||||
var exampleName = 'AngularJS Example';
|
||||
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
|
||||
|
||||
// Load the manifest for the example
|
||||
$http.get(exampleFolder + '/manifest.json')
|
||||
@@ -71,7 +75,7 @@ angular.module('examples', [])
|
||||
postData.private = true;
|
||||
postData.description = exampleName;
|
||||
|
||||
formPostData('http://plnkr.co/edit/?p=preview', postData);
|
||||
formPostData('http://plnkr.co/edit/?p=preview', newWindow, postData);
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
||||
+11
-6
@@ -6,18 +6,18 @@ var packagePath = __dirname;
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
// Create and export a new Dgeni package called angularjs. This package depends upon
|
||||
// the ngdoc,nunjucks and examples packages defined in the dgeni-packages npm module.
|
||||
// the ngdoc, nunjucks, and examples packages defined in the dgeni-packages npm module.
|
||||
module.exports = new Package('angularjs', [
|
||||
require('dgeni-packages/ngdoc'),
|
||||
require('dgeni-packages/nunjucks'),
|
||||
require('dgeni-packages/examples')
|
||||
require('dgeni-packages/examples'),
|
||||
require('dgeni-packages/git')
|
||||
])
|
||||
|
||||
|
||||
.factory(require('./services/errorNamespaceMap'))
|
||||
.factory(require('./services/getMinerrInfo'))
|
||||
.factory(require('./services/getVersion'))
|
||||
.factory(require('./services/gitData'))
|
||||
|
||||
.factory(require('./services/deployments/debug'))
|
||||
.factory(require('./services/deployments/default'))
|
||||
@@ -26,7 +26,6 @@ module.exports = new Package('angularjs', [
|
||||
|
||||
.factory(require('./inline-tag-defs/type'))
|
||||
|
||||
|
||||
.processor(require('./processors/error-docs'))
|
||||
.processor(require('./processors/index-page'))
|
||||
.processor(require('./processors/keywords'))
|
||||
@@ -125,10 +124,16 @@ module.exports = new Package('angularjs', [
|
||||
});
|
||||
|
||||
computeIdsProcessor.idTemplates.push({
|
||||
docTypes: ['error', 'errorNamespace'],
|
||||
docTypes: ['error'],
|
||||
getId: function(doc) { return 'error:' + doc.namespace + ':' + doc.name; },
|
||||
getAliases: function(doc) { return [doc.name, doc.namespace + ':' + doc.name, doc.id]; }
|
||||
},
|
||||
{
|
||||
docTypes: ['errorNamespace'],
|
||||
getId: function(doc) { return 'error:' + doc.name; },
|
||||
getAliases: function(doc) { return [doc.id]; }
|
||||
});
|
||||
}
|
||||
);
|
||||
})
|
||||
|
||||
.config(function(checkAnchorLinksProcessor) {
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var versionInfo = require('../../../lib/versions/version-info');
|
||||
|
||||
/**
|
||||
* @dgService gitData
|
||||
* @description
|
||||
* Information from the local git repository
|
||||
*/
|
||||
module.exports = function gitData() {
|
||||
return {
|
||||
version: versionInfo.currentVersion,
|
||||
versions: versionInfo.previousVersions,
|
||||
info: versionInfo.gitRepoInfo
|
||||
};
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "base.template.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Error: {$ doc.id $}
|
||||
<h1>Error: {$ doc.namespace $}:{$ doc.name $}
|
||||
<div><span class='hint'>{$ doc.fullName $}</span></div>
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
|
||||
<div>
|
||||
<a ng-click="openPlunkr('{$ doc.path $}')" class="btn pull-right">
|
||||
<a ng-click="openPlunkr('{$ doc.path $}', $event)" class="btn pull-right">
|
||||
<i class="glyphicon glyphicon-edit"> </i>
|
||||
Edit in Plunker</a>
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
@ngdoc error
|
||||
@name $animate:nocb
|
||||
@fullName Do not pass a callback to animate methods
|
||||
@description
|
||||
|
||||
Since Angular 1.3, the methods of {@link ng.$animate} do not accept a callback as the last parameter.
|
||||
Instead, they return a promise to which you can attach `then` handlers to be run when the animation completes.
|
||||
|
||||
If you are getting this error then you need to update your code to use the promise-based API.
|
||||
|
||||
See https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 for information about
|
||||
the change to the animation API and the changes you need to make.
|
||||
@@ -0,0 +1,46 @@
|
||||
@ngdoc error
|
||||
@name $controller:ctrlfmt
|
||||
@fullName Badly formed controller string
|
||||
@description
|
||||
|
||||
This error occurs when {@link ng.$controller $controller} service is called
|
||||
with a string that does not match the supported controller string formats.
|
||||
|
||||
Supported formats:
|
||||
|
||||
1. `__name__`
|
||||
2. `__name__ as __identifier__`
|
||||
|
||||
Neither `__name__` or `__identifier__` may contain spaces.
|
||||
|
||||
Example of incorrect usage that leads to this error:
|
||||
```html
|
||||
<!-- unclosed ng-controller attribute messes up the format -->
|
||||
<div ng-controller="myController>
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```js
|
||||
// does not match `__name__` or `__name__ as __identifier__`
|
||||
var myCtrl = $controller("mY contRoller", { $scope: newScope });
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```js
|
||||
directive("myDirective", function() {
|
||||
return {
|
||||
// does not match `__name__` or `__name__ as __identifier__`
|
||||
controller: "mY contRoller",
|
||||
link: function() {}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
To fix the examples above, ensure that the controller string matches the supported
|
||||
formats, and that any html attributes which are used as controller expressions are
|
||||
closed.
|
||||
|
||||
|
||||
Please consult the {@link ng.$controller $controller} service api docs to learn more.
|
||||
@@ -35,7 +35,7 @@ var users = [ { name: 'Hank' }, { name: 'Francisco' } ];
|
||||
|
||||
$scope.getUsers = function() {
|
||||
return users;
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
The maximum number of allowed iterations of the `$digest` cycle is controlled via TTL setting which can be configured via {@link ng.$rootScopeProvider $rootScopeProvider}.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
@ngdoc error
|
||||
@name ng:cpta
|
||||
@fullName Copying TypedArray
|
||||
@description
|
||||
|
||||
Copying TypedArray's with a destination is not supported because TypedArray
|
||||
objects can not be mutated, they are fixed length.
|
||||
@@ -0,0 +1,28 @@
|
||||
@ngdoc error
|
||||
@name ngModel:nopromise
|
||||
@fullName No promise
|
||||
@description
|
||||
|
||||
The return value of an async validator, must always be a promise. If you want to return a
|
||||
non-promise value, you can convert it to a promise using {@link ng.$q#resolve `$q.resolve()`} or
|
||||
{@link ng.$q#reject `$q.reject()`}.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
.directive('asyncValidator', function($q) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elem, attrs, ngModel) {
|
||||
ngModel.$asyncValidators.myAsyncValidation = function(modelValue, viewValue) {
|
||||
if (/* I don't need to hit the backend API */) {
|
||||
return $q.resolve(); // to mark as valid or
|
||||
// return $q.reject(); // to mark as invalid
|
||||
} else {
|
||||
// ...send a request to the backend and return a promise
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
@ngdoc error
|
||||
@name ngModel:numfmt
|
||||
@fullName Model is not of type `number`
|
||||
@description
|
||||
|
||||
The number input directive `<input type="number">` requires the model to be a `number`.
|
||||
|
||||
If the model is something else, this error will be thrown.
|
||||
|
||||
Angular does not set validation errors on the `<input>` in this case
|
||||
as this error is caused by incorrect application logic and not by bad input from the user.
|
||||
|
||||
If your model does not contain actual numbers then it is up to the application developer
|
||||
to use a directive that will do the conversion in the `ngModel` `$formatters` and `$parsers`
|
||||
pipeline.
|
||||
|
||||
## Example
|
||||
|
||||
In this example, our model stores the number as a string, so we provide the `stringToNumber`
|
||||
directive to convert it into the format the `input[number]` directive expects.
|
||||
|
||||
|
||||
<example module="numfmt-error-module">
|
||||
<file name="index.html">
|
||||
<table>
|
||||
<tr ng-repeat="x in ['0', '1']">
|
||||
<td>
|
||||
<input type="number" string-to-number ng-model="x" /> {{ x }} : {{ typeOf(x) }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</file>
|
||||
<file name="app.js">
|
||||
angular.module('numfmt-error-module', [])
|
||||
|
||||
.run(function($rootScope) {
|
||||
$rootScope.typeOf = function(value) {
|
||||
return typeof value;
|
||||
};
|
||||
})
|
||||
|
||||
.directive('stringToNumber', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attrs, ngModel) {
|
||||
ngModel.$parsers.push(function(value) {
|
||||
return '' + value;
|
||||
});
|
||||
ngModel.$formatters.push(function(value) {
|
||||
return parseFloat(value, 10);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
@@ -1,33 +0,0 @@
|
||||
@ngdoc error
|
||||
@name ngOptions:trkslct
|
||||
@fullName Comprehension expression cannot contain both `select as` and `track by` expressions.
|
||||
@description
|
||||
|
||||
NOTE: This error was introduced in 1.3.0-rc.5, and was removed for 1.3.0-rc.6 in order to
|
||||
not break existing apps.
|
||||
|
||||
This error occurs when 'ngOptions' is passed a comprehension expression that contains both a
|
||||
`select as` expression and a `track by` expression. These two expressions are fundamentally
|
||||
incompatible.
|
||||
|
||||
* Example of bad expression: `<select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">`
|
||||
`values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItem'}}]`,
|
||||
`$scope.selected = {name: 'aSubItem'};`
|
||||
* track by is always applied to `value`, with purpose to preserve the selection,
|
||||
(to `item` in this case)
|
||||
* To calculate whether an item is selected, `ngOptions` does the following:
|
||||
1. apply `track by` to the values in the array:
|
||||
In the example: [1,2]
|
||||
2. apply `track by` to the already selected value in `ngModel`:
|
||||
In the example: this is not possible, as `track by` refers to `item.id`, but the selected
|
||||
value from `ngModel` is `{name: aSubItem}`.
|
||||
|
||||
Here's an example of how to make this example work by using `track by` without `select as`:
|
||||
|
||||
```
|
||||
<select ng-model="selected" ng-options="item.label for item in values track by item.id">
|
||||
```
|
||||
|
||||
Note: This would store the whole `item` as the model to `scope.selected` instead of `item.subItem`.
|
||||
|
||||
For more information on valid expression syntax, see 'ngOptions' in {@link ng.directive:select select} directive docs.
|
||||
@@ -16,6 +16,8 @@ Reserved names include:
|
||||
- `this`
|
||||
- `undefined`
|
||||
- `$parent`
|
||||
- `$id`
|
||||
- `$root`
|
||||
- `$even`
|
||||
- `$odd`
|
||||
- `$first`
|
||||
|
||||
@@ -358,7 +358,7 @@ legacy browsers and hashbang links in modern browser:
|
||||
|
||||
Here you can see two `$location` instances, both in **Html5 mode**, but on different browsers, so
|
||||
that you can see the differences. These `$location` services are connected to a fake browsers. Each
|
||||
input represents address bar of the browser.
|
||||
input represents the address bar of the browser.
|
||||
|
||||
Note that when you type hashbang url into first browser (or vice versa) it doesn't rewrite /
|
||||
redirect to regular / hashbang url, as this conversion happens only during parsing the initial URL
|
||||
|
||||
@@ -37,6 +37,7 @@ Currently, ngAria interfaces with the following directives:
|
||||
* {@link guide/accessibility#nghide ngHide}
|
||||
* {@link guide/accessibility#ngclick ngClick}
|
||||
* {@link guide/accessibility#ngdblclick ngDblClick}
|
||||
* {@link guide/accessibility#ngmessages ngMessages}
|
||||
|
||||
<h2 id="ngmodel">ngModel</h2>
|
||||
|
||||
@@ -209,10 +210,16 @@ The default CSS for `ngHide`, the inverse method to `ngShow`, makes ngAria redun
|
||||
`display: none`. See explanation for {@link guide/accessibility#ngshow ngShow} when overriding the default CSS.
|
||||
|
||||
<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` if it isn't there already.
|
||||
Even with this, you must currently still add `ng-keypress` to non-interactive elements such as `div`
|
||||
or `taco-button` to enable keyboard access. Conversation is currently ongoing about whether ngAria
|
||||
should also bind `ng-keypress`.
|
||||
If `ng-click` or `ng-dblclick` is encountered, ngAria will add `tabindex="0"` if it isn't there
|
||||
already.
|
||||
|
||||
To fix widespread accessibility problems with `ng-click` on div elements, ngAria will dynamically
|
||||
bind keypress by default as long as the element isn't an anchor, button, input or textarea.
|
||||
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.
|
||||
|
||||
For `ng-dblclick`, you must still manually add `ng-keypress` and role to non-interactive elements such
|
||||
as `div` or `taco-button` to enable keyboard access.
|
||||
|
||||
<h3>Example</h3>
|
||||
```html
|
||||
@@ -223,13 +230,12 @@ Becomes:
|
||||
```html
|
||||
<div ng-click="toggleMenu()" tabindex="0"></div>
|
||||
```
|
||||
*Note: ngAria still requires `ng-keypress` to be added manually to non-native controls like divs.*
|
||||
|
||||
<h2 id="ngmessages">ngMessages</h2>
|
||||
|
||||
The new ngMessages module makes it easy to display form validation or other messages with priority
|
||||
sequencing and animation. To expose these visual messages to screen readers,
|
||||
ngAria injects `aria-live="polite"`, causing them to be read aloud any time a message is shown,
|
||||
ngAria injects `aria-live="assertive"`, causing them to be read aloud any time a message is shown,
|
||||
regardless of the user's focus location.
|
||||
###Example
|
||||
|
||||
@@ -243,7 +249,7 @@ regardless of the user's focus location.
|
||||
Becomes:
|
||||
|
||||
```html
|
||||
<div ng-messages="myForm.myName.$error" aria-live="polite">
|
||||
<div ng-messages="myForm.myName.$error" aria-live="assertive">
|
||||
<div ng-message="required">You did not enter a field</div>
|
||||
<div ng-message="maxlength">Your field is too long</div>
|
||||
</div>
|
||||
|
||||
@@ -236,7 +236,7 @@ The example below shows how to perform animations during class changes:
|
||||
</file>
|
||||
</example>
|
||||
|
||||
Although the CSS is a little different then what we saw before, the idea is the same.
|
||||
Although the CSS is a little different than what we saw before, the idea is the same.
|
||||
|
||||
## Which directives support animations?
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ As a best practice, consider adding an `ng-strict-di` directive on the same elem
|
||||
```
|
||||
|
||||
This will ensure that all services in your application are properly annotated.
|
||||
See the {@link guide/di#using-strict-dependency-injection dependancy injection strict mode} docs
|
||||
See the {@link guide/di#using-strict-dependency-injection dependency injection strict mode} docs
|
||||
for more.
|
||||
|
||||
|
||||
@@ -156,4 +156,4 @@ until `angular.resumeBootstrap()` is called.
|
||||
|
||||
`angular.resumeBootstrap()` takes an optional array of modules that
|
||||
should be added to the original list of modules that the app was
|
||||
about to be bootstrapped with.
|
||||
about to be bootstrapped with.
|
||||
@@ -179,11 +179,11 @@ The following graphic shows how everything works together after we introduced th
|
||||
|
||||
<img style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-databinding2.png">
|
||||
|
||||
## View independent business logic: Services
|
||||
## View-independent business logic: Services
|
||||
|
||||
Right now, the `InvoiceController` contains all logic of our example. When the application grows it
|
||||
is a good practice to move view independent logic from the controller into a so called
|
||||
<a name="service">"{@link services service}"</a>, so it can be reused by other parts
|
||||
is a good practice to move view-independent logic from the controller into a
|
||||
<a name="service">{@link services service}</a>, so it can be reused by other parts
|
||||
of the application as well. Later on, we could also change that service to load the exchange rates
|
||||
from the web, e.g. by calling the Yahoo Finance API, without changing the controller.
|
||||
|
||||
|
||||
@@ -5,13 +5,16 @@
|
||||
|
||||
# Understanding Controllers
|
||||
|
||||
In Angular, a Controller is a JavaScript **constructor function** that is used to augment the
|
||||
In Angular, a Controller is defined by a JavaScript **constructor function** that is used to augment the
|
||||
{@link scope Angular Scope}.
|
||||
|
||||
When a Controller is attached to the DOM via the {@link ng.directive:ngController ng-controller}
|
||||
directive, Angular will instantiate a new Controller object, using the specified Controller's
|
||||
**constructor function**. A new **child scope** will be available as an injectable parameter to the
|
||||
Controller's constructor function as `$scope`.
|
||||
**constructor function**. A new **child scope** will be created and made available as an injectable
|
||||
parameter to the Controller's constructor function as `$scope`.
|
||||
|
||||
If the controller has been attached using the `controller as` syntax then the controller instance will
|
||||
be assigned to a property on the new scope.
|
||||
|
||||
Use controllers to:
|
||||
|
||||
@@ -106,7 +109,7 @@ needed for a single view.
|
||||
|
||||
The most common way to keep Controllers slim is by encapsulating work that doesn't belong to
|
||||
controllers into services and then using these services in Controllers via dependency injection.
|
||||
This is discussed in the {@link di Dependency Injection} {@link services
|
||||
This is discussed in the {@link di Dependency Injection} and {@link services
|
||||
Services} sections of this guide.
|
||||
|
||||
|
||||
@@ -162,7 +165,7 @@ scope is augmented (managed) by the `SpicyController` Controller.
|
||||
starts with capital letter and ends with "Controller".
|
||||
- Assigning a property to `$scope` creates or updates the model.
|
||||
- Controller methods can be created through direct assignment to scope (see the `chiliSpicy` method)
|
||||
- The Controller methods and properties are available in the template (for the `<div>` element and
|
||||
- The Controller methods and properties are available in the template (for both the `<div>` element and
|
||||
its children).
|
||||
|
||||
## Spicy Arguments Example
|
||||
@@ -302,7 +305,7 @@ describe('myController function', function() {
|
||||
```
|
||||
|
||||
|
||||
If you need to test a nested Controller you need to create the same scope hierarchy
|
||||
If you need to test a nested Controller you must create the same scope hierarchy
|
||||
in your test that exists in the DOM:
|
||||
|
||||
```js
|
||||
|
||||
@@ -163,8 +163,8 @@ someModule.controller('MyController', function($scope, greeter) {
|
||||
});
|
||||
```
|
||||
|
||||
Given a function the injector can infer the names of the services to inject by examining the
|
||||
function declaration and extracting the parameter names. In the above example `$scope`, and
|
||||
Given a function, the injector can infer the names of the services to inject by examining the
|
||||
function declaration and extracting the parameter names. In the above example, `$scope` and
|
||||
`greeter` are two services which need to be injected into the function.
|
||||
|
||||
One advantage of this approach is that there's no array of names to keep in sync with the
|
||||
@@ -293,7 +293,7 @@ Create a new injector that can provide components defined in our `myModule` modu
|
||||
`greeter` service from the injector. (This is usually done automatically by angular bootstrap).
|
||||
|
||||
```js
|
||||
var injector = angular.injector(['myModule', 'ng']);
|
||||
var injector = angular.injector(['ng', 'myModule']);
|
||||
var greeter = injector.get('greeter');
|
||||
```
|
||||
|
||||
|
||||
@@ -51,9 +51,11 @@ In the following example, we say that the `<input>` element **matches** the `ngM
|
||||
The following also **matches** `ngModel`:
|
||||
|
||||
```html
|
||||
<input data-ng:model="foo">
|
||||
<input data-ng-model="foo">
|
||||
```
|
||||
|
||||
### Normalization
|
||||
|
||||
Angular **normalizes** an element's tag and attribute name to determine which elements match which
|
||||
directives. We typically refer to directives by their case-sensitive
|
||||
[camelCase](http://en.wikipedia.org/wiki/CamelCase) **normalized** name (e.g. `ngModel`).
|
||||
@@ -100,6 +102,8 @@ If you want to use an HTML validating tool, you can instead use the `data`-prefi
|
||||
The other forms shown above are accepted for legacy reasons but we advise you to avoid them.
|
||||
</div>
|
||||
|
||||
### Directive types
|
||||
|
||||
`$compile` can match directives based on element names, attributes, class names, as well as comments.
|
||||
|
||||
All of the Angular-provided directives match attribute name, tag name, comments, or class name.
|
||||
@@ -751,9 +755,12 @@ own behavior to it.
|
||||
angular.module('docsIsoFnBindExample', [])
|
||||
.controller('Controller', ['$scope', '$timeout', function($scope, $timeout) {
|
||||
$scope.name = 'Tobias';
|
||||
$scope.hideDialog = function () {
|
||||
$scope.message = '';
|
||||
$scope.hideDialog = function (message) {
|
||||
$scope.message = message;
|
||||
$scope.dialogIsHidden = true;
|
||||
$timeout(function () {
|
||||
$scope.message = '';
|
||||
$scope.dialogIsHidden = false;
|
||||
}, 2000);
|
||||
};
|
||||
@@ -771,14 +778,15 @@ own behavior to it.
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()">
|
||||
{{message}}
|
||||
<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog(message)">
|
||||
Check out the contents, {{name}}!
|
||||
</my-dialog>
|
||||
</div>
|
||||
</file>
|
||||
<file name="my-dialog-close.html">
|
||||
<div class="alert">
|
||||
<a href class="close" ng-click="close()">×</a>
|
||||
<a href class="close" ng-click="close({message: 'closing for now'})">×</a>
|
||||
<div ng-transclude></div>
|
||||
</div>
|
||||
</file>
|
||||
@@ -795,9 +803,15 @@ callback functions to directive behaviors.
|
||||
|
||||
When the user clicks the `x` in the dialog, the directive's `close` function is called, thanks to
|
||||
`ng-click.` This call to `close` on the isolated scope actually evaluates the expression
|
||||
`hideDialog()` in the context of the original scope, thus running `Controller`'s `hideDialog`
|
||||
`hideDialog(message)` in the context of the original scope, thus running `Controller`'s `hideDialog`
|
||||
function.
|
||||
|
||||
Often it's desirable to pass data from the isolate scope via an expression to the
|
||||
parent scope, this can be done by passing a map of local variable names and values into the expression
|
||||
wrapper fn. For example, the hideDialog function takes a message to display when the dialog is hidden.
|
||||
This is specified in the directive by calling `close({message: 'closing for now'})`. Then the local
|
||||
variable `message` will be available within the `on-close` expression.
|
||||
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** use `&attr` in the `scope` option when you want your directive
|
||||
to expose an API for binding to behaviors.
|
||||
@@ -817,37 +831,39 @@ element?
|
||||
<file name="script.js">
|
||||
angular.module('dragModule', [])
|
||||
.directive('myDraggable', ['$document', function($document) {
|
||||
return function(scope, element, attr) {
|
||||
var startX = 0, startY = 0, x = 0, y = 0;
|
||||
return {
|
||||
link: function(scope, element, attr) {
|
||||
var startX = 0, startY = 0, x = 0, y = 0;
|
||||
|
||||
element.css({
|
||||
position: 'relative',
|
||||
border: '1px solid red',
|
||||
backgroundColor: 'lightgrey',
|
||||
cursor: 'pointer'
|
||||
});
|
||||
|
||||
element.on('mousedown', function(event) {
|
||||
// Prevent default dragging of selected content
|
||||
event.preventDefault();
|
||||
startX = event.pageX - x;
|
||||
startY = event.pageY - y;
|
||||
$document.on('mousemove', mousemove);
|
||||
$document.on('mouseup', mouseup);
|
||||
});
|
||||
|
||||
function mousemove(event) {
|
||||
y = event.pageY - startY;
|
||||
x = event.pageX - startX;
|
||||
element.css({
|
||||
top: y + 'px',
|
||||
left: x + 'px'
|
||||
position: 'relative',
|
||||
border: '1px solid red',
|
||||
backgroundColor: 'lightgrey',
|
||||
cursor: 'pointer'
|
||||
});
|
||||
}
|
||||
|
||||
function mouseup() {
|
||||
$document.off('mousemove', mousemove);
|
||||
$document.off('mouseup', mouseup);
|
||||
element.on('mousedown', function(event) {
|
||||
// Prevent default dragging of selected content
|
||||
event.preventDefault();
|
||||
startX = event.pageX - x;
|
||||
startY = event.pageY - y;
|
||||
$document.on('mousemove', mousemove);
|
||||
$document.on('mouseup', mouseup);
|
||||
});
|
||||
|
||||
function mousemove(event) {
|
||||
y = event.pageY - startY;
|
||||
x = event.pageX - startX;
|
||||
element.css({
|
||||
top: y + 'px',
|
||||
left: x + 'px'
|
||||
});
|
||||
}
|
||||
|
||||
function mouseup() {
|
||||
$document.off('mousemove', mousemove);
|
||||
$document.off('mouseup', mouseup);
|
||||
}
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -28,13 +28,13 @@ Angular expressions are like JavaScript expressions with the following differenc
|
||||
|
||||
* **No Control Flow Statements:** You cannot use the following in an Angular expression:
|
||||
conditionals, loops, or exceptions.
|
||||
|
||||
|
||||
* **No Function Declarations:** You cannot declare functions in an Angular expression,
|
||||
even inside `ng-init` directive.
|
||||
|
||||
* **No RegExp Creation With Literal Notation:** You cannot create regular expressions
|
||||
|
||||
* **No RegExp Creation With Literal Notation:** You cannot create regular expressions
|
||||
in an Angular expression.
|
||||
|
||||
|
||||
* **No Comma And Void Operators:** You cannot use `,` or `void` in an Angular expression.
|
||||
|
||||
* **Filters:** You can use {@link guide/filter filters} within expressions to format data before
|
||||
@@ -70,7 +70,7 @@ You can try evaluating different expressions here:
|
||||
<ul>
|
||||
<li ng-repeat="expr in exprs track by $index">
|
||||
[ <a href="" ng-click="removeExp($index)">X</a> ]
|
||||
<tt>{{expr}}</tt> => <span ng-bind="$parent.$eval(expr)"></span>
|
||||
<code>{{expr}}</code> => <span ng-bind="$parent.$eval(expr)"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -175,7 +175,7 @@ expression, delegate to a JavaScript method instead.
|
||||
## No function declarations or RegExp creation with literal notation
|
||||
|
||||
You can't declare functions or create regular expressions from within AngularJS expressions. This is
|
||||
to avoid complex model transformation logic inside templates. Such logic is better placed in a
|
||||
to avoid complex model transformation logic inside templates. Such logic is better placed in a
|
||||
controller or in a dedicated filter where it can be tested properly.
|
||||
|
||||
## `$event`
|
||||
@@ -303,10 +303,14 @@ then the expression is not fulfilled and will remain watched.
|
||||
keep dirty-checking the watch in the future digest loops by following the same
|
||||
algorithm starting from step 1
|
||||
|
||||
#### Special case for object literals
|
||||
|
||||
Unlike simple values, object-literals are watched until every key is defined.
|
||||
See http://www.bennadel.com/blog/2760-one-time-data-bindings-for-object-literal-expressions-in-angularjs-1-3.htm
|
||||
|
||||
### How to benefit from one-time binding
|
||||
|
||||
If the expression will not change once set, it is a candidate for one-time binding.
|
||||
If the expression will not change once set, it is a candidate for one-time binding.
|
||||
Here are three example cases.
|
||||
|
||||
When interpolating text or attributes:
|
||||
@@ -340,5 +344,4 @@ When using a directive that takes an expression:
|
||||
<ul>
|
||||
<li ng-repeat="item in ::items">{{item.name}};</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
```
|
||||
@@ -92,8 +92,10 @@ means that it should be stateless and idempotent. Angular relies on these proper
|
||||
the filter only when the inputs to the function change.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** filter names must be valid angular expression identifiers, such as `uppercase` or `orderBy`.
|
||||
Names with special characters, such as hyphens and dots, are not allowed.
|
||||
**Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
|
||||
Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
|
||||
your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
|
||||
(`myapp_subsection_filterx`).
|
||||
</div>
|
||||
|
||||
The following sample filter reverses a text string. In addition, it conditionally makes the
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
|
||||
A Form is a collection of controls for the purpose of grouping related controls together.
|
||||
|
||||
Form and controls provide validation services, so that the user can be notified of invalid input.
|
||||
This provides a better user experience, because the user gets instant feedback on how to
|
||||
correct the error. Keep in mind that while client-side validation plays an important role
|
||||
in providing good user experience, it can easily be circumvented and thus can not be trusted.
|
||||
Server-side validation is still necessary for a secure application.
|
||||
Form and controls provide validation services, so that the user can be notified of invalid input
|
||||
before submitting a form. This provides a better user experience than server-side validation alone
|
||||
because the user gets instant feedback on how to correct the error. Keep in mind that while
|
||||
client-side validation plays an important role in providing good user experience, it can easily
|
||||
be circumvented and thus can not be trusted. Server-side validation is still necessary for a
|
||||
secure application.
|
||||
|
||||
|
||||
# Simple form
|
||||
@@ -92,6 +93,8 @@ and failing to satisfy its validity.
|
||||
<input type="button" ng-click="reset()" value="Reset" />
|
||||
<input type="submit" ng-click="update(user)" value="Save" />
|
||||
</form>
|
||||
<pre>form = {{user | json}}</pre>
|
||||
<pre>master = {{master | json}}</pre>
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
@@ -131,7 +134,7 @@ A form is an instance of {@link form.FormController FormController}.
|
||||
The form instance can optionally be published into the scope using the `name` attribute.
|
||||
|
||||
Similarly, an input control that has the {@link ng.directive:ngModel ngModel} directive holds an
|
||||
instance of {@link ngModel.NgModelController NgModelController}.Such a control instance
|
||||
instance of {@link ngModel.NgModelController NgModelController}. Such a control instance
|
||||
can be published as a property of the form instance using the `name` attribute on the input control.
|
||||
The name attribute specifies the name of the property on the form instance.
|
||||
|
||||
@@ -180,6 +183,8 @@ didn't interact with a control
|
||||
<input type="button" ng-click="reset(form)" value="Reset" />
|
||||
<input type="submit" ng-click="update(user)" value="Save" />
|
||||
</form>
|
||||
<pre>form = {{user | json}}</pre>
|
||||
<pre>master = {{master | json}}</pre>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
@@ -339,7 +344,7 @@ In the following example we create two directives:
|
||||
<div>
|
||||
Username:
|
||||
<input type="text" ng-model="name" name="name" username />{{name}}<br />
|
||||
<span ng-show="form.name.$pending.username">Checking if this name is available ...</span>
|
||||
<span ng-show="form.name.$pending.username">Checking if this name is available...</span>
|
||||
<span ng-show="form.name.$error.username">This username is already taken!</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ In Angular applications, you move the job of filling page templates with data fr
|
||||
|
||||
## Specific Topics
|
||||
|
||||
* **Login: **[Google example](https://developers.google.com/+/photohunt/python), [Facebook example](http://blog.brunoscopelliti.com/facebook-authentication-in-your-angularjs-web-app), [authentication strategy](http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app), [unix-style authorization](http://frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/)
|
||||
* **Login: **[Google example](https://developers.google.com/+/photohunt/python), [AngularJS Facebook library](https://github.com/pc035860/angular-easyfb), [Facebook example](http://blog.brunoscopelliti.com/facebook-authentication-in-your-angularjs-web-app), [authentication strategy](http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app), [unix-style authorization](http://frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/)
|
||||
* **Mobile:** [Angular on Mobile Guide](http://www.ng-newsletter.com/posts/angular-on-mobile.html), [PhoneGap](http://devgirl.org/2013/06/10/quick-start-guide-phonegap-and-angularjs/)
|
||||
* **Other Languages:** [CoffeeScript](http://www.coffeescriptlove.com/2013/08/angularjs-and-coffeescript-tutorials.html), [Dart](https://github.com/angular/angular.dart.tutorial/wiki)
|
||||
* **Realtime: **[Socket.io](http://www.creativebloq.com/javascript/angularjs-collaboration-board-socketio-2132885), [OmniBinder](https://github.com/jeffbcross/omnibinder)
|
||||
@@ -62,6 +62,7 @@ In Angular applications, you move the job of filling page templates with data fr
|
||||
|
||||
## Tools
|
||||
|
||||
* **Getting Started:** [Comparison of the options for starting a new project](http://www.dancancro.com/comparison-of-angularjs-application-starters/)
|
||||
* **Debugging:** [Batarang](https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en)
|
||||
* **Testing:** [Karma](http://karma-runner.github.io), [Protractor](https://github.com/angular/protractor)
|
||||
* **Editor support:** [Webstorm](http://plugins.jetbrains.com/plugin/6971) (and [video](http://www.youtube.com/watch?v=LJOyrSh1kDU)), [Sublime Text](https://github.com/angular-ui/AngularJS-sublime-package), [Visual Studio](http://madskristensen.net/post/angularjs-intellisense-in-visual-studio-2012)
|
||||
@@ -101,7 +102,7 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
## Learning Resources
|
||||
|
||||
###Books
|
||||
* [AngularJS](http://www.amazon.com/AngularJS-Brad-Green/dp/1449344852) by Brad Green and Shyam Seshadri
|
||||
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
|
||||
* [Mastering Web App Development](http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821) by Pawel Kozlowski and Pete Bacon Darwin
|
||||
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
|
||||
* [Recipes With AngularJS](http://www.amazon.co.uk/Recipes-Angular-js-Frederik-Dietz-ebook/dp/B00DK95V48) by Frederik Dietz
|
||||
|
||||
@@ -12,7 +12,7 @@ succinctly. Angular's data binding and dependency injection eliminate much of th
|
||||
would otherwise have to write. And it all happens within the browser, making it
|
||||
an ideal partner with any server technology.
|
||||
|
||||
Angular is what HTML would have been had it been designed for applications. HTML is a great
|
||||
Angular is what HTML would have been, had it been designed for applications. HTML is a great
|
||||
declarative language for static documents. It does not contain much in the way of creating
|
||||
applications, and as a result building web applications is an exercise in *what do I have to do
|
||||
to trick the browser into doing what I want?*
|
||||
@@ -28,10 +28,10 @@ The impedance mismatch between dynamic applications and static documents is ofte
|
||||
|
||||
Angular takes another approach. It attempts to minimize the impedance mismatch between document
|
||||
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
|
||||
browser new syntax through a construct we call directives. Examples include:
|
||||
browser new syntax through a construct we call *directives*. Examples include:
|
||||
|
||||
* Data binding, as in `{{}}`.
|
||||
* DOM control structures for repeating/hiding DOM fragments.
|
||||
* DOM control structures for repeating, showing and hiding DOM fragments.
|
||||
* Support for forms and form validation.
|
||||
* Attaching new behavior to DOM elements, such as DOM event handling.
|
||||
* Grouping of HTML into reusable components.
|
||||
@@ -42,20 +42,20 @@ browser new syntax through a construct we call directives. Examples include:
|
||||
|
||||
Angular is not a single piece in the overall puzzle of building the client-side of a web
|
||||
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
|
||||
well-defined structure. This makes Angular opinionated about how a CRUD application should be
|
||||
built. But while it is opinionated, it also tries to make sure that its opinion is just a
|
||||
starting point you can easily change. Angular comes with the following out-of-the-box:
|
||||
well-defined structure. This makes Angular opinionated about how a CRUD (Create, Read, Update, Delete)
|
||||
application should be built. But while it is opinionated, it also tries to make sure that its opinion
|
||||
is just a starting point you can easily change. Angular comes with the following out-of-the-box:
|
||||
|
||||
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
|
||||
directives, form validation, routing, deep-linking, reusable components, dependency injection.
|
||||
* Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
|
||||
* Everything you need to build a CRUD app in a cohesive set: Data-binding, basic templating
|
||||
directives, form validation, routing, deep-linking, reusable components and dependency injection.
|
||||
* Testability story: Unit-testing, end-to-end testing, mocks and test harnesses.
|
||||
* Seed application with directory layout and test scripts as a starting point.
|
||||
|
||||
|
||||
## Angular Sweet Spot
|
||||
## Angular's sweet spot
|
||||
|
||||
Angular simplifies application development by presenting a higher level of abstraction to the
|
||||
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
|
||||
developer. Like any abstraction, it comes at a cost of flexibility. In other words, not every app
|
||||
is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD
|
||||
applications represent the majority of web applications. To understand what Angular is
|
||||
good at, though, it helps to understand when an app is not a good fit for Angular.
|
||||
@@ -78,7 +78,7 @@ expressing business logic.
|
||||
* It is an excellent idea to decouple the client side of an app from the server side. This
|
||||
allows development work to progress in parallel, and allows for reuse of both sides.
|
||||
* It is very helpful indeed if the framework guides developers through the entire journey of
|
||||
building an app: from designing the UI, through writing the business logic, to testing.
|
||||
building an app: From designing the UI, through writing the business logic, to testing.
|
||||
* It is always good to make common tasks trivial and difficult tasks possible.
|
||||
|
||||
|
||||
|
||||
@@ -15,13 +15,51 @@ which drives many of these changes.
|
||||
|
||||
# Migrating from 1.2 to 1.3
|
||||
|
||||
## Controllers
|
||||
|
||||
Due to [3f2232b5](https://github.com/angular/angular.js/commit/3f2232b5a181512fac23775b1df4a6ebda67d018),
|
||||
`$controller` will no longer look for controllers on `window`.
|
||||
The old behavior of looking on `window` for controllers was originally intended
|
||||
for use in examples, demos, and toy apps. We found that allowing global controller
|
||||
functions encouraged poor practices, so we resolved to disable this behavior by
|
||||
default.
|
||||
|
||||
To migrate, register your controllers with modules rather than exposing them
|
||||
as globals:
|
||||
|
||||
Before:
|
||||
|
||||
```javascript
|
||||
function MyController() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```javascript
|
||||
angular.module('myApp', []).controller('MyController', [function() {
|
||||
// ...
|
||||
}]);
|
||||
```
|
||||
|
||||
Although it's not recommended, you can re-enable the old behavior like this:
|
||||
|
||||
```javascript
|
||||
angular.module('myModule').config(['$controllerProvider', function($controllerProvider) {
|
||||
// this option might be handy for migrating old apps, but please don't use it
|
||||
// in new ones!
|
||||
$controllerProvider.allowGlobals();
|
||||
}]);
|
||||
```
|
||||
|
||||
## Angular Expression Parsing (`$parse` + `$interpolate`)
|
||||
|
||||
- due to [77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5),
|
||||
|
||||
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
|
||||
This is to disallow changing the behaviour of existing functions
|
||||
in an unforseen fashion.
|
||||
in an unforeseen fashion.
|
||||
|
||||
- due to [6081f207](https://github.com/angular/angular.js/commit/6081f20769e64a800ee8075c168412b21f026d99),
|
||||
|
||||
@@ -877,7 +915,7 @@ of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanit
|
||||
module is not loaded) and the bound expression evaluates to a value that is not trusted an
|
||||
exception is thrown.
|
||||
|
||||
When using this directive you can either include `ngSanitize` in your module's dependencis (See the
|
||||
When using this directive you can either include `ngSanitize` in your module's dependencies (See the
|
||||
example at the {@link ngBindHtml} reference) or use the {@link $sce} service to set the value as
|
||||
trusted.
|
||||
|
||||
@@ -1134,10 +1172,10 @@ freely available to JavaScript code (as before).
|
||||
|
||||
Angular expressions execute in a limited context. They do not have
|
||||
direct access to the global scope, `window`, `document` or the Function
|
||||
constructor. However, they have direct access to names/properties on
|
||||
the scope chain. It has been a long standing best practice to keep
|
||||
constructor. However, they have direct access to names/properties on
|
||||
the scope chain. It has been a long standing best practice to keep
|
||||
sensitive APIs outside of the scope chain (in a closure or your
|
||||
controller.) That's easier said that done for two reasons:
|
||||
controller.) That's easier said than done for two reasons:
|
||||
|
||||
1. JavaScript does not have a notion of private properties so if you need
|
||||
someone on the scope chain for JavaScript use, you also expose it to
|
||||
|
||||
@@ -76,7 +76,7 @@ that you break your application to multiple modules like this:
|
||||
initialization code.
|
||||
|
||||
We've also
|
||||
[written a document](http://blog.angularjs.org/2014/02/an-angularjs-style-guide-and-best.html)
|
||||
[written a document](http://angularjs.blogspot.com/2014/02/an-angularjs-style-guide-and-best.html)
|
||||
on how we organize large apps at Google.
|
||||
|
||||
The above is a suggestion. Tailor it to your needs.
|
||||
|
||||
@@ -10,13 +10,13 @@ There are a few things you might consider when running your AngularJS applicatio
|
||||
|
||||
## Disabling Debug Data
|
||||
|
||||
By default AngularJS attaches information about scopes to DOM nodes, and adds CSS classes
|
||||
to data-bound elements. The information that is not included is:
|
||||
By default AngularJS attaches information about binding and scopes to DOM nodes,
|
||||
and adds CSS classes to data-bound elements:
|
||||
|
||||
As a result of `ngBind`, `ngBindHtml` or `{{...}}` interpolations, binding data and CSS class
|
||||
`ng-class` is attached to the corresponding element.
|
||||
- As a result of `ngBind`, `ngBindHtml` or `{{...}}` interpolations, binding data and CSS class
|
||||
`ng-binding` are attached to the corresponding element.
|
||||
|
||||
Where the compiler has created a new scope, the scope and either `ng-scope` or `ng-isolated-scope`
|
||||
- Where the compiler has created a new scope, the scope and either `ng-scope` or `ng-isolated-scope`
|
||||
CSS class are attached to the corresponding element. These scope references can then be accessed via
|
||||
`element.scope()` and `element.isolateScope()`.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
# What are Scopes?
|
||||
|
||||
{@link ng.$rootScope.Scope scope} is an object that refers to the application
|
||||
{@link ng.$rootScope.Scope Scope} is an object that refers to the application
|
||||
model. It is an execution context for {@link expression expressions}. Scopes are
|
||||
arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can
|
||||
watch {@link guide/expression expressions} and propagate events.
|
||||
@@ -245,7 +245,7 @@ of the `$watch` expressions and compares them with the previous value. This dirt
|
||||
asynchronously. This means that assignment such as `$scope.username="angular"` will not
|
||||
immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until
|
||||
the `$digest` phase. This delay is desirable, since it coalesces multiple model updates into one
|
||||
`$watch` notification as well as it guarantees that during the `$watch` notification no other
|
||||
`$watch` notification as well as guarantees that during the `$watch` notification no other
|
||||
`$watch`es are running. If a `$watch` changes the value of the model, it will force additional
|
||||
`$digest` cycle.
|
||||
|
||||
@@ -264,7 +264,7 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
|
||||
3. **Model mutation**
|
||||
|
||||
For mutations to be properly observed, you should make them only within the {@link
|
||||
ng.$rootScope.Scope#$apply scope.$apply()}. (Angular APIs do this
|
||||
ng.$rootScope.Scope#$apply scope.$apply()}. Angular APIs do this
|
||||
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
|
||||
or asynchronous work with {@link ng.$http $http}, {@link ng.$timeout $timeout}
|
||||
or {@link ng.$interval $interval} services.
|
||||
|
||||
@@ -62,7 +62,7 @@ are available on [the Karma website](http://karma-runner.github.io/0.12/intro/in
|
||||
|
||||
### Jasmine
|
||||
|
||||
[Jasmine](http://jasmine.github.io/1.3/introduction.html) is a test driven development framework for
|
||||
[Jasmine](http://jasmine.github.io/1.3/introduction.html) is a behavior driven development framework for
|
||||
JavaScript that has become the most popular choice for testing Angular applications. Jasmine
|
||||
provides functions to help with structuring your tests and also making assertions. As your tests
|
||||
grow, keeping them well structured and documented is vital, and Jasmine helps achieve this.
|
||||
@@ -260,6 +260,11 @@ myModule.filter('length', function() {
|
||||
});
|
||||
|
||||
describe('length filter', function() {
|
||||
|
||||
beforeEach(inject(function(_$filter_){
|
||||
$filter= _$filter_;
|
||||
}));
|
||||
|
||||
it('returns 0 when given null', function() {
|
||||
var length = $filter('length');
|
||||
expect(length(null)).toEqual(0);
|
||||
|
||||
@@ -153,7 +153,7 @@ grunt test:unit --browsers Opera,Firefox
|
||||
|
||||
Note there should be _no spaces between browsers_. `Opera, Firefox` is INVALID.
|
||||
|
||||
During development it's however more productive to continuously run unit tests every time the source or test files
|
||||
During development, however, it's more productive to continuously run unit tests every time the source or test files
|
||||
change. To execute tests in this mode run:
|
||||
|
||||
1. To start the Karma server, capture Chrome browser and run unit tests, run:
|
||||
|
||||
@@ -15,14 +15,14 @@ development.
|
||||
production.
|
||||
|
||||
To point your code to an angular script on the Google CDN server, use the following template. This
|
||||
example points to the minified version 1.2.0:
|
||||
example points to the minified version 1.3.14:
|
||||
|
||||
```
|
||||
<!doctype html>
|
||||
<html ng-app>
|
||||
<head>
|
||||
<title>My Angular App</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
||||
@@ -67,7 +67,7 @@ illustration we typically build snappy apps with hundreds or thousands of active
|
||||
|
||||
### How big is the angular.js file that I need to include?
|
||||
|
||||
The size of the file is < 36KB compressed and minified.
|
||||
The size of the file is ~50KB compressed and minified.
|
||||
|
||||
|
||||
### Can I use the open-source Closure Library with Angular?
|
||||
|
||||
@@ -33,6 +33,9 @@ To see the app running in a browser, open a *separate* terminal/command line tab
|
||||
run `npm start` to start the web server. Now, open a browser window for the app and navigate to
|
||||
<a href="http://localhost:8000/app/" target="_blank">`http://localhost:8000/app/`</a>
|
||||
|
||||
Note that if you already ran the master branch app prior to checking out step-0, you may see the cached
|
||||
master version of the app in your browser window at this point. Just hit refresh to re-load the page.
|
||||
|
||||
You can now see the page in your browser. It's not very exciting, but that's OK.
|
||||
|
||||
The HTML page that displays "Nothing here yet!" was constructed with the HTML code shown below.
|
||||
@@ -62,7 +65,7 @@ __`app/index.html`:__
|
||||
|
||||
## What is the code doing?
|
||||
|
||||
* `ng-app` directive:
|
||||
**`ng-app` directive:**
|
||||
|
||||
<html ng-app>
|
||||
|
||||
@@ -74,17 +77,17 @@ __`app/index.html`:__
|
||||
This gives application developers the freedom to tell Angular if the entire html page or only a
|
||||
portion of it should be treated as the Angular application.
|
||||
|
||||
* AngularJS script tag:
|
||||
**AngularJS script tag:**
|
||||
|
||||
<script src="bower_components/angular/angular.js">
|
||||
|
||||
This code downloads the `angular.js` script and registers a callback that will be executed by the
|
||||
This code downloads the `angular.js` script which registers a callback that will be executed by the
|
||||
browser when the containing HTML page is fully downloaded. When the callback is executed, Angular
|
||||
looks for the {@link ng.directive:ngApp ngApp} directive. If
|
||||
Angular finds the directive, it will bootstrap the application with the root of the application DOM
|
||||
being the element on which the `ngApp` directive was defined.
|
||||
|
||||
* Double-curly binding with an expression:
|
||||
**Double-curly binding with an expression:**
|
||||
|
||||
Nothing here {{'yet' + '!'}}
|
||||
|
||||
@@ -108,7 +111,7 @@ being the element on which the `ngApp` directive was defined.
|
||||
## Bootstrapping AngularJS apps
|
||||
|
||||
Bootstrapping AngularJS apps automatically using the `ngApp` directive is very easy and suitable
|
||||
for most cases. In advanced cases, such as when using script loaders, you can use
|
||||
for most cases. In advanced cases, such as when using script loaders, you can use the
|
||||
{@link guide/bootstrap imperative / manual way} to bootstrap the app.
|
||||
|
||||
There are 3 important things that happen during the app bootstrap:
|
||||
|
||||
@@ -21,7 +21,7 @@ multiple views by adding routing, using an Angular module called 'ngRoute'.
|
||||
The routing functionality added by this step is provided by angular in the `ngRoute` module, which
|
||||
is distributed separately from the core Angular framework.
|
||||
|
||||
We are using [Bower][bower] to install client side dependencies. This step updates the
|
||||
We are using [Bower][bower] to install client-side dependencies. This step updates the
|
||||
`bower.json` configuration file to include the new dependency:
|
||||
|
||||
```json
|
||||
@@ -46,7 +46,7 @@ The new dependency `"angular-route": "~1.3.0"` tells bower to install a version
|
||||
angular-route component that is compatible with version 1.3.x. We must tell bower to download
|
||||
and install this dependency.
|
||||
|
||||
If you have bower installed globally then you can run `bower install` but for this project we have
|
||||
If you have bower installed globally, then you can run `bower install` but for this project, we have
|
||||
preconfigured npm to run bower install for us:
|
||||
|
||||
```
|
||||
@@ -70,7 +70,7 @@ the current "route" — the view that is currently displayed to the user.
|
||||
Application routes in Angular are declared via the {@link ngRoute.$routeProvider $routeProvider},
|
||||
which is the provider of the {@link ngRoute.$route $route service}. This service makes it easy to
|
||||
wire together controllers, view templates, and the current URL location in the browser. Using this
|
||||
feature we can implement [deep linking](http://en.wikipedia.org/wiki/Deep_linking), which lets us
|
||||
feature, we can implement [deep linking](http://en.wikipedia.org/wiki/Deep_linking), which lets us
|
||||
utilize the browser's history (back and forward navigation) and bookmarks.
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ AngularJS, so it's important for you to understand a thing or two about how it w
|
||||
|
||||
When the application bootstraps, Angular creates an injector that will be used to find and inject all
|
||||
of the services that are required by your app. The injector itself doesn't know anything about what
|
||||
`$http` or `$route` services do, in fact it doesn't even know about the existence of these services
|
||||
`$http` or `$route` services do. In fact, the injector doesn't even know about the existence of these services
|
||||
unless it is configured with proper module definitions.
|
||||
|
||||
The injector only carries out the following steps :
|
||||
@@ -295,7 +295,7 @@ phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams',
|
||||
|
||||
Again, note that we created a new module called `phonecatControllers`. For small AngularJS
|
||||
applications, it's common to create just one module for all of your controllers if there are just a
|
||||
few. As your application grows it is quite common to refactor your code into additional modules.
|
||||
few. As your application grows, it is quite common to refactor your code into additional modules.
|
||||
For larger apps, you will probably want to create separate modules for each major feature of
|
||||
your app.
|
||||
|
||||
@@ -313,7 +313,7 @@ to various URLs and verify that the correct view was rendered.
|
||||
it('should redirect index.html to index.html#/phones', function() {
|
||||
browser.get('app/index.html');
|
||||
browser.getLocationAbsUrl().then(function(url) {
|
||||
expect(url.split('#')[1]).toBe('/phones');
|
||||
expect(url).toEqual('/phones');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -349,7 +349,7 @@ the same binding into the `phone-list.html` template, the binding will work as e
|
||||
|
||||
<div style="display: none">
|
||||
* In `PhoneCatCtrl`, create a new model called "`hero`" with `this.hero = 'Zoro'`. In
|
||||
`PhoneListCtrl` let's shadow it with `this.hero = 'Batman'`, and in `PhoneDetailCtrl` we'll use
|
||||
`PhoneListCtrl`, let's shadow it with `this.hero = 'Batman'`. In `PhoneDetailCtrl`, we'll use
|
||||
`this.hero = "Captain Proton"`. Then add the `<p>hero = {{hero}}</p>` to all three of our templates
|
||||
(`index.html`, `phone-list.html`, and `phone-detail.html`). Open the app and you'll see scope
|
||||
inheritance and model property shadowing do some wonders.
|
||||
|
||||
@@ -31,7 +31,7 @@ phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$h
|
||||
|
||||
$scope.setImage = function(imageUrl) {
|
||||
$scope.mainImageUrl = imageUrl;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
```
|
||||
|
||||
|
||||
@@ -288,5 +288,5 @@ learn how to improve this application with animations.
|
||||
<ul doc-tutorial-nav="11"></ul>
|
||||
|
||||
[restful]: http://en.wikipedia.org/wiki/Representational_State_Transfer
|
||||
[jasmine-matchers]: https://github.com/pivotal/jasmine/wiki/Matchers
|
||||
[jasmine-matchers]: http://jasmine.github.io/1.3/introduction.html#section-Matchers
|
||||
[bower]: http://bower.io/
|
||||
|
||||
@@ -97,7 +97,7 @@ __`app/index.html`.__
|
||||
...
|
||||
|
||||
<!-- jQuery is used for JavaScript animations (include this before angular.js) -->
|
||||
<script src="bower_components/jquery/jquery.js"></script>
|
||||
<script src="bower_components/jquery/dist/jquery.js"></script>
|
||||
|
||||
...
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ function request(method, url, options, response) {
|
||||
res.on('error', function (e) { console.log(e); });
|
||||
break;
|
||||
case 401:
|
||||
console.log('Eror: Login credentials expired! Please login.');
|
||||
console.log('Error: Login credentials expired! Please login.');
|
||||
break;
|
||||
default:
|
||||
data = [];
|
||||
|
||||
@@ -2912,16 +2912,12 @@ goog.i18n.DateTimeSymbols_my = {
|
||||
'ဇွန်', 'ဇူလိုင်', 'ဩဂုတ်',
|
||||
'စက်တင်ဘာ', 'အောက်တိုဘာ',
|
||||
'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],
|
||||
SHORTMONTHS: ['ဇန်နဝါရီ', 'ဖေဖော်ဝါရီ',
|
||||
'မတ်', 'ဧပြီ', 'မေ', 'ဇွန်',
|
||||
'ဇူလိုင်', 'ဩဂုတ်', 'စက်တင်ဘာ',
|
||||
'အောက်တိုဘာ', 'နိုဝင်ဘာ',
|
||||
'ဒီဇင်ဘာ'],
|
||||
STANDALONESHORTMONTHS: ['ဇန်နဝါရီ',
|
||||
'ဖေဖော်ဝါရီ', 'မတ်', 'ဧပြီ', 'မေ',
|
||||
'ဇွန်', 'ဇူလိုင်', 'ဩဂုတ်',
|
||||
'စက်တင်ဘာ', 'အောက်တိုဘာ',
|
||||
'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],
|
||||
SHORTMONTHS: ['ဇန်', 'ဖေ', 'မတ်', 'ဧပြီ', 'မေ',
|
||||
'ဇွန်', 'ဇူ', 'ဩ', 'စက်', 'အောက်',
|
||||
'နို', 'ဒီ'],
|
||||
STANDALONESHORTMONTHS: ['ဇန်', 'ဖေ', 'မတ်', 'ဧပြီ',
|
||||
'မေ', 'ဇွန်', 'ဇူ', 'ဩ', 'စက်', 'အောက်',
|
||||
'နို', 'ဒီ'],
|
||||
WEEKDAYS: ['တနင်္ဂနွေ', 'တနင်္လာ',
|
||||
'အင်္ဂါ', 'ဗုဒ္ဓဟူး',
|
||||
'ကြာသပတေး', 'သောကြာ', 'စနေ'],
|
||||
@@ -2945,7 +2941,7 @@ goog.i18n.DateTimeSymbols_my = {
|
||||
'တတိယ သုံးလပတ်',
|
||||
'စတုတ္ထ သုံးလပတ်'],
|
||||
AMPMS: ['နံနက်', 'ညနေ'],
|
||||
DATEFORMATS: ['EEEE, y MMMM dd', 'y MMMM d', 'y MMM d', 'yy/MM/dd'],
|
||||
DATEFORMATS: ['EEEE, dd MMMM y', 'd MMMM y', 'd MMM y', 'dd-MM-yy'],
|
||||
TIMEFORMATS: ['HH:mm:ss zzzz', 'HH:mm:ss z', 'HH:mm:ss', 'HH:mm'],
|
||||
DATETIMEFORMATS: ['{1}မှာ {0}', '{1} {0}', '{1} {0}', '{1} {0}'],
|
||||
FIRSTDAYOFWEEK: 6,
|
||||
|
||||
@@ -14493,16 +14493,12 @@ goog.i18n.DateTimeSymbols_my_MM = {
|
||||
'ဇွန်', 'ဇူလိုင်', 'ဩဂုတ်',
|
||||
'စက်တင်ဘာ', 'အောက်တိုဘာ',
|
||||
'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],
|
||||
SHORTMONTHS: ['ဇန်နဝါရီ', 'ဖေဖော်ဝါရီ',
|
||||
'မတ်', 'ဧပြီ', 'မေ', 'ဇွန်',
|
||||
'ဇူလိုင်', 'ဩဂုတ်', 'စက်တင်ဘာ',
|
||||
'အောက်တိုဘာ', 'နိုဝင်ဘာ',
|
||||
'ဒီဇင်ဘာ'],
|
||||
STANDALONESHORTMONTHS: ['ဇန်နဝါရီ',
|
||||
'ဖေဖော်ဝါရီ', 'မတ်', 'ဧပြီ', 'မေ',
|
||||
'ဇွန်', 'ဇူလိုင်', 'ဩဂုတ်',
|
||||
'စက်တင်ဘာ', 'အောက်တိုဘာ',
|
||||
'နိုဝင်ဘာ', 'ဒီဇင်ဘာ'],
|
||||
SHORTMONTHS: ['ဇန်', 'ဖေ', 'မတ်', 'ဧပြီ', 'မေ',
|
||||
'ဇွန်', 'ဇူ', 'ဩ', 'စက်', 'အောက်',
|
||||
'နို', 'ဒီ'],
|
||||
STANDALONESHORTMONTHS: ['ဇန်', 'ဖေ', 'မတ်', 'ဧပြီ',
|
||||
'မေ', 'ဇွန်', 'ဇူ', 'ဩ', 'စက်', 'အောက်',
|
||||
'နို', 'ဒီ'],
|
||||
WEEKDAYS: ['တနင်္ဂနွေ', 'တနင်္လာ',
|
||||
'အင်္ဂါ', 'ဗုဒ္ဓဟူး',
|
||||
'ကြာသပတေး', 'သောကြာ', 'စနေ'],
|
||||
@@ -14526,7 +14522,7 @@ goog.i18n.DateTimeSymbols_my_MM = {
|
||||
'တတိယ သုံးလပတ်',
|
||||
'စတုတ္ထ သုံးလပတ်'],
|
||||
AMPMS: ['နံနက်', 'ညနေ'],
|
||||
DATEFORMATS: ['EEEE, y MMMM dd', 'y MMMM d', 'y MMM d', 'yy/MM/dd'],
|
||||
DATEFORMATS: ['EEEE, dd MMMM y', 'd MMMM y', 'd MMM y', 'dd-MM-yy'],
|
||||
TIMEFORMATS: ['HH:mm:ss zzzz', 'HH:mm:ss z', 'HH:mm:ss', 'HH:mm'],
|
||||
DATETIMEFORMATS: ['{1}မှာ {0}', '{1} {0}', '{1} {0}', '{1} {0}'],
|
||||
FIRSTDAYOFWEEK: 6,
|
||||
|
||||
@@ -2112,7 +2112,7 @@ goog.i18n.NumberFormatSymbols_lt = {
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0\u00A0%',
|
||||
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
|
||||
DEF_CURRENCY_CODE: 'LTL'
|
||||
DEF_CURRENCY_CODE: 'EUR'
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -185,6 +185,8 @@ describe("extractDateTimeSymbols", function() {
|
||||
DAY: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
|
||||
SHORTDAY: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
|
||||
AMPMS: ['AM', 'PM'],
|
||||
ERAS: ['av. J.-C.', 'ap. J.-C.'],
|
||||
ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],
|
||||
medium: 'yyyy-MM-dd HH:mm:ss',
|
||||
short: 'yy-MM-dd HH:mm',
|
||||
fullDate: 'EEEE d MMMM y',
|
||||
|
||||
@@ -42,6 +42,8 @@ function convertDatetimeData(dataObj) {
|
||||
datetimeFormats.DAY = dataObj.WEEKDAYS;
|
||||
datetimeFormats.SHORTDAY = dataObj.SHORTWEEKDAYS;
|
||||
datetimeFormats.AMPMS = dataObj.AMPMS;
|
||||
datetimeFormats.ERAS = dataObj.ERAS;
|
||||
datetimeFormats.ERANAMES = dataObj.ERANAMES;
|
||||
|
||||
|
||||
datetimeFormats.medium = dataObj.DATEFORMATS[2] + ' ' + dataObj.TIMEFORMATS[2];
|
||||
|
||||
+18
-6
@@ -35,18 +35,18 @@ module.exports = function(config, specificOptions) {
|
||||
'SL_Chrome': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'chrome',
|
||||
version: '34'
|
||||
version: '39'
|
||||
},
|
||||
'SL_Firefox': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'firefox',
|
||||
version: '26'
|
||||
version: '31'
|
||||
},
|
||||
'SL_Safari': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.9',
|
||||
version: '7'
|
||||
platform: 'OS X 10.10',
|
||||
version: '8'
|
||||
},
|
||||
'SL_IE_9': {
|
||||
base: 'SauceLabs',
|
||||
@@ -66,18 +66,24 @@ module.exports = function(config, specificOptions) {
|
||||
platform: 'Windows 8.1',
|
||||
version: '11'
|
||||
},
|
||||
'SL_iOS': {
|
||||
base: "SauceLabs",
|
||||
browserName: "iphone",
|
||||
platform: "OS X 10.10",
|
||||
version: "8.1"
|
||||
},
|
||||
|
||||
'BS_Chrome': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'chrome',
|
||||
os: 'OS X',
|
||||
os_version: 'Mountain Lion'
|
||||
os_version: 'Yosemite'
|
||||
},
|
||||
'BS_Safari': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'safari',
|
||||
os: 'OS X',
|
||||
os_version: 'Mountain Lion'
|
||||
os_version: 'Yosemite'
|
||||
},
|
||||
'BS_Firefox': {
|
||||
base: 'BrowserStack',
|
||||
@@ -105,6 +111,12 @@ module.exports = function(config, specificOptions) {
|
||||
browser_version: '11.0',
|
||||
os: 'Windows',
|
||||
os_version: '8.1'
|
||||
},
|
||||
'BS_iOS': {
|
||||
base: 'BrowserStack',
|
||||
device: 'iPhone 6',
|
||||
os: 'ios',
|
||||
os_version: '8.0'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
|
||||
echo "Shutting down Browserstack tunnel"
|
||||
echo "TODO: implement me"
|
||||
exit 1
|
||||
+1
-8
@@ -14,13 +14,6 @@ var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP
|
||||
|
||||
module.exports = {
|
||||
|
||||
init: function() {
|
||||
if (!process.env.TRAVIS) {
|
||||
shell.exec('npm install');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
startKarma: function(config, singleRun, done){
|
||||
var browsers = grunt.option('browsers');
|
||||
var reporters = grunt.option('reporters');
|
||||
@@ -123,7 +116,7 @@ module.exports = {
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/'/g, "\\'")
|
||||
.replace(/\r?\n/g, '\\n');
|
||||
js = "!window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type=\"text/css\">" + css + "</style>');";
|
||||
js = "!window.angular.$$csp() && window.angular.element(document.head).prepend('<style type=\"text/css\">" + css + "</style>');";
|
||||
state.js.push(js);
|
||||
|
||||
return state;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var glob = require("glob");
|
||||
var _ = require('lodash');
|
||||
var files = require('../../angularFiles').files;
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('validate-angular-files', function() {
|
||||
var combinedFiles = _.clone(files.angularModules);
|
||||
combinedFiles.ng = files.angularSrc;
|
||||
combinedFiles.angularLoader = files.angularLoader;
|
||||
|
||||
var errorsDetected = false;
|
||||
var directories = [];
|
||||
var detectedFiles = {};
|
||||
|
||||
for (var section in combinedFiles) {
|
||||
var sectionFiles = combinedFiles[section];
|
||||
|
||||
if (section != 'angularLoader') {
|
||||
directories.push('src/' + section);
|
||||
}
|
||||
|
||||
grunt.log.debug('Validating ' + sectionFiles.length + ' files from the "' + section + '" module.');
|
||||
|
||||
sectionFiles.forEach(function(file) {
|
||||
detectedFiles[file] = true;
|
||||
|
||||
if (!fs.existsSync(file)) {
|
||||
grunt.log.error(file + ' does not exist in the local file structure.');
|
||||
errorsDetected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
directories.forEach(function(directory) {
|
||||
glob.sync(directory + '/**/*').forEach(function(filePath) {
|
||||
if (!fs.lstatSync(filePath).isDirectory()) {
|
||||
var fileName = path.basename(filePath);
|
||||
var isHiddenFile = fileName[0] == '.';
|
||||
if (!isHiddenFile && !detectedFiles[filePath]) {
|
||||
grunt.log.error(filePath + ' exists in the local file structure but isn\'t used by any module.');
|
||||
errorsDetected = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (errorsDetected) {
|
||||
throw new Error('Not all files were properly detected in the local file structure.');
|
||||
} else {
|
||||
grunt.log.ok('All files were detected successfully!');
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -12,9 +12,9 @@ set -e
|
||||
# before_script:
|
||||
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
|
||||
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3-linux.tar.gz"
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.7-linux.tar.gz"
|
||||
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
|
||||
CONNECT_DOWNLOAD="sc-4.3-linux.tar.gz"
|
||||
CONNECT_DOWNLOAD="sc-4.3.7-linux.tar.gz"
|
||||
|
||||
CONNECT_LOG="$LOGS_DIR/sauce-connect"
|
||||
CONNECT_STDOUT="$LOGS_DIR/sauce-connect.stdout"
|
||||
@@ -46,5 +46,5 @@ echo "Starting Sauce Connect in the background, logging into:"
|
||||
echo " $CONNECT_LOG"
|
||||
echo " $CONNECT_STDOUT"
|
||||
echo " $CONNECT_STDERR"
|
||||
sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS -v \
|
||||
sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS \
|
||||
--logfile $CONNECT_LOG 2> $CONNECT_STDERR 1> $CONNECT_STDOUT &
|
||||
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/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"
|
||||
File diff suppressed because it is too large
Load Diff
Generated
+7290
-1571
File diff suppressed because it is too large
Load Diff
+16
-5
@@ -1,19 +1,31 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"branchVersion": "1.3.*",
|
||||
"distTag": "previous_1_3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": "~0.10",
|
||||
"npm": "~2.5"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"scripts": {
|
||||
"preinstall": "node scripts/npm/check-node-modules.js --purge",
|
||||
"postinstall": "node scripts/npm/copy-npm-shrinkwrap.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-benchpress": "0.x.x",
|
||||
"benchmark": "1.x.x",
|
||||
"bower": "~1.3.9",
|
||||
"browserstacktunnel-wrapper": "~1.3.1",
|
||||
"canonical-path": "0.0.2",
|
||||
"cheerio": "^0.17.0",
|
||||
"dgeni": "^0.4.0",
|
||||
"dgeni-packages": "^0.10.0",
|
||||
"event-stream": "~3.1.0",
|
||||
"glob": "^6.0.1",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-bump": "~0.0.13",
|
||||
"grunt-contrib-clean": "~0.6.0",
|
||||
@@ -23,7 +35,7 @@
|
||||
"grunt-contrib-jshint": "~0.10.0",
|
||||
"grunt-ddescribe-iit": "~0.0.1",
|
||||
"grunt-jasmine-node": "git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code",
|
||||
"grunt-jscs": "~0.7.1",
|
||||
"grunt-jscs": "~1.2.0",
|
||||
"grunt-merge-conflict": "~0.0.1",
|
||||
"grunt-shell": "~1.1.1",
|
||||
"gulp": "~3.8.0",
|
||||
@@ -37,7 +49,7 @@
|
||||
"jasmine-node": "~1.14.5",
|
||||
"jasmine-reporters": "~1.0.1",
|
||||
"jshint-stylish": "~1.0.0",
|
||||
"karma": "vojtajina/karma#socketio_10",
|
||||
"karma": "0.12.32",
|
||||
"karma-browserstack-launcher": "0.1.2",
|
||||
"karma-chrome-launcher": "0.1.5",
|
||||
"karma-firefox-launcher": "0.1.3",
|
||||
@@ -51,7 +63,7 @@
|
||||
"marked": "~0.3.0",
|
||||
"node-html-encoder": "0.0.2",
|
||||
"promises-aplus-tests": "~2.1.0",
|
||||
"protractor": "1.4.0",
|
||||
"protractor": "^2.0.0",
|
||||
"q": "~1.0.0",
|
||||
"q-io": "^1.10.9",
|
||||
"qq": "^0.3.5",
|
||||
@@ -59,8 +71,7 @@
|
||||
"semver": "~4.0.3",
|
||||
"shelljs": "~0.3.0",
|
||||
"sorted-object": "^1.0.0",
|
||||
"stringmap": "^0.2.2",
|
||||
"cheerio": "^0.17.0"
|
||||
"stringmap": "^0.2.2"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
|
||||
+19
-13
@@ -29,6 +29,8 @@ function init {
|
||||
angular-touch
|
||||
angular-messages
|
||||
)
|
||||
# get the npm dist-tag from a custom property (distTag) in package.json
|
||||
DIST_TAG=$(readJsonProp "package.json" "distTag")
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +65,21 @@ function prepare {
|
||||
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
|
||||
|
||||
|
||||
#
|
||||
# Run local precommit script if there is one
|
||||
#
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
if [ -f $TMP_DIR/bower-$repo/precommit.sh ]
|
||||
then
|
||||
echo "-- Running precommit.sh script for bower-$repo"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
$TMP_DIR/bower-$repo/precommit.sh
|
||||
cd $SCRIPT_DIR
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
#
|
||||
# update bower.json
|
||||
# tag each repo
|
||||
@@ -95,19 +112,8 @@ function publish {
|
||||
|
||||
# don't publish every build to npm
|
||||
if [ "${NEW_VERSION/+sha}" = "$NEW_VERSION" ] ; then
|
||||
if [ "${NEW_VERSION/-}" = "$NEW_VERSION" ] ; then
|
||||
if [[ $NEW_VERSION =~ ^1\.2\.[0-9]+$ ]] ; then
|
||||
# publish 1.2.x releases with the appropriate tag
|
||||
# this ensures that `npm install` by default will not grab `1.2.x` releases
|
||||
npm publish --tag=old
|
||||
else
|
||||
# publish releases as "latest"
|
||||
npm publish
|
||||
fi
|
||||
else
|
||||
# publish prerelease builds with the beta tag
|
||||
npm publish --tag=beta
|
||||
fi
|
||||
echo "-- Publishing to npm as $DIST_TAG"
|
||||
npm publish --tag=$DIST_TAG
|
||||
fi
|
||||
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
@@ -7,6 +7,8 @@ echo "#################################"
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
scripts/jenkins/set-node-version.sh
|
||||
|
||||
# This is the default set of browsers to use on the CI server unless overridden via env variable
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
@@ -19,6 +21,7 @@ rm -f angular.js.size
|
||||
|
||||
|
||||
# BUILD #
|
||||
npm install -g grunt-cli
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
@@ -4,9 +4,7 @@ echo "#################################"
|
||||
echo "#### Update master ##############"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"[--no-test=(true|false)]"
|
||||
)
|
||||
ARG_DEFS=()
|
||||
|
||||
function init {
|
||||
if [[ ! $VERBOSE ]]; then
|
||||
@@ -17,14 +15,7 @@ function init {
|
||||
|
||||
function build {
|
||||
cd ../..
|
||||
|
||||
if [[ $NO_TEST == "true" ]]; then
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
else
|
||||
./jenkins_build.sh
|
||||
fi
|
||||
|
||||
scripts/jenkins/build.sh
|
||||
cd $SCRIPT_DIR
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,10 @@ function init {
|
||||
}
|
||||
|
||||
function build {
|
||||
./set-node-version.sh
|
||||
cd ../..
|
||||
|
||||
npm install -g grunt-cli
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install nvm for this shell
|
||||
source ~/.nvm/nvm.sh
|
||||
|
||||
# Use node.js at 4.2.x
|
||||
nvm install 4.2
|
||||
@@ -0,0 +1,74 @@
|
||||
// Implementation based on:
|
||||
// https://github.com/angular/angular/blob/3b9c08676a4c921bbfa847802e08566fb601ba7a/tools/npm/check-node-modules.js
|
||||
'use strict';
|
||||
|
||||
// Imports
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// Constants
|
||||
var PROJECT_ROOT = path.join(__dirname, '../../');
|
||||
var NODE_MODULES_DIR = 'node_modules';
|
||||
var NPM_SHRINKWRAP_FILE = 'npm-shrinkwrap.json';
|
||||
var NPM_SHRINKWRAP_CACHED_FILE = NODE_MODULES_DIR + '/npm-shrinkwrap.cached.json';
|
||||
|
||||
// Run
|
||||
_main();
|
||||
|
||||
// Functions - Definitions
|
||||
function _main() {
|
||||
var purgeIfStale = process.argv.indexOf('--purge') !== -1;
|
||||
|
||||
process.chdir(PROJECT_ROOT);
|
||||
checkNodeModules(purgeIfStale);
|
||||
}
|
||||
|
||||
function checkNodeModules(purgeIfStale) {
|
||||
var nodeModulesOk = compareMarkerFiles(NPM_SHRINKWRAP_FILE, NPM_SHRINKWRAP_CACHED_FILE);
|
||||
|
||||
if (nodeModulesOk) {
|
||||
console.log(':-) npm dependencies are looking good!');
|
||||
} else if (purgeIfStale) {
|
||||
console.log(':-( npm dependencies are stale or in an unknown state!');
|
||||
console.log(' Purging \'' + NODE_MODULES_DIR + '\'...');
|
||||
deleteDirSync(NODE_MODULES_DIR);
|
||||
} else {
|
||||
var separator = new Array(81).join('!');
|
||||
|
||||
console.warn(separator);
|
||||
console.warn(':-( npm dependencies are stale or in an unknown state!');
|
||||
console.warn('You can rebuild the dependencies by running `npm install`.');
|
||||
console.warn(separator);
|
||||
}
|
||||
|
||||
return nodeModulesOk;
|
||||
}
|
||||
|
||||
function compareMarkerFiles(markerFilePath, cachedMarkerFilePath) {
|
||||
if (!fs.existsSync(cachedMarkerFilePath)) return false;
|
||||
|
||||
var opts = {encoding: 'utf-8'};
|
||||
var markerContent = fs.readFileSync(markerFilePath, opts);
|
||||
var cachedMarkerContent = fs.readFileSync(cachedMarkerFilePath, opts);
|
||||
|
||||
return markerContent === cachedMarkerContent;
|
||||
}
|
||||
|
||||
// Custom implementation of `rm -rf` that works consistently across OSes
|
||||
function deleteDirSync(path) {
|
||||
if (fs.existsSync(path)) {
|
||||
fs.readdirSync(path).forEach(deleteDirOrFileSync);
|
||||
fs.rmdirSync(path);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
function deleteDirOrFileSync(subpath) {
|
||||
var curPath = path + '/' + subpath;
|
||||
|
||||
if (fs.lstatSync(curPath).isDirectory()) {
|
||||
deleteDirSync(curPath);
|
||||
} else {
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,22 +10,17 @@
|
||||
var _ = require('lodash');
|
||||
var sorted = require('sorted-object');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
|
||||
function cleanModule(module, name) {
|
||||
|
||||
// keep `from` and `resolve` properties for git dependencies, delete otherwise
|
||||
if (!(module.resolved && module.resolved.match(/^git:\/\//))) {
|
||||
delete module.from;
|
||||
// keep `resolve` properties for git dependencies, delete otherwise
|
||||
delete module.from;
|
||||
if (!(module.resolved && module.resolved.match(/^git(\+[a-z]+)?:\/\//))) {
|
||||
delete module.resolved;
|
||||
}
|
||||
|
||||
if (name === 'chokidar') {
|
||||
if (module.version === '0.8.1') {
|
||||
delete module.dependencies;
|
||||
}
|
||||
}
|
||||
|
||||
_.forEach(module.dependencies, function(mod, name) {
|
||||
cleanModule(mod, name);
|
||||
});
|
||||
@@ -33,10 +28,11 @@ function cleanModule(module, name) {
|
||||
|
||||
|
||||
console.log('Reading npm-shrinkwrap.json');
|
||||
var shrinkwrap = require('./../npm-shrinkwrap.json');
|
||||
var shrinkwrap = require('../../npm-shrinkwrap.json');
|
||||
|
||||
console.log('Cleaning shrinkwrap object');
|
||||
cleanModule(shrinkwrap, shrinkwrap.name);
|
||||
|
||||
console.log('Writing cleaned npm-shrinkwrap.json');
|
||||
fs.writeFileSync('./npm-shrinkwrap.json', JSON.stringify(sorted(shrinkwrap), null, 2) + "\n");
|
||||
var cleanShrinkwrapPath = path.join(__dirname, '..', '..', 'npm-shrinkwrap.clean.json');
|
||||
console.log('Writing cleaned to', cleanShrinkwrapPath);
|
||||
fs.writeFileSync(cleanShrinkwrapPath, JSON.stringify(sorted(shrinkwrap), null, 2) + "\n");
|
||||
@@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
// Imports
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// Constants
|
||||
var PROJECT_ROOT = path.join(__dirname, '../../');
|
||||
var NODE_MODULES_DIR = 'node_modules';
|
||||
var NPM_SHRINKWRAP_FILE = 'npm-shrinkwrap.json';
|
||||
var NPM_SHRINKWRAP_CACHED_FILE = NODE_MODULES_DIR + '/npm-shrinkwrap.cached.json';
|
||||
|
||||
// Run
|
||||
_main();
|
||||
|
||||
// Functions - Definitions
|
||||
function _main() {
|
||||
process.chdir(PROJECT_ROOT);
|
||||
copyFile(NPM_SHRINKWRAP_FILE, NPM_SHRINKWRAP_CACHED_FILE, onCopied);
|
||||
}
|
||||
|
||||
// Implementation based on:
|
||||
// https://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js#answer-21995878
|
||||
function copyFile(srcPath, dstPath, callback) {
|
||||
var callbackCalled = false;
|
||||
|
||||
if (!fs.existsSync(srcPath)) {
|
||||
done(new Error('Missing source file: ' + srcPath));
|
||||
return;
|
||||
}
|
||||
|
||||
var rs = fs.createReadStream(srcPath);
|
||||
rs.on('error', done);
|
||||
|
||||
var ws = fs.createWriteStream(dstPath);
|
||||
ws.on('error', done);
|
||||
ws.on('finish', done);
|
||||
|
||||
rs.pipe(ws);
|
||||
|
||||
// Helpers
|
||||
function done(err) {
|
||||
if (callback && !callbackCalled) {
|
||||
callbackCalled = true;
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onCopied(err) {
|
||||
if (err) {
|
||||
var separator = new Array(81).join('!');
|
||||
|
||||
console.error(separator);
|
||||
console.error(
|
||||
'Failed to copy `' + NPM_SHRINKWRAP_FILE + '` to `' + NPM_SHRINKWRAP_CACHED_FILE + '`:');
|
||||
console.error(err);
|
||||
console.error(separator);
|
||||
}
|
||||
}
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p $LOGS_DIR
|
||||
|
||||
if [ $JOB != "ci-checks" ]; then
|
||||
echo "start_browser_provider"
|
||||
./scripts/travis/start_browser_provider.sh
|
||||
fi
|
||||
|
||||
npm install -g grunt-cli
|
||||
|
||||
if [ $JOB != "ci-checks" ]; then
|
||||
grunt package
|
||||
echo "wait_for_browser_provider"
|
||||
./scripts/travis/wait_for_browser_provider.sh
|
||||
fi
|
||||
@@ -5,17 +5,19 @@ set -e
|
||||
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
|
||||
export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
|
||||
if [ $JOB = "unit" ]; then
|
||||
if [ $JOB = "ci-checks" ]; then
|
||||
grunt ci-checks
|
||||
elif [ $JOB = "unit" ]; then
|
||||
if [ "$BROWSER_PROVIDER" == "browserstack" ]; then
|
||||
BROWSERS="BS_Chrome,BS_Safari,BS_Firefox,BS_IE_9,BS_IE_10,BS_IE_11"
|
||||
BROWSERS="BS_Chrome,BS_Safari,BS_Firefox,BS_IE_9,BS_IE_10,BS_IE_11,BS_iOS"
|
||||
else
|
||||
BROWSERS="SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11"
|
||||
BROWSERS="SL_Chrome,SL_Safari,SL_Firefox,SL_IE_9,SL_IE_10,SL_IE_11,SL_iOS"
|
||||
fi
|
||||
|
||||
grunt test:promises-aplus
|
||||
grunt test:unit --browsers $BROWSERS --reporters dots
|
||||
grunt ci-checks
|
||||
grunt tests:docs --browsers $BROWSERS --reporters dots
|
||||
elif [ $JOB = "docs-e2e" ]; then
|
||||
grunt test:travis-protractor --specs "docs/app/e2e/**/*.scenario.js"
|
||||
elif [ $JOB = "e2e" ]; then
|
||||
if [ $TEST_TARGET = "jquery" ]; then
|
||||
@@ -30,5 +32,5 @@ elif [ $JOB = "e2e" ]; then
|
||||
export TARGET_SPECS="test/e2e/tests/**/*.js,$TARGET_SPECS"
|
||||
grunt test:travis-protractor --specs "$TARGET_SPECS"
|
||||
else
|
||||
echo "Unknown job type. Please set JOB=unit or JOB=e2e-*."
|
||||
echo "Unknown job type. Please set JOB=ci-checks, JOB=unit or JOB=e2e-*."
|
||||
fi
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
# Has to be run from project root directory.
|
||||
|
||||
./lib/${BROWSER_PROVIDER}/teardown_tunnel.sh
|
||||
@@ -2,6 +2,18 @@
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
"skipDestroyOnNextJQueryCleanData": true,
|
||||
|
||||
"NODE_TYPE_ELEMENT": false,
|
||||
"NODE_TYPE_ATTRIBUTE": false,
|
||||
"NODE_TYPE_TEXT": false,
|
||||
"NODE_TYPE_COMMENT": false,
|
||||
"NODE_TYPE_COMMENT": false,
|
||||
|
||||
+136
-70
@@ -36,6 +36,7 @@
|
||||
isUndefined: true,
|
||||
isDefined: true,
|
||||
isObject: true,
|
||||
isBlankObject: true,
|
||||
isString: true,
|
||||
isNumber: true,
|
||||
isDate: true,
|
||||
@@ -85,6 +86,7 @@
|
||||
createMap: true,
|
||||
|
||||
NODE_TYPE_ELEMENT: true,
|
||||
NODE_TYPE_ATTRIBUTE: true,
|
||||
NODE_TYPE_TEXT: true,
|
||||
NODE_TYPE_COMMENT: true,
|
||||
NODE_TYPE_DOCUMENT: true,
|
||||
@@ -171,6 +173,7 @@ var
|
||||
splice = [].splice,
|
||||
push = [].push,
|
||||
toString = Object.prototype.toString,
|
||||
getPrototypeOf = Object.getPrototypeOf,
|
||||
ngMinErr = minErr('ng'),
|
||||
|
||||
/** @name angular */
|
||||
@@ -196,7 +199,9 @@ function isArrayLike(obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var length = obj.length;
|
||||
// Support: iOS 8.2 (not reproducible in simulator)
|
||||
// "length" in obj used to prevent JIT error (gh-11508)
|
||||
var length = "length" in Object(obj) && obj.length;
|
||||
|
||||
if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
|
||||
return true;
|
||||
@@ -317,8 +322,7 @@ function nextUid() {
|
||||
function setHashKey(obj, h) {
|
||||
if (h) {
|
||||
obj.$$hashKey = h;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
delete obj.$$hashKey;
|
||||
}
|
||||
}
|
||||
@@ -459,6 +463,16 @@ function isObject(value) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a value is an object with a null prototype
|
||||
*
|
||||
* @returns {boolean} True if `value` is an `Object` with a null prototype
|
||||
*/
|
||||
function isBlankObject(value) {
|
||||
return value !== null && typeof value === 'object' && !getPrototypeOf(value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.isString
|
||||
@@ -483,6 +497,12 @@ function isString(value) {return typeof value === 'string';}
|
||||
* @description
|
||||
* Determines if a reference is a `Number`.
|
||||
*
|
||||
* This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
|
||||
*
|
||||
* If you wish to exclude these then you can use the native
|
||||
* [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
|
||||
* method.
|
||||
*
|
||||
* @param {*} value Reference to check.
|
||||
* @returns {boolean} True if `value` is a `Number`.
|
||||
*/
|
||||
@@ -589,6 +609,12 @@ function isPromiseLike(obj) {
|
||||
}
|
||||
|
||||
|
||||
var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
|
||||
function isTypedArray(value) {
|
||||
return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
|
||||
}
|
||||
|
||||
|
||||
var trim = function(value) {
|
||||
return isString(value) ? value.trim() : value;
|
||||
};
|
||||
@@ -627,7 +653,7 @@ function isElement(node) {
|
||||
function makeMap(str) {
|
||||
var obj = {}, items = str.split(","), i;
|
||||
for (i = 0; i < items.length; i++)
|
||||
obj[ items[i] ] = true;
|
||||
obj[items[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -705,77 +731,111 @@ function arrayRemove(array, value) {
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
function copy(source, destination, stackSource, stackDest) {
|
||||
if (isWindow(source) || isScope(source)) {
|
||||
throw ngMinErr('cpws',
|
||||
"Can't copy! Making copies of Window or Scope instances is not supported.");
|
||||
function copy(source, destination) {
|
||||
var stackSource = [];
|
||||
var stackDest = [];
|
||||
|
||||
if (destination) {
|
||||
if (isTypedArray(destination)) {
|
||||
throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
if (source === destination) {
|
||||
throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
|
||||
}
|
||||
|
||||
// Empty the destination object
|
||||
if (isArray(destination)) {
|
||||
destination.length = 0;
|
||||
} else {
|
||||
forEach(destination, function(value, key) {
|
||||
if (key !== '$$hashKey') {
|
||||
delete destination[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
stackSource.push(source);
|
||||
stackDest.push(destination);
|
||||
return copyRecurse(source, destination);
|
||||
}
|
||||
|
||||
if (!destination) {
|
||||
destination = source;
|
||||
if (source) {
|
||||
if (isArray(source)) {
|
||||
destination = copy(source, [], stackSource, stackDest);
|
||||
} else if (isDate(source)) {
|
||||
destination = new Date(source.getTime());
|
||||
} else if (isRegExp(source)) {
|
||||
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
||||
destination.lastIndex = source.lastIndex;
|
||||
} else if (isObject(source)) {
|
||||
var emptyObject = Object.create(Object.getPrototypeOf(source));
|
||||
destination = copy(source, emptyObject, stackSource, stackDest);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (source === destination) throw ngMinErr('cpi',
|
||||
"Can't copy! Source and destination are identical.");
|
||||
return copyElement(source);
|
||||
|
||||
stackSource = stackSource || [];
|
||||
stackDest = stackDest || [];
|
||||
|
||||
if (isObject(source)) {
|
||||
var index = stackSource.indexOf(source);
|
||||
if (index !== -1) return stackDest[index];
|
||||
|
||||
stackSource.push(source);
|
||||
stackDest.push(destination);
|
||||
}
|
||||
|
||||
var result;
|
||||
function copyRecurse(source, destination) {
|
||||
var h = destination.$$hashKey;
|
||||
var result, key;
|
||||
if (isArray(source)) {
|
||||
destination.length = 0;
|
||||
for (var i = 0; i < source.length; i++) {
|
||||
result = copy(source[i], null, stackSource, stackDest);
|
||||
if (isObject(source[i])) {
|
||||
stackSource.push(source[i]);
|
||||
stackDest.push(result);
|
||||
for (var i = 0, ii = source.length; i < ii; i++) {
|
||||
destination.push(copyElement(source[i]));
|
||||
}
|
||||
} else if (isBlankObject(source)) {
|
||||
// createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
|
||||
for (key in source) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
}
|
||||
} else if (source && typeof source.hasOwnProperty === 'function') {
|
||||
// Slow path, which must rely on hasOwnProperty
|
||||
for (key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
}
|
||||
destination.push(result);
|
||||
}
|
||||
} else {
|
||||
var h = destination.$$hashKey;
|
||||
if (isArray(destination)) {
|
||||
destination.length = 0;
|
||||
} else {
|
||||
forEach(destination, function(value, key) {
|
||||
delete destination[key];
|
||||
});
|
||||
}
|
||||
for (var key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
result = copy(source[key], null, stackSource, stackDest);
|
||||
if (isObject(source[key])) {
|
||||
stackSource.push(source[key]);
|
||||
stackDest.push(result);
|
||||
}
|
||||
destination[key] = result;
|
||||
// Slowest path --- hasOwnProperty can't be called as a method
|
||||
for (key in source) {
|
||||
if (hasOwnProperty.call(source, key)) {
|
||||
destination[key] = copyElement(source[key]);
|
||||
}
|
||||
}
|
||||
setHashKey(destination,h);
|
||||
}
|
||||
setHashKey(destination, h);
|
||||
return destination;
|
||||
}
|
||||
|
||||
function copyElement(source) {
|
||||
// Simple values
|
||||
if (!isObject(source)) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// Already copied values
|
||||
var index = stackSource.indexOf(source);
|
||||
if (index !== -1) {
|
||||
return stackDest[index];
|
||||
}
|
||||
|
||||
if (isWindow(source) || isScope(source)) {
|
||||
throw ngMinErr('cpws',
|
||||
"Can't copy! Making copies of Window or Scope instances is not supported.");
|
||||
}
|
||||
|
||||
var needsRecurse = false;
|
||||
var destination;
|
||||
|
||||
if (isArray(source)) {
|
||||
destination = [];
|
||||
needsRecurse = true;
|
||||
} else if (isTypedArray(source)) {
|
||||
destination = new source.constructor(source);
|
||||
} else if (isDate(source)) {
|
||||
destination = new Date(source.getTime());
|
||||
} else if (isRegExp(source)) {
|
||||
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
||||
destination.lastIndex = source.lastIndex;
|
||||
} else if (isFunction(source.cloneNode)) {
|
||||
destination = source.cloneNode(true);
|
||||
} else {
|
||||
destination = Object.create(getPrototypeOf(source));
|
||||
needsRecurse = true;
|
||||
}
|
||||
|
||||
stackSource.push(source);
|
||||
stackDest.push(destination);
|
||||
|
||||
return needsRecurse
|
||||
? copyRecurse(source, destination)
|
||||
: destination;
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -851,10 +911,11 @@ function equals(o1, o2) {
|
||||
} else if (isDate(o1)) {
|
||||
if (!isDate(o2)) return false;
|
||||
return equals(o1.getTime(), o2.getTime());
|
||||
} else if (isRegExp(o1) && isRegExp(o2)) {
|
||||
return o1.toString() == o2.toString();
|
||||
} else if (isRegExp(o1)) {
|
||||
return isRegExp(o2) ? o1.toString() == o2.toString() : false;
|
||||
} else {
|
||||
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
|
||||
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
|
||||
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
|
||||
keySet = {};
|
||||
for (key in o1) {
|
||||
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
||||
@@ -972,8 +1033,8 @@ function toJsonReplacer(key, value) {
|
||||
* stripped since angular uses this notation internally.
|
||||
*
|
||||
* @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
|
||||
* @param {boolean|number=} pretty If set to true, the JSON output will contain newlines and whitespace.
|
||||
* If set to an integer, the JSON output will contain that many spaces per indentation (the default is 2).
|
||||
* @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
|
||||
* If set to an integer, the JSON output will contain that many spaces per indentation.
|
||||
* @returns {string|undefined} JSON-ified string representing `obj`.
|
||||
*/
|
||||
function toJson(obj, pretty) {
|
||||
@@ -1338,7 +1399,7 @@ function angularInit(element, bootstrap) {
|
||||
* @param {DOMElement} element DOM element which is the root of angular application.
|
||||
* @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
|
||||
* Each item in the array should be the name of a predefined module or a (DI annotated)
|
||||
* function that will be invoked by the injector as a run block.
|
||||
* function that will be invoked by the injector as a `config` block.
|
||||
* See: {@link angular.module modules}
|
||||
* @param {Object=} config an object for defining configuration options for the application. The
|
||||
* following keys are supported:
|
||||
@@ -1408,8 +1469,12 @@ function bootstrap(element, modules, config) {
|
||||
forEach(extraModules, function(module) {
|
||||
modules.push(module);
|
||||
});
|
||||
doBootstrap();
|
||||
return doBootstrap();
|
||||
};
|
||||
|
||||
if (isFunction(angular.resumeDeferredBootstrap)) {
|
||||
angular.resumeDeferredBootstrap();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1601,6 +1666,7 @@ function createMap() {
|
||||
}
|
||||
|
||||
var NODE_TYPE_ELEMENT = 1;
|
||||
var NODE_TYPE_ATTRIBUTE = 2;
|
||||
var NODE_TYPE_TEXT = 3;
|
||||
var NODE_TYPE_COMMENT = 8;
|
||||
var NODE_TYPE_DOCUMENT = 9;
|
||||
|
||||
+11
-10
@@ -179,7 +179,7 @@ function annotate(fn, strictDi, name) {
|
||||
* Return an instance of the service.
|
||||
*
|
||||
* @param {string} name The name of the instance to retrieve.
|
||||
* @param {string} caller An optional string to provide the origin of the function call for error messages.
|
||||
* @param {string=} caller An optional string to provide the origin of the function call for error messages.
|
||||
* @return {*} The instance.
|
||||
*/
|
||||
|
||||
@@ -190,8 +190,8 @@ function annotate(fn, strictDi, name) {
|
||||
* @description
|
||||
* Invoke the method and supply the method arguments from the `$injector`.
|
||||
*
|
||||
* @param {!Function} fn The function to invoke. Function parameters are injected according to the
|
||||
* {@link guide/di $inject Annotation} rules.
|
||||
* @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
|
||||
* injected according to the {@link guide/di $inject Annotation} rules.
|
||||
* @param {Object=} self The `this` for the invoked method.
|
||||
* @param {Object=} locals Optional object. If preset then any argument names are read from this
|
||||
* object first, before the `$injector` is consulted.
|
||||
@@ -458,8 +458,8 @@ function annotate(fn, strictDi, name) {
|
||||
* configure your service in a provider.
|
||||
*
|
||||
* @param {string} name The name of the instance.
|
||||
* @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
|
||||
* for `$provide.provider(name, {$get: $getFn})`.
|
||||
* @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
|
||||
* Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
|
||||
* @returns {Object} registered provider instance
|
||||
*
|
||||
* @example
|
||||
@@ -494,7 +494,8 @@ function annotate(fn, strictDi, name) {
|
||||
* as a type/class.
|
||||
*
|
||||
* @param {string} name The name of the instance.
|
||||
* @param {Function} constructor A class (constructor function) that will be instantiated.
|
||||
* @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
|
||||
* that will be instantiated.
|
||||
* @returns {Object} registered provider instance
|
||||
*
|
||||
* @example
|
||||
@@ -593,7 +594,7 @@ function annotate(fn, strictDi, name) {
|
||||
* object which replaces or wraps and delegates to the original service.
|
||||
*
|
||||
* @param {string} name The name of the service to decorate.
|
||||
* @param {function()} decorator This function will be invoked when the service needs to be
|
||||
* @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
|
||||
* instantiated and should return the decorated service instance. The function is called using
|
||||
* the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
|
||||
* Local injection arguments:
|
||||
@@ -800,7 +801,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
}
|
||||
|
||||
var args = [],
|
||||
$inject = annotate(fn, strictDi, serviceName),
|
||||
$inject = createInjector.$$annotate(fn, strictDi, serviceName),
|
||||
length, i,
|
||||
key;
|
||||
|
||||
@@ -829,7 +830,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
// Check if Type is annotated and use just the given function at n-1 as parameter
|
||||
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
||||
// Object creation: http://jsperf.com/create-constructor/2
|
||||
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype);
|
||||
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
|
||||
var returnedValue = invoke(Type, instance, locals, serviceName);
|
||||
|
||||
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
|
||||
@@ -839,7 +840,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
invoke: invoke,
|
||||
instantiate: instantiate,
|
||||
get: getService,
|
||||
annotate: annotate,
|
||||
annotate: createInjector.$$annotate,
|
||||
has: function(name) {
|
||||
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
+17
-2
@@ -1,5 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Any commits to this file should be reviewed with security in mind. *
|
||||
* Changes to this file can potentially create security vulnerabilities. *
|
||||
* An approval from 2 Core members with history of modifying *
|
||||
* this file is required. *
|
||||
* *
|
||||
* Does the change somehow allow for arbitrary javascript to be executed? *
|
||||
* Or allows for someone to change the prototype of built-in objects? *
|
||||
* Or gives undesired access to variables likes document or window? *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/* global JQLitePrototype: true,
|
||||
addEventListenerFn: true,
|
||||
removeEventListenerFn: true,
|
||||
@@ -28,7 +39,7 @@
|
||||
* Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
|
||||
* commonly needed functionality with the goal of having a very small footprint.</div>
|
||||
*
|
||||
* To use jQuery, simply load it before `DOMContentLoaded` event fired.
|
||||
* To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
|
||||
*
|
||||
* <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
|
||||
* jqLite; they are never raw DOM references.</div>
|
||||
@@ -44,7 +55,7 @@
|
||||
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
|
||||
* - [`clone()`](http://api.jquery.com/clone/)
|
||||
* - [`contents()`](http://api.jquery.com/contents/)
|
||||
* - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`
|
||||
* - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
|
||||
* - [`data()`](http://api.jquery.com/data/)
|
||||
* - [`detach()`](http://api.jquery.com/detach/)
|
||||
* - [`empty()`](http://api.jquery.com/empty/)
|
||||
@@ -587,6 +598,10 @@ forEach({
|
||||
},
|
||||
|
||||
attr: function(element, name, value) {
|
||||
var nodeType = element.nodeType;
|
||||
if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
|
||||
return;
|
||||
}
|
||||
var lowercasedName = lowercase(name);
|
||||
if (BOOLEAN_ATTR[lowercasedName]) {
|
||||
if (isDefined(value)) {
|
||||
|
||||
+8
-1
@@ -231,10 +231,17 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc method
|
||||
* @name angular.Module#filter
|
||||
* @module ng
|
||||
* @param {string} name Filter name.
|
||||
* @param {string} name Filter name - this must be a valid angular expression identifier
|
||||
* @param {Function} filterFactory Factory function for creating new instance of filter.
|
||||
* @description
|
||||
* See {@link ng.$filterProvider#register $filterProvider.register()}.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
|
||||
* Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
|
||||
* your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
|
||||
* (`myapp_subsection_filterx`).
|
||||
* </div>
|
||||
*/
|
||||
filter: invokeLater('$filterProvider', 'register'),
|
||||
|
||||
|
||||
@@ -210,6 +210,7 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @return {Promise} the animation callback promise
|
||||
*/
|
||||
leave: function(element, options) {
|
||||
applyStyles(element, options);
|
||||
element.remove();
|
||||
return asyncPromise();
|
||||
},
|
||||
|
||||
+11
-3
@@ -63,7 +63,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
|
||||
function getHash(url) {
|
||||
var index = url.indexOf('#');
|
||||
return index === -1 ? '' : url.substr(index + 1);
|
||||
return index === -1 ? '' : url.substr(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,7 +190,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
// Do the assignment again so that those two variables are referentially identical.
|
||||
lastHistoryState = cachedState;
|
||||
} else {
|
||||
if (!sameBase) {
|
||||
if (!sameBase || reloadLocation) {
|
||||
reloadLocation = url;
|
||||
}
|
||||
if (replace) {
|
||||
@@ -233,11 +233,19 @@ function Browser(window, document, $log, $sniffer) {
|
||||
fireUrlChange();
|
||||
}
|
||||
|
||||
function getCurrentState() {
|
||||
try {
|
||||
return history.state;
|
||||
} catch (e) {
|
||||
// MSIE can reportedly throw when there is no state (UNCONFIRMED).
|
||||
}
|
||||
}
|
||||
|
||||
// This variable should be used *only* inside the cacheState function.
|
||||
var lastCachedState = null;
|
||||
function cacheState() {
|
||||
// This should be the only place in $browser where `history.state` is read.
|
||||
cachedState = window.history.state;
|
||||
cachedState = getCurrentState();
|
||||
cachedState = isUndefined(cachedState) ? null : cachedState;
|
||||
|
||||
// Prevent callbacks fo fire twice if both hashchange & popstate were fired.
|
||||
|
||||
@@ -372,7 +372,7 @@ function $CacheFactoryProvider() {
|
||||
* the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
|
||||
* element with ng-app attribute), otherwise the template will be ignored.
|
||||
*
|
||||
* Adding via the $templateCache service:
|
||||
* Adding via the `$templateCache` service:
|
||||
*
|
||||
* ```js
|
||||
* var myApp = angular.module('myApp', []);
|
||||
|
||||
+31
-9
@@ -1,5 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Any commits to this file should be reviewed with security in mind. *
|
||||
* Changes to this file can potentially create security vulnerabilities. *
|
||||
* An approval from 2 Core members with history of modifying *
|
||||
* this file is required. *
|
||||
* *
|
||||
* Does the change somehow allow for arbitrary javascript to be executed? *
|
||||
* Or allows for someone to change the prototype of built-in objects? *
|
||||
* Or gives undesired access to variables likes document or window? *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
|
||||
*
|
||||
* DOM-related variables:
|
||||
@@ -64,7 +75,8 @@
|
||||
* templateNamespace: 'html',
|
||||
* scope: false,
|
||||
* controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
|
||||
* controllerAs: 'stringAlias',
|
||||
* controllerAs: 'stringIdentifier',
|
||||
* bindToController: false,
|
||||
* require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
|
||||
* compile: function compile(tElement, tAttrs, transclude) {
|
||||
* return {
|
||||
@@ -211,7 +223,8 @@
|
||||
* Require another directive and inject its controller as the fourth argument to the linking function. The
|
||||
* `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
|
||||
* injected argument will be an array in corresponding order. If no such directive can be
|
||||
* found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
|
||||
* found, or if the directive does not have a controller, then an error is raised (unless no link function
|
||||
* is specified, in which case error checking is skipped). The name can be prefixed with:
|
||||
*
|
||||
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
|
||||
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
|
||||
@@ -382,9 +395,15 @@
|
||||
* * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
|
||||
* between all directive linking functions.
|
||||
*
|
||||
* * `controller` - a controller instance - A controller instance if at least one directive on the
|
||||
* element defines a controller. The controller is shared among all the directives, which allows
|
||||
* the directives to use the controllers as a communication channel.
|
||||
* * `controller` - the directive's required controller instance(s) - Instances are shared
|
||||
* among all directives, which allows the directives to use the controllers as a communication
|
||||
* channel. The exact value depends on the directive's `require` property:
|
||||
* * `string`: the controller instance
|
||||
* * `array`: array of controller instances
|
||||
* * no controller(s) required: `undefined`
|
||||
*
|
||||
* If a required controller cannot be found, and it is optional, the instance is `null`,
|
||||
* otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
|
||||
*
|
||||
* * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
|
||||
* This is the same as the `$transclude`
|
||||
@@ -410,7 +429,7 @@
|
||||
*
|
||||
* ### Transclusion
|
||||
*
|
||||
* Transclusion is the process of extracting a collection of DOM element from one part of the DOM and
|
||||
* Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
|
||||
* copying them to another part of the DOM, while maintaining their connection to the original AngularJS
|
||||
* scope from where they were taken.
|
||||
*
|
||||
@@ -1450,6 +1469,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
// use class as directive
|
||||
className = node.className;
|
||||
if (isObject(className)) {
|
||||
// Maybe SVGAnimatedString
|
||||
className = className.animVal;
|
||||
}
|
||||
if (isString(className) && className !== '') {
|
||||
while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
|
||||
nName = directiveNormalize(match[2]);
|
||||
@@ -2151,8 +2174,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
afterTemplateChildLinkFn,
|
||||
beforeTemplateCompileNode = $compileNode[0],
|
||||
origAsyncDirective = directives.shift(),
|
||||
// The fact that we have to copy and patch the directive seems wrong!
|
||||
derivedSyncDirective = extend({}, origAsyncDirective, {
|
||||
derivedSyncDirective = inherit(origAsyncDirective, {
|
||||
templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
|
||||
}),
|
||||
templateUrl = (isFunction(origAsyncDirective.templateUrl))
|
||||
@@ -2162,7 +2184,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
$compileNode.empty();
|
||||
|
||||
$templateRequest($sce.getTrustedResourceUrl(templateUrl))
|
||||
$templateRequest(templateUrl)
|
||||
.then(function(content) {
|
||||
var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var $controllerMinErr = minErr('$controller');
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $controllerProvider
|
||||
@@ -87,7 +89,12 @@ function $ControllerProvider() {
|
||||
}
|
||||
|
||||
if (isString(expression)) {
|
||||
match = expression.match(CNTRL_REG),
|
||||
match = expression.match(CNTRL_REG);
|
||||
if (!match) {
|
||||
throw $controllerMinErr('ctrlfmt',
|
||||
"Badly formed controller string '{0}'. " +
|
||||
"Must match `__name__ as __id__` or `__name__`.", expression);
|
||||
}
|
||||
constructor = match[1],
|
||||
identifier = identifier || match[3];
|
||||
expression = controllers.hasOwnProperty(constructor)
|
||||
@@ -111,7 +118,7 @@ function $ControllerProvider() {
|
||||
// Object creation: http://jsperf.com/create-constructor/2
|
||||
var controllerPrototype = (isArray(expression) ?
|
||||
expression[expression.length - 1] : expression).prototype;
|
||||
instance = Object.create(controllerPrototype);
|
||||
instance = Object.create(controllerPrototype || null);
|
||||
|
||||
if (identifier) {
|
||||
addIdentifier(locals, identifier, instance, constructor || expression.name);
|
||||
|
||||
@@ -18,6 +18,9 @@ var htmlAnchorDirective = valueFn({
|
||||
compile: function(element, attr) {
|
||||
if (!attr.href && !attr.xlinkHref && !attr.name) {
|
||||
return function(scope, element) {
|
||||
// If the linked element is not an anchor tag anymore, do nothing
|
||||
if (element[0].nodeName.toLowerCase() !== 'a') return;
|
||||
|
||||
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
||||
var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
||||
'xlink:href' : 'href';
|
||||
|
||||
@@ -159,20 +159,24 @@
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
|
||||
* This directive sets the `disabled` attribute on the element if the
|
||||
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
|
||||
*
|
||||
* A special directive is necessary because we cannot use interpolation inside the `disabled`
|
||||
* attribute. The following example would make the button enabled on Chrome/Firefox
|
||||
* but not on older IEs:
|
||||
*
|
||||
* ```html
|
||||
* <div ng-init="scope = { isDisabled: false }">
|
||||
* <button disabled="{{scope.isDisabled}}">Disabled</button>
|
||||
* <!-- See below for an example of ng-disabled being used correctly -->
|
||||
* <div ng-init="isDisabled = false">
|
||||
* <button disabled="{{isDisabled}}">Disabled</button>
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
* such as disabled. (Their presence means true and their absence means false.)
|
||||
* This is because the HTML specification does not require browsers to preserve the values of
|
||||
* boolean attributes such as `disabled` (Their presence means true and their absence means false.)
|
||||
* If we put an Angular interpolation expression into such an attribute then the
|
||||
* binding information would be lost when the browser removes the attribute.
|
||||
* The `ngDisabled` directive solves this problem for the `disabled` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
@@ -191,7 +195,7 @@
|
||||
*
|
||||
* @element INPUT
|
||||
* @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
|
||||
* then special attribute "disabled" will be set on the element
|
||||
* then the `disabled` attribute will be set on the element
|
||||
*/
|
||||
|
||||
|
||||
|
||||
+31
-32
@@ -163,6 +163,9 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
forEach(form.$error, function(value, name) {
|
||||
form.$setValidity(name, null, control);
|
||||
});
|
||||
forEach(form.$$success, function(value, name) {
|
||||
form.$setValidity(name, null, control);
|
||||
});
|
||||
|
||||
arrayRemove(controls, control);
|
||||
};
|
||||
@@ -180,23 +183,23 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
addSetValidityMethod({
|
||||
ctrl: this,
|
||||
$element: element,
|
||||
set: function(object, property, control) {
|
||||
set: function(object, property, controller) {
|
||||
var list = object[property];
|
||||
if (!list) {
|
||||
object[property] = [control];
|
||||
object[property] = [controller];
|
||||
} else {
|
||||
var index = list.indexOf(control);
|
||||
var index = list.indexOf(controller);
|
||||
if (index === -1) {
|
||||
list.push(control);
|
||||
list.push(controller);
|
||||
}
|
||||
}
|
||||
},
|
||||
unset: function(object, property, control) {
|
||||
unset: function(object, property, controller) {
|
||||
var list = object[property];
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
arrayRemove(list, control);
|
||||
arrayRemove(list, controller);
|
||||
if (list.length === 0) {
|
||||
delete object[property];
|
||||
}
|
||||
@@ -313,15 +316,11 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
*
|
||||
* # Alias: {@link ng.directive:ngForm `ngForm`}
|
||||
*
|
||||
* In Angular forms can be nested. This means that the outer form is valid when all of the child
|
||||
* In Angular, forms can be nested. This means that the outer form is valid when all of the child
|
||||
* forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
|
||||
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
|
||||
* `<form>` but can be nested. This allows you to have nested forms, which is very useful when
|
||||
* using Angular validation directives in forms that are dynamically generated using the
|
||||
* {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
|
||||
* attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
|
||||
* `ngForm` directive and nest these in an outer `form` element.
|
||||
*
|
||||
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
|
||||
* `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
|
||||
* of controls needs to be determined.
|
||||
*
|
||||
* # CSS classes
|
||||
* - `ng-valid` is set if the form is valid.
|
||||
@@ -412,11 +411,11 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
<form name="myForm" ng-controller="FormController" class="my-form">
|
||||
userType: <input name="input" ng-model="userType" required>
|
||||
<span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
|
||||
<tt>userType = {{userType}}</tt><br>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br>
|
||||
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
|
||||
<code>userType = {{userType}}</code><br>
|
||||
<code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
|
||||
<code>myForm.input.$error = {{myForm.input.$error}}</code><br>
|
||||
<code>myForm.$valid = {{myForm.$valid}}</code><br>
|
||||
<code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
|
||||
</form>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
@@ -451,10 +450,12 @@ var formDirectiveFactory = function(isNgForm) {
|
||||
name: 'form',
|
||||
restrict: isNgForm ? 'EAC' : 'E',
|
||||
controller: FormController,
|
||||
compile: function ngFormCompile(formElement) {
|
||||
compile: function ngFormCompile(formElement, attr) {
|
||||
// Setup initial state of the control
|
||||
formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
|
||||
|
||||
var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
|
||||
|
||||
return {
|
||||
pre: function ngFormPreLink(scope, formElement, attr, controller) {
|
||||
// if `action` attr is not present on the form, prevent the default action (submission)
|
||||
@@ -485,23 +486,21 @@ var formDirectiveFactory = function(isNgForm) {
|
||||
});
|
||||
}
|
||||
|
||||
var parentFormCtrl = controller.$$parentForm,
|
||||
alias = controller.$name;
|
||||
var parentFormCtrl = controller.$$parentForm;
|
||||
|
||||
if (alias) {
|
||||
setter(scope, alias, controller, alias);
|
||||
attr.$observe(attr.name ? 'name' : 'ngForm', function(newValue) {
|
||||
if (alias === newValue) return;
|
||||
setter(scope, alias, undefined, alias);
|
||||
alias = newValue;
|
||||
setter(scope, alias, controller, alias);
|
||||
parentFormCtrl.$$renameControl(controller, alias);
|
||||
if (nameAttr) {
|
||||
setter(scope, null, controller.$name, controller, controller.$name);
|
||||
attr.$observe(nameAttr, function(newValue) {
|
||||
if (controller.$name === newValue) return;
|
||||
setter(scope, null, controller.$name, undefined, controller.$name);
|
||||
parentFormCtrl.$$renameControl(controller, newValue);
|
||||
setter(scope, null, controller.$name, controller, controller.$name);
|
||||
});
|
||||
}
|
||||
formElement.on('$destroy', function() {
|
||||
parentFormCtrl.$removeControl(controller);
|
||||
if (alias) {
|
||||
setter(scope, alias, undefined, alias);
|
||||
if (nameAttr) {
|
||||
setter(scope, null, attr[nameAttr], undefined, controller.$name);
|
||||
}
|
||||
extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
|
||||
});
|
||||
|
||||
+110
-1693
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngChange
|
||||
*
|
||||
* @description
|
||||
* Evaluate the given expression when the user changes the input.
|
||||
* The expression is evaluated immediately, unlike the JavaScript onchange event
|
||||
* which only triggers at the end of a change (usually, when the user leaves the
|
||||
* form element or presses the return key).
|
||||
*
|
||||
* The `ngChange` expression is only evaluated when a change in the input value causes
|
||||
* a new value to be committed to the model.
|
||||
*
|
||||
* It will not be evaluated:
|
||||
* * if the value returned from the `$parsers` transformation pipeline has not changed
|
||||
* * if the input has continued to be invalid since the model will stay `null`
|
||||
* * if the model is changed programmatically and not by a change to the input value
|
||||
*
|
||||
*
|
||||
* Note, this directive requires `ngModel` to be present.
|
||||
*
|
||||
* @element input
|
||||
* @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
|
||||
* in input value.
|
||||
*
|
||||
* @example
|
||||
* <example name="ngChange-directive" module="changeExample">
|
||||
* <file name="index.html">
|
||||
* <script>
|
||||
* angular.module('changeExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.counter = 0;
|
||||
* $scope.change = function() {
|
||||
* $scope.counter++;
|
||||
* };
|
||||
* }]);
|
||||
* </script>
|
||||
* <div ng-controller="ExampleController">
|
||||
* <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
|
||||
* <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
|
||||
* <label for="ng-change-example2">Confirmed</label><br />
|
||||
* <tt>debug = {{confirmed}}</tt><br/>
|
||||
* <tt>counter = {{counter}}</tt><br/>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
* var counter = element(by.binding('counter'));
|
||||
* var debug = element(by.binding('confirmed'));
|
||||
*
|
||||
* it('should evaluate the expression if changing from view', function() {
|
||||
* expect(counter.getText()).toContain('0');
|
||||
*
|
||||
* element(by.id('ng-change-example1')).click();
|
||||
*
|
||||
* expect(counter.getText()).toContain('1');
|
||||
* expect(debug.getText()).toContain('true');
|
||||
* });
|
||||
*
|
||||
* it('should not evaluate the expression if changing from model', function() {
|
||||
* element(by.id('ng-change-example2')).click();
|
||||
|
||||
* expect(counter.getText()).toContain('0');
|
||||
* expect(debug.getText()).toContain('true');
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
var ngChangeDirective = valueFn({
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attr, ctrl) {
|
||||
ctrl.$viewChangeListeners.push(function() {
|
||||
scope.$eval(attr.ngChange);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -141,8 +141,9 @@ function classDirective(name, selector) {
|
||||
* new classes are added.
|
||||
*
|
||||
* @animations
|
||||
* add - happens just before the class is applied to the element
|
||||
* remove - happens just before the class is removed from the element
|
||||
* **add** - happens just before the class is applied to the elements
|
||||
*
|
||||
* **remove** - happens just before the class is removed from the element
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} ngClass {@link guide/expression Expression} to eval. The result
|
||||
|
||||
@@ -33,17 +33,13 @@
|
||||
* document; alternatively, the css rule above must be included in the external stylesheet of the
|
||||
* application.
|
||||
*
|
||||
* Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
|
||||
* cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
|
||||
* class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
|
||||
*
|
||||
* @element ANY
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<div id="template1" ng-cloak>{{ 'hello' }}</div>
|
||||
<div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
|
||||
<div id="template2" class="ng-cloak">{{ 'world' }}</div>
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should remove the template directive and css class', function() {
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<select ng-model="template" ng-options="t.name for t in templates">
|
||||
<option value="">(blank)</option>
|
||||
</select>
|
||||
url of the template: <tt>{{template.url}}</tt>
|
||||
url of the template: <code>{{template.url}}</code>
|
||||
<hr/>
|
||||
<div class="slide-animate-container">
|
||||
<div class="slide-animate" ng-include="template.url"></div>
|
||||
@@ -173,13 +173,13 @@
|
||||
* @name ngInclude#$includeContentError
|
||||
* @eventType emit on the scope ngInclude was declared in
|
||||
* @description
|
||||
* Emitted when a template HTTP request yields an erronous response (status < 200 || status > 299)
|
||||
* Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {String} src URL of content to load.
|
||||
*/
|
||||
var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce',
|
||||
function($templateRequest, $anchorScroll, $animate, $sce) {
|
||||
var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
||||
function($templateRequest, $anchorScroll, $animate) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: 400,
|
||||
@@ -215,7 +215,7 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce
|
||||
}
|
||||
};
|
||||
|
||||
scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
|
||||
scope.$watch(srcExp, function ngIncludeWatchAction(src) {
|
||||
var afterAnimation = function() {
|
||||
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
|
||||
* sure you have parenthesis for correct precedence:
|
||||
* <pre class="prettyprint">
|
||||
* <div ng-init="test1 = (data | orderBy:'name')"></div>
|
||||
* `<div ng-init="test1 = (data | orderBy:'name')"></div>`
|
||||
* </pre>
|
||||
* </div>
|
||||
*
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngList
|
||||
*
|
||||
* @description
|
||||
* Text input that converts between a delimited string and an array of strings. The default
|
||||
* delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
|
||||
* delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
|
||||
*
|
||||
* The behaviour of the directive is affected by the use of the `ngTrim` attribute.
|
||||
* * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
|
||||
* list item is respected. This implies that the user of the directive is responsible for
|
||||
* dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
|
||||
* tab or newline character.
|
||||
* * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
|
||||
* when joining the list items back together) and whitespace around each list item is stripped
|
||||
* before it is added to the model.
|
||||
*
|
||||
* ### Example with Validation
|
||||
*
|
||||
* <example name="ngList-directive" module="listExample">
|
||||
* <file name="app.js">
|
||||
* angular.module('listExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.names = ['morpheus', 'neo', 'trinity'];
|
||||
* }]);
|
||||
* </file>
|
||||
* <file name="index.html">
|
||||
* <form name="myForm" ng-controller="ExampleController">
|
||||
* List: <input name="namesInput" ng-model="names" ng-list required>
|
||||
* <span class="error" ng-show="myForm.namesInput.$error.required">
|
||||
* Required!</span>
|
||||
* <br>
|
||||
* <tt>names = {{names}}</tt><br/>
|
||||
* <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
|
||||
* <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
|
||||
* <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
|
||||
* <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
|
||||
* </form>
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
* var listInput = element(by.model('names'));
|
||||
* var names = element(by.exactBinding('names'));
|
||||
* var valid = element(by.binding('myForm.namesInput.$valid'));
|
||||
* var error = element(by.css('span.error'));
|
||||
*
|
||||
* it('should initialize to model', function() {
|
||||
* expect(names.getText()).toContain('["morpheus","neo","trinity"]');
|
||||
* expect(valid.getText()).toContain('true');
|
||||
* expect(error.getCssValue('display')).toBe('none');
|
||||
* });
|
||||
*
|
||||
* it('should be invalid if empty', function() {
|
||||
* listInput.clear();
|
||||
* listInput.sendKeys('');
|
||||
*
|
||||
* expect(names.getText()).toContain('');
|
||||
* expect(valid.getText()).toContain('false');
|
||||
* expect(error.getCssValue('display')).not.toBe('none');
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* ### Example - splitting on whitespace
|
||||
* <example name="ngList-directive-newlines">
|
||||
* <file name="index.html">
|
||||
* <textarea ng-model="list" ng-list=" " ng-trim="false"></textarea>
|
||||
* <pre>{{ list | json }}</pre>
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
* it("should split the text by newlines", function() {
|
||||
* var listInput = element(by.model('list'));
|
||||
* var output = element(by.binding('list | json'));
|
||||
* listInput.sendKeys('abc\ndef\nghi');
|
||||
* expect(output.getText()).toContain('[\n "abc",\n "def",\n "ghi"\n]');
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* @element input
|
||||
* @param {string=} ngList optional delimiter that should be used to split the value.
|
||||
*/
|
||||
var ngListDirective = function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
priority: 100,
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attr, ctrl) {
|
||||
// We want to control whitespace trimming so we use this convoluted approach
|
||||
// to access the ngList attribute, which doesn't pre-trim the attribute
|
||||
var ngList = element.attr(attr.$attr.ngList) || ', ';
|
||||
var trimValues = attr.ngTrim !== 'false';
|
||||
var separator = trimValues ? trim(ngList) : ngList;
|
||||
|
||||
var parse = function(viewValue) {
|
||||
// If the viewValue is invalid (say required but empty) it will be `undefined`
|
||||
if (isUndefined(viewValue)) return;
|
||||
|
||||
var list = [];
|
||||
|
||||
if (viewValue) {
|
||||
forEach(viewValue.split(separator), function(value) {
|
||||
if (value) list.push(trimValues ? trim(value) : value);
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
ctrl.$parsers.push(parse);
|
||||
ctrl.$formatters.push(function(value) {
|
||||
if (isArray(value)) {
|
||||
return value.join(ngList);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// Override the standard $isEmpty because an empty array means the input is empty.
|
||||
ctrl.$isEmpty = function(value) {
|
||||
return !value || !value.length;
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,78 @@
|
||||
* Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
|
||||
* This may be useful when, for instance, nesting ngRepeats.
|
||||
*
|
||||
* # Iterating over object properties
|
||||
*
|
||||
* It is possible to get `ngRepeat` to iterate over the properties of an object using the following
|
||||
* syntax:
|
||||
*
|
||||
* ```js
|
||||
* <div ng-repeat="(key, value) in myObj"> ... </div>
|
||||
* ```
|
||||
*
|
||||
* You need to be aware that the JavaScript specification does not define what order
|
||||
* it will return the keys for an object. In order to have a guaranteed deterministic order
|
||||
* for the keys, Angular versions up to and including 1.3 **sort the keys alphabetically**.
|
||||
*
|
||||
* If this is not desired, the recommended workaround is to convert your object into an array
|
||||
* that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
|
||||
* do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
|
||||
* or implement a `$watch` on the object yourself.
|
||||
*
|
||||
* In version 1.4 we will remove the sorting, since it seems that browsers generally follow the
|
||||
* strategy of providing keys in the order in which they were defined, although there are exceptions
|
||||
* when keys are deleted and reinstated.
|
||||
*
|
||||
*
|
||||
* # Tracking and Duplicates
|
||||
*
|
||||
* When the contents of the collection change, `ngRepeat` makes the corresponding changes to the DOM:
|
||||
*
|
||||
* * When an item is added, a new instance of the template is added to the DOM.
|
||||
* * When an item is removed, its template instance is removed from the DOM.
|
||||
* * When items are reordered, their respective templates are reordered in the DOM.
|
||||
*
|
||||
* By default, `ngRepeat` does not allow duplicate items in arrays. This is because when
|
||||
* there are duplicates, it is not possible to maintain a one-to-one mapping between collection
|
||||
* items and DOM elements.
|
||||
*
|
||||
* If you do need to repeat duplicate items, you can substitute the default tracking behavior
|
||||
* with your own using the `track by` expression.
|
||||
*
|
||||
* For example, you may track items by the index of each item in the collection, using the
|
||||
* special scope property `$index`:
|
||||
* ```html
|
||||
* <div ng-repeat="n in [42, 42, 43, 43] track by $index">
|
||||
* {{n}}
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* You may use arbitrary expressions in `track by`, including references to custom functions
|
||||
* on the scope:
|
||||
* ```html
|
||||
* <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
|
||||
* {{n}}
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* If you are working with objects that have an identifier property, you can track
|
||||
* by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
|
||||
* will not have to rebuild the DOM elements for items it has already rendered, even if the
|
||||
* JavaScript objects in the collection have been substituted for new ones:
|
||||
* ```html
|
||||
* <div ng-repeat="model in collection track by model.id">
|
||||
* {{model.name}}
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* When no `track by` expression is provided, it is equivalent to tracking by the built-in
|
||||
* `$id` function, which tracks items by their identity:
|
||||
* ```html
|
||||
* <div ng-repeat="obj in collection track by $id(obj)">
|
||||
* {{obj.prop}}
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* # Special repeat start and end points
|
||||
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
|
||||
* the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
|
||||
@@ -90,12 +162,12 @@
|
||||
*
|
||||
* For example: `(name, age) in {'adam':10, 'amalie':12}`.
|
||||
*
|
||||
* * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
|
||||
* which can be used to associate the objects in the collection with the DOM elements. If no tracking function
|
||||
* is specified the ng-repeat associates elements by identity in the collection. It is an error to have
|
||||
* more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
|
||||
* mapped to the same DOM element, which is not possible.) Filters should be applied to the expression,
|
||||
* before specifying a tracking expression.
|
||||
* * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
|
||||
* which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
|
||||
* is specified, ng-repeat associates elements by identity. It is an error to have
|
||||
* more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
|
||||
* mapped to the same DOM element, which is not possible.) If filters are used in the expression, they should be
|
||||
* applied before the tracking expression.
|
||||
*
|
||||
* For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
|
||||
* will be associated by item identity in the array.
|
||||
@@ -267,7 +339,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
var keyIdentifier = match[2];
|
||||
|
||||
if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
|
||||
/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent)$/.test(aliasAs))) {
|
||||
/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
|
||||
throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
|
||||
aliasAs);
|
||||
}
|
||||
|
||||
@@ -40,10 +40,11 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
|
||||
*
|
||||
* By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
|
||||
* the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
|
||||
* class in CSS:
|
||||
* class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
|
||||
* with extra animation classes that can be added.
|
||||
*
|
||||
* ```css
|
||||
* .ng-hide {
|
||||
* .ng-hide:not(.ng-hide-animate) {
|
||||
* /* this is just another form of hiding an element */
|
||||
* display: block!important;
|
||||
* position: absolute;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user