Compare commits
130 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -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.
|
||||
|
||||
{
|
||||
"validateParameterSeparator": ", ", // Re-assert this rule when JSCS allows multiple spaces
|
||||
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
|
||||
"disallowImplicitTypeConversion": ["string"],
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"validateJSDoc": {
|
||||
"checkParamNames": true,
|
||||
"requireParamTypes": true
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,4 +1,5 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '0.10'
|
||||
|
||||
@@ -47,7 +48,7 @@ install:
|
||||
- npm config set loglevel http
|
||||
- npm install -g npm@2.5
|
||||
# Instal npm dependecies and ensure that npm cache is not stale
|
||||
- scripts/npm/install-dependencies.sh
|
||||
- npm install
|
||||
|
||||
before_script:
|
||||
- mkdir -p $LOGS_DIR
|
||||
@@ -60,6 +61,7 @@ script:
|
||||
- ./scripts/travis/build.sh
|
||||
|
||||
after_script:
|
||||
- ./scripts/travis/tear_down_browser_provider.sh
|
||||
- ./scripts/travis/print_logs.sh
|
||||
|
||||
notifications:
|
||||
|
||||
+615
-2
@@ -1,3 +1,616 @@
|
||||
<a name="1.3.20"></a>
|
||||
# 1.3.20 shallow-translucence (2015-09-29)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$parse:** do not convert to string computed properties multiple times
|
||||
([d434f3db](https://github.com/angular/angular.js/commit/d434f3db53d6209eb140b904e83bbde401686c16))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
|
||||
<a name="1.3.19"></a>
|
||||
# 1.3.19 glutinous-shriek (2015-09-15)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$http:** propagate status -1 for timed out requests
|
||||
([f13055a0](https://github.com/angular/angular.js/commit/f13055a0a53a39b160448713a5617edee6042801),
|
||||
[#4491](https://github.com/angular/angular.js/issues/4491), [#8756](https://github.com/angular/angular.js/issues/8756))
|
||||
- **$location:** don't crash if navigating outside the app base
|
||||
([623ce1ad](https://github.com/angular/angular.js/commit/623ce1ad2cf68024719c5cae5d682d00195df30c),
|
||||
[#11667](https://github.com/angular/angular.js/issues/11667))
|
||||
- **$parse:** throw error when accessing a restricted property indirectly
|
||||
([ec98c94c](https://github.com/angular/angular.js/commit/ec98c94ccbfc97b655447956738d5f6ff98b2f33),
|
||||
[#12833](https://github.com/angular/angular.js/issues/12833))
|
||||
- **ngModel:** validate pattern against the viewValue
|
||||
([274e9353](https://github.com/angular/angular.js/commit/274e93537ed4e95aefeacea48909eb334894f0ac),
|
||||
[#12344](https://github.com/angular/angular.js/issues/12344))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **ngAnimate:** introduce `$animate.flush` for unit testing
|
||||
([f98e0384](https://github.com/angular/angular.js/commit/f98e038418f7367b2373adcf4887f64a8e8bdcb0))
|
||||
|
||||
|
||||
## Possible Breaking Changes
|
||||
|
||||
- **ngModel:** due to [274e9353](https://github.com/angular/angular.js/commit/274e93537ed4e95aefeacea48909eb334894f0ac),
|
||||
|
||||
|
||||
The `ngPattern` and `pattern` directives will validate the regex
|
||||
against the `viewValue` of `ngModel`, i.e. the value of the model
|
||||
before the $parsers are applied. Previously, the modelValue
|
||||
(the result of the $parsers) was validated.
|
||||
|
||||
This fixes issues where `input[date]` and `input[number]` cannot
|
||||
be validated because the viewValue string is parsed into
|
||||
`Date` and `Number` respectively (starting with Angular 1.3).
|
||||
It also brings the directives in line with HTML5 constraint
|
||||
validation, which validates against the input value.
|
||||
|
||||
This change is unlikely to cause applications to fail, because even
|
||||
in Angular 1.2, the value that was validated by pattern could have
|
||||
been manipulated by the $parsers, as all validation was done
|
||||
inside this pipeline.
|
||||
|
||||
If you rely on the pattern being validated against the modelValue,
|
||||
you must create your own validator directive that overwrites
|
||||
the built-in pattern validator:
|
||||
|
||||
```
|
||||
.directive('patternModelOverwrite', function patternModelOverwriteDirective() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '?ngModel',
|
||||
priority: 1,
|
||||
compile: function() {
|
||||
var regexp, patternExp;
|
||||
|
||||
return {
|
||||
pre: function(scope, elm, attr, ctrl) {
|
||||
if (!ctrl) return;
|
||||
|
||||
attr.$observe('pattern', function(regex) {
|
||||
/**
|
||||
* The built-in directive will call our overwritten validator
|
||||
* (see below). We just need to update the regex.
|
||||
* The preLink fn guaranetees our observer is called first.
|
||||
*/
|
||||
if (isString(regex) && regex.length > 0) {
|
||||
regex = new RegExp('^' + regex + '$');
|
||||
}
|
||||
|
||||
if (regex && !regex.test) {
|
||||
//The built-in validator will throw at this point
|
||||
return;
|
||||
}
|
||||
|
||||
regexp = regex || undefined;
|
||||
});
|
||||
|
||||
},
|
||||
post: function(scope, elm, attr, ctrl) {
|
||||
if (!ctrl) return;
|
||||
|
||||
regexp, patternExp = attr.ngPattern || attr.pattern;
|
||||
|
||||
//The postLink fn guarantees we overwrite the built-in pattern validator
|
||||
ctrl.$validators.pattern = function(value) {
|
||||
return ctrl.$isEmpty(value) ||
|
||||
isUndefined(regexp) ||
|
||||
regexp.test(value);
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.3.18"></a>
|
||||
# 1.3.18 collective-penmanship (2015-08-18)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- clear class animations cache if animation is not started
|
||||
([2c03a357](https://github.com/angular/angular.js/commit/2c03a3574336ed814d020cf7ba36cee5b87e65b5),
|
||||
[#12604](https://github.com/angular/angular.js/issues/12604), [#12603](https://github.com/angular/angular.js/issues/12603))
|
||||
- do not throw errors if element is removed before animation starts
|
||||
([6b72598b](https://github.com/angular/angular.js/commit/6b72598b87022e1dd96bddc4451e007ef0601579),
|
||||
[#10205](https://github.com/angular/angular.js/issues/10205))
|
||||
- **ngModel:** correct minErr usage for correct doc creation
|
||||
([64a142b5](https://github.com/angular/angular.js/commit/64a142b58ed0a0e3896d82f3f9ce35373548d0ff),
|
||||
[#12386](https://github.com/angular/angular.js/issues/12386), [#12416](https://github.com/angular/angular.js/issues/12416))
|
||||
|
||||
|
||||
|
||||
<a name="1.3.17"></a>
|
||||
# 1.3.17 tsktskskly-euouae (2015-07-06)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$browser:** prevent infinite digest if changing hash when there is no hashPrefix
|
||||
([61a3fb67](https://github.com/angular/angular.js/commit/61a3fb676a186e22564fb0181c17647b35ca4e5e),
|
||||
[#10423](https://github.com/angular/angular.js/issues/10423), [#12145](https://github.com/angular/angular.js/issues/12145))
|
||||
- **$location:**
|
||||
- allow navigating outside the original base URL
|
||||
([0bb57d53](https://github.com/angular/angular.js/commit/0bb57d538f25a1b6f20025d87a451c39671b59aa),
|
||||
[#11302](https://github.com/angular/angular.js/issues/11302), [#4776](https://github.com/angular/angular.js/issues/4776))
|
||||
- do not get caught in infinite digest in IE9
|
||||
([f486ebe8](https://github.com/angular/angular.js/commit/f486ebe80b6d7854d3eb9029f14d94299cf493cb),
|
||||
[#11439](https://github.com/angular/angular.js/issues/11439), [#11675](https://github.com/angular/angular.js/issues/11675), [#11935](https://github.com/angular/angular.js/issues/11935), [#12083](https://github.com/angular/angular.js/issues/12083))
|
||||
- **linky:** allow case insensitive scheme detection
|
||||
([6b28aef1](https://github.com/angular/angular.js/commit/6b28aef1c537bfb2da21820d6ca154344efe266e),
|
||||
[#12073](https://github.com/angular/angular.js/issues/12073), [#12074](https://github.com/angular/angular.js/issues/12074))
|
||||
|
||||
|
||||
|
||||
<a name="1.3.16"></a>
|
||||
# 1.3.16 cookie-oatmealification (2015-06-05)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** throw error on invalid directive name
|
||||
([634e4671](https://github.com/angular/angular.js/commit/634e467172efa696eb32ef8942ffbedeecbd030e),
|
||||
[#11281](https://github.com/angular/angular.js/issues/11281), [#11109](https://github.com/angular/angular.js/issues/11109))
|
||||
- **$cookies:** update $cookies to prevent duplicate cookie writes and play nice with external code
|
||||
([706a93ab](https://github.com/angular/angular.js/commit/706a93ab6960e3474698ccf9a8048b3c32e567c6),
|
||||
[#11490](https://github.com/angular/angular.js/issues/11490), [#11515](https://github.com/angular/angular.js/issues/11515))
|
||||
- **$http:** throw error if `success` and `error` methods do not receive a function
|
||||
([731e1f65](https://github.com/angular/angular.js/commit/731e1f6534ab7fd1e053b8d7a25c902fcd934fea),
|
||||
[#11330](https://github.com/angular/angular.js/issues/11330), [#11333](https://github.com/angular/angular.js/issues/11333))
|
||||
- **core:** ensure that multiple requests to requestAnimationFrame are buffered
|
||||
([0adc0364](https://github.com/angular/angular.js/commit/0adc0364265b06c567ccc8e90a7f09cc46f235b2),
|
||||
[#11791](https://github.com/angular/angular.js/issues/11791))
|
||||
- **filterFilter:** fix matching against `null`/`undefined`
|
||||
([9dd0fe35](https://github.com/angular/angular.js/commit/9dd0fe35d1027e59b84b2396abee00d8683f3b50),
|
||||
[#11573](https://github.com/angular/angular.js/issues/11573), [#11617](https://github.com/angular/angular.js/issues/11617))
|
||||
- **jqLite:**
|
||||
- check for "length" in obj in isArrayLike to prevent iOS8 JIT bug from surfacing
|
||||
([647f3f55](https://github.com/angular/angular.js/commit/647f3f55eb7100a255272f7277f0f962de234a32),
|
||||
[#11508](https://github.com/angular/angular.js/issues/11508))
|
||||
- attr should ignore comment, text and attribute nodes
|
||||
([181e5ebc](https://github.com/angular/angular.js/commit/181e5ebc3fce5312feacaeace4fcad0d32f4d73c))
|
||||
- **ngAnimate:**
|
||||
- ensure that minified repaint code isn't removed
|
||||
([d5c99ea4](https://github.com/angular/angular.js/commit/d5c99ea42b834343fd0362cfc572f47e7536ccfb),
|
||||
[#9936](https://github.com/angular/angular.js/issues/9936))
|
||||
- **ngAria:** handle elements with role="checkbox/menuitemcheckbox"
|
||||
([1c282af5](https://github.com/angular/angular.js/commit/1c282af5abc205d4aac37c05c5cb725d71747134),
|
||||
[#11317](https://github.com/angular/angular.js/issues/11317), [#11321](https://github.com/angular/angular.js/issues/11321))
|
||||
- **ngModel:** allow setting model to NaN when asyncValidator is present
|
||||
([b64519fe](https://github.com/angular/angular.js/commit/b64519fea7f1a5ec75e32c4b71b012b827314153),
|
||||
[#11315](https://github.com/angular/angular.js/issues/11315), [#11411](https://github.com/angular/angular.js/issues/11411))
|
||||
- **ngTouch:**
|
||||
- check undefined tagName for SVG event target
|
||||
([7560a8d2](https://github.com/angular/angular.js/commit/7560a8d2d65955ddb60ede9d586502f4e3cbd062))
|
||||
- register touches properly when jQuery is used
|
||||
([40441f6d](https://github.com/angular/angular.js/commit/40441f6dfc5ebd5cdc679c269c4639238f5351eb),
|
||||
[#4001](https://github.com/angular/angular.js/issues/4001), [#8584](https://github.com/angular/angular.js/issues/8584), [#10797](https://github.com/angular/angular.js/issues/10797), [#11488](https://github.com/angular/angular.js/issues/11488))
|
||||
- **select:** prevent unknown option being added to select when bound to null property
|
||||
([9e3f82bb](https://github.com/angular/angular.js/commit/9e3f82bbaf83cad7bb3121db756099b0880562e6),
|
||||
[#11872](https://github.com/angular/angular.js/issues/11872), [#11875](https://github.com/angular/angular.js/issues/11875))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **travis:** run unit tests on iOS 8
|
||||
([1f650871](https://github.com/angular/angular.js/commit/1f650871266b88b3dab4a894a839a82ac9a06b69),
|
||||
[#11479](https://github.com/angular/angular.js/issues/11479))
|
||||
|
||||
|
||||
|
||||
<a name="1.4.0"></a>
|
||||
# 1.4.0 jaracimrman-existence (2015-05-26)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- ignore invalid option parameter values
|
||||
([72edd4df](https://github.com/angular/angular.js/commit/72edd4dff931c644eecb8f0d1c878dc839c76947),
|
||||
[#11826](https://github.com/angular/angular.js/issues/11826))
|
||||
- accept unwrapped DOM elements as inputs for enter + move
|
||||
([f26fc26f](https://github.com/angular/angular.js/commit/f26fc26f6ea283b2fc5ddb18627b13850de2663e),
|
||||
[#11848](https://github.com/angular/angular.js/issues/11848))
|
||||
- **$animateCss:** ensure that custom durations do not confuse the gcs cache
|
||||
([e0e1b520](https://github.com/angular/angular.js/commit/e0e1b5208767dd62f5586fdc607cb2e31dac9516),
|
||||
[#11723](https://github.com/angular/angular.js/issues/11723), [#11852](https://github.com/angular/angular.js/issues/11852))
|
||||
- **$http:** do not modify the config object passed into $http short methods
|
||||
([f7a4b481](https://github.com/angular/angular.js/commit/f7a4b48121ed2b04af89bd2b754f500d1872360d))
|
||||
- **ngAnimate:**
|
||||
- close follow-up class-based animations when the same class is added/removed when removed/added
|
||||
([db246eb7](https://github.com/angular/angular.js/commit/db246eb701529b41049fc118908e528920f13b24),
|
||||
[#11717](https://github.com/angular/angular.js/issues/11717))
|
||||
- ensure nested class-based animations are spaced out with a RAF
|
||||
([213c2a70](https://github.com/angular/angular.js/commit/213c2a703293ee0af8229dde2b608687cd77ccfa),
|
||||
[#11812](https://github.com/angular/angular.js/issues/11812))
|
||||
- class-based animations must not set addClass/removeClass CSS classes on the element
|
||||
([3a3db690](https://github.com/angular/angular.js/commit/3a3db690a16e888aa7371e3b02e2954b9ec2d558),
|
||||
[#11810](https://github.com/angular/angular.js/issues/11810))
|
||||
- ensure that repeated structural calls during pre-digest function
|
||||
([2327f5a0](https://github.com/angular/angular.js/commit/2327f5a0a7e018a9b03aefabe1fbd0c9330e2eeb),
|
||||
[#11867](https://github.com/angular/angular.js/issues/11867))
|
||||
- ensure that cancelled class-based animations are properly cleaned up
|
||||
([718ff844](https://github.com/angular/angular.js/commit/718ff84405558ac64402e1fca5caefd7d307ea1e),
|
||||
[#11652](https://github.com/angular/angular.js/issues/11652))
|
||||
- throw an error if a callback is passed to animate methods
|
||||
([9bb4d6cc](https://github.com/angular/angular.js/commit/9bb4d6ccbe80b7704c6b7f53317ca8146bc103ca),
|
||||
[#11826](https://github.com/angular/angular.js/issues/11826), [#11713](https://github.com/angular/angular.js/issues/11713))
|
||||
- ensure anchored animations remove the leave element at correct time
|
||||
([64c66d0e](https://github.com/angular/angular.js/commit/64c66d0eea11b575d2a71d00c70cfc5be12cd450),
|
||||
[#11850](https://github.com/angular/angular.js/issues/11850))
|
||||
- **select:** prevent unknown option being added to select when bound to null property
|
||||
([4090491c](https://github.com/angular/angular.js/commit/4090491c73910c169d4fba0494a4e26b45dca7ec),
|
||||
[#11872](https://github.com/angular/angular.js/issues/11872), [#11875](https://github.com/angular/angular.js/issues/11875))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **filterFilter:** allow array like objects to be filtered
|
||||
([1b0d0fd8](https://github.com/angular/angular.js/commit/1b0d0fd8d00b42dffd798845fe0947d594372613),
|
||||
[#11782](https://github.com/angular/angular.js/issues/11782), [#11787](https://github.com/angular/angular.js/issues/11787))
|
||||
|
||||
|
||||
|
||||
<a name="1.4.0-rc.2"></a>
|
||||
# 1.4.0-rc.2 rocket-zambonimation (2015-05-12)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** ensure directive names have no leading or trailing whitespace
|
||||
([bab474aa](https://github.com/angular/angular.js/commit/bab474aa8b146f6732857c3af1a8b3b010fda8b0),
|
||||
[#11397](https://github.com/angular/angular.js/issues/11397), [#11772](https://github.com/angular/angular.js/issues/11772))
|
||||
- **$httpParamSerializerJQLike:** follow jQuery logic for nested params
|
||||
([2420a0a7](https://github.com/angular/angular.js/commit/2420a0a77e27b530dbb8c41319b2995eccf76791),
|
||||
[#11551](https://github.com/angular/angular.js/issues/11551), [#11635](https://github.com/angular/angular.js/issues/11635))
|
||||
- **jqLite:** check for "length" in obj in isArrayLike to prevent iOS8 JIT bug from surfacing
|
||||
([426a5ac0](https://github.com/angular/angular.js/commit/426a5ac0547109648e5c5e358f668c274a111ab2),
|
||||
[#11508](https://github.com/angular/angular.js/issues/11508))
|
||||
- **ngAnimate:**
|
||||
- ensure that multiple requests to requestAnimationFrame are buffered
|
||||
([db20b830](https://github.com/angular/angular.js/commit/db20b830fc6074a00dc11d3f47d665c55e8bb515),
|
||||
[#11791](https://github.com/angular/angular.js/issues/11791))
|
||||
- ensure that an object is always returned even when no animation is set to run
|
||||
([d5683d21](https://github.com/angular/angular.js/commit/d5683d21165e725bc5a850e795f681b0a8a008f5))
|
||||
- force use of `ng-anchor` instead of a suffixed `-anchor` CSS class when triggering anchor animations
|
||||
([df24410c](https://github.com/angular/angular.js/commit/df24410c17d51a8d44929b9cffee2c91cedfed72))
|
||||
- rename `ng-animate-anchor` to `ng-anchor`
|
||||
([e6d053de](https://github.com/angular/angular.js/commit/e6d053de0993c0d38de46ad8a9c6760537316430))
|
||||
- ensure that shared CSS classes between anchor nodes are retained
|
||||
([e0014002](https://github.com/angular/angular.js/commit/e0014002370278778077d0612f9fab6beb80d07a),
|
||||
[#11681](https://github.com/angular/angular.js/issues/11681))
|
||||
- prohibit usage of the `ng-animate` class with classNameFilter
|
||||
([1002b80a](https://github.com/angular/angular.js/commit/1002b80a6fb5d98c424a01330234276d65d93c0b),
|
||||
[#11431](https://github.com/angular/angular.js/issues/11431), [#11807](https://github.com/angular/angular.js/issues/11807))
|
||||
- ensure that the temporary CSS classes are applied before detection
|
||||
([f7e9ff1a](https://github.com/angular/angular.js/commit/f7e9ff1aba9ed70835c084e6e154f6b0bf9c3a19),
|
||||
[#11769](https://github.com/angular/angular.js/issues/11769), [#11804](https://github.com/angular/angular.js/issues/11804))
|
||||
- ensure that all jqLite elements are deconstructed properly
|
||||
([64d05180](https://github.com/angular/angular.js/commit/64d05180a667e586328fbdbd328889d3b003571d),
|
||||
[#11658](https://github.com/angular/angular.js/issues/11658))
|
||||
- ensure animations are not attempted on text nodes
|
||||
([2aacc2d6](https://github.com/angular/angular.js/commit/2aacc2d622893e05eb94b3974d562e681cc3a17f),
|
||||
[#11703](https://github.com/angular/angular.js/issues/11703))
|
||||
- ensure JS animations recognize $animateCss directly
|
||||
([0681a540](https://github.com/angular/angular.js/commit/0681a5400e4150a961f9c8651e55623ca23b0cc2))
|
||||
- **ngClass:** add/remove classes which are properties of Object.prototype
|
||||
([f7b99970](https://github.com/angular/angular.js/commit/f7b999703f4f3bdaea035ce692f1a656b0c1a933),
|
||||
[#11813](https://github.com/angular/angular.js/issues/11813), [#11814](https://github.com/angular/angular.js/issues/11814))
|
||||
- **ngOptions:**
|
||||
- ensure that tracked properties are always watched
|
||||
([b5a9053b](https://github.com/angular/angular.js/commit/b5a9053ba33d48db2482ca6736d1fcae8b33d0f8),
|
||||
[#11784](https://github.com/angular/angular.js/issues/11784))
|
||||
- ensure label is watched in all cases
|
||||
([ae98dadf](https://github.com/angular/angular.js/commit/ae98dadf6dca3313746f42a441c7659654dd9d50),
|
||||
[#11765](https://github.com/angular/angular.js/issues/11765))
|
||||
- iterate over the options collection in the same way as `ngRepeat`
|
||||
([dfa722a8](https://github.com/angular/angular.js/commit/dfa722a8a6864793fd9580d8ae704a06d10b5509),
|
||||
[#11733](https://github.com/angular/angular.js/issues/11733))
|
||||
- use watchCollection not deep watch of ngModel
|
||||
([47f9fc3e](https://github.com/angular/angular.js/commit/47f9fc3e70bc361e8c11fe68dc3ec4489238efb3),
|
||||
[#11372](https://github.com/angular/angular.js/issues/11372), [#11653](https://github.com/angular/angular.js/issues/11653), [#11743](https://github.com/angular/angular.js/issues/11743))
|
||||
- **ngTouch:**
|
||||
- check undefined tagName for SVG event target
|
||||
([74eb17d7](https://github.com/angular/angular.js/commit/74eb17d7c8232f72f134bf2546f10fed7234d276))
|
||||
- don't prevent click event after a touchmove
|
||||
([95521876](https://github.com/angular/angular.js/commit/95521876eb9eb330548b0549f0cfe22a26d88f6e),
|
||||
[#10985](https://github.com/angular/angular.js/issues/10985))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$resource:** include request context in error message
|
||||
([266bc652](https://github.com/angular/angular.js/commit/266bc6520ba4d188dbc949643def102604f98905),
|
||||
[#11363](https://github.com/angular/angular.js/issues/11363))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
### ngAnimate
|
||||
|
||||
- **$animateCss:** due to [d5683d21](https://github.com/angular/angular.js/commit/d5683d21165e725bc5a850e795f681b0a8a008f5),
|
||||
The $animateCss service will now always return an
|
||||
object even if the animation is not set to run. If your code is using
|
||||
$animateCss then please consider the following code change:
|
||||
|
||||
```
|
||||
// before
|
||||
var animator = $animateCss(element, { ... });
|
||||
if (!animator) {
|
||||
continueApp();
|
||||
return;
|
||||
}
|
||||
var runner = animator.start();
|
||||
runner.done(continueApp);
|
||||
runner.then(continueApp);
|
||||
|
||||
// now
|
||||
var animator = $animateCss(element, { ... });
|
||||
var runner = animator.start();
|
||||
runner.done(continueApp);
|
||||
runner.then(continueApp);
|
||||
```
|
||||
|
||||
- due to [df24410c](https://github.com/angular/angular.js/commit/df24410c17d51a8d44929b9cffee2c91cedfed72),
|
||||
Prior to this fix there were to ways to apply CSS
|
||||
animation code to an anchor animation. With this fix, the suffixed
|
||||
CSS -anchor classes are now not used anymore for CSS anchor animations.
|
||||
|
||||
Instead just use the `ng-anchor` CSS class like so:
|
||||
|
||||
```html
|
||||
<div class="container-animation" ng-if="on">
|
||||
<div ng-animate-ref="1" class="my-anchor-element"></div>
|
||||
</div>
|
||||
|
||||
<div class="container-animation" ng-if="!on">
|
||||
<div ng-animate-ref="1" class="my-anchor-element"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**before**:
|
||||
```css
|
||||
/* before (notice the container-animation CSS class) */
|
||||
.container-animation-anchor {
|
||||
transition:0.5s linear all;
|
||||
}
|
||||
```
|
||||
|
||||
**now**:
|
||||
```css
|
||||
/* now (just use `ng-anchor` on a class that both the
|
||||
elements that contain `ng-animate-ref` share) */
|
||||
.my-anchor-element.ng-anchor {
|
||||
transition:0.5s linear all;
|
||||
}
|
||||
```
|
||||
|
||||
- due to [e6d053de](https://github.com/angular/angular.js/commit/e6d053de0993c0d38de46ad8a9c6760537316430),
|
||||
if your CSS code made use of the `ng-animate-anchor`
|
||||
CSS class for referencing the anchored animation element then your
|
||||
code must now use `ng-anchor` instead.
|
||||
|
||||
- due to [1002b80a](https://github.com/angular/angular.js/commit/1002b80a6fb5d98c424a01330234276d65d93c0b),
|
||||
partially or fully using a regex value containing
|
||||
`ng-animate` as a token is not allowed anymore. Doing so will trigger a
|
||||
minErr exception to be thrown.
|
||||
|
||||
So don't do this:
|
||||
|
||||
```js
|
||||
// only animate elements that contain the `ng-animate` CSS class
|
||||
$animateProvider.classNameFilter(/ng-animate/);
|
||||
|
||||
// or partially contain it
|
||||
$animateProvider.classNameFilter(/some-class ng-animate another-class/);
|
||||
```
|
||||
|
||||
but this is OK:
|
||||
|
||||
```js
|
||||
$animateProvider.classNameFilter(/ng-animate-special/);
|
||||
```
|
||||
|
||||
|
||||
### ngOptions
|
||||
|
||||
- ** due to [dfa722a8](https://github.com/angular/angular.js/commit/dfa722a8a6864793fd9580d8ae704a06d10b5509),
|
||||
|
||||
|
||||
Although it is unlikely that anyone is using it in this way, this change does change the
|
||||
behaviour of `ngOptions` in the following case:
|
||||
|
||||
* you are iterating over an array-like object, using the array form of the `ngOptions` syntax
|
||||
(`item.label for item in items`) and that object contains non-numeric property keys.
|
||||
|
||||
In this case these properties with non-numeric keys will be ignored.
|
||||
|
||||
** Here array-like is defined by the result of a call to this internal function:
|
||||
https://github.com/angular/angular.js/blob/v1.4.0-rc.1/src/Angular.js#L198-L211 **
|
||||
|
||||
To get the desired behaviour you need to iterate using the object form of the `ngOptions` syntax
|
||||
(`value.label` for (key, value) in items)`).
|
||||
|
||||
|
||||
|
||||
<a name="1.4.0-beta.6"></a>
|
||||
# 1.4.0-beta.6 cookie-liberation (2015-03-17)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** call `applyStyles` from options on `leave`
|
||||
([4374f892](https://github.com/angular/angular.js/commit/4374f892c6fa4af6ba1f2ed47c5f888fdb5fadc5),
|
||||
[#10068](https://github.com/angular/angular.js/issues/10068))
|
||||
- **$browser:** don't crash if `history.state` access causes error in IE
|
||||
([3b8163b7](https://github.com/angular/angular.js/commit/3b8163b7b664f24499e75460ab50c066eaec0f78),
|
||||
[#10367](https://github.com/angular/angular.js/issues/10367), [#10369](https://github.com/angular/angular.js/issues/10369))
|
||||
- **$sanitize:** disallow unsafe svg animation tags
|
||||
([67688d5c](https://github.com/angular/angular.js/commit/67688d5ca00f6de4c7fe6084e2fa762a00d25610),
|
||||
[#11290](https://github.com/angular/angular.js/issues/11290))
|
||||
- **Angular:** properly compare RegExp with other objects for equality
|
||||
([f22e1fc9](https://github.com/angular/angular.js/commit/f22e1fc9610ae111a3ea8746a3a57169c99ce142),
|
||||
[#11204](https://github.com/angular/angular.js/issues/11204), [#11205](https://github.com/angular/angular.js/issues/11205))
|
||||
- **date filter:** display localised era for `G` format codes
|
||||
([2b4dfa9e](https://github.com/angular/angular.js/commit/2b4dfa9e2b63d7ebb78f3b0fd3439d18f932e1cd),
|
||||
[#10503](https://github.com/angular/angular.js/issues/10503), [#11266](https://github.com/angular/angular.js/issues/11266))
|
||||
- **filterFilter:**
|
||||
- fix filtering using an object expression when the filter value is undefined
|
||||
([c62fa6bd](https://github.com/angular/angular.js/commit/c62fa6bd898e1048d4690d41034489dc60ba6ac2),
|
||||
[#10419](https://github.com/angular/angular.js/issues/10419), [#10424](https://github.com/angular/angular.js/issues/10424))
|
||||
- do not throw an error if property is null when comparing objects
|
||||
([2c4ffd6a](https://github.com/angular/angular.js/commit/2c4ffd6af4eb012c4054fe7c096267bbc5510af0),
|
||||
[#10991](https://github.com/angular/angular.js/issues/10991), [#10992](https://github.com/angular/angular.js/issues/10992), [#11116](https://github.com/angular/angular.js/issues/11116))
|
||||
- **form:** allow dynamic form names which initially evaluate to blank
|
||||
([410f7c68](https://github.com/angular/angular.js/commit/410f7c682633c681be641cd2a321f9e51671d474))
|
||||
- **jqLite:** attr should ignore comment, text and attribute nodes
|
||||
([bb5bf7f8](https://github.com/angular/angular.js/commit/bb5bf7f8162d11610a53428e630b47030bdc38e5))
|
||||
- **ng/$locale:** add ERA info in generic locale
|
||||
([4acb0af2](https://github.com/angular/angular.js/commit/4acb0af24c7fb3705a197ca96adc532de4766a7a))
|
||||
- **ngJq:** don't rely on existence of jqlite
|
||||
([342e5f3c](https://github.com/angular/angular.js/commit/342e5f3ce38d2fd10c5d5a98ca66f864286a7922),
|
||||
[#11044](https://github.com/angular/angular.js/issues/11044))
|
||||
- **ngMessages:** ensure that multi-level transclusion works with `ngMessagesInclude`
|
||||
([d7ec5f39](https://github.com/angular/angular.js/commit/d7ec5f392e1550658ddf271a30627b1749eccb69),
|
||||
[#11196](https://github.com/angular/angular.js/issues/11196))
|
||||
- **ngOptions:** fix model<->option interaction when using `track by`
|
||||
([6a03ca27](https://github.com/angular/angular.js/commit/6a03ca274314352052c3082163367a146bb11c2d),
|
||||
[#10869](https://github.com/angular/angular.js/issues/10869), [#10893](https://github.com/angular/angular.js/issues/10893))
|
||||
- **rootScope:** prevent memory leak when destroying scopes
|
||||
([fb7db4a0](https://github.com/angular/angular.js/commit/fb7db4a07bd1b0b67824d3808fe315419b272689),
|
||||
[#11173](https://github.com/angular/angular.js/issues/11173), [#11169](https://github.com/angular/angular.js/issues/11169))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$cookies:**
|
||||
- allow passing cookie options
|
||||
([92c366d2](https://github.com/angular/angular.js/commit/92c366d205da36ec26502aded23db71a6473dad7),
|
||||
[#8324](https://github.com/angular/angular.js/issues/8324), [#3988](https://github.com/angular/angular.js/issues/3988), [#1786](https://github.com/angular/angular.js/issues/1786), [#950](https://github.com/angular/angular.js/issues/950))
|
||||
- move logic into $cookies and deprecate $cookieStore
|
||||
([38fbe3ee](https://github.com/angular/angular.js/commit/38fbe3ee8370fc449b82d80df07b5c2ed2cd5fbe),
|
||||
[#6411](https://github.com/angular/angular.js/issues/6411), [#7631](https://github.com/angular/angular.js/issues/7631))
|
||||
- **$cookiesProvider:** provide path, domain, expires and secure options
|
||||
([53c66369](https://github.com/angular/angular.js/commit/53c663699126815eabc2a3bc1e3bafc8b3874268))
|
||||
- **$interval:** pass additional arguments to the callback
|
||||
([4f1f9cfd](https://github.com/angular/angular.js/commit/4f1f9cfdb721cf308ca1162b2227836dc1d28388),
|
||||
[#10632](https://github.com/angular/angular.js/issues/10632))
|
||||
- **$timeout:** pass additional arguments to the callback
|
||||
([3a4b6b83](https://github.com/angular/angular.js/commit/3a4b6b83efdb8051e5c4803c0892c19ceb2cba50),
|
||||
[#10631](https://github.com/angular/angular.js/issues/10631))
|
||||
- **angular.merge:** provide an alternative to `angular.extend` that merges 'deeply'
|
||||
([c0498d45](https://github.com/angular/angular.js/commit/c0498d45feb913c318224ea70b5adf7112df6bac),
|
||||
[#10507](https://github.com/angular/angular.js/issues/10507), [#10519](https://github.com/angular/angular.js/issues/10519))
|
||||
- **filterFilter:** compare object with custom `toString()` to primitive
|
||||
([f8c42161](https://github.com/angular/angular.js/commit/f8c421617096a8d613f4eb6d0f5b098ee149c029),
|
||||
[#10464](https://github.com/angular/angular.js/issues/10464), [#10548](https://github.com/angular/angular.js/issues/10548))
|
||||
- **ngAria:**
|
||||
- add `button` role to `ngClick`
|
||||
([bb365070](https://github.com/angular/angular.js/commit/bb365070a3ed7c2d26056d378ab6a8ef493b23cc),
|
||||
[#9254](https://github.com/angular/angular.js/issues/9254), [#10318](https://github.com/angular/angular.js/issues/10318))
|
||||
- add roles to custom inputs
|
||||
([29cdaee2](https://github.com/angular/angular.js/commit/29cdaee2b6e853bc3f8882a00661698d146ecd18),
|
||||
[#10012](https://github.com/angular/angular.js/issues/10012), [#10318](https://github.com/angular/angular.js/issues/10318))
|
||||
- **ngLocale:** Add FIRSTDAYOFWEEK and WEEKENDRANGE from google data
|
||||
([3d149c7f](https://github.com/angular/angular.js/commit/3d149c7f20ffabab5a635af9ddcfc7105112ab4a))
|
||||
- **ngMock:**
|
||||
- allow mock $controller service to set up controller bindings
|
||||
([d02d0585](https://github.com/angular/angular.js/commit/d02d0585a086ecd2e1de628218b5a6d85c8fc7bd),
|
||||
[#9425](https://github.com/angular/angular.js/issues/9425), [#11239](https://github.com/angular/angular.js/issues/11239))
|
||||
- add `they` helpers for testing multiple specs
|
||||
([e650c458](https://github.com/angular/angular.js/commit/e650c45894abe6314a806e6b3e32c908df5c00fd),
|
||||
[#10864](https://github.com/angular/angular.js/issues/10864))
|
||||
- **ngModel:** support conversion to timezone other than UTC
|
||||
([0413bee8](https://github.com/angular/angular.js/commit/0413bee8cc563a6555f8d42d5f183f6fbefc7350),
|
||||
[#11005](https://github.com/angular/angular.js/issues/11005))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$cookies:** due to [38fbe3ee](https://github.com/angular/angular.js/commit/38fbe3ee8370fc449b82d80df07b5c2ed2cd5fbe),
|
||||
|
||||
|
||||
`$cookies` no longer exposes properties that represent the current browser cookie
|
||||
values. Now you must explicitly the methods described above to access the cookie
|
||||
values. This also means that you can no longer watch the `$cookies` properties for
|
||||
changes to the browser's cookies.
|
||||
|
||||
This feature is generally only needed if a 3rd party library was programmatically
|
||||
changing the cookies at runtime. If you rely on this then you must either write code that
|
||||
can react to the 3rd party library making the changes to cookies or implement your own polling
|
||||
mechanism.
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.3.15"></a>
|
||||
# 1.3.15 locality-filtration (2015-03-17)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** call `applyStyles` with options on `leave`
|
||||
([ebd84e80](https://github.com/angular/angular.js/commit/ebd84e8008f45ccaa84290f6da8c2a114fcfa8cd),
|
||||
[#10068](https://github.com/angular/angular.js/issues/10068))
|
||||
- **$browser:** don't crash if history.state access causes error in IE
|
||||
([92767c09](https://github.com/angular/angular.js/commit/92767c098feaf8c58faf2d67f882305019d8160e),
|
||||
[#10367](https://github.com/angular/angular.js/issues/10367), [#10369](https://github.com/angular/angular.js/issues/10369))
|
||||
- **Angular:** properly compare RegExp with other objects for equality
|
||||
([b8e8f9af](https://github.com/angular/angular.js/commit/b8e8f9af78f4ef3e556dd3cef6bfee35ad4cb82a),
|
||||
[#11204](https://github.com/angular/angular.js/issues/11204), [#11205](https://github.com/angular/angular.js/issues/11205))
|
||||
- **date filter:** display localised era for `G` format codes
|
||||
([f2683f95](https://github.com/angular/angular.js/commit/f2683f956fcd3216eaa263db20b31e0d46338800),
|
||||
[#10503](https://github.com/angular/angular.js/issues/10503), [#11266](https://github.com/angular/angular.js/issues/11266))
|
||||
- **filterFilter:**
|
||||
- fix filtering using an object expression when the filter value is `undefined`
|
||||
([63b9956f](https://github.com/angular/angular.js/commit/63b9956faf4c3679c88a9401b8ccbb111c0294ee),
|
||||
[#10419](https://github.com/angular/angular.js/issues/10419), [#10424](https://github.com/angular/angular.js/issues/10424))
|
||||
- do not throw an error if property is null when comparing objects
|
||||
([01161a0e](https://github.com/angular/angular.js/commit/01161a0e9fb1af93e9f06535aed8392ed7f116a4),
|
||||
[#10991](https://github.com/angular/angular.js/issues/10991), [#10992](https://github.com/angular/angular.js/issues/10992), [#11116](https://github.com/angular/angular.js/issues/11116))
|
||||
- **form:** allow dynamic form names which initially evaluate to blank
|
||||
([190ea883](https://github.com/angular/angular.js/commit/190ea883c588d63f8b900a8de1d45c6c9ebb01ec),
|
||||
[#11096](https://github.com/angular/angular.js/issues/11096))
|
||||
- **ng/$locale:** add ERA info in generic locale
|
||||
([57842530](https://github.com/angular/angular.js/commit/578425303f2480959da80f31920d08f277d42010))
|
||||
- **rootScope:** prevent memory leak when destroying scopes
|
||||
([528cf09e](https://github.com/angular/angular.js/commit/528cf09e3f78ad4e3bb6a329ebe315c4f29b4cdb),
|
||||
[#11173](https://github.com/angular/angular.js/issues/11173), [#11169](https://github.com/angular/angular.js/issues/11169))
|
||||
- **templateRequest:** avoid throwing syntax error in Android 2.3
|
||||
([75abbd52](https://github.com/angular/angular.js/commit/75abbd525f07866fdcc6fb311802b8fe700af174),
|
||||
[#11089](https://github.com/angular/angular.js/issues/11089), [#11051](https://github.com/angular/angular.js/issues/11051), [#11088](https://github.com/angular/angular.js/issues/11088))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **ngAria:**
|
||||
- add `button` role to `ngClick`
|
||||
([b9ad91cf](https://github.com/angular/angular.js/commit/b9ad91cf1e86310a2d2bf13b29fa13a9b835e1ce),
|
||||
[#9254](https://github.com/angular/angular.js/issues/9254), [#10318](https://github.com/angular/angular.js/issues/10318))
|
||||
- add roles to custom inputs
|
||||
([21369943](https://github.com/angular/angular.js/commit/21369943fafd577b36827a641b021b1c14cefb57),
|
||||
[#10012](https://github.com/angular/angular.js/issues/10012), [#10318](https://github.com/angular/angular.js/issues/10318))
|
||||
- **ngMock:**
|
||||
- allow mock $controller service to set up controller bindings
|
||||
([b3878a36](https://github.com/angular/angular.js/commit/b3878a36d9f8e56ad7be1eedb9691c9bd12568cb),
|
||||
[#9425](https://github.com/angular/angular.js/issues/9425), [#11239](https://github.com/angular/angular.js/issues/11239))
|
||||
- add `they` helpers for testing multiple specs
|
||||
([7288be25](https://github.com/angular/angular.js/commit/7288be25a75d6ca6ac7eca05a7d6b12ccb3a22f8),
|
||||
[#10864](https://github.com/angular/angular.js/issues/10864))
|
||||
|
||||
|
||||
<a name="1.4.0-beta.5"></a>
|
||||
# 1.4.0-beta.5 karmic-stabilization (2015-02-24)
|
||||
|
||||
@@ -4467,7 +5080,7 @@ For more info: http://blog.angularjs.org/2013/12/angularjs-13-new-release-approa
|
||||
- properly toggle multiple classes
|
||||
([4e73c80b](https://github.com/angular/angular.js/commit/4e73c80b17bd237a8491782bcf9e19f1889e12ed),
|
||||
[#4467](https://github.com/angular/angular.js/issues/4467), [#6448](https://github.com/angular/angular.js/issues/6448))
|
||||
- make jqLite('<iframe src="someurl">').contents() return iframe document, as in jQuery
|
||||
- make `jqLite(<iframe src="someurl">').contents()` return iframe document, as in jQuery
|
||||
([05fbed57](https://github.com/angular/angular.js/commit/05fbed5710b702c111c1425a9e241c40d13b0a54),
|
||||
[#6320](https://github.com/angular/angular.js/issues/6320), [#6323](https://github.com/angular/angular.js/issues/6323))
|
||||
- **numberFilter:** convert all non-finite/non-numbers/non-numeric strings to the empty string
|
||||
@@ -8843,7 +9456,7 @@ with the `$route` service
|
||||
mocks now part of `angular-mocks.js` (commit f5d08963)
|
||||
|
||||
### Bug Fixes
|
||||
- <select> (one/multiple) could not chose from a list of objects (commit 347be5ae)
|
||||
- `<select>` (one/multiple) could not chose from a list of objects (commit 347be5ae)
|
||||
- null and other falsy values should not be rendered in the view (issue #242)
|
||||
|
||||
### Docs
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -235,6 +240,7 @@ The body should include the motivation for the change and contrast this with pre
|
||||
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].
|
||||
|
||||
|
||||
+2
-2
@@ -155,7 +155,7 @@ module.exports = function(grunt) {
|
||||
jscs: {
|
||||
src: ['src/**/*.js', 'test/**/*.js'],
|
||||
options: {
|
||||
config: ".jscs.json"
|
||||
config: ".jscsrc"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -293,7 +293,7 @@ module.exports = function(grunt) {
|
||||
|
||||
shell: {
|
||||
"npm-install": {
|
||||
command: path.normalize('scripts/npm/install-dependencies.sh')
|
||||
command: 'node scripts/npm/check-node-modules.js'
|
||||
},
|
||||
|
||||
"promises-aplus-tests": {
|
||||
|
||||
+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
|
||||
|
||||
@@ -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;
|
||||
|
||||
+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>
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -11,7 +11,7 @@ Supported formats:
|
||||
1. `__name__`
|
||||
2. `__name__ as __identifier__`
|
||||
|
||||
N'either `__name__` or `__identifier__` may contain spaces.
|
||||
Neither `__name__` or `__identifier__` may contain spaces.
|
||||
|
||||
Example of incorrect usage that leads to this error:
|
||||
```html
|
||||
|
||||
@@ -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.
|
||||
@@ -235,7 +235,7 @@ Becomes:
|
||||
|
||||
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
|
||||
|
||||
@@ -249,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>
|
||||
|
||||
@@ -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,7 +51,7 @@ 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
|
||||
@@ -831,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
|
||||
|
||||
@@ -93,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">
|
||||
@@ -181,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>
|
||||
|
||||
|
||||
@@ -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), [AngularJS Faceb0ok 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/)
|
||||
* **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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -66,6 +66,12 @@ 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',
|
||||
@@ -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
-1
@@ -116,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;
|
||||
|
||||
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"
|
||||
+502
-282
File diff suppressed because it is too large
Load Diff
Generated
+1367
-1028
File diff suppressed because it is too large
Load Diff
+6
-1
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"branchVersion": "1.3.*",
|
||||
"distTag": "previous_1_3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
@@ -10,6 +11,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",
|
||||
@@ -57,7 +62,7 @@
|
||||
"marked": "~0.3.0",
|
||||
"node-html-encoder": "0.0.2",
|
||||
"promises-aplus-tests": "~2.1.0",
|
||||
"protractor": "^1.6.0",
|
||||
"protractor": "^2.0.0",
|
||||
"q": "~1.0.0",
|
||||
"q-io": "^1.10.9",
|
||||
"qq": "^0.3.5",
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -110,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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
SHRINKWRAP_FILE=npm-shrinkwrap.json
|
||||
SHRINKWRAP_CACHED_FILE=node_modules/npm-shrinkwrap.cached.json
|
||||
|
||||
if diff -q $SHRINKWRAP_FILE $SHRINKWRAP_CACHED_FILE; then
|
||||
echo 'No shrinkwrap changes detected. npm install will be skipped...';
|
||||
else
|
||||
echo 'Blowing away node_modules and reinstalling npm dependencies...'
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
cp $SHRINKWRAP_FILE $SHRINKWRAP_CACHED_FILE
|
||||
echo 'npm install successful!'
|
||||
fi
|
||||
@@ -7,9 +7,9 @@ export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
|
||||
if [ $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
|
||||
|
||||
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,
|
||||
|
||||
+7
-3
@@ -85,6 +85,7 @@
|
||||
createMap: true,
|
||||
|
||||
NODE_TYPE_ELEMENT: true,
|
||||
NODE_TYPE_ATTRIBUTE: true,
|
||||
NODE_TYPE_TEXT: true,
|
||||
NODE_TYPE_COMMENT: true,
|
||||
NODE_TYPE_DOCUMENT: true,
|
||||
@@ -196,7 +197,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;
|
||||
@@ -978,8 +981,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) {
|
||||
@@ -1611,6 +1614,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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
+6
-2
@@ -39,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>
|
||||
@@ -55,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/)
|
||||
@@ -598,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'),
|
||||
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
+13
-6
@@ -75,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 {
|
||||
@@ -394,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`
|
||||
@@ -422,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.
|
||||
*
|
||||
@@ -2177,7 +2184,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
$compileNode.empty();
|
||||
|
||||
$templateRequest($sce.getTrustedResourceUrl(templateUrl))
|
||||
$templateRequest(templateUrl)
|
||||
.then(function(content) {
|
||||
var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
|
||||
|
||||
|
||||
@@ -415,11 +415,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">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
DIRTY_CLASS: false,
|
||||
UNTOUCHED_CLASS: false,
|
||||
TOUCHED_CLASS: false,
|
||||
$ngModelMinErr: false,
|
||||
ngModelMinErr: false,
|
||||
*/
|
||||
|
||||
// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
|
||||
@@ -587,7 +587,11 @@ var inputType = {
|
||||
* Text input with number validation and transformation. Sets the `number` validation
|
||||
* error if not a valid number.
|
||||
*
|
||||
* The model must always be a number, otherwise Angular will throw an error.
|
||||
* <div class="alert alert-warning">
|
||||
* The model must always be of type `number` otherwise Angular will throw an error.
|
||||
* Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
|
||||
* error docs for more information and an example of how to convert your model if necessary.
|
||||
* </div>
|
||||
*
|
||||
* @param {string} ngModel Assignable angular expression to data-bind to.
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
@@ -1166,7 +1170,7 @@ function createDateInputType(type, regexp, parseDate, format) {
|
||||
|
||||
ctrl.$formatters.push(function(value) {
|
||||
if (value && !isDate(value)) {
|
||||
throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
|
||||
throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
|
||||
}
|
||||
if (isValidDate(value)) {
|
||||
previousDate = value;
|
||||
@@ -1243,7 +1247,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
ctrl.$formatters.push(function(value) {
|
||||
if (!ctrl.$isEmpty(value)) {
|
||||
if (!isNumber(value)) {
|
||||
throw $ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
|
||||
throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
|
||||
}
|
||||
value = value.toString();
|
||||
}
|
||||
@@ -1336,7 +1340,7 @@ function parseConstantExpr($parse, context, name, expression, fallback) {
|
||||
if (isDefined(expression)) {
|
||||
parseFn = $parse(expression);
|
||||
if (!parseFn.constant) {
|
||||
throw minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' +
|
||||
throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
|
||||
'`{1}`.', name, expression);
|
||||
}
|
||||
return parseFn(context);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -178,8 +178,8 @@
|
||||
* @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();
|
||||
|
||||
+18
-11
@@ -16,8 +16,7 @@ var VALID_CLASS = 'ng-valid',
|
||||
TOUCHED_CLASS = 'ng-touched',
|
||||
PENDING_CLASS = 'ng-pending';
|
||||
|
||||
|
||||
var $ngModelMinErr = new minErr('ngModel');
|
||||
var ngModelMinErr = minErr('ngModel');
|
||||
|
||||
/**
|
||||
* @ngdoc type
|
||||
@@ -268,7 +267,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
}
|
||||
};
|
||||
} else if (!parsedNgModel.assign) {
|
||||
throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
|
||||
throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
|
||||
$attr.ngModel, startingTag($element));
|
||||
}
|
||||
};
|
||||
@@ -502,7 +501,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* If the validity changes to invalid, the model will be set to `undefined`,
|
||||
* unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
|
||||
* If the validity changes to valid, it will set the model to the last available valid
|
||||
* modelValue, i.e. either the last parsed value or the last value set from the scope.
|
||||
* `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
|
||||
*/
|
||||
this.$validate = function() {
|
||||
// ignore $validate before model is initialized
|
||||
@@ -597,7 +596,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
forEach(ctrl.$asyncValidators, function(validator, name) {
|
||||
var promise = validator(modelValue, viewValue);
|
||||
if (!isPromiseLike(promise)) {
|
||||
throw $ngModelMinErr("$asyncValidators",
|
||||
throw ngModelMinErr("$asyncValidators",
|
||||
"Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
|
||||
}
|
||||
setValidity(name, undefined);
|
||||
@@ -810,7 +809,10 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
|
||||
// if scope model value and ngModel value are out of sync
|
||||
// TODO(perf): why not move this to the action fn?
|
||||
if (modelValue !== ctrl.$modelValue) {
|
||||
if (modelValue !== ctrl.$modelValue &&
|
||||
// checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
|
||||
(ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
|
||||
) {
|
||||
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
|
||||
parserValid = undefined;
|
||||
|
||||
@@ -987,10 +989,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
var _name = 'Brian';
|
||||
$scope.user = {
|
||||
name: function(newName) {
|
||||
if (angular.isDefined(newName)) {
|
||||
_name = newName;
|
||||
}
|
||||
return _name;
|
||||
// Note that newName can be undefined for two reasons:
|
||||
// 1. Because it is called as a getter and thus called with no arguments
|
||||
// 2. Because the property should actually be set to undefined. This happens e.g. if the
|
||||
// input is invalid
|
||||
return arguments.length ? (_name = newName) : _name;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -1202,7 +1205,11 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
|
||||
var _name = 'Brian';
|
||||
$scope.user = {
|
||||
name: function(newName) {
|
||||
return angular.isDefined(newName) ? (_name = newName) : _name;
|
||||
// Note that newName can be undefined for two reasons:
|
||||
// 1. Because it is called as a getter and thus called with no arguments
|
||||
// 2. Because the property should actually be set to undefined. This happens e.g. if the
|
||||
// input is invalid
|
||||
return arguments.length ? (_name = newName) : _name;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -47,10 +47,10 @@
|
||||
</example>
|
||||
*/
|
||||
var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
||||
scope.$watchCollection(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
|
||||
scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
|
||||
if (oldStyles && (newStyles !== oldStyles)) {
|
||||
forEach(oldStyles, function(val, style) { element.css(style, '');});
|
||||
}
|
||||
if (newStyles) element.css(newStyles);
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
*
|
||||
* @scope
|
||||
* @priority 1200
|
||||
* @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
|
||||
* @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
|
||||
* On child elements add:
|
||||
*
|
||||
* * `ngSwitchWhen`: the case statement to match against. If match then this
|
||||
@@ -60,7 +60,7 @@
|
||||
<div ng-controller="ExampleController">
|
||||
<select ng-model="selection" ng-options="item for item in items">
|
||||
</select>
|
||||
<tt>selection={{selection}}</tt>
|
||||
<code>selection={{selection}}</code>
|
||||
<hr/>
|
||||
<div class="animate-switch-container"
|
||||
ng-switch on="selection">
|
||||
|
||||
@@ -316,7 +316,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
selectElement.val(viewValue);
|
||||
if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
|
||||
} else {
|
||||
if (isUndefined(viewValue) && emptyOption) {
|
||||
if (viewValue == null && emptyOption) {
|
||||
selectElement.val('');
|
||||
} else {
|
||||
selectCtrl.renderUnknownOption(viewValue);
|
||||
|
||||
@@ -43,8 +43,9 @@ var patternDirective = function() {
|
||||
ctrl.$validate();
|
||||
});
|
||||
|
||||
ctrl.$validators.pattern = function(value) {
|
||||
return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value);
|
||||
ctrl.$validators.pattern = function(modelValue, viewValue) {
|
||||
// HTML5 pattern constraint validates the input value, so we validate the viewValue
|
||||
return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
* Dependency Injected. To achieve this a filter definition consists of a factory function which is
|
||||
* annotated with dependencies and is responsible for creating a filter function.
|
||||
*
|
||||
* <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>
|
||||
*
|
||||
* ```js
|
||||
* // Filter registration
|
||||
* function MyModule($provide, $filterProvider) {
|
||||
@@ -101,6 +108,13 @@ function $FilterProvider($provide) {
|
||||
* @name $filterProvider#register
|
||||
* @param {string|Object} name Name of the filter function, or an object map of filters where
|
||||
* the keys are the filter names and the values are the filter factories.
|
||||
*
|
||||
* <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>
|
||||
* @returns {Object} Registered filter instance, or if a map of filters was provided then a map
|
||||
* of the registered filter instances.
|
||||
*/
|
||||
|
||||
+11
-1
@@ -126,14 +126,16 @@ function filterFilter() {
|
||||
return function(array, expression, comparator) {
|
||||
if (!isArray(array)) return array;
|
||||
|
||||
var expressionType = (expression !== null) ? typeof expression : 'null';
|
||||
var predicateFn;
|
||||
var matchAgainstAnyProp;
|
||||
|
||||
switch (typeof expression) {
|
||||
switch (expressionType) {
|
||||
case 'function':
|
||||
predicateFn = expression;
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
case 'number':
|
||||
case 'string':
|
||||
matchAgainstAnyProp = true;
|
||||
@@ -159,6 +161,14 @@ function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
|
||||
comparator = equals;
|
||||
} else if (!isFunction(comparator)) {
|
||||
comparator = function(actual, expected) {
|
||||
if (isUndefined(actual)) {
|
||||
// No substring matching against `undefined`
|
||||
return false;
|
||||
}
|
||||
if ((actual === null) || (expected === null)) {
|
||||
// No substring matching against `null`; only match against `null`
|
||||
return actual === expected;
|
||||
}
|
||||
if (isObject(actual) || isObject(expected)) {
|
||||
// Prevent an object to be considered equal to a string like `'[object'`
|
||||
return false;
|
||||
|
||||
@@ -80,6 +80,8 @@ function currencyFilter($locale) {
|
||||
* @description
|
||||
* Formats a number as text.
|
||||
*
|
||||
* If the input is null or undefined, it will just be returned.
|
||||
* If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
|
||||
* If the input is not a number an empty string is returned.
|
||||
*
|
||||
* @param {number|string} number Number to format.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Can be one of:
|
||||
*
|
||||
* - `function`: Getter function. The result of this function will be sorted using the
|
||||
* `<`, `=`, `>` operator.
|
||||
* `<`, `===`, `>` operator.
|
||||
* - `string`: An Angular expression. The result of this expression is used to compare elements
|
||||
* (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
|
||||
* 3 first characters of a property called `name`). The result of a constant expression
|
||||
|
||||
+7
-3
@@ -371,7 +371,7 @@ function $HttpProvider() {
|
||||
* headers: {
|
||||
* 'Content-Type': undefined
|
||||
* },
|
||||
* data: { test: 'test' },
|
||||
* data: { test: 'test' }
|
||||
* }
|
||||
*
|
||||
* $http(req).success(function(){...}).error(function(){...});
|
||||
@@ -806,6 +806,8 @@ function $HttpProvider() {
|
||||
}
|
||||
|
||||
promise.success = function(fn) {
|
||||
assertArgFn(fn, 'fn');
|
||||
|
||||
promise.then(function(response) {
|
||||
fn(response.data, response.status, response.headers, config);
|
||||
});
|
||||
@@ -813,6 +815,8 @@ function $HttpProvider() {
|
||||
};
|
||||
|
||||
promise.error = function(fn) {
|
||||
assertArgFn(fn, 'fn');
|
||||
|
||||
promise.then(null, function(response) {
|
||||
fn(response.data, response.status, response.headers, config);
|
||||
});
|
||||
@@ -1106,8 +1110,8 @@ function $HttpProvider() {
|
||||
* Resolves the raw $http promise.
|
||||
*/
|
||||
function resolvePromise(response, status, headers, statusText) {
|
||||
// normalize internal statuses to 0
|
||||
status = Math.max(status, 0);
|
||||
//status: HTTP response status code, 0, -1 (aborted by timeout / promise)
|
||||
status = status >= -1 ? status : 0;
|
||||
|
||||
(isSuccess(status) ? deferred.resolve : deferred.reject)({
|
||||
data: response,
|
||||
|
||||
@@ -58,7 +58,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
||||
xhr.onload = function requestLoaded() {
|
||||
var statusText = xhr.statusText || '';
|
||||
|
||||
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
||||
// responseText is the old-school way of retrieving response (supported by IE9)
|
||||
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
|
||||
var response = ('response' in xhr) ? xhr.response : xhr.responseText;
|
||||
|
||||
@@ -137,7 +137,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
||||
};
|
||||
|
||||
function jsonpReq(url, callbackId, done) {
|
||||
// we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
|
||||
// we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
|
||||
// - fetches local scripts via XHR and evals them
|
||||
// - adds and immediately removes script elements from the document
|
||||
var script = rawDocument.createElement('script'), callback = null;
|
||||
|
||||
+35
-11
@@ -89,12 +89,12 @@ function serverBase(url) {
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} appBase application base URL
|
||||
* @param {string} appBaseNoFile application base URL stripped of any filename
|
||||
* @param {string} basePrefix url path prefix
|
||||
*/
|
||||
function LocationHtml5Url(appBase, basePrefix) {
|
||||
function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
|
||||
this.$$html5 = true;
|
||||
basePrefix = basePrefix || '';
|
||||
var appBaseNoFile = stripFile(appBase);
|
||||
parseAbsoluteUrl(appBase, this);
|
||||
|
||||
|
||||
@@ -168,10 +168,10 @@ function LocationHtml5Url(appBase, basePrefix) {
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} appBase application base URL
|
||||
* @param {string} appBaseNoFile application base URL stripped of any filename
|
||||
* @param {string} hashPrefix hashbang prefix
|
||||
*/
|
||||
function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
var appBaseNoFile = stripFile(appBase);
|
||||
function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
|
||||
|
||||
parseAbsoluteUrl(appBase, this);
|
||||
|
||||
@@ -185,7 +185,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
|
||||
var withoutHashUrl;
|
||||
|
||||
if (withoutBaseUrl.charAt(0) === '#') {
|
||||
if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
|
||||
|
||||
// The rest of the url starts with a hash so we have
|
||||
// got either a hashbang path or a plain hash fragment
|
||||
@@ -199,7 +199,15 @@ function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
// There was no hashbang path nor hash fragment:
|
||||
// If we are in HTML5 mode we use what is left as the path;
|
||||
// Otherwise we ignore what is left
|
||||
withoutHashUrl = this.$$html5 ? withoutBaseUrl : '';
|
||||
if (this.$$html5) {
|
||||
withoutHashUrl = withoutBaseUrl;
|
||||
} else {
|
||||
withoutHashUrl = '';
|
||||
if (isUndefined(withoutBaseUrl)) {
|
||||
appBase = url;
|
||||
this.replace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseAppUrl(withoutHashUrl, this);
|
||||
@@ -272,14 +280,13 @@ function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} appBase application base URL
|
||||
* @param {string} appBaseNoFile application base URL stripped of any filename
|
||||
* @param {string} hashPrefix hashbang prefix
|
||||
*/
|
||||
function LocationHashbangInHtml5Url(appBase, hashPrefix) {
|
||||
function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
|
||||
this.$$html5 = true;
|
||||
LocationHashbangUrl.apply(this, arguments);
|
||||
|
||||
var appBaseNoFile = stripFile(appBase);
|
||||
|
||||
this.$$parseLinkUrl = function(url, relHref) {
|
||||
if (relHref && relHref[0] === '#') {
|
||||
// special case for links to hash fragments:
|
||||
@@ -309,7 +316,7 @@ function LocationHashbangInHtml5Url(appBase, hashPrefix) {
|
||||
hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
|
||||
|
||||
this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
|
||||
// include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
|
||||
// include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
|
||||
this.$$absUrl = appBase + hashPrefix + this.$$url;
|
||||
};
|
||||
|
||||
@@ -413,11 +420,19 @@ var locationPrototype = {
|
||||
*
|
||||
* Return host of current url.
|
||||
*
|
||||
* Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* // given url http://example.com/#/some/path?foo=bar&baz=xoxo
|
||||
* var host = $location.host();
|
||||
* // => "example.com"
|
||||
*
|
||||
* // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
|
||||
* host = $location.host();
|
||||
* // => "example.com"
|
||||
* host = location.host;
|
||||
* // => "example.com:8080"
|
||||
* ```
|
||||
*
|
||||
* @return {string} host of current url.
|
||||
@@ -807,7 +822,9 @@ function $LocationProvider() {
|
||||
appBase = stripHash(initialUrl);
|
||||
LocationMode = LocationHashbangUrl;
|
||||
}
|
||||
$location = new LocationMode(appBase, '#' + hashPrefix);
|
||||
var appBaseNoFile = stripFile(appBase);
|
||||
|
||||
$location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
|
||||
$location.$$parseLinkUrl(initialUrl, initialUrl);
|
||||
|
||||
$location.$$state = $browser.state();
|
||||
@@ -887,6 +904,13 @@ function $LocationProvider() {
|
||||
|
||||
// update $location when $browser url changes
|
||||
$browser.onUrlChange(function(newUrl, newState) {
|
||||
|
||||
if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
|
||||
// If we are navigating outside of the app then force a reload
|
||||
$window.location.href = newUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
$rootScope.$evalAsync(function() {
|
||||
var oldUrl = $location.absUrl();
|
||||
var oldState = $location.$$state;
|
||||
|
||||
+21
-2
@@ -48,6 +48,25 @@ function ensureSafeMemberName(name, fullExpression) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function getStringValue(name, fullExpression) {
|
||||
// From the JavaScript docs:
|
||||
// Property names must be strings. This means that non-string objects cannot be used
|
||||
// as keys in an object. Any non-string object, including a number, is typecasted
|
||||
// into a string via the toString method.
|
||||
//
|
||||
// So, to ensure that we are checking the same `name` that JavaScript would use,
|
||||
// we cast it to a string, if possible.
|
||||
// Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
|
||||
// this is, this will handle objects that misbehave.
|
||||
name = name + '';
|
||||
if (!isString(name)) {
|
||||
throw $parseMinErr('iseccst',
|
||||
'Cannot convert object to primitive value! '
|
||||
+ 'Expression: {0}', fullExpression);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
function ensureSafeObject(obj, fullExpression) {
|
||||
// nifty check if obj is Function that is fast and works across iframes and other contexts
|
||||
if (obj) {
|
||||
@@ -689,7 +708,7 @@ Parser.prototype = {
|
||||
|
||||
return extend(function $parseObjectIndex(self, locals) {
|
||||
var o = obj(self, locals),
|
||||
i = indexFn(self, locals),
|
||||
i = getStringValue(indexFn(self, locals), expression),
|
||||
v;
|
||||
|
||||
ensureSafeMemberName(i, expression);
|
||||
@@ -698,7 +717,7 @@ Parser.prototype = {
|
||||
return v;
|
||||
}, {
|
||||
assign: function(self, value, locals) {
|
||||
var key = ensureSafeMemberName(indexFn(self, locals), expression);
|
||||
var key = ensureSafeMemberName(getStringValue(indexFn(self, locals), expression), expression);
|
||||
// prevent overwriting of Function.constructor which would break ensureSafeObject check
|
||||
var o = ensureSafeObject(obj(self, locals), expression);
|
||||
if (!o) obj.assign(self, o = {}, locals);
|
||||
|
||||
+41
-3
@@ -10,7 +10,7 @@ function $$RAFProvider() { //rAF
|
||||
$window.webkitCancelRequestAnimationFrame;
|
||||
|
||||
var rafSupported = !!requestAnimationFrame;
|
||||
var raf = rafSupported
|
||||
var rafFn = rafSupported
|
||||
? function(fn) {
|
||||
var id = requestAnimationFrame(fn);
|
||||
return function() {
|
||||
@@ -24,8 +24,46 @@ function $$RAFProvider() { //rAF
|
||||
};
|
||||
};
|
||||
|
||||
raf.supported = rafSupported;
|
||||
queueFn.supported = rafSupported;
|
||||
|
||||
return raf;
|
||||
var cancelLastRAF;
|
||||
var taskCount = 0;
|
||||
var taskQueue = [];
|
||||
return queueFn;
|
||||
|
||||
function flush() {
|
||||
for (var i = 0; i < taskQueue.length; i++) {
|
||||
var task = taskQueue[i];
|
||||
if (task) {
|
||||
taskQueue[i] = null;
|
||||
task();
|
||||
}
|
||||
}
|
||||
taskCount = taskQueue.length = 0;
|
||||
}
|
||||
|
||||
function queueFn(asyncFn) {
|
||||
var index = taskQueue.length;
|
||||
|
||||
taskCount++;
|
||||
taskQueue.push(asyncFn);
|
||||
|
||||
if (index === 0) {
|
||||
cancelLastRAF = rafFn(flush);
|
||||
}
|
||||
|
||||
return function cancelQueueFn() {
|
||||
if (index >= 0) {
|
||||
taskQueue[index] = null;
|
||||
index = null;
|
||||
|
||||
if (--taskCount === 0 && cancelLastRAF) {
|
||||
cancelLastRAF();
|
||||
cancelLastRAF = null;
|
||||
taskQueue.length = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+5
-9
@@ -86,7 +86,6 @@ function $RootScopeProvider() {
|
||||
this.$$childHead = this.$$childTail = null;
|
||||
this.$$listeners = {};
|
||||
this.$$listenerCount = {};
|
||||
this.$$watchersCount = 0;
|
||||
this.$id = nextUid();
|
||||
this.$$ChildScope = null;
|
||||
}
|
||||
@@ -109,12 +108,9 @@ function $RootScopeProvider() {
|
||||
* A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
|
||||
* {@link auto.$injector $injector}. Child scopes are created using the
|
||||
* {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
|
||||
* compiled HTML template is executed.)
|
||||
* compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
|
||||
* an in-depth introduction and usage examples.
|
||||
*
|
||||
* Here is a simple scope snippet to show how you can interact with the scope.
|
||||
* ```html
|
||||
* <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
|
||||
* ```
|
||||
*
|
||||
* # Inheritance
|
||||
* A scope can inherit from a parent scope, as in this example:
|
||||
@@ -275,9 +271,9 @@ function $RootScopeProvider() {
|
||||
*
|
||||
*
|
||||
* If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
|
||||
* you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
|
||||
* can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
|
||||
* change is detected, be prepared for multiple calls to your listener.)
|
||||
* you can register a `watchExpression` function with no `listener`. (Be prepared for
|
||||
* multiple calls to your `watchExpression` because it will execute multiple times in a
|
||||
* single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
|
||||
*
|
||||
* After a watcher is registered with the scope, the `listener` fn is called asynchronously
|
||||
* (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
|
||||
|
||||
+4
-4
@@ -545,7 +545,7 @@ function $SceDelegateProvider() {
|
||||
* characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'. It's a useful wildcard for use
|
||||
* in a whitelist.
|
||||
* - `**`: matches zero or more occurrences of *any* character. As such, it's not
|
||||
* not appropriate to use in for a scheme, domain, etc. as it would match too much. (e.g.
|
||||
* appropriate for use in a scheme, domain, etc. as it would match too much. (e.g.
|
||||
* http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
|
||||
* not have been the intention.) Its usage at the very end of the path is ok. (e.g.
|
||||
* http://foo.example.com/templates/**).
|
||||
@@ -553,11 +553,11 @@ function $SceDelegateProvider() {
|
||||
* - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax
|
||||
* (and all the inevitable escaping) makes them *harder to maintain*. It's easy to
|
||||
* accidentally introduce a bug when one updates a complex expression (imho, all regexes should
|
||||
* have good test coverage.). For instance, the use of `.` in the regex is correct only in a
|
||||
* have good test coverage). For instance, the use of `.` in the regex is correct only in a
|
||||
* small number of cases. A `.` character in the regex used when matching the scheme or a
|
||||
* subdomain could be matched against a `:` or literal `.` that was likely not intended. It
|
||||
* is highly recommended to use the string patterns and only fall back to regular expressions
|
||||
* if they as a last resort.
|
||||
* as a last resort.
|
||||
* - The regular expression must be an instance of RegExp (i.e. not a string.) It is
|
||||
* matched against the **entire** *normalized / absolute URL* of the resource being tested
|
||||
* (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags
|
||||
@@ -567,7 +567,7 @@ function $SceDelegateProvider() {
|
||||
* remember to escape your regular expression (and be aware that you might need more than
|
||||
* one level of escaping depending on your templating engine and the way you interpolated
|
||||
* the value.) Do make use of your platform's escaping mechanism as it might be good
|
||||
* enough before coding your own. e.g. Ruby has
|
||||
* enough before coding your own. E.g. Ruby has
|
||||
* [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
|
||||
* and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
|
||||
* Javascript lacks a similar built in function for escaping. Take a look at Google
|
||||
|
||||
@@ -7,12 +7,14 @@ var $compileMinErr = minErr('$compile');
|
||||
* @name $templateRequest
|
||||
*
|
||||
* @description
|
||||
* The `$templateRequest` service downloads the provided template using `$http` and, upon success,
|
||||
* stores the contents inside of `$templateCache`. If the HTTP request fails or the response data
|
||||
* of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted
|
||||
* by setting the 2nd parameter of the function to true).
|
||||
* The `$templateRequest` service runs security checks then downloads the provided template using
|
||||
* `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
|
||||
* fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
|
||||
* exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
|
||||
* contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
|
||||
* when `tpl` is of type string and `$templateCache` has the matching entry.
|
||||
*
|
||||
* @param {string} tpl The HTTP request template URL
|
||||
* @param {string|TrustedResourceUrl} tpl The HTTP request template URL
|
||||
* @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
|
||||
*
|
||||
* @return {Promise} the HTTP Promise for the given.
|
||||
@@ -20,10 +22,19 @@ var $compileMinErr = minErr('$compile');
|
||||
* @property {number} totalPendingRequests total amount of pending template requests being downloaded.
|
||||
*/
|
||||
function $TemplateRequestProvider() {
|
||||
this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) {
|
||||
this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
|
||||
function handleRequestFn(tpl, ignoreRequestError) {
|
||||
handleRequestFn.totalPendingRequests++;
|
||||
|
||||
// We consider the template cache holds only trusted templates, so
|
||||
// there's no need to go through whitelisting again for keys that already
|
||||
// are included in there. This also makes Angular accept any script
|
||||
// directive, no matter its name. However, we still need to unwrap trusted
|
||||
// types.
|
||||
if (!isString(tpl) || !$templateCache.get(tpl)) {
|
||||
tpl = $sce.getTrustedResourceUrl(tpl);
|
||||
}
|
||||
|
||||
var transformResponse = $http.defaults && $http.defaults.transformResponse;
|
||||
|
||||
if (isArray(transformResponse)) {
|
||||
|
||||
+1
-8
@@ -24,20 +24,13 @@ var originUrl = urlResolve(window.location.href);
|
||||
*
|
||||
* Implementation Notes for IE
|
||||
* ---------------------------
|
||||
* IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
|
||||
* IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
|
||||
* browsers. However, the parsed components will not be set if the URL assigned did not specify
|
||||
* them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We
|
||||
* work around that by performing the parsing in a 2nd step by taking a previously normalized
|
||||
* URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the
|
||||
* properties such as protocol, hostname, port, etc.
|
||||
*
|
||||
* IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one
|
||||
* uses the inner HTML approach to assign the URL as part of an HTML snippet -
|
||||
* http://stackoverflow.com/a/472729) However, setting img[src] does normalize the URL.
|
||||
* Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
|
||||
* Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
|
||||
* method and IE < 8 is unsupported.
|
||||
*
|
||||
* References:
|
||||
* http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
|
||||
* http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
|
||||
|
||||
@@ -432,9 +432,11 @@ angular.module('ngAnimate', ['ng'])
|
||||
//so that all the animated elements within the animation frame
|
||||
//will be properly updated and drawn on screen. This is
|
||||
//required to perform multi-class CSS based animations with
|
||||
//Firefox. DO NOT REMOVE THIS LINE.
|
||||
var a = bod.offsetWidth + 1;
|
||||
fn();
|
||||
//Firefox. DO NOT REMOVE THIS LINE. DO NOT OPTIMIZE THIS LINE.
|
||||
//THE MINIFIER WILL REMOVE IT OTHERWISE WHICH WILL RESULT IN AN
|
||||
//UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND WILL
|
||||
//TAKE YEARS AWAY FROM YOUR LIFE!
|
||||
fn(bod.offsetWidth);
|
||||
});
|
||||
};
|
||||
}])
|
||||
@@ -1192,18 +1194,21 @@ angular.module('ngAnimate', ['ng'])
|
||||
}
|
||||
|
||||
return cache.promise = runAnimationPostDigest(function(done) {
|
||||
var parentElement = element.parent();
|
||||
var elementNode = extractElementNode(element);
|
||||
var parentNode = elementNode.parentNode;
|
||||
var cache, parentNode, parentElement, elementNode = extractElementNode(element);
|
||||
if (elementNode) {
|
||||
cache = element.data(STORAGE_KEY);
|
||||
element.removeData(STORAGE_KEY);
|
||||
|
||||
parentElement = element.parent();
|
||||
parentNode = elementNode.parentNode;
|
||||
}
|
||||
|
||||
// TODO(matsko): move this code into the animationsDisabled() function once #8092 is fixed
|
||||
if (!parentNode || parentNode['$$NG_REMOVED'] || elementNode['$$NG_REMOVED']) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
var cache = element.data(STORAGE_KEY);
|
||||
element.removeData(STORAGE_KEY);
|
||||
|
||||
var state = element.data(NG_ANIMATE_STATE) || {};
|
||||
var classes = resolveElementClasses(element, cache, state.active);
|
||||
return !classes
|
||||
|
||||
+91
-78
@@ -211,88 +211,101 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
restrict: 'A',
|
||||
require: '?ngModel',
|
||||
priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
|
||||
link: function(scope, elem, attr, ngModel) {
|
||||
compile: function(elem, attr) {
|
||||
var shape = getShape(attr, elem);
|
||||
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem);
|
||||
|
||||
function ngAriaWatchModelValue() {
|
||||
return ngModel.$modelValue;
|
||||
}
|
||||
return {
|
||||
pre: function(scope, elem, attr, ngModel) {
|
||||
if (shape === 'checkbox' && attr.type !== 'checkbox') {
|
||||
//Use the input[checkbox] $isEmpty implementation for elements with checkbox roles
|
||||
ngModel.$isEmpty = function(value) {
|
||||
return value === false;
|
||||
};
|
||||
}
|
||||
},
|
||||
post: function(scope, elem, attr, ngModel) {
|
||||
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem);
|
||||
|
||||
function getRadioReaction() {
|
||||
if (needsTabIndex) {
|
||||
needsTabIndex = false;
|
||||
return function ngAriaRadioReaction(newVal) {
|
||||
var boolVal = (attr.value == ngModel.$viewValue);
|
||||
elem.attr('aria-checked', boolVal);
|
||||
elem.attr('tabindex', 0 - !boolVal);
|
||||
};
|
||||
} else {
|
||||
return function ngAriaRadioReaction(newVal) {
|
||||
elem.attr('aria-checked', (attr.value == ngModel.$viewValue));
|
||||
};
|
||||
function ngAriaWatchModelValue() {
|
||||
return ngModel.$modelValue;
|
||||
}
|
||||
|
||||
function getRadioReaction() {
|
||||
if (needsTabIndex) {
|
||||
needsTabIndex = false;
|
||||
return function ngAriaRadioReaction(newVal) {
|
||||
var boolVal = (attr.value == ngModel.$viewValue);
|
||||
elem.attr('aria-checked', boolVal);
|
||||
elem.attr('tabindex', 0 - !boolVal);
|
||||
};
|
||||
} else {
|
||||
return function ngAriaRadioReaction(newVal) {
|
||||
elem.attr('aria-checked', (attr.value == ngModel.$viewValue));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function ngAriaCheckboxReaction() {
|
||||
elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
|
||||
}
|
||||
|
||||
switch (shape) {
|
||||
case 'radio':
|
||||
case 'checkbox':
|
||||
if (shouldAttachRole(shape, elem)) {
|
||||
elem.attr('role', shape);
|
||||
}
|
||||
if (shouldAttachAttr('aria-checked', 'ariaChecked', elem)) {
|
||||
scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
|
||||
getRadioReaction() : ngAriaCheckboxReaction);
|
||||
}
|
||||
break;
|
||||
case 'range':
|
||||
if (shouldAttachRole(shape, elem)) {
|
||||
elem.attr('role', 'slider');
|
||||
}
|
||||
if ($aria.config('ariaValue')) {
|
||||
if (attr.min && !elem.attr('aria-valuemin')) {
|
||||
elem.attr('aria-valuemin', attr.min);
|
||||
}
|
||||
if (attr.max && !elem.attr('aria-valuemax')) {
|
||||
elem.attr('aria-valuemax', attr.max);
|
||||
}
|
||||
if (!elem.attr('aria-valuenow')) {
|
||||
scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {
|
||||
elem.attr('aria-valuenow', newVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'multiline':
|
||||
if (shouldAttachAttr('aria-multiline', 'ariaMultiline', elem)) {
|
||||
elem.attr('aria-multiline', true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (needsTabIndex) {
|
||||
elem.attr('tabindex', 0);
|
||||
}
|
||||
|
||||
if (ngModel.$validators.required && shouldAttachAttr('aria-required', 'ariaRequired', elem)) {
|
||||
scope.$watch(function ngAriaRequiredWatch() {
|
||||
return ngModel.$error.required;
|
||||
}, function ngAriaRequiredReaction(newVal) {
|
||||
elem.attr('aria-required', !!newVal);
|
||||
});
|
||||
}
|
||||
|
||||
if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem)) {
|
||||
scope.$watch(function ngAriaInvalidWatch() {
|
||||
return ngModel.$invalid;
|
||||
}, function ngAriaInvalidReaction(newVal) {
|
||||
elem.attr('aria-invalid', !!newVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ngAriaCheckboxReaction(newVal) {
|
||||
elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
|
||||
}
|
||||
|
||||
switch (shape) {
|
||||
case 'radio':
|
||||
case 'checkbox':
|
||||
if (shouldAttachRole(shape, elem)) {
|
||||
elem.attr('role', shape);
|
||||
}
|
||||
if (shouldAttachAttr('aria-checked', 'ariaChecked', elem)) {
|
||||
scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
|
||||
getRadioReaction() : ngAriaCheckboxReaction);
|
||||
}
|
||||
break;
|
||||
case 'range':
|
||||
if (shouldAttachRole(shape, elem)) {
|
||||
elem.attr('role', 'slider');
|
||||
}
|
||||
if ($aria.config('ariaValue')) {
|
||||
if (attr.min && !elem.attr('aria-valuemin')) {
|
||||
elem.attr('aria-valuemin', attr.min);
|
||||
}
|
||||
if (attr.max && !elem.attr('aria-valuemax')) {
|
||||
elem.attr('aria-valuemax', attr.max);
|
||||
}
|
||||
if (!elem.attr('aria-valuenow')) {
|
||||
scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {
|
||||
elem.attr('aria-valuenow', newVal);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'multiline':
|
||||
if (shouldAttachAttr('aria-multiline', 'ariaMultiline', elem)) {
|
||||
elem.attr('aria-multiline', true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (needsTabIndex) {
|
||||
elem.attr('tabindex', 0);
|
||||
}
|
||||
|
||||
if (ngModel.$validators.required && shouldAttachAttr('aria-required', 'ariaRequired', elem)) {
|
||||
scope.$watch(function ngAriaRequiredWatch() {
|
||||
return ngModel.$error.required;
|
||||
}, function ngAriaRequiredReaction(newVal) {
|
||||
elem.attr('aria-required', !!newVal);
|
||||
});
|
||||
}
|
||||
|
||||
if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem)) {
|
||||
scope.$watch(function ngAriaInvalidWatch() {
|
||||
return ngModel.$invalid;
|
||||
}, function ngAriaInvalidReaction(newVal) {
|
||||
elem.attr('aria-invalid', !!newVal);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}])
|
||||
|
||||
@@ -86,6 +86,7 @@ angular.module('ngCookies', ['ng']).
|
||||
for (name in lastCookies) {
|
||||
if (isUndefined(cookies[name])) {
|
||||
$browser.cookies(name, undefined);
|
||||
delete lastCookies[name];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,13 +99,13 @@ angular.module('ngCookies', ['ng']).
|
||||
}
|
||||
if (value !== lastCookies[name]) {
|
||||
$browser.cookies(name, value);
|
||||
lastCookies[name] = value;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
//verify what was actually stored
|
||||
if (updated) {
|
||||
updated = false;
|
||||
browserCookies = $browser.cookies();
|
||||
|
||||
for (name in cookies) {
|
||||
@@ -112,10 +113,10 @@ angular.module('ngCookies', ['ng']).
|
||||
//delete or reset all cookies that the browser dropped from $cookies
|
||||
if (isUndefined(browserCookies[name])) {
|
||||
delete cookies[name];
|
||||
delete lastCookies[name];
|
||||
} else {
|
||||
cookies[name] = browserCookies[name];
|
||||
cookies[name] = lastCookies[name] = browserCookies[name];
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+50
-11
@@ -782,8 +782,8 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
|
||||
};
|
||||
});
|
||||
|
||||
$provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser',
|
||||
function($delegate, $$asyncCallback, $timeout, $browser) {
|
||||
$provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser', '$rootScope', '$$rAF',
|
||||
function($delegate, $$asyncCallback, $timeout, $browser, $rootScope, $$rAF) {
|
||||
var animate = {
|
||||
queue: [],
|
||||
cancel: $delegate.cancel,
|
||||
@@ -803,6 +803,43 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
|
||||
fn();
|
||||
});
|
||||
reflowQueue = [];
|
||||
},
|
||||
flush: function() {
|
||||
$rootScope.$digest();
|
||||
var doNextRun, somethingFlushed = false;
|
||||
do {
|
||||
doNextRun = false;
|
||||
if (reflowQueue.length) {
|
||||
doNextRun = somethingFlushed = true;
|
||||
this.triggerReflow();
|
||||
}
|
||||
if ($$rAF.queue.length) {
|
||||
doNextRun = somethingFlushed = true;
|
||||
$$rAF.flush();
|
||||
}
|
||||
if ($$asyncCallback.queue.length) {
|
||||
doNextRun = somethingFlushed = true;
|
||||
this.triggerCallbackEvents();
|
||||
}
|
||||
if (timeoutsRemaining()) {
|
||||
var oldValue = timeoutsRemaining();
|
||||
this.triggerCallbackPromise();
|
||||
var newValue = timeoutsRemaining();
|
||||
if (newValue < oldValue) {
|
||||
doNextRun = somethingFlushed = true;
|
||||
}
|
||||
}
|
||||
} while (doNextRun);
|
||||
|
||||
if (!somethingFlushed) {
|
||||
throw new Error('No pending animations ready to be closed or flushed');
|
||||
}
|
||||
|
||||
$rootScope.$digest();
|
||||
|
||||
function timeoutsRemaining() {
|
||||
return $browser.deferredFns.length;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1752,8 +1789,7 @@ angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $
|
||||
}];
|
||||
|
||||
angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
|
||||
var queue = [];
|
||||
var rafFn = function(fn) {
|
||||
var queue, rafFn = function(fn) {
|
||||
var index = queue.length;
|
||||
queue.push(fn);
|
||||
return function() {
|
||||
@@ -1761,6 +1797,8 @@ angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
|
||||
};
|
||||
};
|
||||
|
||||
queue = rafFn.queue = [];
|
||||
|
||||
rafFn.supported = $delegate.supported;
|
||||
|
||||
rafFn.flush = function() {
|
||||
@@ -1773,22 +1811,22 @@ angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
|
||||
queue[i]();
|
||||
}
|
||||
|
||||
queue = [];
|
||||
queue.length = 0;
|
||||
};
|
||||
|
||||
return rafFn;
|
||||
}];
|
||||
|
||||
angular.mock.$AsyncCallbackDecorator = ['$delegate', function($delegate) {
|
||||
var callbacks = [];
|
||||
var addFn = function(fn) {
|
||||
callbacks.push(fn);
|
||||
var queue, addFn = function(fn) {
|
||||
queue.push(fn);
|
||||
};
|
||||
queue = addFn.queue = [];
|
||||
addFn.flush = function() {
|
||||
angular.forEach(callbacks, function(fn) {
|
||||
angular.forEach(queue, function(fn) {
|
||||
fn();
|
||||
});
|
||||
callbacks = [];
|
||||
queue.length = 0;
|
||||
};
|
||||
return addFn;
|
||||
}];
|
||||
@@ -2237,7 +2275,8 @@ if (window.jasmine || window.mocha) {
|
||||
|
||||
if (injector) {
|
||||
injector.get('$rootElement').off();
|
||||
injector.get('$browser').pollFns.length = 0;
|
||||
var $browser = injector.get('$browser');
|
||||
if ($browser.pollFns) $browser.pollFns.length = 0;
|
||||
}
|
||||
|
||||
// clean up jquery's fragment cache
|
||||
|
||||
@@ -407,7 +407,9 @@ function $RouteProvider() {
|
||||
* @name $route#$routeChangeSuccess
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted after a route dependencies are resolved.
|
||||
* Broadcasted after a route change has happened successfully.
|
||||
* The `resolve` dependencies are now available in the `current.locals` property.
|
||||
*
|
||||
* {@link ngRoute.directive:ngView ngView} listens for the directive
|
||||
* to instantiate the controller and render the view.
|
||||
*
|
||||
@@ -435,9 +437,11 @@ function $RouteProvider() {
|
||||
* @name $route#$routeUpdate
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
*
|
||||
* The `reloadOnSearch` property has been set to false, and we are reusing the same
|
||||
* instance of the Controller.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object
|
||||
* @param {Route} current Current/previous route information.
|
||||
*/
|
||||
|
||||
var forceReload = false,
|
||||
@@ -589,9 +593,8 @@ function $RouteProvider() {
|
||||
if (angular.isFunction(templateUrl)) {
|
||||
templateUrl = templateUrl(nextRoute.params);
|
||||
}
|
||||
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
||||
if (angular.isDefined(templateUrl)) {
|
||||
nextRoute.loadedTemplateUrl = templateUrl;
|
||||
nextRoute.loadedTemplateUrl = $sce.valueOf(templateUrl);
|
||||
template = $templateRequest(templateUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +104,8 @@
|
||||
*/
|
||||
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
||||
var LINKY_URL_REGEXP =
|
||||
/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"”’]/,
|
||||
MAILTO_REGEXP = /^mailto:/;
|
||||
/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"”’]/i,
|
||||
MAILTO_REGEXP = /^mailto:/i;
|
||||
|
||||
return function(text, target) {
|
||||
if (!text) return text;
|
||||
|
||||
@@ -77,6 +77,8 @@
|
||||
evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
|
||||
}
|
||||
}
|
||||
} else if (/touch/.test(eventType) && supportsTouchEvents()) {
|
||||
evnt = createTouchEvent(element, eventType, x, y);
|
||||
} else {
|
||||
evnt = document.createEvent('MouseEvents');
|
||||
x = x || 0;
|
||||
@@ -112,4 +114,35 @@
|
||||
|
||||
return finalProcessDefault;
|
||||
};
|
||||
|
||||
function supportsTouchEvents() {
|
||||
if ('_cached' in supportsTouchEvents) {
|
||||
return supportsTouchEvents._cached;
|
||||
}
|
||||
if (!document.createTouch || !document.createTouchList) {
|
||||
supportsTouchEvents._cached = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
document.createEvent('TouchEvent');
|
||||
} catch (e) {
|
||||
supportsTouchEvents._cached = false;
|
||||
return false;
|
||||
}
|
||||
supportsTouchEvents._cached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function createTouchEvent(element, eventType, x, y) {
|
||||
var evnt = new Event(eventType);
|
||||
x = x || 0;
|
||||
y = y || 0;
|
||||
|
||||
var touch = document.createTouch(window, element, Date.now(), x, y, x, y);
|
||||
var touches = document.createTouchList(touch);
|
||||
|
||||
evnt.touches = touches;
|
||||
|
||||
return evnt;
|
||||
}
|
||||
}());
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
/* global ngTouch: false */
|
||||
/* global ngTouch: false,
|
||||
nodeName_: false
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
@@ -142,7 +144,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
||||
lastLabelClickCoordinates = null;
|
||||
}
|
||||
// remember label click coordinates to prevent click busting of trigger click event on input
|
||||
if (event.target.tagName.toLowerCase() === 'label') {
|
||||
if (nodeName_(event.target) === 'label') {
|
||||
lastLabelClickCoordinates = [x, y];
|
||||
}
|
||||
|
||||
@@ -158,7 +160,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
||||
event.preventDefault();
|
||||
|
||||
// Blur focused form elements
|
||||
event.target && event.target.blur();
|
||||
event.target && event.target.blur && event.target.blur();
|
||||
}
|
||||
|
||||
|
||||
@@ -221,8 +223,10 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
||||
|
||||
startTime = Date.now();
|
||||
|
||||
var touches = event.touches && event.touches.length ? event.touches : [event];
|
||||
var e = touches[0].originalEvent || touches[0];
|
||||
// Use jQuery originalEvent
|
||||
var originalEvent = event.originalEvent || event;
|
||||
var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];
|
||||
var e = touches[0];
|
||||
touchStartX = e.clientX;
|
||||
touchStartY = e.clientY;
|
||||
});
|
||||
@@ -238,9 +242,12 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
||||
element.on('touchend', function(event) {
|
||||
var diff = Date.now() - startTime;
|
||||
|
||||
var touches = (event.changedTouches && event.changedTouches.length) ? event.changedTouches :
|
||||
((event.touches && event.touches.length) ? event.touches : [event]);
|
||||
var e = touches[0].originalEvent || touches[0];
|
||||
// Use jQuery originalEvent
|
||||
var originalEvent = event.originalEvent || event;
|
||||
var touches = (originalEvent.changedTouches && originalEvent.changedTouches.length) ?
|
||||
originalEvent.changedTouches :
|
||||
((originalEvent.touches && originalEvent.touches.length) ? originalEvent.touches : [originalEvent]);
|
||||
var e = touches[0];
|
||||
var x = e.clientX;
|
||||
var y = e.clientY;
|
||||
var dist = Math.sqrt(Math.pow(x - touchStartX, 2) + Math.pow(y - touchStartY, 2));
|
||||
|
||||
@@ -40,11 +40,9 @@ ngTouch.factory('$swipe', [function() {
|
||||
};
|
||||
|
||||
function getCoordinates(event) {
|
||||
var touches = event.touches && event.touches.length ? event.touches : [event];
|
||||
var e = (event.changedTouches && event.changedTouches[0]) ||
|
||||
(event.originalEvent && event.originalEvent.changedTouches &&
|
||||
event.originalEvent.changedTouches[0]) ||
|
||||
touches[0].originalEvent || touches[0];
|
||||
var originalEvent = event.originalEvent || event;
|
||||
var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent];
|
||||
var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0];
|
||||
|
||||
return {
|
||||
x: e.clientX,
|
||||
|
||||
@@ -22,3 +22,6 @@
|
||||
/* global -ngTouch */
|
||||
var ngTouch = angular.module('ngTouch', []);
|
||||
|
||||
function nodeName_(element) {
|
||||
return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));
|
||||
}
|
||||
|
||||
+2
-1
@@ -165,6 +165,7 @@
|
||||
"spyOnlyCallsWithArgs": false,
|
||||
"createMockStyleSheet": false,
|
||||
"browserTrigger": false,
|
||||
"jqLiteCacheSize": false
|
||||
"jqLiteCacheSize": false,
|
||||
"browserSupportsCssAnimations": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,3 +56,12 @@ function createMockStyleSheet(doc, wind) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function browserSupportsCssAnimations() {
|
||||
var nav = window.navigator.appVersion;
|
||||
if (nav.indexOf('MSIE') >= 0) {
|
||||
var version = parseInt(navigator.appVersion.match(/MSIE ([\d.]+)/)[1]);
|
||||
return version >= 10; //only IE10+ support keyframes / transitions
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -612,6 +612,30 @@ describe('jqLite', function() {
|
||||
expect(elm.attr('readOnly')).toBeUndefined();
|
||||
expect(elm.attr('disabled')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should do nothing when setting or getting on attribute nodes', function() {
|
||||
var attrNode = jqLite(document.createAttribute('myattr'));
|
||||
expect(attrNode).toBeDefined();
|
||||
expect(attrNode[0].nodeType).toEqual(2);
|
||||
expect(attrNode.attr('some-attribute','somevalue')).toEqual(attrNode);
|
||||
expect(attrNode.attr('some-attribute')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should do nothing when setting or getting on text nodes', function() {
|
||||
var textNode = jqLite(document.createTextNode('some text'));
|
||||
expect(textNode).toBeDefined();
|
||||
expect(textNode[0].nodeType).toEqual(3);
|
||||
expect(textNode.attr('some-attribute','somevalue')).toEqual(textNode);
|
||||
expect(textNode.attr('some-attribute')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should do nothing when setting or getting on comment nodes', function() {
|
||||
var comment = jqLite(document.createComment('some comment'));
|
||||
expect(comment).toBeDefined();
|
||||
expect(comment[0].nodeType).toEqual(8);
|
||||
expect(comment.attr('some-attribute','somevalue')).toEqual(comment);
|
||||
expect(comment.attr('some-attribute')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +57,9 @@ function MockWindow(options) {
|
||||
return getHash(locationHref);
|
||||
},
|
||||
set hash(value) {
|
||||
locationHref = stripHash(locationHref) + '#' + value;
|
||||
// replace the hash with the new one (stripping off a leading hash if there is one)
|
||||
// See hash setter spec: https://url.spec.whatwg.org/#urlutils-and-urlutilsreadonly-members
|
||||
locationHref = stripHash(locationHref) + '#' + value.replace(/^#/,'');
|
||||
},
|
||||
replace: function(url) {
|
||||
locationHref = url;
|
||||
@@ -193,7 +195,7 @@ describe('browser', function() {
|
||||
expect(browser.cookies).toBeDefined();
|
||||
});
|
||||
|
||||
describe('outstading requests', function() {
|
||||
describe('outstanding requests', function() {
|
||||
it('should process callbacks immedietly with no outstanding requests', function() {
|
||||
var callback = jasmine.createSpy('callback');
|
||||
browser.notifyWhenNoOutstandingRequests(callback);
|
||||
|
||||
+12
-2
@@ -1271,14 +1271,24 @@ describe('$compile', function() {
|
||||
));
|
||||
|
||||
it('should not load cross domain templates by default', inject(
|
||||
function($compile, $rootScope, $templateCache, $sce) {
|
||||
function($compile, $rootScope) {
|
||||
expect(function() {
|
||||
$templateCache.put('http://example.com/should-not-load.html', 'Should not load even if in cache.');
|
||||
$compile('<div class="crossDomainTemplate"></div>')($rootScope);
|
||||
}).toThrowMinErr('$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example.com/should-not-load.html');
|
||||
}
|
||||
));
|
||||
|
||||
it('should trust what is already in the template cache', inject(
|
||||
function($compile, $httpBackend, $rootScope, $templateCache) {
|
||||
$httpBackend.expect('GET', 'http://example.com/should-not-load.html').respond('<span>example.com/remote-version</span>');
|
||||
$templateCache.put('http://example.com/should-not-load.html', '<span>example.com/cached-version</span>');
|
||||
element = $compile('<div class="crossDomainTemplate"></div>')($rootScope);
|
||||
expect(sortedHtml(element)).toEqual('<div class="crossDomainTemplate"></div>');
|
||||
$rootScope.$digest();
|
||||
expect(sortedHtml(element)).toEqual('<div class="crossDomainTemplate"><span>example.com/cached-version</span></div>');
|
||||
}
|
||||
));
|
||||
|
||||
it('should load cross domain templates when trusted', inject(
|
||||
function($compile, $httpBackend, $rootScope, $sce) {
|
||||
$httpBackend.expect('GET', 'http://example.com/trusted-template.html').respond('<span>example.com/trusted_template_contents</span>');
|
||||
|
||||
@@ -472,7 +472,7 @@ describe('ngClass animations', function() {
|
||||
//is spaced-out then it is required so that the original digestion
|
||||
//is kicked into gear
|
||||
$rootScope.$digest();
|
||||
$animate.triggerCallbacks();
|
||||
$animate.flush();
|
||||
|
||||
expect(element.data('state')).toBe('crazy-enter');
|
||||
expect(enterComplete).toBe(true);
|
||||
|
||||
@@ -433,7 +433,7 @@ describe('ngInclude', function() {
|
||||
|
||||
expect(autoScrollSpy).not.toHaveBeenCalled();
|
||||
expect($animate.queue.shift().event).toBe('enter');
|
||||
$animate.triggerCallbacks();
|
||||
$animate.flush();
|
||||
|
||||
expect(autoScrollSpy).toHaveBeenCalledOnce();
|
||||
}));
|
||||
@@ -450,7 +450,7 @@ describe('ngInclude', function() {
|
||||
});
|
||||
|
||||
expect($animate.queue.shift().event).toBe('enter');
|
||||
$animate.triggerCallbacks();
|
||||
$animate.flush();
|
||||
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.tpl = 'another.html';
|
||||
@@ -459,7 +459,7 @@ describe('ngInclude', function() {
|
||||
|
||||
expect($animate.queue.shift().event).toBe('leave');
|
||||
expect($animate.queue.shift().event).toBe('enter');
|
||||
$animate.triggerCallbacks();
|
||||
$animate.flush();
|
||||
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.tpl = 'template.html';
|
||||
@@ -468,7 +468,7 @@ describe('ngInclude', function() {
|
||||
|
||||
expect($animate.queue.shift().event).toBe('leave');
|
||||
expect($animate.queue.shift().event).toBe('enter');
|
||||
$animate.triggerCallbacks();
|
||||
$animate.flush();
|
||||
|
||||
expect(autoScrollSpy).toHaveBeenCalled();
|
||||
expect(autoScrollSpy.callCount).toBe(3);
|
||||
@@ -484,7 +484,7 @@ describe('ngInclude', function() {
|
||||
});
|
||||
|
||||
expect($animate.queue.shift().event).toBe('enter');
|
||||
$animate.triggerCallbacks();
|
||||
$animate.flush();
|
||||
expect(autoScrollSpy).not.toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
@@ -500,7 +500,7 @@ describe('ngInclude', function() {
|
||||
});
|
||||
|
||||
expect($animate.queue.shift().event).toBe('enter');
|
||||
$animate.triggerCallbacks();
|
||||
$animate.flush();
|
||||
|
||||
$rootScope.$apply(function() {
|
||||
$rootScope.tpl = 'template.html';
|
||||
@@ -522,7 +522,7 @@ describe('ngInclude', function() {
|
||||
|
||||
$rootScope.$apply("tpl = 'template.html'");
|
||||
expect($animate.queue.shift().event).toBe('enter');
|
||||
$animate.triggerCallbacks();
|
||||
$animate.flush();
|
||||
|
||||
expect(autoScrollSpy).toHaveBeenCalledOnce();
|
||||
}
|
||||
|
||||
@@ -578,6 +578,29 @@ describe('ngModel', function() {
|
||||
|
||||
dealoc(form);
|
||||
}));
|
||||
|
||||
|
||||
it('should set NaN as the $modelValue when an asyncValidator is present',
|
||||
inject(function($q) {
|
||||
|
||||
ctrl.$asyncValidators.test = function() {
|
||||
return $q(function(resolve, reject) {
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
scope.$apply('value = 10');
|
||||
expect(ctrl.$modelValue).toBe(10);
|
||||
|
||||
expect(function() {
|
||||
scope.$apply(function() {
|
||||
scope.value = NaN;
|
||||
});
|
||||
}).not.toThrow();
|
||||
|
||||
expect(ctrl.$modelValue).toBeNaN();
|
||||
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -1083,7 +1083,7 @@ describe('ngRepeat', function() {
|
||||
beforeEach(function() {
|
||||
element = $compile(
|
||||
'<ul>' +
|
||||
'<li ng-repeat="item in items">{{key}}:{{val}}|></li>' +
|
||||
'<li ng-repeat="item in items">{{item}}</li>' +
|
||||
'</ul>')(scope);
|
||||
a = {};
|
||||
b = {};
|
||||
@@ -1486,7 +1486,7 @@ describe('ngRepeat animations', function() {
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(element.text()).toBe('123'); // the original order should be preserved
|
||||
$animate.triggerReflow();
|
||||
$animate.flush();
|
||||
$timeout.flush(1500); // 1s * 1.5 closing buffer
|
||||
expect(element.text()).toBe('13');
|
||||
|
||||
|
||||
@@ -23,6 +23,15 @@ describe('ngStyle', function() {
|
||||
}));
|
||||
|
||||
|
||||
it('should support lazy one-time binding for object literals', inject(function($rootScope, $compile) {
|
||||
element = $compile('<div ng-style="::{height: heightStr}"></div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(parseInt(element.css('height') + 0)).toEqual(0); // height could be '' or '0px'
|
||||
$rootScope.$apply('heightStr = "40px"');
|
||||
expect(element.css('height')).toBe('40px');
|
||||
}));
|
||||
|
||||
|
||||
describe('preserving styles set before and after compilation', function() {
|
||||
var scope, preCompStyle, preCompVal, postCompStyle, postCompVal, element;
|
||||
|
||||
|
||||
@@ -362,7 +362,7 @@ describe('select', function() {
|
||||
scope.$apply(function() {
|
||||
scope.robot = null;
|
||||
});
|
||||
expect(element).toEqualSelect(['? object:null ?'], '', 'c3p0', 'r2d2');
|
||||
expect(element).toEqualSelect([''], 'c3p0', 'r2d2');
|
||||
|
||||
scope.$apply(function() {
|
||||
scope.robot = 'r2d2';
|
||||
|
||||
@@ -204,6 +204,21 @@ describe('validators', function() {
|
||||
expect($rootScope.form.test.$error.pattern).toBe(true);
|
||||
expect(inputElm).not.toBeValid();
|
||||
});
|
||||
|
||||
|
||||
it('should validate the viewValue and not the modelValue', function() {
|
||||
var inputElm = helper.compileInput('<input type="text" name="test" ng-model="value" pattern="\\d{4}">');
|
||||
var ctrl = inputElm.controller('ngModel');
|
||||
|
||||
ctrl.$parsers.push(function(value) {
|
||||
return (value * 10) + '';
|
||||
});
|
||||
|
||||
helper.changeInputValueTo('1234');
|
||||
expect($rootScope.form.test.$error.pattern).not.toBe(true);
|
||||
expect($rootScope.form.test.$modelValue).toBe('12340');
|
||||
expect(inputElm).toBeValid();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -435,8 +435,59 @@ describe('Filter: filter', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should match `null` against `null` only', function() {
|
||||
var items = [
|
||||
{value: null},
|
||||
{value: undefined},
|
||||
{value: true},
|
||||
{value: false},
|
||||
{value: NaN},
|
||||
{value: 42},
|
||||
{value: 'null'},
|
||||
{value: 'test'},
|
||||
{value: {}},
|
||||
{value: new Date()}
|
||||
];
|
||||
var flt;
|
||||
|
||||
flt = null;
|
||||
expect(filter(items, flt).length).toBe(1);
|
||||
expect(filter(items, flt)[0]).toBe(items[0]);
|
||||
|
||||
flt = {value: null};
|
||||
expect(filter(items, flt).length).toBe(1);
|
||||
expect(filter(items, flt)[0]).toBe(items[0]);
|
||||
|
||||
flt = {value: undefined};
|
||||
expect(filter(items, flt).length).toBe(items.length);
|
||||
|
||||
flt = {value: NaN};
|
||||
expect(includes(filter(items, flt), items[0])).toBeFalsy();
|
||||
|
||||
flt = {value: false};
|
||||
expect(includes(filter(items, flt), items[0])).toBeFalsy();
|
||||
|
||||
flt = '';
|
||||
expect(includes(filter(items, flt), items[0])).toBeFalsy();
|
||||
|
||||
flt = {value: 'null'};
|
||||
expect(includes(filter(items, flt), items[0])).toBeFalsy();
|
||||
});
|
||||
|
||||
|
||||
describe('should support comparator', function() {
|
||||
|
||||
it('not convert `null` or `undefined` to string in non-strict comparison', function() {
|
||||
var items = [
|
||||
{value: null},
|
||||
{value: undefined}
|
||||
];
|
||||
var flt = {value: 'u'};
|
||||
|
||||
expect(filter(items, flt).length).toBe(0);
|
||||
});
|
||||
|
||||
|
||||
it('not consider `object === "[object Object]"` in non-strict comparison', function() {
|
||||
var items = [{test: {}}];
|
||||
var expr = '[object';
|
||||
|
||||
@@ -235,7 +235,7 @@ describe('$httpBackend', function() {
|
||||
|
||||
|
||||
it('should read responseText if response was not defined', function() {
|
||||
// old browsers like IE8, don't support responseType, so they always respond with responseText
|
||||
// old browsers like IE9, don't support responseType, so they always respond with responseText
|
||||
|
||||
$backend('GET', '/whatever', null, callback, {}, null, null, 'blob');
|
||||
|
||||
|
||||
+57
-1
@@ -432,6 +432,34 @@ describe('$http', function() {
|
||||
var httpPromise = $http({url: '/url', method: 'GET'});
|
||||
expect(httpPromise.success(callback)).toBe(httpPromise);
|
||||
});
|
||||
|
||||
|
||||
it('should error if the callback is not a function', function() {
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).success();
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).success(undefined);
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).success(null);
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).success({});
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).success([]);
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).success('error');
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -456,6 +484,34 @@ describe('$http', function() {
|
||||
var httpPromise = $http({url: '/url', method: 'GET'});
|
||||
expect(httpPromise.error(callback)).toBe(httpPromise);
|
||||
});
|
||||
|
||||
|
||||
it('should error if the callback is not a function', function() {
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).error();
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).error(undefined);
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).error(null);
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).error({});
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).error([]);
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
|
||||
expect(function() {
|
||||
$http({url: '/url', method: 'GET'}).error('error');
|
||||
}).toThrowMinErr('ng', 'areq');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1601,7 +1657,7 @@ describe('$http', function() {
|
||||
$http({method: 'GET', url: '/some', timeout: canceler.promise}).error(
|
||||
function(data, status, headers, config) {
|
||||
expect(data).toBeUndefined();
|
||||
expect(status).toBe(0);
|
||||
expect(status).toBe(-1);
|
||||
expect(headers()).toEqual({});
|
||||
expect(config.url).toBe('/some');
|
||||
callback();
|
||||
|
||||
+1068
-742
File diff suppressed because it is too large
Load Diff
+7
-6
@@ -1,12 +1,6 @@
|
||||
/* global $LogProvider: false */
|
||||
'use strict';
|
||||
|
||||
function initService(debugEnabled) {
|
||||
return module(function($logProvider) {
|
||||
$logProvider.debugEnabled(debugEnabled);
|
||||
});
|
||||
}
|
||||
|
||||
describe('$log', function() {
|
||||
var $window, logger, log, warn, info, error, debug;
|
||||
|
||||
@@ -178,4 +172,11 @@ describe('$log', function() {
|
||||
expect(errorArgs).toEqual(['abc', 'message\nsourceURL:123']);
|
||||
});
|
||||
});
|
||||
|
||||
function initService(debugEnabled) {
|
||||
return module(function($logProvider) {
|
||||
$logProvider.debugEnabled(debugEnabled);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user