Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dcfcf81893 | |||
| d7cc863105 | |||
| 6e91f9c25d | |||
| 7f1b8bdfe1 | |||
| cc92da0d67 | |||
| c9bb5b9fa4 | |||
| c54921008d | |||
| 69f59f2d01 | |||
| f4fb6e0983 | |||
| a18be15137 | |||
| 05a9d3a73c | |||
| 60035f597c | |||
| 0af21a48e5 | |||
| 991a2b30e0 |
+85
-3
@@ -1,4 +1,84 @@
|
||||
|
||||
<a name="1.6.0-rc.2"></a>
|
||||
# 1.6.0-rc.2 safety-insurance (2016-11-24)
|
||||
|
||||
|
||||
## Security Fixes
|
||||
- **bootstrap:** explicitly whitelist URL schemes for bootstrap. (#15427)
|
||||
([7f1b8b](https://github.com/angular/angular.js/commit/7f1b8bdfe1043871c5ead2ec602efc41e0de5e53))
|
||||
|
||||
## Bug Fixes
|
||||
- **$sce:** fix `adjustMatcher` to replace multiple '*' and '**'
|
||||
([991a2b](https://github.com/angular/angular.js/commit/991a2b30e00aed1d312e29555e356a795f9e3d62))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
- ***:** don't trigger digests after enter/leave of structural directives
|
||||
([f4fb6e](https://github.com/angular/angular.js/commit/f4fb6e0983a6a700dc4a246a913504550b55f1e9)
|
||||
[#15322](https://github.com/angular/angular.js/issues/15322))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.5.9"></a>
|
||||
# 1.5.9 timeturning-lockdown (2016-11-24)
|
||||
|
||||
This is an interim release primarily to publish some security fixes, in particular a modification to
|
||||
ensure that Angular 1 can pass the linter checks for Mozilla add-ons.
|
||||
|
||||
## Security Fixes
|
||||
- **bootstrap:**
|
||||
- do not auto-bootstrap when loaded from an extension
|
||||
([6ce291](https://github.com/angular/angular.js/commit/6ce2913d99bb0dade6027ba9733295d0aa13b242))
|
||||
- explicitly whitelist URL schemes for bootstrap (#15427)
|
||||
([4edd2d](https://github.com/angular/angular.js/commit/4edd2d95c11819ece2dda6e65f95f32638fda218))
|
||||
- **$location:** throw if the path starts with double (back)slashes
|
||||
([353e3a](https://github.com/angular/angular.js/commit/353e3a6cd8b3a785b5f73a38236155621048522f))
|
||||
- **$sniffer:** don't use `history.pushState` in sandboxed Chrome Packaged Apps
|
||||
([367da5](https://github.com/angular/angular.js/commit/367da583bc12e6f5f01edf757305409cf63fb1f4))
|
||||
- **$parse:**
|
||||
- block assigning to fields of a constructor prototype
|
||||
([d7e31b](https://github.com/angular/angular.js/commit/d7e31b5dc71253edb22190a5850034934e7b778a)
|
||||
[#14939](https://github.com/angular/angular.js/issues/14939))
|
||||
- correctly escape unsafe identifier characters
|
||||
([b01460](https://github.com/angular/angular.js/commit/b014607030835358ed7887e9fd1724cdada56690))
|
||||
- **$compile:**
|
||||
- ensure that hidden input values are correct after history.back
|
||||
([6a2488](https://github.com/angular/angular.js/commit/6a24885771cf8c140b5d2895e92b321e60d86b55))
|
||||
- lower the $sce context for `src` on video, audio, source, track
|
||||
([68fb70](https://github.com/angular/angular.js/commit/68fb70ed295119d7b00c670d796c1b4186091adb))
|
||||
|
||||
|
||||
## New Features
|
||||
- **input:**
|
||||
- add support for binding to `input[range]`
|
||||
([2e7121](https://github.com/angular/angular.js/commit/2e7121b8e4dcac23f28e2375e775ca56b6baf252))
|
||||
- make support for `input[range]` opt-in
|
||||
([07b876](https://github.com/angular/angular.js/commit/07b8761233aaa3d719d94698296295e51c2a1077))
|
||||
- fix `step` validation for `input[number][ng-range-input]`
|
||||
([64f6a6](https://github.com/angular/angular.js/commit/64f6a616d401febc3f06309ed5a5efa46b131717)
|
||||
[#15257](https://github.com/angular/angular.js/issues/15257))
|
||||
- **ngMock/$httpBackend:** flush requests in any order
|
||||
([098b6f](https://github.com/angular/angular.js/commit/098b6f519a53f6348127cd4ce09bca1423cbeb1a))
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
- **$httpBackend:** complete the request on timeout
|
||||
([549edc](https://github.com/angular/angular.js/commit/549edc9d0123d50657d5a03ba0c547cb0f91727f)
|
||||
[#14969](https://github.com/angular/angular.js/issues/14969))
|
||||
- **ngOptions:** remove selected attribute from unselected options
|
||||
([d31b3a](https://github.com/angular/angular.js/commit/d31b3a65b65b73ab077026fc028ddf5b6232fba2)
|
||||
[#14892](https://github.com/angular/angular.js/issues/14892))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
- **$parse:** improve performance of assignment expressions
|
||||
([f83c3d](https://github.com/angular/angular.js/commit/f83c3dea23f910aed25dcf9b85fadf7f11a2a366))
|
||||
- **$compile:** add provider option to turn off compilation of css class and comment directives
|
||||
([775c24](https://github.com/angular/angular.js/commit/775c247085765e08845ae45ed19dd0120c61acc1))
|
||||
|
||||
|
||||
|
||||
<a name="1.6.0-rc.1"></a>
|
||||
# 1.6.0-rc.1 proximity-warning (2016-11-21)
|
||||
|
||||
@@ -7,6 +87,7 @@
|
||||
- **ngModelOptions:** allow options to be inherited from ancestor `ngModelOptions` ([296cfc](https://github.com/angular/angular.js/commit/296cfce40c25e9438bfa46a0eb27240707a10ffa) [#10922](https://github.com/angular/angular.js/issues/10922))
|
||||
- **$compile:** set `preAssignBindingsEnabled` to false by default ([bcd0d4](https://github.com/angular/angular.js/commit/bcd0d4d896d0dfdd988ff4f849c1d40366125858) [#15352](https://github.com/angular/angular.js/issues/15352))
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **ngModelOptions:** handle debounce of `updateOn` triggers that are not in debounce list ([789790](https://github.com/angular/angular.js/commit/789790feee4d6c5b1f5d5b18ecb0ccf6edd36fb3))
|
||||
@@ -14,7 +95,7 @@
|
||||
- **$location:** throw if the path starts with double (back)slashes ([4aa953](https://github.com/angular/angular.js/commit/4aa9534b0fea732d6492a2863c3ee7e077c8d004))
|
||||
- **core:** do not auto-bootstrap when loaded from an extension. ([0ff10e](https://github.com/angular/angular.js/commit/0ff10e1b56c6b7c4ac465e35c96a5886e294bac5))
|
||||
- **input[radio]:** use strict comparison when evaluating checked-ness ([5ac7da](https://github.com/angular/angular.js/commit/5ac7daea72ec31cf337d1d21b13f0d17ff33994f) [#15288](https://github.com/angular/angular.js/issues/15288))
|
||||
- **docsApp:** show correct version number in api index ([433c87](https://github.com/angular/angular.js/commit/433c8714f3d065a9a842502579b65d0388dd47ec))
|
||||
|
||||
|
||||
## Reverts
|
||||
|
||||
@@ -25,7 +106,6 @@
|
||||
- **ngOptions:** avoid calls to `element.value` ([3b7f29](https://github.com/angular/angular.js/commit/3b7f29ff63e8bf02327a1430dcc2a4c83915a206))
|
||||
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **feat($compile): set preAssignBindingsEnabled to false by default ([bcd0d4](https://github.com/angular/angular.js/commit/bcd0d4d896d0dfdd988ff4f849c1d40366125858))**:
|
||||
@@ -469,6 +549,8 @@ $scope.$watch('something', function() {
|
||||
or possibly by using `Function.prototype.bind` or `angular.bind`.
|
||||
|
||||
|
||||
### `aria/ngModel` due to:
|
||||
|
||||
- **[975a61](https://github.com/angular/angular.js/commit/975a6170efceb2a5e6377c57329731c0636eb8c8)**: do not overwrite the default `$isEmpty()` method for checkboxes
|
||||
|
||||
Custom `checkbox`-shaped controls (e.g. checkboxes, menuitemcheckboxes), no longer have a custom
|
||||
@@ -854,7 +936,7 @@ The breaking change should be rare, as it relates to incorrect API use that shou
|
||||
production apps in the first place.
|
||||
|
||||
|
||||
- **fix($compile): secure `link[href]` as a `RESOURCE_URL`s in `$sce`. ([04cad4](https://github.com/angular/angular.js/commit/04cad41d26ebaf44b5ee0c29a152d61f235f3efa))**:
|
||||
- **[04cad4](https://github.com/angular/angular.js/commit/04cad41d26ebaf44b5ee0c29a152d61f235f3efa)**: secure `link[href]` as a `RESOURCE_URL` in `$sce`
|
||||
|
||||
`link[href]` attributes are now protected via `$sce`, which prevents interpolated
|
||||
values that fail the `RESOURCE_URL` context tests from being used in interpolation.
|
||||
|
||||
@@ -380,3 +380,106 @@ restrict: 'E',
|
||||
replace: true
|
||||
```
|
||||
|
||||
### Double Compilation, and how to avoid it
|
||||
|
||||
Double compilation occurs when an already compiled part of the DOM gets compiled again. This is an
|
||||
undesired effect and can lead to misbehaving directives, performance issues, and memory
|
||||
leaks.
|
||||
A common scenario where this happens is a directive that calls `$compile` in a directive link
|
||||
function on the directive element. In the following **faulty example**, a directive adds a mouseover behavior
|
||||
to a button with `ngClick` on it:
|
||||
|
||||
```
|
||||
angular.module('app').directive('addMouseover', function($compile) {
|
||||
return {
|
||||
link: function(scope, element, attrs) {
|
||||
var newEl = angular.element('<span ng-show="showHint"> My Hint</span>');
|
||||
element.on('mouseenter mouseleave', function() {
|
||||
scope.$apply('showHint = !showHint');
|
||||
});
|
||||
|
||||
attrs.$set('addMouseover', null); // To stop infinite compile loop
|
||||
element.append(newEl);
|
||||
$compile(element)(scope); // Double compilation
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
At first glance, it looks like removing the original `addMouseover` attribute is all there is needed
|
||||
to make this example work.
|
||||
However, if the directive element or its children have other directives attached, they will be compiled and
|
||||
linked again, because the compiler doesn't keep track of which directives have been assigned to which
|
||||
elements.
|
||||
|
||||
This can cause unpredictable behavior, e.g. `ngClick` or other event handlers will be attached
|
||||
again. It can also degrade performance, as watchers for text interpolation are added twice to the scope.
|
||||
|
||||
Double compilation should therefore be avoided. In the above example, only the new element should
|
||||
be compiled:
|
||||
|
||||
```
|
||||
angular.module('app').directive('addMouseover', function($compile) {
|
||||
return {
|
||||
link: function(scope, element, attrs) {
|
||||
var newEl = angular.element('<span ng-show="showHint"> My Hint</span>');
|
||||
element.on('mouseenter mouseleave', function() {
|
||||
scope.$apply('showHint = !showHint');
|
||||
});
|
||||
|
||||
element.append(newEl);
|
||||
$compile(newEl)(scope); // Only compile the new element
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Another scenario is adding a directive programmatically to a compiled element and then executing
|
||||
compile again. See the following **faulty example**:
|
||||
|
||||
```html
|
||||
<input ng-model="$ctrl.value" add-options>
|
||||
```
|
||||
|
||||
```
|
||||
angular.module('app').directive('addOptions', function($compile) {
|
||||
return {
|
||||
link: function(scope, element, attrs) {
|
||||
attrs.$set('addOptions', null) // To stop infinite compile loop
|
||||
attrs.$set('ngModelOptions', '{debounce: 1000}');
|
||||
$compile(element)(scope); // Double compilation
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
In that case, it is necessary to intercept the *initial* compilation of the element:
|
||||
|
||||
1. Give your directive the `terminal` property and a higher priority than directives
|
||||
that should not be compiled twice. In the example, the compiler will only compile directives
|
||||
which have a priority of 100 or higher.
|
||||
2. Inside this directive's compile function, add any other directive attributes to the template.
|
||||
3. Compile the element, but restrict the maximum priority, so that any already compiled directives
|
||||
(including the `addOptions` directive) are not compiled again.
|
||||
4. In the link function, link the compiled element with the element's scope.
|
||||
|
||||
```
|
||||
angular.module('app').directive('addOptions', function($compile) {
|
||||
return {
|
||||
priority: 100, // ngModel has priority 1
|
||||
terminal: true,
|
||||
compile: function(templateElement, templateAttributes) {
|
||||
templateAttributes.$set('ngModelOptions', '{debounce: 1000}');
|
||||
|
||||
// The third argument is the max priority. Only directives with priority < 100 will be compiled,
|
||||
// therefore we don't need to remove the attribute
|
||||
var compiled = $compile(templateElement, null, 100);
|
||||
|
||||
return function linkFn(scope) {
|
||||
compiled(scope) // Link compiled element to scope
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<div class="alert alert-warning">
|
||||
**Note:** this guide is targeted towards developers who are already familiar with AngularJS basics.
|
||||
If you're just getting started, we recommend the {@link tutorial/ tutorial} first.
|
||||
If you're looking for the **directives API**, we recently moved it to {@link ng.$compile `$compile`}.
|
||||
If you're looking for the **directives API**, you can find it in the
|
||||
{@link ng.$compile `$compile` API docs}.
|
||||
</div>
|
||||
|
||||
|
||||
@@ -58,7 +59,7 @@ The following `<input>` element also **matches** `ngModel`:
|
||||
<input data-ng-model="foo">
|
||||
```
|
||||
|
||||
And the following <person> element **matches** the `person` directive:
|
||||
And the following `<person>` element **matches** the `person` directive:
|
||||
|
||||
```html
|
||||
<person>{{name}}</person>
|
||||
@@ -335,9 +336,7 @@ Let's change our directive to use `restrict: 'E'`:
|
||||
</file>
|
||||
</example>
|
||||
|
||||
For more on the
|
||||
{@link ng.$compile#directive-definition-object `restrict`}
|
||||
property, see the
|
||||
For more on the `restrict` property, see the
|
||||
{@link ng.$compile#directive-definition-object API docs}.
|
||||
|
||||
<div class="alert alert-info">
|
||||
@@ -450,8 +449,8 @@ scope: {
|
||||
The **scope option** is an object that contains a property for each isolate scope binding. In this
|
||||
case it has just one property:
|
||||
|
||||
- Its name (`customerInfo`) corresponds to the
|
||||
directive's **isolate scope** property `customerInfo`.
|
||||
- Its name (`customerInfo`) corresponds to the directive's **isolate scope** property,
|
||||
`customerInfo`.
|
||||
- Its value (`=info`) tells `$compile` to bind to the `info` attribute.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
@@ -517,8 +516,8 @@ that you explicitly pass in.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** Normally, a scope prototypically inherits from its parent. An isolated scope does not.
|
||||
See the {@link $compile#directive-definition-object
|
||||
"Directive Definition Object - scope"} section for more information about isolate scopes.
|
||||
See the {@link $compile#directive-definition-object "Directive Definition Object - scope"} section
|
||||
for more information about isolate scopes.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success">
|
||||
|
||||
@@ -117,16 +117,17 @@ You can find a larger list of Angular external libraries at [ngmodules.org](http
|
||||
## General Learning Resources
|
||||
|
||||
### Books
|
||||
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
|
||||
* [Mastering Web App Development](http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821) by Pawel Kozlowski and Pete Bacon Darwin
|
||||
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
|
||||
* [Recipes With AngularJS](http://www.amazon.co.uk/Recipes-Angular-js-Frederik-Dietz-ebook/dp/B00DK95V48) by Frederik Dietz
|
||||
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
|
||||
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
|
||||
* [AngularJS Essentials (Free eBook)](https://www.packtpub.com/packt/free-ebook/angularjs-essentials) by Rodrigo Branas
|
||||
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
|
||||
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
|
||||
* [Responsive Web Design with AngularJS](http://www.amazon.com/Responsive-Design-AngularJS-Sandeep-Kumar/dp/178439842X) by Sandeep Kumar Patel
|
||||
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
|
||||
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
|
||||
* [Mastering Web App Development](http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821) by Pawel Kozlowski and Pete Bacon Darwin
|
||||
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
|
||||
* [Professional AngularJS](http://www.amazon.com/Professional-AngularJS-Valeri-Karpov/dp/1118832078/)
|
||||
* [Recipes With AngularJS](http://www.amazon.co.uk/Recipes-Angular-js-Frederik-Dietz-ebook/dp/B00DK95V48) by Frederik Dietz
|
||||
* [Responsive Web Design with AngularJS](http://www.amazon.com/Responsive-Design-AngularJS-Sandeep-Kumar/dp/178439842X) by Sandeep Kumar Patel
|
||||
|
||||
### Videos:
|
||||
* [egghead.io](http://egghead.io/)
|
||||
|
||||
+15
-5
@@ -169,6 +169,7 @@ var
|
||||
angularModule,
|
||||
uid = 0;
|
||||
|
||||
// Support: IE 9-11 only
|
||||
/**
|
||||
* documentMode is an IE-only property
|
||||
* http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
|
||||
@@ -1279,6 +1280,7 @@ function fromJson(json) {
|
||||
|
||||
var ALL_COLONS = /:/g;
|
||||
function timezoneToOffset(timezone, fallback) {
|
||||
// Support: IE 9-11 only, Edge 13-14+
|
||||
// IE/Edge do not "understand" colon (`:`) in timezone
|
||||
timezone = timezone.replace(ALL_COLONS, '');
|
||||
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
|
||||
@@ -1453,12 +1455,20 @@ function allowAutoBootstrap(document) {
|
||||
link.href = src;
|
||||
var scriptProtocol = link.protocol;
|
||||
var docLoadProtocol = document.location.protocol;
|
||||
if ((scriptProtocol === 'resource:' ||
|
||||
scriptProtocol === 'chrome-extension:') &&
|
||||
docLoadProtocol !== scriptProtocol) {
|
||||
return false;
|
||||
if (docLoadProtocol === scriptProtocol) {
|
||||
return true;
|
||||
}
|
||||
switch (scriptProtocol) {
|
||||
case 'http:':
|
||||
case 'https:':
|
||||
case 'ftp:':
|
||||
case 'blob:':
|
||||
case 'file:':
|
||||
case 'data:':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cached as it has to run during loading so that document.currentScript is available.
|
||||
|
||||
@@ -849,8 +849,9 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
}
|
||||
|
||||
function isClass(func) {
|
||||
// Support: IE 9-11 only
|
||||
// IE 9-11 do not support classes and IE9 leaks with the code below.
|
||||
if (msie <= 11 || typeof func !== 'function') {
|
||||
if (msie || typeof func !== 'function') {
|
||||
return false;
|
||||
}
|
||||
var result = func.$$ngIsClass;
|
||||
|
||||
@@ -943,6 +943,16 @@
|
||||
*
|
||||
* For information on how the compiler works, see the
|
||||
* {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
|
||||
*
|
||||
* @knownIssue
|
||||
*
|
||||
* ### Double Compilation
|
||||
*
|
||||
Double compilation occurs when an already compiled part of the DOM gets
|
||||
compiled again. This is an undesired effect and can lead to misbehaving directives, performance issues,
|
||||
and memory leaks. Refer to the Compiler Guide {@link guide/compiler#double-compilation-and-how-to-avoid-it
|
||||
section on double compilation} for an in-depth explanation and ways to avoid it.
|
||||
*
|
||||
*/
|
||||
|
||||
var $compileMinErr = minErr('$compile');
|
||||
@@ -1949,6 +1959,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
attrs = new Attributes();
|
||||
|
||||
// Support: IE 11 only
|
||||
// Workaround for #11781 and #14924
|
||||
if (msie === 11) {
|
||||
mergeConsecutiveTextNodes(nodeList, i, notLiveList);
|
||||
|
||||
@@ -61,7 +61,8 @@ function $ControllerProvider() {
|
||||
* @description If called, allows `$controller` to find controller constructors on `window`
|
||||
*
|
||||
* @deprecated
|
||||
* removeVersion="v1.7"
|
||||
* sinceVersion="v1.3.0"
|
||||
* removeVersion="v1.7.0"
|
||||
* This method of finding controllers has been deprecated.
|
||||
*/
|
||||
this.allowGlobals = function() {
|
||||
|
||||
@@ -426,10 +426,11 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
|
||||
|
||||
attr.$set(name, value);
|
||||
|
||||
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
|
||||
// Support: IE 9-11 only
|
||||
// On IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
|
||||
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
|
||||
// to set the property as well to achieve the desired effect.
|
||||
// we use attr[attrName] value since $set can sanitize the url.
|
||||
// We use attr[attrName] value since $set can sanitize the url.
|
||||
if (msie && propName) element.prop(propName, attr[name]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -115,8 +115,8 @@ var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
|
||||
}
|
||||
if (block) {
|
||||
previousElements = getBlockNodes(block.clone);
|
||||
$animate.leave(previousElements).then(function() {
|
||||
previousElements = null;
|
||||
$animate.leave(previousElements).done(function(response) {
|
||||
if (response !== false) previousElements = null;
|
||||
});
|
||||
block = null;
|
||||
}
|
||||
|
||||
@@ -214,8 +214,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
||||
currentScope = null;
|
||||
}
|
||||
if (currentElement) {
|
||||
$animate.leave(currentElement).then(function() {
|
||||
previousElement = null;
|
||||
$animate.leave(currentElement).done(function(response) {
|
||||
if (response !== false) previousElement = null;
|
||||
});
|
||||
previousElement = currentElement;
|
||||
currentElement = null;
|
||||
@@ -223,9 +223,10 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
||||
};
|
||||
|
||||
scope.$watch(srcExp, function ngIncludeWatchAction(src) {
|
||||
var afterAnimation = function() {
|
||||
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
var afterAnimation = function(response) {
|
||||
if (response !== false && isDefined(autoScrollExp) &&
|
||||
(!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
}
|
||||
};
|
||||
var thisChangeId = ++changeCounter;
|
||||
@@ -248,7 +249,7 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
||||
// directives to non existing elements.
|
||||
var clone = $transclude(newScope, function(clone) {
|
||||
cleanupLastIncludeContent();
|
||||
$animate.enter(clone, null, $element).then(afterAnimation);
|
||||
$animate.enter(clone, null, $element).done(afterAnimation);
|
||||
});
|
||||
|
||||
currentScope = newScope;
|
||||
|
||||
@@ -153,21 +153,24 @@ var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
|
||||
selectedScopes = [];
|
||||
|
||||
var spliceFactory = function(array, index) {
|
||||
return function() { array.splice(index, 1); };
|
||||
return function(response) {
|
||||
if (response !== false) array.splice(index, 1);
|
||||
};
|
||||
};
|
||||
|
||||
scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
|
||||
var i, ii;
|
||||
for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
|
||||
$animate.cancel(previousLeaveAnimations[i]);
|
||||
|
||||
// Start with the last, in case the array is modified during the loop
|
||||
while (previousLeaveAnimations.length) {
|
||||
$animate.cancel(previousLeaveAnimations.pop());
|
||||
}
|
||||
previousLeaveAnimations.length = 0;
|
||||
|
||||
for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
|
||||
var selected = getBlockNodes(selectedElements[i].clone);
|
||||
selectedScopes[i].$destroy();
|
||||
var promise = previousLeaveAnimations[i] = $animate.leave(selected);
|
||||
promise.then(spliceFactory(previousLeaveAnimations, i));
|
||||
var runner = previousLeaveAnimations[i] = $animate.leave(selected);
|
||||
runner.done(spliceFactory(previousLeaveAnimations, i));
|
||||
}
|
||||
|
||||
selectedElements.length = 0;
|
||||
|
||||
@@ -105,6 +105,7 @@ function $RootScopeProvider() {
|
||||
|
||||
function cleanUpScope($scope) {
|
||||
|
||||
// Support: IE 9 only
|
||||
if (msie === 9) {
|
||||
// There is a memory leak in IE9 if all child scopes are not disconnected
|
||||
// completely when a scope is destroyed. So this code will recurse up through
|
||||
|
||||
+3
-2
@@ -47,8 +47,8 @@ function adjustMatcher(matcher) {
|
||||
'Illegal sequence *** in string matcher. String: {0}', matcher);
|
||||
}
|
||||
matcher = escapeForRegexp(matcher).
|
||||
replace('\\*\\*', '.*').
|
||||
replace('\\*', '[^:/.?&;]*');
|
||||
replace(/\\\*\\\*/g, '.*').
|
||||
replace(/\\\*/g, '[^:/.?&;]*');
|
||||
return new RegExp('^' + matcher + '$');
|
||||
} else if (isRegExp(matcher)) {
|
||||
// The only other type of matcher allowed is a Regexp.
|
||||
@@ -748,6 +748,7 @@ function $SceProvider() {
|
||||
|
||||
this.$get = ['$parse', '$sceDelegate', function(
|
||||
$parse, $sceDelegate) {
|
||||
// Support: IE 9-11 only
|
||||
// Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow
|
||||
// the "expression(javascript expression)" syntax which is insecure.
|
||||
if (enabled && msie < 8) {
|
||||
|
||||
+2
-1
@@ -57,12 +57,13 @@ function $SnifferProvider() {
|
||||
// We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
|
||||
history: !!(hasHistoryPushState && !(android < 4) && !boxee),
|
||||
hasEvent: function(event) {
|
||||
// Support: IE 9-11 only
|
||||
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
|
||||
// it. In particular the event is not fired when backspace or delete key are pressed or
|
||||
// when cut operation is performed.
|
||||
// IE10+ implements 'input' event but it erroneously fires under various situations,
|
||||
// e.g. when placeholder changes, or a form is focused.
|
||||
if (event === 'input' && msie <= 11) return false;
|
||||
if (event === 'input' && msie) return false;
|
||||
|
||||
if (isUndefined(eventSupport[event])) {
|
||||
var divElm = document.createElement('div');
|
||||
|
||||
@@ -58,6 +58,7 @@ var originUrl = urlResolve(window.location.href);
|
||||
function urlResolve(url) {
|
||||
var href = url;
|
||||
|
||||
// Support: IE 9-11 only
|
||||
if (msie) {
|
||||
// Normalize before parse. Refer Implementation Notes on why this is
|
||||
// done in two steps on IE.
|
||||
|
||||
@@ -5,6 +5,7 @@ angular.module('ngCookies').
|
||||
* @ngdoc service
|
||||
* @name $cookieStore
|
||||
* @deprecated
|
||||
* sinceVersion="v1.4.0"
|
||||
* Please use the {@link ngCookies.$cookies `$cookies`} service instead.
|
||||
*
|
||||
* @requires $cookies
|
||||
|
||||
@@ -207,8 +207,8 @@ function ngViewFactory($route, $anchorScroll, $animate) {
|
||||
}
|
||||
if (currentElement) {
|
||||
previousLeaveAnimation = $animate.leave(currentElement);
|
||||
previousLeaveAnimation.then(function() {
|
||||
previousLeaveAnimation = null;
|
||||
previousLeaveAnimation.done(function(response) {
|
||||
if (response !== false) previousLeaveAnimation = null;
|
||||
});
|
||||
currentElement = null;
|
||||
}
|
||||
@@ -229,8 +229,8 @@ function ngViewFactory($route, $anchorScroll, $animate) {
|
||||
// function is called before linking the content, which would apply child
|
||||
// directives to non existing elements.
|
||||
var clone = $transclude(newScope, function(clone) {
|
||||
$animate.enter(clone, null, currentElement || $element).then(function onNgViewEnter() {
|
||||
if (angular.isDefined(autoScrollExp)
|
||||
$animate.enter(clone, null, currentElement || $element).done(function onNgViewEnter(response) {
|
||||
if (response !== false && angular.isDefined(autoScrollExp)
|
||||
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
}
|
||||
|
||||
@@ -201,6 +201,13 @@ angular.scenario.dsl('binding', function() {
|
||||
*/
|
||||
angular.scenario.dsl('input', function() {
|
||||
var chain = {};
|
||||
|
||||
// Support: IE 9-11 only
|
||||
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
|
||||
// it. In particular the event is not fired when backspace or delete key are pressed or
|
||||
// when cut operation is performed.
|
||||
// IE10+ implements 'input' event but it erroneously fires under various situations,
|
||||
// e.g. when placeholder changes, or a form is focused.
|
||||
var supportInputEvent = 'oninput' in window.document.createElement('div') && !msie;
|
||||
|
||||
chain.enter = function(value, event) {
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
* @ngdoc directive
|
||||
* @name ngClick
|
||||
* @deprecated
|
||||
* Beginning with Angular 1.5, this directive is deprecated and by default **disabled**.
|
||||
* sinceVersion="v1.5.0"
|
||||
* This directive is deprecated and **disabled** by default.
|
||||
* The directive will receive no further support and might be removed from future releases.
|
||||
* If you need the directive, you can enable it with the {@link ngTouch.$touchProvider $touchProvider#ngClickOverrideEnabled}
|
||||
* function. We also recommend that you migrate to [FastClick](https://github.com/ftlabs/fastclick).
|
||||
|
||||
@@ -357,8 +357,11 @@ beforeEach(function() {
|
||||
|
||||
toBeMarkedAsSelected: function() {
|
||||
// Selected is special because the element property and attribute reflect each other's state.
|
||||
|
||||
// Support: IE 9 only
|
||||
// IE9 will wrongly report hasAttribute('selected') === true when the property is
|
||||
// undefined or null, and the dev tools show that no attribute is set
|
||||
|
||||
return {
|
||||
compare: function(actual) {
|
||||
var errors = [];
|
||||
@@ -366,6 +369,7 @@ beforeEach(function() {
|
||||
errors.push('Expected option property "selected" to be truthy');
|
||||
}
|
||||
|
||||
// Support: IE 9 only
|
||||
if (msie !== 9 && actual.hasAttribute('selected') === false) {
|
||||
errors.push('Expected option to have attribute "selected"');
|
||||
}
|
||||
@@ -383,6 +387,7 @@ beforeEach(function() {
|
||||
errors.push('Expected option property "selected" to be falsy');
|
||||
}
|
||||
|
||||
// Support: IE 9 only
|
||||
if (msie !== 9 && actual.hasAttribute('selected')) {
|
||||
errors.push('Expected option not to have attribute "selected"');
|
||||
}
|
||||
|
||||
+13
-3
@@ -469,6 +469,10 @@ describe('$compile', function() {
|
||||
}));
|
||||
|
||||
// NOTE: This test may be redundant.
|
||||
// Support: Edge 14+
|
||||
// An `<svg>` element inside a `<foreignObject>` element on MS Edge has no
|
||||
// size, causing the included `<circle>` element to also have no size and thus fails an
|
||||
// assertion (relying on the element having a non-zero size).
|
||||
if (!isEdge) {
|
||||
it('should handle custom svg containers that transclude to foreignObject' +
|
||||
' that transclude to custom svg containers that transclude to custom elements', inject(function() {
|
||||
@@ -1127,7 +1131,8 @@ describe('$compile', function() {
|
||||
expect(element).toHaveClass('class_2');
|
||||
}));
|
||||
|
||||
if (!msie || msie > 11) {
|
||||
// Support: IE 9-11 only
|
||||
if (!msie) {
|
||||
// style interpolation not working on IE (including IE11).
|
||||
it('should handle interpolated css style from replacing directive', inject(
|
||||
function($compile, $rootScope) {
|
||||
@@ -10698,6 +10703,8 @@ describe('$compile', function() {
|
||||
expect(element.text()).toBe('102030');
|
||||
expect(newWatcherCount).toBe(3);
|
||||
|
||||
// Support: IE 11 only
|
||||
// See #11781 and #14924
|
||||
if (msie === 11) {
|
||||
expect(element.find('ng-transclude').contents().length).toBe(1);
|
||||
}
|
||||
@@ -10719,9 +10726,10 @@ describe('$compile', function() {
|
||||
expect(element.attr('src')).toEqual('http://example.com/image2.png');
|
||||
}));
|
||||
|
||||
// Support: IE 9 only
|
||||
// IE9 rejects the video / audio tag with "Error: Not implemented" and the source tag with
|
||||
// "Unable to get value of the property 'childNodes': object is null or undefined"
|
||||
if (!msie || msie > 9) {
|
||||
if (msie !== 9) {
|
||||
they('should NOT require trusted values for $prop src', ['video', 'audio'],
|
||||
function(tag) {
|
||||
inject(function($rootScope, $compile, $sce) {
|
||||
@@ -11154,7 +11162,9 @@ describe('$compile', function() {
|
||||
}));
|
||||
});
|
||||
|
||||
if (!msie || msie >= 11) {
|
||||
// Support: IE 9-10 only
|
||||
// IEs <11 don't support srcdoc
|
||||
if (!msie || msie === 11) {
|
||||
describe('iframe[srcdoc]', function() {
|
||||
it('should NOT set iframe contents for untrusted values', inject(function($compile, $rootScope, $sce) {
|
||||
element = $compile('<iframe srcdoc="{{html}}"></iframe>')($rootScope);
|
||||
|
||||
@@ -182,6 +182,7 @@ describe('ngSrc', function() {
|
||||
}));
|
||||
|
||||
|
||||
// Support: IE 9-11 only
|
||||
if (msie) {
|
||||
it('should update the element property as well as the attribute', inject(
|
||||
function($compile, $rootScope, $sce) {
|
||||
@@ -283,8 +284,9 @@ describe('ngHref', function() {
|
||||
expect(element.attr('href')).toEqual(undefined);
|
||||
}));
|
||||
|
||||
if (msie) {
|
||||
// IE11/10/Edge fail when setting a href to a URL containing a % that isn't a valid escape sequence
|
||||
// Support: IE 9-11 only, Edge 12-14+
|
||||
if (msie || /\bEdge\/[\d\.]+\b/.test(window.navigator.userAgent)) {
|
||||
// IE/Edge fail when setting a href to a URL containing a % that isn't a valid escape sequence
|
||||
// See https://github.com/angular/angular.js/issues/13388
|
||||
it('should throw error if ng-href contains a non-escaped percent symbol', inject(function($rootScope, $compile) {
|
||||
element = $compile('<a ng-href="http://www.google.com/{{\'a%link\'}}">')($rootScope);
|
||||
|
||||
@@ -135,6 +135,7 @@ describe('input', function() {
|
||||
|
||||
|
||||
describe('IE placeholder input events', function() {
|
||||
// Support: IE 9-11 only
|
||||
//IE fires an input event whenever a placeholder visually changes, essentially treating it as a value
|
||||
//Events:
|
||||
// placeholder attribute change: *input*
|
||||
|
||||
+364
-342
@@ -1,371 +1,393 @@
|
||||
'use strict';
|
||||
|
||||
describe('ngIf', function() {
|
||||
var $scope, $compile, element, $compileProvider;
|
||||
|
||||
beforeEach(module(function(_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
}));
|
||||
beforeEach(inject(function($rootScope, _$compile_) {
|
||||
$scope = $rootScope.$new();
|
||||
$compile = _$compile_;
|
||||
element = $compile('<div></div>')($scope);
|
||||
}));
|
||||
describe('basic', function() {
|
||||
var $scope, $compile, element, $compileProvider;
|
||||
|
||||
afterEach(function() {
|
||||
dealoc(element);
|
||||
});
|
||||
beforeEach(module(function(_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
}));
|
||||
beforeEach(inject(function($rootScope, _$compile_) {
|
||||
$scope = $rootScope.$new();
|
||||
$compile = _$compile_;
|
||||
element = $compile('<div></div>')($scope);
|
||||
}));
|
||||
|
||||
function makeIf() {
|
||||
forEach(arguments, function(expr) {
|
||||
element.append($compile('<div class="my-class" ng-if="' + expr + '"><div>Hi</div></div>')($scope));
|
||||
});
|
||||
$scope.$apply();
|
||||
}
|
||||
|
||||
it('should immediately remove the element if condition is falsy', function() {
|
||||
makeIf('false', 'undefined', 'null', 'NaN', '\'\'', '0');
|
||||
expect(element.children().length).toBe(0);
|
||||
});
|
||||
|
||||
it('should leave the element if condition is true', function() {
|
||||
makeIf('true');
|
||||
expect(element.children().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should leave the element if the condition is a non-empty string', function() {
|
||||
makeIf('\'f\'', '\'0\'', '\'false\'', '\'no\'', '\'n\'', '\'[]\'');
|
||||
expect(element.children().length).toBe(6);
|
||||
});
|
||||
|
||||
it('should leave the element if the condition is an object', function() {
|
||||
makeIf('[]', '{}');
|
||||
expect(element.children().length).toBe(2);
|
||||
});
|
||||
|
||||
it('should not add the element twice if the condition goes from true to true', function() {
|
||||
$scope.hello = 'true1';
|
||||
makeIf('hello');
|
||||
expect(element.children().length).toBe(1);
|
||||
$scope.$apply('hello = "true2"');
|
||||
expect(element.children().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should not recreate the element if the condition goes from true to true', function() {
|
||||
$scope.hello = 'true1';
|
||||
makeIf('hello');
|
||||
element.children().data('flag', true);
|
||||
$scope.$apply('hello = "true2"');
|
||||
expect(element.children().data('flag')).toBe(true);
|
||||
});
|
||||
|
||||
it('should create then remove the element if condition changes', function() {
|
||||
$scope.hello = true;
|
||||
makeIf('hello');
|
||||
expect(element.children().length).toBe(1);
|
||||
$scope.$apply('hello = false');
|
||||
expect(element.children().length).toBe(0);
|
||||
});
|
||||
|
||||
it('should create a new scope every time the expression evaluates to true', function() {
|
||||
$scope.$apply('value = true');
|
||||
element.append($compile(
|
||||
'<div ng-if="value"><span ng-init="value=false"></span></div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
expect(element.children('div').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should destroy the child scope every time the expression evaluates to false', function() {
|
||||
$scope.value = true;
|
||||
element.append($compile(
|
||||
'<div ng-if="value"></div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
|
||||
var childScope = element.children().scope();
|
||||
var destroyed = false;
|
||||
|
||||
childScope.$on('$destroy', function() {
|
||||
destroyed = true;
|
||||
});
|
||||
|
||||
$scope.value = false;
|
||||
$scope.$apply();
|
||||
|
||||
expect(destroyed).toBe(true);
|
||||
});
|
||||
|
||||
it('should play nice with other elements beside it', function() {
|
||||
$scope.values = [1, 2, 3, 4];
|
||||
element.append($compile(
|
||||
'<div ng-repeat="i in values"></div>' +
|
||||
'<div ng-if="values.length==4"></div>' +
|
||||
'<div ng-repeat="i in values"></div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
expect(element.children().length).toBe(9);
|
||||
$scope.$apply('values.splice(0,1)');
|
||||
expect(element.children().length).toBe(6);
|
||||
$scope.$apply('values.push(1)');
|
||||
expect(element.children().length).toBe(9);
|
||||
});
|
||||
|
||||
it('should play nice with ngInclude on the same element', inject(function($templateCache) {
|
||||
$templateCache.put('test.html', [200, '{{value}}', {}]);
|
||||
|
||||
$scope.value = 'first';
|
||||
element.append($compile(
|
||||
'<div ng-if="value==\'first\'" ng-include="\'test.html\'"></div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('first');
|
||||
|
||||
$scope.value = 'later';
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('');
|
||||
}));
|
||||
|
||||
it('should work with multiple elements', function() {
|
||||
$scope.show = true;
|
||||
$scope.things = [1, 2, 3];
|
||||
element.append($compile(
|
||||
'<div>before;</div>' +
|
||||
'<div ng-if-start="show">start;</div>' +
|
||||
'<div ng-repeat="thing in things">{{thing}};</div>' +
|
||||
'<div ng-if-end>end;</div>' +
|
||||
'<div>after;</div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('before;start;1;2;3;end;after;');
|
||||
|
||||
$scope.things.push(4);
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('before;start;1;2;3;4;end;after;');
|
||||
|
||||
$scope.show = false;
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('before;after;');
|
||||
});
|
||||
|
||||
it('should restore the element to its compiled state', function() {
|
||||
$scope.value = true;
|
||||
makeIf('value');
|
||||
expect(element.children().length).toBe(1);
|
||||
jqLite(element.children()[0]).removeClass('my-class');
|
||||
expect(element.children()[0].className).not.toContain('my-class');
|
||||
$scope.$apply('value = false');
|
||||
expect(element.children().length).toBe(0);
|
||||
$scope.$apply('value = true');
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.children()[0].className).toContain('my-class');
|
||||
});
|
||||
|
||||
it('should work when combined with an ASYNC template that loads after the first digest', inject(function($httpBackend, $compile, $rootScope) {
|
||||
$compileProvider.directive('test', function() {
|
||||
return {
|
||||
templateUrl: 'test.html'
|
||||
};
|
||||
});
|
||||
$httpBackend.whenGET('test.html').respond('hello');
|
||||
element.append('<div ng-if="show" test></div>');
|
||||
$compile(element)($rootScope);
|
||||
$rootScope.show = true;
|
||||
$rootScope.$apply();
|
||||
expect(element.text()).toBe('');
|
||||
|
||||
$httpBackend.flush();
|
||||
expect(element.text()).toBe('hello');
|
||||
|
||||
$rootScope.show = false;
|
||||
$rootScope.$apply();
|
||||
// Note: there are still comments in element!
|
||||
expect(element.children().length).toBe(0);
|
||||
expect(element.text()).toBe('');
|
||||
}));
|
||||
});
|
||||
|
||||
describe('ngIf and transcludes', function() {
|
||||
it('should allow access to directive controller from children when used in a replace template', function() {
|
||||
var controller;
|
||||
module(function($compileProvider) {
|
||||
var directive = $compileProvider.directive;
|
||||
directive('template', valueFn({
|
||||
template: '<div ng-if="true"><span test></span></div>',
|
||||
replace: true,
|
||||
controller: function() {
|
||||
this.flag = true;
|
||||
}
|
||||
}));
|
||||
directive('test', valueFn({
|
||||
require: '^template',
|
||||
link: function(scope, el, attr, ctrl) {
|
||||
controller = ctrl;
|
||||
}
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
var element = $compile('<div><div template></div></div>')($rootScope);
|
||||
$rootScope.$apply();
|
||||
expect(controller.flag).toBe(true);
|
||||
afterEach(function() {
|
||||
dealoc(element);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should use the correct transcluded scope', function() {
|
||||
module(function($compileProvider) {
|
||||
$compileProvider.directive('iso', valueFn({
|
||||
link: function(scope) {
|
||||
scope.val = 'value in iso scope';
|
||||
},
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
template: '<div ng-if="true">val={{val}}-<div ng-transclude></div></div>',
|
||||
scope: {}
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
$rootScope.val = 'transcluded content';
|
||||
var element = $compile('<iso><span ng-bind="val"></span></iso>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(trim(element.text())).toEqual('val=value in iso scope-transcluded content');
|
||||
dealoc(element);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ngIf animations', function() {
|
||||
var body, element, $rootElement;
|
||||
|
||||
function html(content) {
|
||||
$rootElement.html(content);
|
||||
element = $rootElement.children().eq(0);
|
||||
return element;
|
||||
}
|
||||
|
||||
beforeEach(module('ngAnimateMock'));
|
||||
|
||||
beforeEach(module(function() {
|
||||
// we need to run animation on attached elements;
|
||||
return function(_$rootElement_) {
|
||||
$rootElement = _$rootElement_;
|
||||
body = jqLite(window.document.body);
|
||||
body.append($rootElement);
|
||||
};
|
||||
}));
|
||||
|
||||
afterEach(function() {
|
||||
dealoc(body);
|
||||
dealoc(element);
|
||||
});
|
||||
|
||||
beforeEach(module(function($animateProvider, $provide) {
|
||||
return function($animate) {
|
||||
$animate.enabled(true);
|
||||
};
|
||||
}));
|
||||
|
||||
it('should fire off the enter animation',
|
||||
inject(function($compile, $rootScope, $animate) {
|
||||
var item;
|
||||
var $scope = $rootScope.$new();
|
||||
element = $compile(html(
|
||||
'<div>' +
|
||||
'<div ng-if="value"><div>Hi</div></div>' +
|
||||
'</div>'
|
||||
))($scope);
|
||||
|
||||
$rootScope.$digest();
|
||||
$scope.$apply('value = true');
|
||||
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('enter');
|
||||
expect(item.element.text()).toBe('Hi');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
})
|
||||
);
|
||||
|
||||
it('should fire off the leave animation',
|
||||
inject(function($compile, $rootScope, $animate) {
|
||||
var item;
|
||||
var $scope = $rootScope.$new();
|
||||
element = $compile(html(
|
||||
'<div>' +
|
||||
'<div ng-if="value"><div>Hi</div></div>' +
|
||||
'</div>'
|
||||
))($scope);
|
||||
$scope.$apply('value = true');
|
||||
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('enter');
|
||||
expect(item.element.text()).toBe('Hi');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
$scope.$apply('value = false');
|
||||
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('leave');
|
||||
expect(item.element.text()).toBe('Hi');
|
||||
|
||||
expect(element.children().length).toBe(0);
|
||||
})
|
||||
);
|
||||
|
||||
it('should destroy the previous leave animation if a new one takes place', function() {
|
||||
module(function($provide) {
|
||||
$provide.decorator('$animate', function($delegate, $$q) {
|
||||
var emptyPromise = $$q.defer().promise;
|
||||
$delegate.leave = function() {
|
||||
return emptyPromise;
|
||||
};
|
||||
return $delegate;
|
||||
function makeIf() {
|
||||
forEach(arguments, function(expr) {
|
||||
element.append($compile('<div class="my-class" ng-if="' + expr + '"><div>Hi</div></div>')($scope));
|
||||
});
|
||||
$scope.$apply();
|
||||
}
|
||||
|
||||
it('should immediately remove the element if condition is falsy', function() {
|
||||
makeIf('false', 'undefined', 'null', 'NaN', '\'\'', '0');
|
||||
expect(element.children().length).toBe(0);
|
||||
});
|
||||
inject(function($compile, $rootScope, $animate) {
|
||||
var item;
|
||||
var $scope = $rootScope.$new();
|
||||
element = $compile(html(
|
||||
'<div>' +
|
||||
'<div ng-if="value">Yo</div>' +
|
||||
'</div>'
|
||||
))($scope);
|
||||
|
||||
it('should leave the element if condition is true', function() {
|
||||
makeIf('true');
|
||||
expect(element.children().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should leave the element if the condition is a non-empty string', function() {
|
||||
makeIf('\'f\'', '\'0\'', '\'false\'', '\'no\'', '\'n\'', '\'[]\'');
|
||||
expect(element.children().length).toBe(6);
|
||||
});
|
||||
|
||||
it('should leave the element if the condition is an object', function() {
|
||||
makeIf('[]', '{}');
|
||||
expect(element.children().length).toBe(2);
|
||||
});
|
||||
|
||||
it('should not add the element twice if the condition goes from true to true', function() {
|
||||
$scope.hello = 'true1';
|
||||
makeIf('hello');
|
||||
expect(element.children().length).toBe(1);
|
||||
$scope.$apply('hello = "true2"');
|
||||
expect(element.children().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should not recreate the element if the condition goes from true to true', function() {
|
||||
$scope.hello = 'true1';
|
||||
makeIf('hello');
|
||||
element.children().data('flag', true);
|
||||
$scope.$apply('hello = "true2"');
|
||||
expect(element.children().data('flag')).toBe(true);
|
||||
});
|
||||
|
||||
it('should create then remove the element if condition changes', function() {
|
||||
$scope.hello = true;
|
||||
makeIf('hello');
|
||||
expect(element.children().length).toBe(1);
|
||||
$scope.$apply('hello = false');
|
||||
expect(element.children().length).toBe(0);
|
||||
});
|
||||
|
||||
it('should create a new scope every time the expression evaluates to true', function() {
|
||||
$scope.$apply('value = true');
|
||||
element.append($compile(
|
||||
'<div ng-if="value"><span ng-init="value=false"></span></div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
expect(element.children('div').length).toBe(1);
|
||||
});
|
||||
|
||||
var destroyed, inner = element.children(0);
|
||||
inner.on('$destroy', function() {
|
||||
it('should destroy the child scope every time the expression evaluates to false', function() {
|
||||
$scope.value = true;
|
||||
element.append($compile(
|
||||
'<div ng-if="value"></div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
|
||||
var childScope = element.children().scope();
|
||||
var destroyed = false;
|
||||
|
||||
childScope.$on('$destroy', function() {
|
||||
destroyed = true;
|
||||
});
|
||||
|
||||
$scope.$apply('value = false');
|
||||
|
||||
$scope.$apply('value = true');
|
||||
|
||||
$scope.$apply('value = false');
|
||||
$scope.value = false;
|
||||
$scope.$apply();
|
||||
|
||||
expect(destroyed).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with svg elements when the svg container is transcluded', function() {
|
||||
module(function($compileProvider) {
|
||||
$compileProvider.directive('svgContainer', function() {
|
||||
it('should play nice with other elements beside it', function() {
|
||||
$scope.values = [1, 2, 3, 4];
|
||||
element.append($compile(
|
||||
'<div ng-repeat="i in values"></div>' +
|
||||
'<div ng-if="values.length==4"></div>' +
|
||||
'<div ng-repeat="i in values"></div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
expect(element.children().length).toBe(9);
|
||||
$scope.$apply('values.splice(0,1)');
|
||||
expect(element.children().length).toBe(6);
|
||||
$scope.$apply('values.push(1)');
|
||||
expect(element.children().length).toBe(9);
|
||||
});
|
||||
|
||||
it('should play nice with ngInclude on the same element', inject(function($templateCache) {
|
||||
$templateCache.put('test.html', [200, '{{value}}', {}]);
|
||||
|
||||
$scope.value = 'first';
|
||||
element.append($compile(
|
||||
'<div ng-if="value==\'first\'" ng-include="\'test.html\'"></div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('first');
|
||||
|
||||
$scope.value = 'later';
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('');
|
||||
}));
|
||||
|
||||
it('should work with multiple elements', function() {
|
||||
$scope.show = true;
|
||||
$scope.things = [1, 2, 3];
|
||||
element.append($compile(
|
||||
'<div>before;</div>' +
|
||||
'<div ng-if-start="show">start;</div>' +
|
||||
'<div ng-repeat="thing in things">{{thing}};</div>' +
|
||||
'<div ng-if-end>end;</div>' +
|
||||
'<div>after;</div>'
|
||||
)($scope));
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('before;start;1;2;3;end;after;');
|
||||
|
||||
$scope.things.push(4);
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('before;start;1;2;3;4;end;after;');
|
||||
|
||||
$scope.show = false;
|
||||
$scope.$apply();
|
||||
expect(element.text()).toBe('before;after;');
|
||||
});
|
||||
|
||||
it('should restore the element to its compiled state', function() {
|
||||
$scope.value = true;
|
||||
makeIf('value');
|
||||
expect(element.children().length).toBe(1);
|
||||
jqLite(element.children()[0]).removeClass('my-class');
|
||||
expect(element.children()[0].className).not.toContain('my-class');
|
||||
$scope.$apply('value = false');
|
||||
expect(element.children().length).toBe(0);
|
||||
$scope.$apply('value = true');
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.children()[0].className).toContain('my-class');
|
||||
});
|
||||
|
||||
it('should work when combined with an ASYNC template that loads after the first digest', inject(function($httpBackend, $compile, $rootScope) {
|
||||
$compileProvider.directive('test', function() {
|
||||
return {
|
||||
template: '<svg ng-transclude></svg>',
|
||||
replace: true,
|
||||
transclude: true
|
||||
templateUrl: 'test.html'
|
||||
};
|
||||
});
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
element = $compile('<svg-container><circle ng-if="flag"></circle></svg-container>')($rootScope);
|
||||
$rootScope.flag = true;
|
||||
$httpBackend.whenGET('test.html').respond('hello');
|
||||
element.append('<div ng-if="show" test></div>');
|
||||
$compile(element)($rootScope);
|
||||
$rootScope.show = true;
|
||||
$rootScope.$apply();
|
||||
expect(element.text()).toBe('');
|
||||
|
||||
var circle = element.find('circle');
|
||||
expect(circle[0].toString()).toMatch(/SVG/);
|
||||
$httpBackend.flush();
|
||||
expect(element.text()).toBe('hello');
|
||||
|
||||
$rootScope.show = false;
|
||||
$rootScope.$apply();
|
||||
// Note: there are still comments in element!
|
||||
expect(element.children().length).toBe(0);
|
||||
expect(element.text()).toBe('');
|
||||
}));
|
||||
|
||||
it('should not trigger a digest when the element is removed', inject(function($$rAF, $rootScope, $timeout) {
|
||||
var spy = spyOn($rootScope, '$digest').and.callThrough();
|
||||
|
||||
$scope.hello = true;
|
||||
makeIf('hello');
|
||||
expect(element.children().length).toBe(1);
|
||||
$scope.$apply('hello = false');
|
||||
spy.calls.reset();
|
||||
expect(element.children().length).toBe(0);
|
||||
// The animation completion is async even without actual animations
|
||||
$$rAF.flush();
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
// A digest may have been triggered asynchronously, so check the queue
|
||||
$timeout.verifyNoPendingTasks();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('and transcludes', function() {
|
||||
it('should allow access to directive controller from children when used in a replace template', function() {
|
||||
var controller;
|
||||
module(function($compileProvider) {
|
||||
var directive = $compileProvider.directive;
|
||||
directive('template', valueFn({
|
||||
template: '<div ng-if="true"><span test></span></div>',
|
||||
replace: true,
|
||||
controller: function() {
|
||||
this.flag = true;
|
||||
}
|
||||
}));
|
||||
directive('test', valueFn({
|
||||
require: '^template',
|
||||
link: function(scope, el, attr, ctrl) {
|
||||
controller = ctrl;
|
||||
}
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
var element = $compile('<div><div template></div></div>')($rootScope);
|
||||
$rootScope.$apply();
|
||||
expect(controller.flag).toBe(true);
|
||||
dealoc(element);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should use the correct transcluded scope', function() {
|
||||
module(function($compileProvider) {
|
||||
$compileProvider.directive('iso', valueFn({
|
||||
link: function(scope) {
|
||||
scope.val = 'value in iso scope';
|
||||
},
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
template: '<div ng-if="true">val={{val}}-<div ng-transclude></div></div>',
|
||||
scope: {}
|
||||
}));
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
$rootScope.val = 'transcluded content';
|
||||
var element = $compile('<iso><span ng-bind="val"></span></iso>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(trim(element.text())).toEqual('val=value in iso scope-transcluded content');
|
||||
dealoc(element);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('and animations', function() {
|
||||
var body, element, $rootElement;
|
||||
|
||||
function html(content) {
|
||||
$rootElement.html(content);
|
||||
element = $rootElement.children().eq(0);
|
||||
return element;
|
||||
}
|
||||
|
||||
beforeEach(module('ngAnimateMock'));
|
||||
|
||||
beforeEach(module(function() {
|
||||
// we need to run animation on attached elements;
|
||||
return function(_$rootElement_) {
|
||||
$rootElement = _$rootElement_;
|
||||
body = jqLite(window.document.body);
|
||||
body.append($rootElement);
|
||||
};
|
||||
}));
|
||||
|
||||
afterEach(function() {
|
||||
dealoc(body);
|
||||
dealoc(element);
|
||||
});
|
||||
|
||||
beforeEach(module(function($animateProvider, $provide) {
|
||||
return function($animate) {
|
||||
$animate.enabled(true);
|
||||
};
|
||||
}));
|
||||
|
||||
it('should fire off the enter animation',
|
||||
inject(function($compile, $rootScope, $animate) {
|
||||
var item;
|
||||
var $scope = $rootScope.$new();
|
||||
element = $compile(html(
|
||||
'<div>' +
|
||||
'<div ng-if="value"><div>Hi</div></div>' +
|
||||
'</div>'
|
||||
))($scope);
|
||||
|
||||
$rootScope.$digest();
|
||||
$scope.$apply('value = true');
|
||||
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('enter');
|
||||
expect(item.element.text()).toBe('Hi');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
})
|
||||
);
|
||||
|
||||
it('should fire off the leave animation',
|
||||
inject(function($compile, $rootScope, $animate) {
|
||||
var item;
|
||||
var $scope = $rootScope.$new();
|
||||
element = $compile(html(
|
||||
'<div>' +
|
||||
'<div ng-if="value"><div>Hi</div></div>' +
|
||||
'</div>'
|
||||
))($scope);
|
||||
$scope.$apply('value = true');
|
||||
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('enter');
|
||||
expect(item.element.text()).toBe('Hi');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
$scope.$apply('value = false');
|
||||
|
||||
item = $animate.queue.shift();
|
||||
expect(item.event).toBe('leave');
|
||||
expect(item.element.text()).toBe('Hi');
|
||||
|
||||
expect(element.children().length).toBe(0);
|
||||
})
|
||||
);
|
||||
|
||||
it('should destroy the previous leave animation if a new one takes place', function() {
|
||||
module(function($provide) {
|
||||
$provide.decorator('$animate', function($delegate, $$q) {
|
||||
var emptyPromise = $$q.defer().promise;
|
||||
emptyPromise.done = noop;
|
||||
|
||||
$delegate.leave = function() {
|
||||
return emptyPromise;
|
||||
};
|
||||
return $delegate;
|
||||
});
|
||||
});
|
||||
inject(function($compile, $rootScope, $animate) {
|
||||
var item;
|
||||
var $scope = $rootScope.$new();
|
||||
element = $compile(html(
|
||||
'<div>' +
|
||||
'<div ng-if="value">Yo</div>' +
|
||||
'</div>'
|
||||
))($scope);
|
||||
|
||||
$scope.$apply('value = true');
|
||||
|
||||
var destroyed, inner = element.children(0);
|
||||
inner.on('$destroy', function() {
|
||||
destroyed = true;
|
||||
});
|
||||
|
||||
$scope.$apply('value = false');
|
||||
|
||||
$scope.$apply('value = true');
|
||||
|
||||
$scope.$apply('value = false');
|
||||
|
||||
expect(destroyed).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with svg elements when the svg container is transcluded', function() {
|
||||
module(function($compileProvider) {
|
||||
$compileProvider.directive('svgContainer', function() {
|
||||
return {
|
||||
template: '<svg ng-transclude></svg>',
|
||||
replace: true,
|
||||
transclude: true
|
||||
};
|
||||
});
|
||||
});
|
||||
inject(function($compile, $rootScope) {
|
||||
element = $compile('<svg-container><circle ng-if="flag"></circle></svg-container>')($rootScope);
|
||||
$rootScope.flag = true;
|
||||
$rootScope.$apply();
|
||||
|
||||
var circle = element.find('circle');
|
||||
expect(circle[0].toString()).toMatch(/SVG/);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+741
-708
File diff suppressed because it is too large
Load Diff
@@ -54,12 +54,14 @@ describe('ngSwitch', function() {
|
||||
$rootScope.name = 'shyam';
|
||||
$rootScope.$apply();
|
||||
expect(element.text()).toEqual('first:shyam, first too:shyam');
|
||||
|
||||
$rootScope.select = 2;
|
||||
$rootScope.$apply();
|
||||
expect(element.text()).toEqual('second:shyam');
|
||||
$rootScope.name = 'misko';
|
||||
$rootScope.$apply();
|
||||
expect(element.text()).toEqual('second:misko');
|
||||
|
||||
$rootScope.select = true;
|
||||
$rootScope.$apply();
|
||||
expect(element.text()).toEqual('true:misko');
|
||||
@@ -301,7 +303,66 @@ describe('ngSwitch', function() {
|
||||
}));
|
||||
|
||||
|
||||
it('should not trigger a digest after an element is removed', inject(function($$rAF, $compile, $rootScope, $timeout) {
|
||||
var spy = spyOn($rootScope, '$digest').and.callThrough();
|
||||
|
||||
$rootScope.select = 1;
|
||||
element = $compile(
|
||||
'<div ng-switch="select">' +
|
||||
'<div ng-switch-when="1">first</div>' +
|
||||
'<div ng-switch-when="2">second</div>' +
|
||||
'</div>')($rootScope);
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(element.text()).toEqual('first');
|
||||
|
||||
$rootScope.select = 2;
|
||||
$rootScope.$apply();
|
||||
spy.calls.reset();
|
||||
expect(element.text()).toEqual('second');
|
||||
// If ngSwitch re-introduces code that triggers a digest after an element is removed (in an
|
||||
// animation .then callback), flushing the queue ensures the callback will be called, and the test
|
||||
// fails
|
||||
$$rAF.flush();
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
// A digest may have been triggered asynchronously, so check the queue
|
||||
$timeout.verifyNoPendingTasks();
|
||||
}));
|
||||
|
||||
|
||||
it('should handle changes to the switch value in a digest loop with multiple value matches',
|
||||
inject(function($compile, $rootScope) {
|
||||
var scope = $rootScope.$new();
|
||||
scope.value = 'foo';
|
||||
|
||||
scope.$watch('value', function() {
|
||||
if (scope.value === 'bar') {
|
||||
scope.$evalAsync(function() {
|
||||
scope.value = 'baz';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
element = $compile(
|
||||
'<div ng-switch="value">' +
|
||||
'<div ng-switch-when="foo">FOO 1</div>' +
|
||||
'<div ng-switch-when="foo">FOO 2</div>' +
|
||||
'<div ng-switch-when="bar">BAR</div>' +
|
||||
'<div ng-switch-when="baz">BAZ</div>' +
|
||||
'</div>')(scope);
|
||||
|
||||
scope.$apply();
|
||||
expect(element.text()).toBe('FOO 1FOO 2');
|
||||
|
||||
scope.$apply('value = "bar"');
|
||||
expect(element.text()).toBe('BAZ');
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
describe('ngSwitchWhen separator', function() {
|
||||
|
||||
it('should be possible to define a separator', inject(function($rootScope, $compile) {
|
||||
element = $compile(
|
||||
'<div ng-switch="mode">' +
|
||||
@@ -315,9 +376,11 @@ describe('ngSwitch', function() {
|
||||
expect(element.children().length).toBe(2);
|
||||
expect(element.text()).toBe('Block1|Block2|');
|
||||
$rootScope.$apply('mode = "b"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block1|');
|
||||
$rootScope.$apply('mode = "c"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block3|');
|
||||
}));
|
||||
@@ -336,9 +399,11 @@ describe('ngSwitch', function() {
|
||||
expect(element.children().length).toBe(2);
|
||||
expect(element.text()).toBe('Block1|Block2|');
|
||||
$rootScope.$apply('mode = ""');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block1|');
|
||||
$rootScope.$apply('mode = "c"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block3|');
|
||||
}));
|
||||
@@ -357,9 +422,11 @@ describe('ngSwitch', function() {
|
||||
expect(element.children().length).toBe(2);
|
||||
expect(element.text()).toBe('Block1|Block2|');
|
||||
$rootScope.$apply('mode = "b"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block1|');
|
||||
$rootScope.$apply('mode = "c"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block3|');
|
||||
}));
|
||||
@@ -378,9 +445,11 @@ describe('ngSwitch', function() {
|
||||
expect(element.children().length).toBe(2);
|
||||
expect(element.text()).toBe('Block1|Block2|');
|
||||
$rootScope.$apply('mode = "b|a"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block1|');
|
||||
$rootScope.$apply('mode = "c"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block3|');
|
||||
}));
|
||||
@@ -399,9 +468,11 @@ describe('ngSwitch', function() {
|
||||
expect(element.children().length).toBe(2);
|
||||
expect(element.text()).toBe('Block1|Block2|');
|
||||
$rootScope.$apply('mode = "b"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block1|');
|
||||
$rootScope.$apply('mode = "c"');
|
||||
|
||||
expect(element.children().length).toBe(1);
|
||||
expect(element.text()).toBe('Block3|');
|
||||
}));
|
||||
|
||||
+10
-6
@@ -39,8 +39,11 @@ describe('$location', function() {
|
||||
/* global urlParsingNode: true */
|
||||
var urlParsingNodePlaceholder;
|
||||
|
||||
beforeEach(inject(function($sniffer) {
|
||||
if (msie) return;
|
||||
beforeEach(function() {
|
||||
// Support: non-Windows browsers
|
||||
// These tests expect a Windows environment which we can only guarantee
|
||||
// on IE & Edge.
|
||||
if (msie || /\bEdge\/[\d\.]+\b/.test(window.navigator.userAgent)) return;
|
||||
|
||||
urlParsingNodePlaceholder = urlParsingNode;
|
||||
|
||||
@@ -57,13 +60,14 @@ describe('$location', function() {
|
||||
search: '',
|
||||
setAttribute: angular.noop
|
||||
};
|
||||
}));
|
||||
});
|
||||
|
||||
afterEach(inject(function($sniffer) {
|
||||
if (msie) return;
|
||||
afterEach(function() {
|
||||
// Support: non-Windows browsers
|
||||
if (msie || /\bEdge\/[\d\.]+\b/.test(window.navigator.userAgent)) return;
|
||||
//reset urlParsingNode
|
||||
urlParsingNode = urlParsingNodePlaceholder;
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
it('should not include the drive name in path() on WIN', function() {
|
||||
|
||||
@@ -2180,8 +2180,9 @@ describe('parser', function() {
|
||||
expect(scope.$eval('getter()()')).toBe(33);
|
||||
});
|
||||
|
||||
// Support: IE 9 only
|
||||
// There is no "strict mode" in IE9
|
||||
if (!msie || msie > 9) {
|
||||
if (msie !== 9) {
|
||||
it('should set no context to functions returned by other functions', function() {
|
||||
scope.getter = function() { return function() { expect(this).toBeUndefined(); }; };
|
||||
scope.$eval('getter()()');
|
||||
|
||||
@@ -13,9 +13,7 @@ describe('Scope', function() {
|
||||
|
||||
|
||||
it('should expose the constructor', inject(function($rootScope) {
|
||||
if (msie < 11) return;
|
||||
// eslint-disable-next-line no-proto
|
||||
expect($rootScope.__proto__).toBe($rootScope.constructor.prototype);
|
||||
expect(Object.getPrototypeOf($rootScope)).toBe($rootScope.constructor.prototype);
|
||||
}));
|
||||
|
||||
|
||||
@@ -125,7 +123,9 @@ describe('Scope', function() {
|
||||
function Listener() {
|
||||
expect(this).toBeUndefined();
|
||||
}
|
||||
if (msie < 10) return;
|
||||
// Support: IE 9 only
|
||||
// IE 9 doesn't support strict mode so its `this` will always be defined.
|
||||
if (msie === 9) return;
|
||||
$rootScope.$watch(Getter, Listener);
|
||||
$rootScope.$digest();
|
||||
}));
|
||||
@@ -1227,6 +1227,7 @@ describe('Scope', function() {
|
||||
}));
|
||||
|
||||
|
||||
// Support: IE 9 only
|
||||
if (msie === 9) {
|
||||
// See issue https://github.com/angular/angular.js/issues/10706
|
||||
it('should completely disconnect all child scopes on IE9', inject(function($rootScope) {
|
||||
|
||||
@@ -334,6 +334,10 @@ describe('SCE', function() {
|
||||
expect(adjustMatcher(/^a.*b$/).exec('a.b')).not.toBeNull();
|
||||
expect(adjustMatcher(/^a.*b$/).exec('-a.b-')).toBeNull();
|
||||
});
|
||||
|
||||
it('should should match * and **', function() {
|
||||
expect(adjustMatcher('*://*.example.com/**').exec('http://www.example.com/path')).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('regex matcher', function() {
|
||||
|
||||
@@ -153,11 +153,12 @@ describe('$sniffer', function() {
|
||||
|
||||
|
||||
it('should claim that IE9 doesn\'t have support for "oninput"', function() {
|
||||
// Support: IE 9-11 only
|
||||
// IE9 implementation is fubared, so it's better to pretend that it doesn't have the support
|
||||
// IE10+ implementation is fubared when mixed with placeholders
|
||||
mockDivElement = {oninput: noop};
|
||||
|
||||
expect($sniffer.hasEvent('input')).toBe(!(msie && msie <= 11));
|
||||
expect($sniffer.hasEvent('input')).toBe(!msie);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -327,8 +327,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
inject(function($animateCss) {
|
||||
|
||||
element.attr('style', '');
|
||||
ss.addRule('.ng-enter', '-webkit-animation:1.5s keyframe_animation;' +
|
||||
'animation:1.5s keyframe_animation;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:1.5s keyframe_animation;');
|
||||
|
||||
animator = $animateCss(element, {
|
||||
event: 'enter',
|
||||
@@ -348,8 +347,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
inject(function($animateCss) {
|
||||
|
||||
element.attr('style', '');
|
||||
ss.addRule('.ng-enter', '-webkit-animation:1.5s keyframe_animation;' +
|
||||
'animation:1.5s keyframe_animation;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:1.5s keyframe_animation;');
|
||||
|
||||
animator = $animateCss(element, {
|
||||
event: 'enter',
|
||||
@@ -478,8 +476,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
});
|
||||
|
||||
it('should use the highest transition duration value detected in the CSS class', inject(function($animateCss) {
|
||||
ss.addRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-duration:10s, 15s, 20s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-duration:10s, 15s, 20s;');
|
||||
|
||||
var animator = $animateCss(element, options);
|
||||
animator.start();
|
||||
@@ -497,8 +495,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
}));
|
||||
|
||||
it('should use the highest transition delay value detected in the CSS class', inject(function($animateCss) {
|
||||
ss.addRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-delay:10s, 15s, 20s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-delay:10s, 15s, 20s;');
|
||||
|
||||
var animator = $animateCss(element, options);
|
||||
animator.start();
|
||||
@@ -518,7 +516,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should only close when both the animation delay and duration have passed',
|
||||
inject(function($animateCss) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition:10s 5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:10s 5s linear all;');
|
||||
|
||||
var animator = $animateCss(element, options);
|
||||
animator.start();
|
||||
@@ -535,8 +533,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
}));
|
||||
|
||||
it('should use the highest keyframe duration value detected in the CSS class', inject(function($animateCss) {
|
||||
ss.addRule('.ng-enter', 'animation:animation 1s, animation 2s, animation 3s;' +
|
||||
'-webkit-animation:animation 1s, animation 2s, animation 3s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:animation 1s, animation 2s, animation 3s;');
|
||||
|
||||
var animator = $animateCss(element, options);
|
||||
animator.start();
|
||||
@@ -554,8 +551,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
}));
|
||||
|
||||
it('should use the highest keyframe delay value detected in the CSS class', inject(function($animateCss) {
|
||||
ss.addRule('.ng-enter', 'animation:animation 1s 2s, animation 1s 10s, animation 1s 1000ms;' +
|
||||
'-webkit-animation:animation 1s 2s, animation 1s 10s, animation 1s 1000ms;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:animation 1s 2s, animation 1s 10s, animation 1s 1000ms;');
|
||||
|
||||
var animator = $animateCss(element, options);
|
||||
animator.start();
|
||||
@@ -573,9 +569,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
}));
|
||||
|
||||
it('should use the highest keyframe duration value detected in the CSS class with respect to the animation-iteration-count property', inject(function($animateCss) {
|
||||
ss.addRule('.ng-enter',
|
||||
'animation:animation 1s 2s 3, animation 1s 10s 2, animation 1s 1000ms infinite;' +
|
||||
'-webkit-animation:animation 1s 2s 3, animation 1s 10s 2, animation 1s 1000ms infinite;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter',
|
||||
'animation:animation 1s 2s 3, animation 1s 10s 2, animation 1s 1000ms infinite;');
|
||||
|
||||
var animator = $animateCss(element, options);
|
||||
animator.start();
|
||||
@@ -593,10 +588,9 @@ describe('ngAnimate $animateCss', function() {
|
||||
}));
|
||||
|
||||
it('should use the highest duration value when both transitions and keyframes are used', inject(function($animateCss) {
|
||||
ss.addRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-duration:10s, 15s, 20s;' +
|
||||
'animation:animation 1s, animation 2s, animation 3s 0s 7;' +
|
||||
'-webkit-animation:animation 1s, animation 2s, animation 3s 0s 7;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-duration:10s, 15s, 20s;' +
|
||||
'animation:animation 1s, animation 2s, animation 3s 0s 7;');
|
||||
|
||||
var animator = $animateCss(element, options);
|
||||
animator.start();
|
||||
@@ -622,10 +616,9 @@ describe('ngAnimate $animateCss', function() {
|
||||
}));
|
||||
|
||||
it('should use the highest delay value when both transitions and keyframes are used', inject(function($animateCss) {
|
||||
ss.addRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-delay:10s, 15s, 20s;' +
|
||||
'animation:animation 1s 2s, animation 1s 16s, animation 1s 19s;' +
|
||||
'-webkit-animation:animation 1s 2s, animation 1s 16s, animation 1s 19s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-delay:10s, 15s, 20s;' +
|
||||
'animation:animation 1s 2s, animation 1s 16s, animation 1s 19s;');
|
||||
|
||||
var animator = $animateCss(element, options);
|
||||
animator.start();
|
||||
@@ -656,8 +649,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.ng-enter-stagger', 'transition-delay:0.2s');
|
||||
ss.addRule('.ng-enter', 'transition:2s linear all');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter-stagger', 'transition-delay:0.2s');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:2s linear all');
|
||||
|
||||
var elements = [];
|
||||
var i;
|
||||
@@ -697,13 +690,13 @@ describe('ngAnimate $animateCss', function() {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.red-add-stagger,' +
|
||||
'.blue-remove-stagger,' +
|
||||
'.green-add-stagger', 'transition-delay:0.2s');
|
||||
ss.addPossiblyPrefixedRule('.red-add-stagger,' +
|
||||
'.blue-remove-stagger,' +
|
||||
'.green-add-stagger', 'transition-delay:0.2s');
|
||||
|
||||
ss.addRule('.red-add,' +
|
||||
'.blue-remove,' +
|
||||
'.green-add', 'transition:2s linear all');
|
||||
ss.addPossiblyPrefixedRule('.red-add,' +
|
||||
'.blue-remove,' +
|
||||
'.green-add', 'transition:2s linear all');
|
||||
|
||||
var elements = [];
|
||||
var i;
|
||||
@@ -767,8 +760,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.ng-enter-stagger', 'transition-delay:0.2s');
|
||||
ss.addRule('.ng-enter', 'transition:2s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter-stagger', 'transition-delay:0.2s');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:2s linear all;');
|
||||
|
||||
var element;
|
||||
var i;
|
||||
@@ -827,7 +820,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.transition-animation', 'transition:2s 5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.transition-animation', 'transition:2s 5s linear all;');
|
||||
|
||||
for (var i = 0; i < 5; i++) {
|
||||
var element = angular.element('<div class="transition-animation"></div>');
|
||||
@@ -846,8 +839,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.transition-animation', 'transition:2s 5s linear all;');
|
||||
ss.addRule('.transition-animation.ng-enter-stagger',
|
||||
ss.addPossiblyPrefixedRule('.transition-animation', 'transition:2s 5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.transition-animation.ng-enter-stagger',
|
||||
'transition-duration:0s; transition-delay:0.2s;');
|
||||
|
||||
var element, i, elms = [];
|
||||
@@ -892,7 +885,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.ng-enter-stagger', 'transition-delay:0.2s');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter-stagger', 'transition-delay:0.2s');
|
||||
ss.addPossiblyPrefixedRule('.transition-animation', 'animation: 2s 5s my_animation;');
|
||||
|
||||
for (var i = 0; i < 5; i++) {
|
||||
@@ -950,8 +943,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.ng-enter-stagger', 'transition-delay:1s;');
|
||||
ss.addRule('.ng-enter', 'transition:10s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter-stagger', 'transition-delay:1s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:10s linear all;');
|
||||
|
||||
var elm, i, elms = [];
|
||||
for (i = 0; i < 5; i++) {
|
||||
@@ -977,8 +970,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.ng-enter-stagger', 'transition-delay:1s;');
|
||||
ss.addRule('.ng-enter', 'transition:10s linear all; transition-delay:50s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter-stagger', 'transition-delay:1s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:10s linear all; transition-delay:50s;');
|
||||
|
||||
var elm, i, elms = [];
|
||||
for (i = 0; i < 5; i++) {
|
||||
@@ -1003,7 +996,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
inject(function($animateCss, $document, $rootElement, $timeout) {
|
||||
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
ss.addRule('.ng-enter', 'transition:2s linear all');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:2s linear all');
|
||||
|
||||
var elm, i, elements = [];
|
||||
for (i = 0; i < 5; i++) {
|
||||
@@ -1068,7 +1061,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should close off the animation after 150% of the animation time has passed',
|
||||
inject(function($animateCss, $document, $rootElement, $timeout) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition:10s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:10s linear all;');
|
||||
|
||||
var element = angular.element('<div></div>');
|
||||
$rootElement.append(element);
|
||||
@@ -1091,7 +1084,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should close off the animation after 150% of the animation time has passed and consider the detected delay value',
|
||||
inject(function($animateCss, $document, $rootElement, $timeout) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition:10s linear all; transition-delay:30s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:10s linear all; transition-delay:30s;');
|
||||
|
||||
var element = angular.element('<div></div>');
|
||||
$rootElement.append(element);
|
||||
@@ -1114,7 +1107,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should still resolve the animation once expired',
|
||||
inject(function($animateCss, $document, $rootElement, $timeout, $animate, $rootScope) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition:10s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:10s linear all;');
|
||||
|
||||
var element = angular.element('<div></div>');
|
||||
$rootElement.append(element);
|
||||
@@ -1139,7 +1132,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should not resolve/reject after passing if the animation completed successfully',
|
||||
inject(function($animateCss, $document, $rootElement, $timeout, $rootScope, $animate) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition:10s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:10s linear all;');
|
||||
|
||||
var element = angular.element('<div></div>');
|
||||
$rootElement.append(element);
|
||||
@@ -1184,9 +1177,9 @@ describe('ngAnimate $animateCss', function() {
|
||||
var cancelSpy = spyOn($timeout, 'cancel').and.callThrough();
|
||||
var doneSpy = jasmine.createSpy();
|
||||
|
||||
ss.addRule('.elm', 'transition:1s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.elm', 'transition:1s linear all;');
|
||||
ss.addRule('.elm.red', 'background:red;');
|
||||
ss.addRule('.elm.blue', 'transition:2s linear all; background:blue;');
|
||||
ss.addPossiblyPrefixedRule('.elm.blue', 'transition:2s linear all; background:blue;');
|
||||
ss.addRule('.elm.green', 'background:green;');
|
||||
|
||||
var element = angular.element('<div class="elm"></div>');
|
||||
@@ -1238,7 +1231,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
$rootElement.append(element);
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.red', 'transition:1s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.red', 'transition:1s linear all;');
|
||||
|
||||
$animateCss(element, { addClass: 'red' }).start();
|
||||
triggerAnimationStartFrame();
|
||||
@@ -1319,7 +1312,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should cancel the timeout when the animation is ended normally',
|
||||
inject(function($animateCss, $document, $rootElement, $timeout) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition:10s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:10s linear all;');
|
||||
|
||||
var element = angular.element('<div></div>');
|
||||
$rootElement.append(element);
|
||||
@@ -1449,12 +1442,11 @@ describe('ngAnimate $animateCss', function() {
|
||||
function setStyles(event) {
|
||||
switch (event) {
|
||||
case TRANSITIONEND_EVENT:
|
||||
ss.addRule('.ng-enter', 'transition: 10s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition: 10s linear all;');
|
||||
progress = transitionProgress;
|
||||
break;
|
||||
case ANIMATIONEND_EVENT:
|
||||
ss.addRule('.ng-enter', '-webkit-animation: animation 10s;' +
|
||||
'animation: animation 10s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation: animation 10s;');
|
||||
progress = keyframeProgress;
|
||||
break;
|
||||
}
|
||||
@@ -1626,8 +1618,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
expect(animator.$$willAnimate).toBeFalsy();
|
||||
|
||||
$$rAF.flush();
|
||||
ss.addRule('.ng-enter', '-webkit-animation:3.5s keyframe_animation;' +
|
||||
'animation:3.5s keyframe_animation;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:3.5s keyframe_animation;');
|
||||
animator = $animateCss(element, options);
|
||||
expect(animator.$$willAnimate).toBeTruthy();
|
||||
}));
|
||||
@@ -1753,7 +1744,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
$rootElement.append(element);
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.cool-animation', 'transition:1.5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.cool-animation', 'transition:1.5s linear all;');
|
||||
element.addClass('cool-animation');
|
||||
|
||||
var data = {};
|
||||
@@ -1783,7 +1774,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
$rootElement.append(element);
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.cool-animation', 'transition:1.5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.cool-animation', 'transition:1.5s linear all;');
|
||||
element.addClass('cool-animation');
|
||||
|
||||
var data = {};
|
||||
@@ -1824,7 +1815,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
$rootElement.append(element);
|
||||
angular.element($document[0].body).append($rootElement);
|
||||
|
||||
ss.addRule('.cool-animation', 'transition:1.5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.cool-animation', 'transition:1.5s linear all;');
|
||||
element.addClass('cool-animation');
|
||||
|
||||
var data = {};
|
||||
@@ -1973,10 +1964,10 @@ describe('ngAnimate $animateCss', function() {
|
||||
var element = angular.element('<div></div>');
|
||||
|
||||
if (event === 'add') {
|
||||
ss.addRule('.natural-class', 'transition:1s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.natural-class', 'transition:1s linear all;');
|
||||
} else {
|
||||
ss.addRule('.natural-class', 'transition:0s linear none;');
|
||||
ss.addRule('.base-class', 'transition:1s linear none;');
|
||||
ss.addPossiblyPrefixedRule('.natural-class', 'transition:0s linear none;');
|
||||
ss.addPossiblyPrefixedRule('.base-class', 'transition:1s linear none;');
|
||||
|
||||
element.addClass('base-class');
|
||||
element.addClass('natural-class');
|
||||
@@ -2006,7 +1997,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
['enter', 'leave', 'move'], function(event) {
|
||||
inject(function($animateCss, $rootElement, $document) {
|
||||
|
||||
ss.addRule('.blue.ng-' + event, 'transition:2s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.blue.ng-' + event, 'transition:2s linear all;');
|
||||
|
||||
var element = angular.element('<div class="red"></div>');
|
||||
$rootElement.append(element);
|
||||
@@ -2169,8 +2160,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should be applied to a CSS keyframe animation directly if keyframes are detected within the CSS class',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-animation:1.5s keyframe_animation;' +
|
||||
'animation:1.5s keyframe_animation;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:1.5s keyframe_animation;');
|
||||
|
||||
var options = {
|
||||
duration: 5,
|
||||
@@ -2188,8 +2178,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should remove all inline keyframe styling when an animation completes if a custom duration was applied',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-animation:1.5s keyframe_animation;' +
|
||||
'animation:1.5s keyframe_animation;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:1.5s keyframe_animation;');
|
||||
|
||||
var options = {
|
||||
duration: 5,
|
||||
@@ -2210,8 +2199,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should remove all inline keyframe delay styling when an animation completes if a custom duration was applied',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-animation:1.5s keyframe_animation;' +
|
||||
'animation:1.5s keyframe_animation;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:1.5s keyframe_animation;');
|
||||
|
||||
var options = {
|
||||
delay: 5,
|
||||
@@ -2234,8 +2222,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should not prepare the animation at all if a duration of zero is provided',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-transition:1s linear all;' +
|
||||
'transition:1s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:1s linear all;');
|
||||
|
||||
var options = {
|
||||
duration: 0,
|
||||
@@ -2251,9 +2238,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should apply a transition and keyframe duration directly if both transitions and keyframe classes are detected',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-animation:3s keyframe_animation;' +
|
||||
'animation:3s keyframe_animation;' +
|
||||
'transition:5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:3s keyframe_animation;' +
|
||||
'transition:5s linear all;');
|
||||
|
||||
var options = {
|
||||
duration: 4,
|
||||
@@ -2314,10 +2300,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should override the delay value present in the CSS class',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-transition:1s linear all;' +
|
||||
'transition:1s linear all;' +
|
||||
'-webkit-transition-delay:10s;' +
|
||||
'transition-delay:10s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-delay:10s;');
|
||||
|
||||
var element = angular.element('<div></div>');
|
||||
$rootElement.append(element);
|
||||
@@ -2339,10 +2323,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should allow the delay value to zero if provided',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-transition:1s linear all;' +
|
||||
'transition:1s linear all;' +
|
||||
'-webkit-transition-delay:10s;' +
|
||||
'transition-delay:10s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:1s linear all;' +
|
||||
'transition-delay:10s;');
|
||||
|
||||
var element = angular.element('<div></div>');
|
||||
$rootElement.append(element);
|
||||
@@ -2364,8 +2346,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should be applied to a CSS keyframe animation if detected within the CSS class',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-animation:1.5s keyframe_animation;' +
|
||||
'animation:1.5s keyframe_animation;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:1.5s keyframe_animation;');
|
||||
|
||||
var options = {
|
||||
delay: 400,
|
||||
@@ -2384,9 +2365,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should apply a transition and keyframe delay if both transitions and keyframe classes are detected',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-animation:3s keyframe_animation;' +
|
||||
'animation:3s keyframe_animation;' +
|
||||
'transition:5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:3s keyframe_animation;' +
|
||||
'transition:5s linear all;');
|
||||
|
||||
var options = {
|
||||
delay: 10,
|
||||
@@ -2419,9 +2399,8 @@ describe('ngAnimate $animateCss', function() {
|
||||
});
|
||||
inject(function($animateCss, $rootElement) {
|
||||
element.addClass('element');
|
||||
ss.addRule('.element', '-webkit-animation:3s keyframe_animation;' +
|
||||
'animation:3s keyframe_animation;' +
|
||||
'transition:5s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.element', 'animation:3s keyframe_animation;' +
|
||||
'transition:5s linear all;');
|
||||
|
||||
var options = {
|
||||
delay: 2,
|
||||
@@ -2455,7 +2434,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should apply blocking before the animation starts, but then apply the detected delay when options.delay is true',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition:2s linear all; transition-delay: 1s;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition:2s linear all; transition-delay: 1s;');
|
||||
|
||||
var options = {
|
||||
delay: true,
|
||||
@@ -2834,7 +2813,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should always apply the from styles before the start function is called even if no transition is detected when started',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.my-class', 'transition: 0s linear color');
|
||||
ss.addPossiblyPrefixedRule('.my-class', 'transition: 0s linear color');
|
||||
|
||||
var options = {
|
||||
addClass: 'my-class',
|
||||
@@ -2925,7 +2904,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should remove all inline transition delay styling when an animation completes',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition: 1s linear color');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition: 1s linear color');
|
||||
|
||||
var options = {
|
||||
event: 'enter',
|
||||
@@ -3000,7 +2979,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should apply a transition duration if the existing transition duration\'s property value is not \'all\'',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', 'transition: 1s linear color');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'transition: 1s linear color');
|
||||
|
||||
var emptyObject = {};
|
||||
var options = {
|
||||
@@ -3023,8 +3002,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should apply a transition duration and an animation duration if duration + styles options are provided for a matching keyframe animation',
|
||||
inject(function($animateCss, $rootElement) {
|
||||
|
||||
ss.addRule('.ng-enter', '-webkit-animation:3.5s keyframe_animation;' +
|
||||
'animation:3.5s keyframe_animation;');
|
||||
ss.addPossiblyPrefixedRule('.ng-enter', 'animation:3.5s keyframe_animation;');
|
||||
|
||||
var emptyObject = {};
|
||||
var options = {
|
||||
@@ -3056,7 +3034,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
}));
|
||||
|
||||
it('should apply easing to a transition animation if it exists', inject(function($animateCss) {
|
||||
ss.addRule('.red', 'transition:1s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.red', 'transition:1s linear all;');
|
||||
var easing = 'ease-out';
|
||||
var animator = $animateCss(element, { addClass: 'red', easing: easing });
|
||||
animator.start();
|
||||
@@ -3081,7 +3059,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should apply easing to both keyframes and transition animations if detected',
|
||||
inject(function($animateCss) {
|
||||
|
||||
ss.addRule('.red', 'transition: 1s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.red', 'transition: 1s linear all;');
|
||||
ss.addPossiblyPrefixedRule('.blue', 'animation: 1s my_keyframe;');
|
||||
var easing = 'ease-out';
|
||||
var animator = $animateCss(element, { addClass: 'red blue', easing: easing });
|
||||
@@ -3162,8 +3140,7 @@ describe('ngAnimate $animateCss', function() {
|
||||
it('should round up long elapsedTime values to close off a CSS3 animation',
|
||||
inject(function($animateCss) {
|
||||
|
||||
ss.addRule('.millisecond-transition.ng-leave', '-webkit-transition:510ms linear all;' +
|
||||
'transition:510ms linear all;');
|
||||
ss.addPossiblyPrefixedRule('.millisecond-transition.ng-leave', 'transition:510ms linear all;');
|
||||
|
||||
element.addClass('millisecond-transition');
|
||||
var animator = $animateCss(element, {
|
||||
|
||||
@@ -584,6 +584,40 @@ describe('ngView', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should not trigger a digest when the view is changed', function() {
|
||||
module(function($routeProvider) {
|
||||
$routeProvider.when('/foo', {templateUrl: 'myUrl1'});
|
||||
$routeProvider.when('/bar', {templateUrl: 'myUrl2'});
|
||||
});
|
||||
|
||||
inject(function($$rAF, $templateCache, $rootScope, $compile, $timeout, $location, $httpBackend) {
|
||||
var spy = spyOn($rootScope, '$digest').and.callThrough();
|
||||
|
||||
$templateCache.put('myUrl1', 'my template content');
|
||||
$templateCache.put('myUrl2', 'my other template content');
|
||||
|
||||
$location.path('/foo');
|
||||
$rootScope.$digest();
|
||||
|
||||
// The animation completion is async even without actual animations
|
||||
$$rAF.flush();
|
||||
expect(element.text()).toEqual('my template content');
|
||||
|
||||
$location.path('/bar');
|
||||
$rootScope.$digest();
|
||||
spy.calls.reset();
|
||||
|
||||
$$rAF.flush();
|
||||
expect(element.text()).toEqual('my other template content');
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
// A digest may have been triggered asynchronously, so check the queue
|
||||
$timeout.verifyNoPendingTasks();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('and transcludes', function() {
|
||||
|
||||
Reference in New Issue
Block a user