Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98ee3719f9 | |||
| 94b5f2dadb | |||
| fe7decd1b0 | |||
| cef084ade9 | |||
| 937caab647 | |||
| 3fc8017119 | |||
| 54637a335f | |||
| 277a5ea05d | |||
| 9865a7c0ad | |||
| efba4731e4 | |||
| a965984733 | |||
| 14d3e559d4 | |||
| 3d156a76e3 | |||
| c7a1d1ab0b | |||
| 26d43cacdc | |||
| 4f5758e666 | |||
| 274a6734ef | |||
| f0e3dfd008 | |||
| bc3ff2cecd | |||
| 8f329ffb82 | |||
| 864b2596b2 | |||
| f3a796e522 | |||
| 09f8962df2 | |||
| a13c4ba770 | |||
| 040e743b39 | |||
| bf816d3ade | |||
| 74b4ab8867 | |||
| 6e2359caa0 | |||
| 41534816a4 | |||
| 30252a0504 | |||
| 3dc18037e8 | |||
| 57d50582aa | |||
| 73c66715c9 | |||
| cb29632a58 | |||
| 5c97731a22 | |||
| b2e472e7a2 | |||
| 6ac773f350 | |||
| 3174f73336 | |||
| 3c62e4244e | |||
| c432999572 | |||
| f8d319c11a | |||
| 4f72433392 | |||
| 2f91cfd0d2 | |||
| d5c5e2b584 | |||
| cbb3ce2c30 | |||
| 45af02de04 | |||
| 6144df52af | |||
| b0474cb984 | |||
| 9a4c9e6487 | |||
| 11fff8fa0d | |||
| da8ab2f928 | |||
| 6d01384a55 | |||
| 109ffac975 | |||
| 8c10db3847 | |||
| 03088d6010 | |||
| 18e0768a2b | |||
| ed4a1fddce | |||
| cfde6f507c |
@@ -1,3 +1,61 @@
|
||||
<a name="1.2.6"></a>
|
||||
# 1.2.6 taco-salsafication (2013-12-19)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** use a scheduled timeout in favor of a fallback property to close transitions
|
||||
([54637a33](https://github.com/angular/angular.js/commit/54637a335f885110efaa702a3bab29c77644b36c),
|
||||
[#5255](https://github.com/angular/angular.js/issues/5255), [#5241](https://github.com/angular/angular.js/issues/5241), [#5405](https://github.com/angular/angular.js/issues/5405))
|
||||
- **$compile:** remove invalid IE exceptional case for `href`
|
||||
([c7a1d1ab](https://github.com/angular/angular.js/commit/c7a1d1ab0b663edffc1ac7b54deea847e372468d),
|
||||
[#5479](https://github.com/angular/angular.js/issues/5479))
|
||||
- **$location:** parse xlink:href for SVGAElements
|
||||
([bc3ff2ce](https://github.com/angular/angular.js/commit/bc3ff2cecd0861766a9e8606f3cc2c582d9875df),
|
||||
[#5472](https://github.com/angular/angular.js/issues/5472), [#5198](https://github.com/angular/angular.js/issues/5198), [#5199](https://github.com/angular/angular.js/issues/5199), [#4098](https://github.com/angular/angular.js/issues/4098), [#1420](https://github.com/angular/angular.js/issues/1420))
|
||||
- **$log:** should work in IE8
|
||||
([4f5758e6](https://github.com/angular/angular.js/commit/4f5758e6669222369889c9e789601d25ff885530),
|
||||
[#5400](https://github.com/angular/angular.js/issues/5400))
|
||||
- **$parse:** return `undefined` if an intermetiate property's value is `null`
|
||||
([26d43cac](https://github.com/angular/angular.js/commit/26d43cacdc106765bd928d41600352198f887aef),
|
||||
[#5480](https://github.com/angular/angular.js/issues/5480))
|
||||
- **closure:** add type definition for `Scope#$watchCollection`
|
||||
([8f329ffb](https://github.com/angular/angular.js/commit/8f329ffb829410e1fd8f86a766929134e736e3e5),
|
||||
[#5475](https://github.com/angular/angular.js/issues/5475))
|
||||
- **forEach:** allow looping over result of `querySelectorAll` in IE8
|
||||
([274a6734](https://github.com/angular/angular.js/commit/274a6734ef1fff543cc50388a0958d1988baeb57))
|
||||
- **input:** do not hold input for composition on Android
|
||||
([3dc18037](https://github.com/angular/angular.js/commit/3dc18037e8db8766641a4d39f0fee96077db1fcb),
|
||||
[#5308](https://github.com/angular/angular.js/issues/5308))
|
||||
- **jqLite:** support unbind self within handler
|
||||
([2f91cfd0](https://github.com/angular/angular.js/commit/2f91cfd0d2986899c38641100c1851b2f9d3888a))
|
||||
- **ngRepeat:** allow multiline expressions
|
||||
([cbb3ce2c](https://github.com/angular/angular.js/commit/cbb3ce2c309052b951d0cc87e4c6daa9c48a3dd8),
|
||||
[#5000](https://github.com/angular/angular.js/issues/5000))
|
||||
- **select:** invalidate when `multiple`, `required`, and model is `[]`
|
||||
([5c97731a](https://github.com/angular/angular.js/commit/5c97731a22ed87d64712e673efea0e8a05eae65f),
|
||||
[#5337](https://github.com/angular/angular.js/issues/5337))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **jqLite:** provide support for `element.one()`
|
||||
([937caab6](https://github.com/angular/angular.js/commit/937caab6475e53a7ea0206e992f8a52449232e78))
|
||||
- **ngAnimate:** provide configuration support to match specific className values to trigger animations
|
||||
([cef084ad](https://github.com/angular/angular.js/commit/cef084ade9072090259d8c679751cac3ffeaed51),
|
||||
[#5357](https://github.com/angular/angular.js/issues/5357), [#5283](https://github.com/angular/angular.js/issues/5283))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **compile:** add class 'ng-scope' before cloning and other micro-optimizations
|
||||
([f3a796e5](https://github.com/angular/angular.js/commit/f3a796e522afdbd3b640d14426edb2fbfab463c5),
|
||||
[#5471](https://github.com/angular/angular.js/issues/5471))
|
||||
- **$parse:** use a faster path when the number of path parts is low
|
||||
([f4462319](https://github.com/angular/angular.js/commit/864b2596b246470cca9d4e223eaed720f4462319))
|
||||
- use faster check for `$$` prefix
|
||||
([06c5cfc7](https://github.com/angular/angular.js/commit/cb29632a5802e930262919b3db64ca4806c5cfc7))
|
||||
|
||||
<a name="1.2.5"></a>
|
||||
# 1.2.5 singularity-expansion (2013-12-13)
|
||||
|
||||
|
||||
+11
-1
@@ -4,6 +4,7 @@ var path = require('path');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
//grunt plugins
|
||||
grunt.loadNpmTasks('grunt-bump');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
@@ -268,6 +269,15 @@ module.exports = function(grunt) {
|
||||
write: {
|
||||
versionTXT: {file: 'build/version.txt', val: NG_VERSION.full},
|
||||
versionJSON: {file: 'build/version.json', val: JSON.stringify(NG_VERSION)}
|
||||
},
|
||||
|
||||
bump: {
|
||||
options: {
|
||||
files: ['package.json'],
|
||||
commit: false,
|
||||
createTag: false,
|
||||
push: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -287,6 +297,6 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('webserver', ['connect:devserver']);
|
||||
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('package-without-bower', ['clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'test:docgen']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint']);
|
||||
grunt.registerTask('default', ['package']);
|
||||
};
|
||||
|
||||
Vendored
+10
-1
@@ -762,7 +762,9 @@ angular.Module.requires;
|
||||
* $parent: angular.Scope,
|
||||
* $root: angular.Scope,
|
||||
* $watch: function(
|
||||
* (string|Function), (string|Function)=, boolean=):function()
|
||||
* (string|Function), (string|Function)=, boolean=):function(),
|
||||
* $watchCollection: function(
|
||||
* (string|Function), (string|Function)=):function()
|
||||
* }}
|
||||
*/
|
||||
angular.Scope;
|
||||
@@ -834,6 +836,13 @@ angular.Scope.$root;
|
||||
*/
|
||||
angular.Scope.$watch = function(exp, opt_listener, opt_objectEquality) {};
|
||||
|
||||
/**
|
||||
* @param {string|Function} exp
|
||||
* @param {(string|Function)=} opt_listener
|
||||
* @return {function()}
|
||||
*/
|
||||
angular.Scope.$watchCollection = function(exp, opt_listener) {};
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* currentScope: angular.Scope,
|
||||
|
||||
@@ -9,14 +9,3 @@
|
||||
ng\:form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* The styles below ensure that the CSS transition will ALWAYS
|
||||
* animate and close. A nasty bug occurs with CSS transitions where
|
||||
* when the active class isn't set, or if the active class doesn't
|
||||
* contain any styles to transition to, then, if ngAnimate is used,
|
||||
* it will appear as if the webpage is broken due to the forever hanging
|
||||
* animations. The border-spacing (!ie) and zoom (ie) CSS properties are
|
||||
* used below since they trigger a transition without making the browser
|
||||
* animate anything and they're both highly underused CSS properties */
|
||||
.ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; }
|
||||
.ng-animate-active { border-spacing:0px 0px; -ms-zoom:1; }
|
||||
|
||||
+1
-11
@@ -215,17 +215,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
|
||||
}];
|
||||
this.html5Mode = angular.noop;
|
||||
});
|
||||
$provide.decorator('$timeout', ['$rootScope', '$delegate', function($rootScope, $delegate) {
|
||||
return angular.extend(function(fn, delay) {
|
||||
if (delay && delay > 50) {
|
||||
return setTimeout(function() {
|
||||
$rootScope.$apply(fn);
|
||||
}, delay);
|
||||
} else {
|
||||
return $delegate.apply(this, arguments);
|
||||
}
|
||||
}, $delegate);
|
||||
}]);
|
||||
|
||||
$provide.decorator('$rootScope', ['$delegate', function($delegate) {
|
||||
embedRootScope = $delegate;
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
@description
|
||||
|
||||
# ng (core module)
|
||||
The ng module is loaded by default when an AngularJS application is started. The module itself contains the essential components to for an AngularJS application to function. The table below lists a high level breakdown of each of the services/factories, filters, directives and testing components available within this core module.
|
||||
The ng module is loaded by default when an AngularJS application is started. The module itself
|
||||
contains the essential components for an AngularJS application to function. The table below
|
||||
lists a high level breakdown of each of the services/factories, filters, directives and testing
|
||||
components available within this core module.
|
||||
|
||||
<div doc-module-components="ng"></div>
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
@description
|
||||
This error occurs when 'ngPattern' is passed an expression that isn't a regular expression or doesn't have the expected format.
|
||||
|
||||
For more information on valid expression syntax, see 'ngPattern' in {@link api/ng.directive:select input} directive docs.
|
||||
For more information on valid expression syntax, see 'ngPattern' in {@link api/ng.directive:input input} directive docs.
|
||||
|
||||
@@ -50,7 +50,7 @@ of which depend on other services that are provided by the Angular framework:
|
||||
* @param {*} message Message to be logged.
|
||||
*/
|
||||
function batchLogModule($provide){
|
||||
$provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) {
|
||||
$provide.factory('batchLog', ['$interval', '$log', function($interval, $log) {
|
||||
var messageQueue = [];
|
||||
|
||||
function log() {
|
||||
@@ -58,11 +58,10 @@ of which depend on other services that are provided by the Angular framework:
|
||||
$log('batchLog messages: ', messageQueue);
|
||||
messageQueue = [];
|
||||
}
|
||||
$timeout(log, 50000);
|
||||
}
|
||||
|
||||
// start periodic checking
|
||||
log();
|
||||
$interval(log, 50000);
|
||||
|
||||
return function(message) {
|
||||
messageQueue.push(message);
|
||||
@@ -82,13 +81,13 @@ of which depend on other services that are provided by the Angular framework:
|
||||
}]);
|
||||
}
|
||||
|
||||
// get the main service to kick of the application
|
||||
// get the main service to kick off the application
|
||||
angular.injector([batchLogModule]).get('routeTemplateMonitor');
|
||||
</pre>
|
||||
|
||||
Things to notice in this example:
|
||||
|
||||
* The `batchLog` service depends on the built-in {@link api/ng.$timeout $timeout} and
|
||||
* The `batchLog` service depends on the built-in {@link api/ng.$interval $interval} and
|
||||
{@link api/ng.$log $log} services, and allows messages to be logged into the
|
||||
`console.log` in batches.
|
||||
* The `routeTemplateMonitor` service depends on the built-in {@link api/ngRoute.$route
|
||||
|
||||
@@ -506,6 +506,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 guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive
|
||||
"Isolating the Scope of a Directive"} section for more information about isolate scopes.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success">
|
||||
@@ -528,8 +530,10 @@ where:
|
||||
* `attrs` is an object with the normalized attribute names and their corresponding values.
|
||||
|
||||
In our `link` function, we want to update the displayed time once a second, or whenever a user
|
||||
changes the time formatting string that our directive binds to. We also want to remove the timeout
|
||||
if the directive is deleted so we don't introduce a memory leak.
|
||||
changes the time formatting string that our directive binds to. We will use the `$interval` service
|
||||
to call a handler on a regular basis. This is easier than using `$timeout` but also works better with
|
||||
end 2 end testing, where we want to ensure that all $timeouts have completed before completing the test.
|
||||
We also want to remove the `$interval` if the directive is deleted so we don't introduce a memory leak.
|
||||
|
||||
<example module="docsTimeDirective">
|
||||
<file name="script.js">
|
||||
@@ -537,7 +541,7 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
.controller('Ctrl2', function($scope) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
})
|
||||
.directive('myCurrentTime', function($timeout, dateFilter) {
|
||||
.directive('myCurrentTime', function($interval, dateFilter) {
|
||||
|
||||
function link(scope, element, attrs) {
|
||||
var format,
|
||||
@@ -552,20 +556,14 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
updateTime();
|
||||
});
|
||||
|
||||
function scheduleUpdate() {
|
||||
// save the timeoutId for canceling
|
||||
timeoutId = $timeout(function() {
|
||||
updateTime(); // update DOM
|
||||
scheduleUpdate(); // schedule the next update
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
element.on('$destroy', function() {
|
||||
$timeout.cancel(timeoutId);
|
||||
$interval.cancel(timeoutId);
|
||||
});
|
||||
|
||||
// start the UI update process.
|
||||
scheduleUpdate();
|
||||
// start the UI update process; save the timeoutId for canceling
|
||||
timeoutId = $interval(function() {
|
||||
updateTime(); // update DOM
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -583,7 +581,7 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
|
||||
There are a couple of things to note here.
|
||||
Just like the `module.controller` API, the function argument in `module.directive` is dependency
|
||||
injected. Because of this, we can use `$timeout` and `dateFilter` inside our directive's `link`
|
||||
injected. Because of this, we can use `$interval` and `dateFilter` inside our directive's `link`
|
||||
function.
|
||||
|
||||
We register an event `element.on('$destroy', ...)`. What fires this `$destroy` event?
|
||||
|
||||
@@ -116,7 +116,7 @@ This ensures that the user is not distracted with an error until after interacti
|
||||
A form is an instance of {@link api/ng.directive:form.FormController FormController}.
|
||||
The form instance can optionally be published into the scope using the `name` attribute.
|
||||
|
||||
Similarly, an input control that has the {@link api.ng.directive:ng-model} directive holds an
|
||||
Similarly, an input control that has the {@link api/ng.directive:ngModel} directive holds an
|
||||
instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
|
||||
Such a control instance can be published as a property of the form instance using the `name` attribute
|
||||
on the input control. The name attribute specifies the name of the property on the form instance.
|
||||
|
||||
@@ -18,8 +18,12 @@ watch {@link guide/expression expressions} and propagate events.
|
||||
propagate any model changes through the system into the view from outside of the "Angular
|
||||
realm" (controllers, services, Angular event handlers).
|
||||
|
||||
- Scopes can be nested to isolate application components while providing access to shared model
|
||||
properties. A scope (prototypically) inherits properties from its parent scope.
|
||||
- Scopes can be nested to limit access to the properties of application components while providing
|
||||
access to shared model properties. Nested scopes are either "child scopes" or "isolate scopes".
|
||||
A "child scope" (prototypically) inherits properties from its parent scope. An "isolate scope"
|
||||
does not. See {@link
|
||||
guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive isolated
|
||||
scopes} for more information.
|
||||
|
||||
- Scopes provide context against which {@link guide/expression expressions} are evaluated. For
|
||||
example `{{username}}` expression is meaningless, unless it is evaluated against a specific
|
||||
@@ -259,8 +263,8 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
|
||||
For mutations to be properly observed, you should make them only within the {@link
|
||||
api/ng.$rootScope.Scope#methods_$apply scope.$apply()}. (Angular APIs do this
|
||||
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
|
||||
or asynchronous work with {@link api/ng.$http $http} or {@link
|
||||
api/ng.$timeout $timeout} services.
|
||||
or asynchronous work with {@link api/ng.$http $http}, {@link api/ng.$timeout $timeout}
|
||||
or {@link api/ng.$interval $interval} services.
|
||||
|
||||
4. **Mutation observation**
|
||||
|
||||
@@ -306,6 +310,8 @@ api/ng.directive:ngController ng-controller} and {@link
|
||||
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
|
||||
and attach the child scope to the corresponding DOM element. You can retrieve a scope for any DOM
|
||||
element by using an `angular.element(aDomElement).scope()` method call.
|
||||
See the {@link guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive
|
||||
directives guide} for more information about isolate scopes.
|
||||
|
||||
### Controllers and Scopes
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ and included in your {@link http://docs.oracle.com/javase/tutorial/essential/env
|
||||
npm install -g bower
|
||||
```
|
||||
|
||||
**Note:** You may need to use sudo (for OSX, *nix, BSD etc) or run your command shell as Administrator (for Windows) to install Grunt &
|
||||
Bower globally.
|
||||
|
||||
## Forking Angular on Github
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ For the purposes of this tutorial, we modified the angular-seed with the followi
|
||||
* Removed the example app
|
||||
* Added phone images to `app/img/phones/`
|
||||
* Added phone data files (JSON) to `app/phones/`
|
||||
* Added [Bootstrap](http://twitter.github.com/bootstrap/) files to `app/css/` and `app/img/`
|
||||
* Added [Bootstrap](http://getbootstrap.com) files to `app/css/` and `app/img/`
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ phonecatApp.controller('PhoneListCtrl', function ($scope) {
|
||||
record. This property is used to order phones by age.
|
||||
|
||||
* We added a line to the controller that sets the default value of `orderProp` to `age`. If we had
|
||||
not set the default value here, the model would stay uninitialized until our user would pick an
|
||||
not set the default value here, the model would stay uninitialized until our user picks an
|
||||
option from the drop down menu.
|
||||
|
||||
This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the
|
||||
|
||||
@@ -199,7 +199,7 @@ isolated from the work done in other tests.
|
||||
|
||||
* We created a new scope for our controller by calling `$rootScope.$new()`
|
||||
|
||||
* We called the injected `$controller` function passing the name of the`PhoneListCtrl` controller
|
||||
* We called the injected `$controller` function passing the name of the `PhoneListCtrl` controller
|
||||
and the created scope as parameters.
|
||||
|
||||
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
||||
|
||||
@@ -11,7 +11,7 @@ In this step, you will improve the way our app fetches data.
|
||||
<div doc-tutorial-reset="11"></div>
|
||||
|
||||
|
||||
The last improvement we will make to our app is to define a custom service that represents a {@link
|
||||
The next improvement we will make to our app is to define a custom service that represents a {@link
|
||||
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
||||
can make XHR requests for data in an easier way, without having to deal with the lower-level {@link
|
||||
api/ng.$http $http} API, HTTP methods and URLs.
|
||||
@@ -185,7 +185,7 @@ describe('PhoneCat controllers', function() {
|
||||
xyzPhoneData = function() {
|
||||
return {
|
||||
name: 'phone xyz',
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
exports.appCache = appCache;
|
||||
var fs = require('q-fs');
|
||||
var fs = require('q-io/fs');
|
||||
var Q = require('qq');
|
||||
function identity($) {return $;}
|
||||
|
||||
|
||||
@@ -74,10 +74,10 @@ function writeTheRest(writesFuture) {
|
||||
var versions = ngdoc.ngVersions();
|
||||
var currentVersion = ngdoc.ngCurrentVersion();
|
||||
|
||||
writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'directory'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'directory'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'directory'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'directory'));
|
||||
|
||||
var manifest = 'manifest="/build/docs/appcache.manifest"';
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ exports.collect = collect;
|
||||
|
||||
var ngdoc = require('./ngdoc.js'),
|
||||
Q = require('qq'),
|
||||
qfs = require('q-fs'),
|
||||
qfs = require('q-io/fs'),
|
||||
PATH = require('path');
|
||||
|
||||
var NEW_LINE = /\n\r?/;
|
||||
|
||||
@@ -543,6 +543,10 @@ pre ol li {
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
.definition-table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.component-heading {
|
||||
text-transform:capitalize;
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
* for testability
|
||||
*/
|
||||
var pathUtils = require('path');
|
||||
var qfs = require('q-fs');
|
||||
var qfs = require('q-io/fs');
|
||||
var Q = require('qq');
|
||||
var OUTPUT_DIR = pathUtils.join('build','docs');
|
||||
var TEMPLATES_DIR = pathUtils.join('docs','src','templates');
|
||||
@@ -76,7 +76,7 @@ function symlink(from, to, type) {
|
||||
// qfs will normalize the path arguments for us here
|
||||
return qfs.exists(to).then(function(exists) {
|
||||
if (!exists) {
|
||||
return qfs.symbolicLink(to, from, type);
|
||||
return qfs.symbolicLink(to, from, type || 'file');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,9 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
|
||||
# Define reasonable set of browsers in case we are running manually from commandline
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
@@ -25,11 +28,12 @@ rm -f angular.js.size
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
# DOCS generator unit tests #
|
||||
grunt test:docgen --no-color
|
||||
|
||||
# UNIT TESTS #
|
||||
grunt test:unit --browsers $BROWSERS --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
# END TO END TESTS #
|
||||
grunt test:e2e --browsers $BROWSERS_E2E --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
@@ -13,7 +13,10 @@ module.exports = function(config, specificOptions) {
|
||||
// SauceLabs config for local development.
|
||||
sauceLabs: {
|
||||
testName: specificOptions.testName || 'AngularJS',
|
||||
startConnect: true
|
||||
startConnect: true,
|
||||
options: {
|
||||
'selenium-version': '2.37.0'
|
||||
}
|
||||
},
|
||||
|
||||
// BrowserStack config for local development.
|
||||
|
||||
+7
-2
@@ -36,13 +36,12 @@ module.exports = {
|
||||
var package = JSON.parse(fs.readFileSync('package.json', 'UTF-8'));
|
||||
var match = package.version.match(/^([^\-]*)(?:\-(.+))?$/);
|
||||
var semver = match[1].split('.');
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
|
||||
var fullVersion = match[1];
|
||||
|
||||
if (match[2]) {
|
||||
fullVersion += '-';
|
||||
fullVersion += (match[2] == 'snapshot') ? hash : match[2];
|
||||
fullVersion += (match[2] == 'snapshot') ? getSnapshotSuffix() : match[2];
|
||||
}
|
||||
|
||||
version = {
|
||||
@@ -55,6 +54,12 @@ module.exports = {
|
||||
};
|
||||
|
||||
return version;
|
||||
|
||||
function getSnapshotSuffix() {
|
||||
var jenkinsBuild = process.env.BUILD_NUMBER || 'local';
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
return 'build.'+jenkinsBuild+'+sha.'+hash;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
+5
-4
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"version": "1.2.5",
|
||||
"cdnVersion": "1.2.4",
|
||||
"codename": "singularity-expansion",
|
||||
"version": "1.2.6",
|
||||
"cdnVersion": "1.2.5",
|
||||
"codename": "taco-salsafication",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
@@ -10,13 +10,14 @@
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.1",
|
||||
"bower": "~1.2.2",
|
||||
"grunt-bump": "~0.0.13",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-connect": "~0.5.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"jasmine-node": "~1.11.0",
|
||||
"q": "~0.9.2",
|
||||
"q-fs": "~0.1.36",
|
||||
"q-io": "~1.10.6",
|
||||
"qq": "~0.3.5",
|
||||
"shelljs": "~0.2.6",
|
||||
"karma": "~0.11",
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function catch_errors() {
|
||||
echo "ERROR. That's life."
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap catch_errors ERR
|
||||
|
||||
TMP_FILE='changelog.tmp'
|
||||
CHANGELOG_FILE='CHANGELOG.md'
|
||||
|
||||
echo "Getting current version..."
|
||||
VERSION=`./version.js --current`
|
||||
|
||||
echo "Generating changelog..."
|
||||
./changelog.js $VERSION $TMP_FILE
|
||||
|
||||
cat $CHANGELOG_FILE >> $TMP_FILE
|
||||
mv -f $TMP_FILE $CHANGELOG_FILE
|
||||
|
||||
|
||||
echo "Updating version..."
|
||||
./version.js --remove-snapshot
|
||||
|
||||
echo "CONFIRM TO COMMIT"
|
||||
read WHATEVER
|
||||
|
||||
|
||||
echo "Creating commit..."
|
||||
git commit version.yaml CHANGELOG.md -m "chore(relase): cutting the v$VERSION release"
|
||||
|
||||
echo "Creating tag..."
|
||||
git tag "v$VERSION"
|
||||
+3
-11
@@ -1,23 +1,15 @@
|
||||
# Angular Bower Script
|
||||
|
||||
Script for updating the Angular bower repos from a code.angularjs.org package
|
||||
|
||||
Requires `node` (for parsing `bower.json`) and `wget` (for fetching the `angular.zip` from `code.angularjs.org`)
|
||||
|
||||
Script for updating the Angular bower repos from current local build.
|
||||
|
||||
## Instructions
|
||||
|
||||
You need to run `./init.sh` the first time you use this script to clone all the repos.
|
||||
|
||||
For subsequent updates:
|
||||
`grunt package`: Build angular locally
|
||||
|
||||
```shell
|
||||
./publish.sh NEW_VERSION
|
||||
./publish.sh
|
||||
```
|
||||
|
||||
Where `NEW_VERSION` is a version number like `1.2.3`.
|
||||
|
||||
|
||||
## License
|
||||
MIT
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# init all of the bower repos
|
||||
#
|
||||
|
||||
set -e # fail if any command fails
|
||||
|
||||
REPOS=(
|
||||
angular \
|
||||
angular-animate \
|
||||
angular-cookies \
|
||||
angular-i18n \
|
||||
angular-loader \
|
||||
angular-mocks \
|
||||
angular-route \
|
||||
angular-resource \
|
||||
angular-sanitize \
|
||||
angular-scenario \
|
||||
angular-touch \
|
||||
)
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
git clone git@github.com:angular/bower-$repo.git
|
||||
done
|
||||
+33
-35
@@ -1,18 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# update all the things
|
||||
#
|
||||
|
||||
set -e # fail if any command fails
|
||||
echo "#################################"
|
||||
echo "#### Update bower ###############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`
|
||||
|
||||
NEW_VERSION=$1
|
||||
|
||||
ZIP_FILE=angular-$NEW_VERSION.zip
|
||||
ZIP_FILE_URL=http://code.angularjs.org/$NEW_VERSION/angular-$NEW_VERSION.zip
|
||||
ZIP_DIR=angular-$NEW_VERSION
|
||||
SCRIPT_DIR=`pwd`
|
||||
TMP_DIR=../../tmp
|
||||
BUILD_DIR=../../build
|
||||
NEW_VERSION=`cat $BUILD_DIR/version.txt`
|
||||
|
||||
REPOS=(
|
||||
angular \
|
||||
@@ -28,50 +28,42 @@ REPOS=(
|
||||
angular-touch \
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# download and unzip the file
|
||||
# clone repos
|
||||
#
|
||||
|
||||
if [ ! -f $ZIP_FILE ]; then
|
||||
wget $ZIP_FILE_URL
|
||||
unzip $ZIP_FILE
|
||||
fi
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
echo "-- Cloning bower-$repo"
|
||||
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
|
||||
done
|
||||
|
||||
|
||||
#
|
||||
# move the files from the zip
|
||||
# move the files from the build
|
||||
#
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
if [ -f $ZIP_DIR/$repo.js ] # ignore i18l
|
||||
if [ -f $BUILD_DIR/$repo.js ] # ignore i18l
|
||||
then
|
||||
cd bower-$repo
|
||||
echo "-- Updating files in bower-$repo"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
git reset --hard HEAD
|
||||
git checkout master
|
||||
git fetch --all
|
||||
git reset --hard origin/master
|
||||
cd ..
|
||||
mv $ZIP_DIR/$repo.* bower-$repo/
|
||||
cd $SCRIPT_DIR
|
||||
cp $BUILD_DIR/$repo.* $TMP_DIR/bower-$repo/
|
||||
fi
|
||||
done
|
||||
|
||||
# move i18n files
|
||||
mv $ZIP_DIR/i18n/*.js bower-angular-i18n/
|
||||
cp $BUILD_DIR/i18n/*.js $TMP_DIR/bower-angular-i18n/
|
||||
|
||||
# move csp.css
|
||||
mv $ZIP_DIR/angular-csp.css bower-angular
|
||||
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
|
||||
|
||||
|
||||
#
|
||||
# get the old version number
|
||||
#
|
||||
|
||||
OLD_VERSION=$(node -e "console.log(require('./bower-angular/bower').version)" | sed -e 's/\r//g')
|
||||
echo $OLD_VERSION
|
||||
echo $NEW_VERSION
|
||||
|
||||
#
|
||||
# update bower.json
|
||||
# tag each repo
|
||||
@@ -79,12 +71,18 @@ echo $NEW_VERSION
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
cd bower-$repo
|
||||
sed -i '' -e "s/$OLD_VERSION/$NEW_VERSION/g" bower.json
|
||||
echo "-- Updating version in bower-$repo to $NEW_VERSION"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
sed -i .tmp -E 's/"(version)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
|
||||
sed -i .tmp -E 's/"(angular.*)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
|
||||
# delete tmp files
|
||||
rm *.tmp
|
||||
git add -A
|
||||
|
||||
echo "-- Committing, tagging and pushing bower-$repo"
|
||||
git commit -m "v$NEW_VERSION"
|
||||
git tag v$NEW_VERSION
|
||||
git push origin master
|
||||
git push origin v$NEW_VERSION
|
||||
cd ..
|
||||
cd $SCRIPT_DIR
|
||||
done
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# code.angular.js.org Script
|
||||
|
||||
Script for updating code.angularjs.org repo from current local build.
|
||||
|
||||
Note: For a snapshot build, this will fetch the data from the ci server
|
||||
and NOT take the local build!
|
||||
|
||||
## Instructions
|
||||
|
||||
`grunt package`: Build angular locally
|
||||
|
||||
```shell
|
||||
./publish.sh
|
||||
```
|
||||
|
||||
## License
|
||||
MIT
|
||||
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update code.angular.js.org ###"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`
|
||||
|
||||
TMP_DIR=../../tmp
|
||||
REPO_DIR=$TMP_DIR/code.angularjs.org
|
||||
BUILD_DIR=../../build
|
||||
SCRIPT_DIR=`pwd`
|
||||
NEW_VERSION=`cat $BUILD_DIR/version.txt`
|
||||
|
||||
#
|
||||
# Snapshot builds are kept in a temp directory in code.angularjs.org
|
||||
# that is filled by calling a php script there.
|
||||
#
|
||||
if [[ "$NEW_VERSION" =~ sha ]] ;then
|
||||
echo "-- updating snapshot version"
|
||||
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
#
|
||||
# clone
|
||||
#
|
||||
|
||||
echo "-- Cloning code.angularjs.org"
|
||||
git clone git@github.com:angular/code.angularjs.org.git $REPO_DIR
|
||||
|
||||
#
|
||||
# copy the files from the build
|
||||
#
|
||||
|
||||
echo "-- Updating code.angularjs.org"
|
||||
mkdir $REPO_DIR/$NEW_VERSION
|
||||
cd $REPO_DIR
|
||||
git reset --hard HEAD
|
||||
git checkout master
|
||||
git fetch --all
|
||||
git reset --hard origin/master
|
||||
cd $SCRIPT_DIR
|
||||
cp -r $BUILD_DIR/* $REPO_DIR/$NEW_VERSION/
|
||||
|
||||
#
|
||||
# commit and push
|
||||
#
|
||||
echo "-- Committing and pushing code.angularjs.org"
|
||||
cd $REPO_DIR
|
||||
git add -A
|
||||
git commit -m "v$NEW_VERSION"
|
||||
git push origin master
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
#
|
||||
# refresh code.angularjs.org from github
|
||||
#
|
||||
curl http://code.angularjs.org/gitFetchSite.php
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "############################################"
|
||||
echo "## Increment version and add "-snapshot" ##"
|
||||
echo "############################################"
|
||||
|
||||
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
|
||||
echo "Please specify the next version type: patch|minor|major"
|
||||
exit 1
|
||||
fi
|
||||
BUMP_TYPE=$1
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "-- increment version "
|
||||
grunt bump:$BUMP_TYPE
|
||||
NEXT_VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
|
||||
sed -i .tmp -E 's/"version": "(.*)"/"version": "\1-snapshot"/' package.json
|
||||
echo "-- new version: `grep '"version"' package.json`"
|
||||
echo "-- commit"
|
||||
git add package.json
|
||||
git commit -m "chore(release): start v$NEXT_VERSION"
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "############################################"
|
||||
echo "## Remove "-snapshot" from version ########"
|
||||
echo "############################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "-- old version: `grep '"version"' package.json`"
|
||||
sed -i .tmp -E 's/"version": "(.*)-snapshot"/"version": "\1"/' package.json
|
||||
VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
|
||||
echo "-- local version: $VERSION"
|
||||
|
||||
echo "-- commit and tag with v$VERSION"
|
||||
git add package.json
|
||||
git commit -m "chore(release): cut v$VERSION release"
|
||||
git tag -m "v$VERSION" v$VERSION
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update master ##############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
./jenkins_build.sh
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update code.angular.js.org ###"
|
||||
echo "#################################"
|
||||
./scripts/code.angularjs.org/publish.sh
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update bower ###############"
|
||||
echo "#################################"
|
||||
./scripts/bower/publish.sh
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Cut release ################"
|
||||
echo "#################################"
|
||||
|
||||
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
|
||||
echo "Please specify the next version type: patch|minor|major"
|
||||
exit 1
|
||||
fi
|
||||
BUMP_TYPE=$1
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
# Jump onto the master branch and make sure we are using the latest
|
||||
git checkout -f master
|
||||
git merge --ff-only origin/master
|
||||
|
||||
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
|
||||
# Bump versions: remove "-snapshot" suffix
|
||||
./scripts/jenkins/bump-remove-snapshot.sh
|
||||
|
||||
# Build
|
||||
./jenkins_build.sh
|
||||
|
||||
# Bump versions: Increment version and add "-snapshot"
|
||||
./scripts/jenkins/bump-increment.sh $BUMP_TYPE
|
||||
|
||||
echo "-- push to Github"
|
||||
# push to github
|
||||
git push --all
|
||||
|
||||
# Update code.angularjs.org
|
||||
./scripts/code.angularjs.org/publish.sh
|
||||
|
||||
# Update bower
|
||||
./scripts/bower/publish.sh
|
||||
+4
-2
@@ -213,7 +213,9 @@ function forEach(obj, iterator, context) {
|
||||
if (obj) {
|
||||
if (isFunction(obj)){
|
||||
for (key in obj) {
|
||||
if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
|
||||
// Need to check if hasOwnProperty exists,
|
||||
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
|
||||
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
|
||||
iterator.call(context, obj[key], key);
|
||||
}
|
||||
}
|
||||
@@ -769,7 +771,7 @@ function shallowCopy(src, dst) {
|
||||
for(var key in src) {
|
||||
// shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
|
||||
// so we don't need to worry about using our custom hasOwnProperty here
|
||||
if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
|
||||
if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,15 +485,15 @@ function annotate(fn) {
|
||||
* {@link AUTO.$provide#methods_service $provide.service(class)} that is defined as a CoffeeScript class.
|
||||
* <pre>
|
||||
* class Ping
|
||||
* constructor: (@$http)->
|
||||
* send: ()=>
|
||||
* constructor: (@$http) ->
|
||||
* send: () =>
|
||||
* @$http.get('/ping')
|
||||
*
|
||||
* $provide.service('ping', ['$http', Ping])
|
||||
* </pre>
|
||||
* You would then inject and use this service like this:
|
||||
* <pre>
|
||||
* someModule.controller 'Ctrl', ['ping', (ping)->
|
||||
* someModule.controller 'Ctrl', ['ping', (ping) ->
|
||||
* ping.send()
|
||||
* ]
|
||||
* </pre>
|
||||
|
||||
+18
-1
@@ -54,6 +54,7 @@
|
||||
* - [`next()`](http://api.jquery.com/next/) - Does not support selectors
|
||||
* - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
|
||||
* - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
|
||||
* - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
|
||||
* - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
|
||||
* - [`prepend()`](http://api.jquery.com/prepend/)
|
||||
* - [`prop()`](http://api.jquery.com/prop/)
|
||||
@@ -645,7 +646,10 @@ function createEventHandler(element, events) {
|
||||
return event.defaultPrevented || event.returnValue === false;
|
||||
};
|
||||
|
||||
forEach(events[type || event.type], function(fn) {
|
||||
// Copy event handlers in case event handlers array is modified during execution.
|
||||
var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
|
||||
|
||||
forEach(eventHandlersCopy, function(fn) {
|
||||
fn.call(element, event);
|
||||
});
|
||||
|
||||
@@ -741,6 +745,19 @@ forEach({
|
||||
|
||||
off: jqLiteOff,
|
||||
|
||||
one: function(element, type, fn) {
|
||||
element = jqLite(element);
|
||||
|
||||
//add the listener twice so that when it is called
|
||||
//you can remove the original function and still be
|
||||
//able to call element.off(ev, fn) normally
|
||||
element.on(type, function onFn() {
|
||||
element.off(type, fn);
|
||||
element.off(type, onFn);
|
||||
});
|
||||
element.on(type, fn);
|
||||
},
|
||||
|
||||
replaceWith: function(element, replaceNode) {
|
||||
var index, parent = element.parentNode;
|
||||
jqLiteDealoc(element);
|
||||
|
||||
@@ -61,6 +61,28 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
$provide.factory(key, factory);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name ng.$animateProvider#classNameFilter
|
||||
* @methodOf ng.$animateProvider
|
||||
*
|
||||
* @description
|
||||
* Sets and/or returns the CSS class regular expression that is checked when performing
|
||||
* an animation. Upon bootstrap the classNameFilter value is not set at all and will
|
||||
* therefore enable $animate to attempt to perform an animation on any element.
|
||||
* When setting the classNameFilter value, animations will only be performed on elements
|
||||
* that successfully match the filter expression. This in turn can boost performance
|
||||
* for low-powered devices as well as applications containing a lot of structural operations.
|
||||
* @param {RegExp=} expression The className expression which will be checked against all animations
|
||||
* @return {RegExp} The current CSS className expression value. If null then there is no expression value
|
||||
*/
|
||||
this.classNameFilter = function(expression) {
|
||||
if(arguments.length === 1) {
|
||||
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
|
||||
}
|
||||
return this.$$classNameFilter;
|
||||
};
|
||||
|
||||
this.$get = ['$timeout', function($timeout) {
|
||||
|
||||
/**
|
||||
|
||||
+25
-22
@@ -469,14 +469,14 @@
|
||||
* example would not point to the clone, but rather to the original template that was cloned. In
|
||||
* this case, you can access the clone via the cloneAttachFn:
|
||||
* <pre>
|
||||
* var templateHTML = angular.element('<p>{{total}}</p>'),
|
||||
* var templateElement = angular.element('<p>{{total}}</p>'),
|
||||
* scope = ....;
|
||||
*
|
||||
* var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
|
||||
* var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
|
||||
* //attach the clone to DOM document at the right place
|
||||
* });
|
||||
*
|
||||
* //now we have reference to the cloned DOM via `clone`
|
||||
* //now we have reference to the cloned DOM via `clonedElement`
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
@@ -818,6 +818,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var compositeLinkFn =
|
||||
compileNodes($compileNodes, transcludeFn, $compileNodes,
|
||||
maxPriority, ignoreDirective, previousCompileContext);
|
||||
safeAddClass($compileNodes, 'ng-scope');
|
||||
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
|
||||
assertArg(scope, 'scope');
|
||||
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
|
||||
@@ -832,12 +833,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
// Attach scope only to non-text nodes.
|
||||
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
|
||||
var node = $linkNode[i];
|
||||
if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
|
||||
var node = $linkNode[i],
|
||||
nodeType = node.nodeType;
|
||||
if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
|
||||
$linkNode.eq(i).data('$scope', scope);
|
||||
}
|
||||
}
|
||||
safeAddClass($linkNode, 'ng-scope');
|
||||
|
||||
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
||||
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
|
||||
return $linkNode;
|
||||
@@ -865,15 +867,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
* @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
|
||||
* the rootElement must be set the jqLite collection of the compile root. This is
|
||||
* needed so that the jqLite collection items can be replaced with widgets.
|
||||
* @param {number=} max directive priority
|
||||
* @param {number=} maxPriority Max directive priority.
|
||||
* @returns {?function} A composite linking function of all of the matched directives or null.
|
||||
*/
|
||||
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
|
||||
previousCompileContext) {
|
||||
var linkFns = [],
|
||||
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
|
||||
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
|
||||
|
||||
for(var i = 0; i < nodeList.length; i++) {
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
attrs = new Attributes();
|
||||
|
||||
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
||||
@@ -885,16 +887,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
null, [], [], previousCompileContext)
|
||||
: null;
|
||||
|
||||
if (nodeLinkFn && nodeLinkFn.scope) {
|
||||
safeAddClass(jqLite(nodeList[i]), 'ng-scope');
|
||||
}
|
||||
|
||||
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
|
||||
!nodeList[i].childNodes ||
|
||||
!nodeList[i].childNodes.length)
|
||||
!(childNodes = nodeList[i].childNodes) ||
|
||||
!childNodes.length)
|
||||
? null
|
||||
: compileNodes(nodeList[i].childNodes,
|
||||
: compileNodes(childNodes,
|
||||
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
||||
|
||||
linkFns.push(nodeLinkFn);
|
||||
linkFns.push(childLinkFn);
|
||||
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
||||
linkFns.push(nodeLinkFn, childLinkFn);
|
||||
linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
|
||||
//use the previous context only for the first element in the virtual group
|
||||
previousCompileContext = null;
|
||||
}
|
||||
@@ -906,9 +911,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
|
||||
|
||||
// copy nodeList so that linking doesn't break due to live list updates.
|
||||
var stableNodeList = [];
|
||||
for (i = 0, ii = nodeList.length; i < ii; i++) {
|
||||
stableNodeList.push(nodeList[i]);
|
||||
var nodeListLength = nodeList.length,
|
||||
stableNodeList = new Array(nodeListLength);
|
||||
for (i = 0; i < nodeListLength; i++) {
|
||||
stableNodeList[i] = nodeList[i];
|
||||
}
|
||||
|
||||
for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
|
||||
@@ -921,7 +927,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (nodeLinkFn.scope) {
|
||||
childScope = scope.$new();
|
||||
$node.data('$scope', childScope);
|
||||
safeAddClass($node, 'ng-scope');
|
||||
} else {
|
||||
childScope = scope;
|
||||
}
|
||||
@@ -1004,9 +1009,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
nName = directiveNormalize(name.toLowerCase());
|
||||
attrsMap[nName] = name;
|
||||
attrs[nName] = value = trim((msie && name == 'href')
|
||||
? decodeURIComponent(node.getAttribute(name, 2))
|
||||
: attr.value);
|
||||
attrs[nName] = value = trim(attr.value);
|
||||
if (getBooleanAttrName(node, nName)) {
|
||||
attrs[nName] = true; // presence means true
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngHref
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in an href attribute will
|
||||
@@ -87,6 +88,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSrc
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in a `src` attribute doesn't
|
||||
@@ -112,6 +114,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSrcset
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
|
||||
@@ -137,6 +140,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngDisabled
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
*
|
||||
@@ -180,6 +184,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngChecked
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
@@ -214,6 +219,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngReadonly
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
@@ -223,7 +229,6 @@
|
||||
* The `ngReadonly` directive solves this problem for the `readonly` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -249,6 +254,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSelected
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
@@ -258,6 +264,7 @@
|
||||
* The `ngSelected` directive solves this problem for the `selected` atttribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -285,6 +292,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngOpen
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
@@ -294,8 +302,6 @@
|
||||
* The `ngOpen` directive solves this problem for the `open` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
|
||||
@@ -395,15 +395,17 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
// In composition mode, users are still inputing intermediate text buffer,
|
||||
// hold the listener until composition is done.
|
||||
// More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
|
||||
var composing = false;
|
||||
if (!$sniffer.android) {
|
||||
var composing = false;
|
||||
|
||||
element.on('compositionstart', function() {
|
||||
composing = true;
|
||||
});
|
||||
element.on('compositionstart', function(data) {
|
||||
composing = true;
|
||||
});
|
||||
|
||||
element.on('compositionend', function() {
|
||||
composing = false;
|
||||
});
|
||||
element.on('compositionend', function() {
|
||||
composing = false;
|
||||
});
|
||||
}
|
||||
|
||||
var listener = function() {
|
||||
if (composing) return;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
*
|
||||
* Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
|
||||
* cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
|
||||
* class `ngCloak` in addition to the `ngCloak` directive as shown in the example below.
|
||||
* class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
|
||||
*
|
||||
* @element ANY
|
||||
*
|
||||
|
||||
@@ -69,7 +69,14 @@ forEach(
|
||||
* a dblclick. (The Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-dblclick="count = count + 1" ng-init="count=0">
|
||||
Increment (on double click)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -85,7 +92,14 @@ forEach(
|
||||
* mousedown. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mousedown="count = count + 1" ng-init="count=0">
|
||||
Increment (on mouse down)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -101,7 +115,14 @@ forEach(
|
||||
* mouseup. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseup="count = count + 1" ng-init="count=0">
|
||||
Increment (on mouse up)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -116,7 +137,14 @@ forEach(
|
||||
* mouseover. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseover="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse is over)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -132,7 +160,14 @@ forEach(
|
||||
* mouseenter. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseenter="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse enters)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -148,7 +183,14 @@ forEach(
|
||||
* mouseleave. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseleave="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse leaves)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -164,7 +206,14 @@ forEach(
|
||||
* mousemove. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mousemove="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse moves)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -180,7 +229,12 @@ forEach(
|
||||
* keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keydown="count = count + 1" ng-init="count=0">
|
||||
key down count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -196,7 +250,12 @@ forEach(
|
||||
* keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keyup="count = count + 1" ng-init="count=0">
|
||||
key up count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -212,7 +271,12 @@ forEach(
|
||||
* keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keypress="count = count + 1" ng-init="count=0">
|
||||
key press count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -311,7 +375,12 @@ forEach(
|
||||
* copy. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
|
||||
copied: {{copied}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -326,7 +395,12 @@ forEach(
|
||||
* cut. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
|
||||
cut: {{cut}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -341,5 +415,10 @@ forEach(
|
||||
* paste. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
|
||||
pasted: {{paste}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
/*
|
||||
The transition styles can also be placed on the CSS base class above
|
||||
*/
|
||||
.animate-if.ng-enter, .animate-if.ng-leave {
|
||||
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* current scope.
|
||||
*
|
||||
* <div class="alert alert-error">
|
||||
* The only appropriate use of `ngInit` for aliasing special properties of
|
||||
* The only appropriate use of `ngInit` is for aliasing special properties of
|
||||
* {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
|
||||
* should use {@link guide/controller controllers} rather than `ngInit`
|
||||
* to initialize values on a scope.
|
||||
|
||||
@@ -203,7 +203,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
$$tlb: true,
|
||||
link: function($scope, $element, $attr, ctrl, $transclude){
|
||||
var expression = $attr.ngRepeat;
|
||||
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
|
||||
var match = expression.match(/^\s*(.+)\s+in\s+([\r\n\s\S]*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
|
||||
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
|
||||
lhs, rhs, valueIdentifier, keyIdentifier,
|
||||
hashFnLocals = {$id: hashKey};
|
||||
|
||||
@@ -221,18 +221,10 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
|
||||
|
||||
// required validator
|
||||
if (multiple && (attr.required || attr.ngRequired)) {
|
||||
var requiredValidator = function(value) {
|
||||
ngModelCtrl.$setValidity('required', !attr.required || (value && value.length));
|
||||
return value;
|
||||
if (multiple) {
|
||||
ngModelCtrl.$isEmpty = function(value) {
|
||||
return !value || value.length === 0;
|
||||
};
|
||||
|
||||
ngModelCtrl.$parsers.push(requiredValidator);
|
||||
ngModelCtrl.$formatters.unshift(requiredValidator);
|
||||
|
||||
attr.$observe('required', function() {
|
||||
requiredValidator(ngModelCtrl.$viewValue);
|
||||
});
|
||||
}
|
||||
|
||||
if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
|
||||
|
||||
@@ -24,6 +24,14 @@ function $IntervalProvider() {
|
||||
* In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
|
||||
* move forward by `millis` milliseconds and trigger any functions scheduled to run in that
|
||||
* time.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note**: Intervals created by this service must be explicitly destroyed when you are finished
|
||||
* with them. In particular they are not automatically destroyed when a controller's scope or a
|
||||
* directive's element are destroyed.
|
||||
* You should take this into consideration and make sure to always cancel the interval at the
|
||||
* appropriate moment. See the example below for more details on how and when to do this.
|
||||
* </div>
|
||||
*
|
||||
* @param {function()} fn A function that should be called repeatedly.
|
||||
* @param {number} delay Number of milliseconds between each function call.
|
||||
@@ -32,6 +40,95 @@ function $IntervalProvider() {
|
||||
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
||||
* will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
|
||||
* @returns {promise} A promise which will be notified on each iteration.
|
||||
*
|
||||
* @example
|
||||
<doc:example module="time">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl2($scope,$interval) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
|
||||
var stop;
|
||||
$scope.fight = function() {
|
||||
// Don't start a new fight if we are already fighting
|
||||
if ( angular.isDefined(stop) ) return;
|
||||
|
||||
stop = $interval(function() {
|
||||
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
||||
$scope.blood_1 = $scope.blood_1 - 3;
|
||||
$scope.blood_2 = $scope.blood_2 - 4;
|
||||
} else {
|
||||
$scope.stopFight();
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.stopFight = function() {
|
||||
if (angular.isDefined(stop)) {
|
||||
$interval.cancel(stop);
|
||||
stop = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.resetFight = function() {
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
}
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
// Make sure that the interval is destroyed too
|
||||
$scope.stopFight();
|
||||
});
|
||||
}
|
||||
|
||||
angular.module('time', [])
|
||||
// Register the 'myCurrentTime' directive factory method.
|
||||
// We inject $interval and dateFilter service since the factory method is DI.
|
||||
.directive('myCurrentTime', function($interval, dateFilter) {
|
||||
// return the directive link function. (compile function not needed)
|
||||
return function(scope, element, attrs) {
|
||||
var format, // date format
|
||||
stopTime; // so that we can cancel the time updates
|
||||
|
||||
// used to update the UI
|
||||
function updateTime() {
|
||||
element.text(dateFilter(new Date(), format));
|
||||
}
|
||||
|
||||
// watch the expression, and update the UI on change.
|
||||
scope.$watch(attrs.myCurrentTime, function(value) {
|
||||
format = value;
|
||||
updateTime();
|
||||
});
|
||||
|
||||
stopTime = $interval(updateTime, 1000);
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$interval.cancel(stopTime);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div ng-controller="Ctrl2">
|
||||
Date format: <input ng-model="format"> <hr/>
|
||||
Current time is: <span my-current-time="format"></span>
|
||||
<hr/>
|
||||
Blood 1 : <font color='red'>{{blood_1}}</font>
|
||||
Blood 2 : <font color='red'>{{blood_2}}</font>
|
||||
<button type="button" data-ng-click="fight()">Fight</button>
|
||||
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
||||
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
function interval(fn, delay, count, invokeApply) {
|
||||
var setInterval = $window.setInterval,
|
||||
|
||||
@@ -629,6 +629,13 @@ function $LocationProvider(){
|
||||
}
|
||||
|
||||
var absHref = elm.prop('href');
|
||||
|
||||
if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
|
||||
// SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
|
||||
// an animation.
|
||||
absHref = urlResolve(absHref.animVal).href;
|
||||
}
|
||||
|
||||
var rewrittenUrl = $location.$$rewrite(absHref);
|
||||
|
||||
if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
|
||||
|
||||
+9
-2
@@ -139,9 +139,16 @@ function $LogProvider(){
|
||||
|
||||
function consoleLog(type) {
|
||||
var console = $window.console || {},
|
||||
logFn = console[type] || console.log || noop;
|
||||
logFn = console[type] || console.log || noop,
|
||||
hasApply = false;
|
||||
|
||||
if (logFn.apply) {
|
||||
// Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
|
||||
// The reason behind this is that console.log has type "object" in IE8...
|
||||
try {
|
||||
hasApply = !! logFn.apply;
|
||||
} catch (e) {}
|
||||
|
||||
if (hasApply) {
|
||||
return function() {
|
||||
var args = [];
|
||||
forEach(arguments, function(arg) {
|
||||
|
||||
+42
-17
@@ -891,19 +891,19 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
? function cspSafeGetter(scope, locals) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
|
||||
|
||||
if (pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return pathVal;
|
||||
pathVal = pathVal[key0];
|
||||
|
||||
if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key1 ? undefined : pathVal;
|
||||
pathVal = pathVal[key1];
|
||||
|
||||
if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key2 ? undefined : pathVal;
|
||||
pathVal = pathVal[key2];
|
||||
|
||||
if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key3 ? undefined : pathVal;
|
||||
pathVal = pathVal[key3];
|
||||
|
||||
if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key4 ? undefined : pathVal;
|
||||
pathVal = pathVal[key4];
|
||||
|
||||
return pathVal;
|
||||
@@ -912,7 +912,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
|
||||
promise;
|
||||
|
||||
if (pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return pathVal;
|
||||
|
||||
pathVal = pathVal[key0];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -924,7 +924,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key1 ? undefined : pathVal;
|
||||
|
||||
pathVal = pathVal[key1];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -936,7 +936,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key2 ? undefined : pathVal;
|
||||
|
||||
pathVal = pathVal[key2];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -948,7 +948,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key3 ? undefined : pathVal;
|
||||
|
||||
pathVal = pathVal[key3];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -960,7 +960,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key4 ? undefined : pathVal;
|
||||
|
||||
pathVal = pathVal[key4];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -976,6 +976,26 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
};
|
||||
}
|
||||
|
||||
function simpleGetterFn1(key0, fullExp) {
|
||||
ensureSafeMemberName(key0, fullExp);
|
||||
|
||||
return function simpleGetterFn1(scope, locals) {
|
||||
if (scope == null) return undefined;
|
||||
return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
||||
};
|
||||
}
|
||||
|
||||
function simpleGetterFn2(key0, key1, fullExp) {
|
||||
ensureSafeMemberName(key0, fullExp);
|
||||
ensureSafeMemberName(key1, fullExp);
|
||||
|
||||
return function simpleGetterFn2(scope, locals) {
|
||||
if (scope == null) return undefined;
|
||||
scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
||||
return scope == null ? undefined : scope[key1];
|
||||
};
|
||||
}
|
||||
|
||||
function getterFn(path, options, fullExp) {
|
||||
// Check whether the cache has this getter already.
|
||||
// We can use hasOwnProperty directly on the cache because we ensure,
|
||||
@@ -988,7 +1008,13 @@ function getterFn(path, options, fullExp) {
|
||||
pathKeysLength = pathKeys.length,
|
||||
fn;
|
||||
|
||||
if (options.csp) {
|
||||
// When we have only 1 or 2 tokens, use optimized special case closures.
|
||||
// http://jsperf.com/angularjs-parse-getter/6
|
||||
if (!options.unwrapPromises && pathKeysLength === 1) {
|
||||
fn = simpleGetterFn1(pathKeys[0], fullExp);
|
||||
} else if (!options.unwrapPromises && pathKeysLength === 2) {
|
||||
fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
|
||||
} else if (options.csp) {
|
||||
if (pathKeysLength < 6) {
|
||||
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
|
||||
options);
|
||||
@@ -1006,11 +1032,10 @@ function getterFn(path, options, fullExp) {
|
||||
};
|
||||
}
|
||||
} else {
|
||||
var code = 'var l, fn, p;\n';
|
||||
var code = 'var p;\n';
|
||||
forEach(pathKeys, function(key, index) {
|
||||
ensureSafeMemberName(key, fullExp);
|
||||
code += 'if(s === null || s === undefined) return s;\n' +
|
||||
'l=s;\n' +
|
||||
code += 'if(s == null) return undefined;\n' +
|
||||
's='+ (index
|
||||
// we simply dereference 's' on any .dot notation
|
||||
? 's'
|
||||
@@ -1033,10 +1058,10 @@ function getterFn(path, options, fullExp) {
|
||||
/* jshint -W054 */
|
||||
var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
|
||||
/* jshint +W054 */
|
||||
evaledFnGetter.toString = function() { return code; };
|
||||
fn = function(scope, locals) {
|
||||
evaledFnGetter.toString = valueFn(code);
|
||||
fn = options.unwrapPromises ? function(scope, locals) {
|
||||
return evaledFnGetter(scope, locals, promiseWarning);
|
||||
};
|
||||
} : evaledFnGetter;
|
||||
}
|
||||
|
||||
// Only cache the value if it's not going to mess up the cache object
|
||||
|
||||
@@ -85,6 +85,7 @@ function $SnifferProvider() {
|
||||
vendorPrefix: vendorPrefix,
|
||||
transitions : transitions,
|
||||
animations : animations,
|
||||
android: android,
|
||||
msie : msie,
|
||||
msieDocumentMode: documentMode
|
||||
};
|
||||
|
||||
@@ -32,93 +32,6 @@ function $TimeoutProvider() {
|
||||
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
|
||||
* promise will be resolved with is the return value of the `fn` function.
|
||||
*
|
||||
* @example
|
||||
<doc:example module="time">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl2($scope,$timeout) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
|
||||
var stop;
|
||||
$scope.fight = function() {
|
||||
stop = $timeout(function() {
|
||||
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
||||
$scope.blood_1 = $scope.blood_1 - 3;
|
||||
$scope.blood_2 = $scope.blood_2 - 4;
|
||||
$scope.fight();
|
||||
} else {
|
||||
$timeout.cancel(stop);
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.stopFight = function() {
|
||||
$timeout.cancel(stop);
|
||||
};
|
||||
|
||||
$scope.resetFight = function() {
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('time', [])
|
||||
// Register the 'myCurrentTime' directive factory method.
|
||||
// We inject $timeout and dateFilter service since the factory method is DI.
|
||||
.directive('myCurrentTime', function($timeout, dateFilter) {
|
||||
// return the directive link function. (compile function not needed)
|
||||
return function(scope, element, attrs) {
|
||||
var format, // date format
|
||||
timeoutId; // timeoutId, so that we can cancel the time updates
|
||||
|
||||
// used to update the UI
|
||||
function updateTime() {
|
||||
element.text(dateFilter(new Date(), format));
|
||||
}
|
||||
|
||||
// watch the expression, and update the UI on change.
|
||||
scope.$watch(attrs.myCurrentTime, function(value) {
|
||||
format = value;
|
||||
updateTime();
|
||||
});
|
||||
|
||||
// schedule update in one second
|
||||
function updateLater() {
|
||||
// save the timeoutId for canceling
|
||||
timeoutId = $timeout(function() {
|
||||
updateTime(); // update DOM
|
||||
updateLater(); // schedule another update
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$timeout.cancel(timeoutId);
|
||||
});
|
||||
|
||||
updateLater(); // kick off the UI update process.
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div ng-controller="Ctrl2">
|
||||
Date format: <input ng-model="format"> <hr/>
|
||||
Current time is: <span my-current-time="format"></span>
|
||||
<hr/>
|
||||
Blood 1 : <font color='red'>{{blood_1}}</font>
|
||||
Blood 2 : <font color='red'>{{blood_2}}</font>
|
||||
<button type="button" data-ng-click="fight()">Fight</button>
|
||||
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
||||
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
function timeout(fn, delay, invokeApply) {
|
||||
var deferred = $q.defer(),
|
||||
|
||||
+91
-39
@@ -288,6 +288,13 @@ angular.module('ngAnimate', ['ng'])
|
||||
});
|
||||
});
|
||||
|
||||
var classNameFilter = $animateProvider.classNameFilter();
|
||||
var isAnimatableClassName = !classNameFilter
|
||||
? function() { return true; }
|
||||
: function(className) {
|
||||
return classNameFilter.test(className);
|
||||
};
|
||||
|
||||
function lookup(name) {
|
||||
if (name) {
|
||||
var matches = [],
|
||||
@@ -569,17 +576,20 @@ angular.module('ngAnimate', ['ng'])
|
||||
and the onComplete callback will be fired once the animation is fully complete.
|
||||
*/
|
||||
function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
|
||||
var node = extractElementNode(element);
|
||||
var currentClassName, classes, node = extractElementNode(element);
|
||||
if(node) {
|
||||
currentClassName = node.className;
|
||||
classes = currentClassName + ' ' + className;
|
||||
}
|
||||
|
||||
//transcluded directives may sometimes fire an animation using only comment nodes
|
||||
//best to catch this early on to prevent any animation operations from occurring
|
||||
if(!node) {
|
||||
if(!node || !isAnimatableClassName(classes)) {
|
||||
fireDOMOperation();
|
||||
closeAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
var currentClassName = node.className;
|
||||
var classes = currentClassName + ' ' + className;
|
||||
var animationLookup = (' ' + classes).replace(/\s+/g,'.');
|
||||
if (!parentElement) {
|
||||
parentElement = afterElement ? afterElement.parent() : element.parent();
|
||||
@@ -881,27 +891,73 @@ angular.module('ngAnimate', ['ng'])
|
||||
var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
|
||||
var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
|
||||
var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
|
||||
var NG_ANIMATE_FALLBACK_CLASS_NAME = 'ng-animate-start';
|
||||
var NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME = 'ng-animate-active';
|
||||
var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
|
||||
var CLOSING_TIME_BUFFER = 1.5;
|
||||
var ONE_SECOND = 1000;
|
||||
|
||||
var animationCounter = 0;
|
||||
var lookupCache = {};
|
||||
var parentCounter = 0;
|
||||
|
||||
var animationReflowQueue = [], animationTimer, timeOut = false;
|
||||
function afterReflow(callback) {
|
||||
animationReflowQueue.push(callback);
|
||||
var animationReflowQueue = [];
|
||||
var animationElementQueue = [];
|
||||
var animationTimer;
|
||||
var closingAnimationTime = 0;
|
||||
var timeOut = false;
|
||||
function afterReflow(element, callback) {
|
||||
$timeout.cancel(animationTimer);
|
||||
|
||||
animationReflowQueue.push(callback);
|
||||
|
||||
var node = extractElementNode(element);
|
||||
element = angular.element(node);
|
||||
animationElementQueue.push(element);
|
||||
|
||||
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
closingAnimationTime = Math.max(closingAnimationTime,
|
||||
(elementData.maxDelay + elementData.maxDuration) * CLOSING_TIME_BUFFER * ONE_SECOND);
|
||||
|
||||
//by placing a counter we can avoid an accidental
|
||||
//race condition which may close an animation when
|
||||
//a follow-up animation is midway in its animation
|
||||
elementData.animationCount = animationCounter;
|
||||
|
||||
animationTimer = $timeout(function() {
|
||||
forEach(animationReflowQueue, function(fn) {
|
||||
fn();
|
||||
});
|
||||
|
||||
//copy the list of elements so that successive
|
||||
//animations won't conflict if they're added before
|
||||
//the closing animation timeout has run
|
||||
var elementQueueSnapshot = [];
|
||||
var animationCounterSnapshot = animationCounter;
|
||||
forEach(animationElementQueue, function(elm) {
|
||||
elementQueueSnapshot.push(elm);
|
||||
});
|
||||
|
||||
$timeout(function() {
|
||||
closeAllAnimations(elementQueueSnapshot, animationCounterSnapshot);
|
||||
elementQueueSnapshot = null;
|
||||
}, closingAnimationTime, false);
|
||||
|
||||
animationReflowQueue = [];
|
||||
animationElementQueue = [];
|
||||
animationTimer = null;
|
||||
lookupCache = {};
|
||||
closingAnimationTime = 0;
|
||||
animationCounter++;
|
||||
}, 10, false);
|
||||
}
|
||||
|
||||
function closeAllAnimations(elements, count) {
|
||||
forEach(elements, function(element) {
|
||||
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
if(elementData && elementData.animationCount == count) {
|
||||
(elementData.closeAnimationFn || noop)();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getElementAnimationDetails(element, cacheKey) {
|
||||
var data = cacheKey ? lookupCache[cacheKey] : null;
|
||||
if(!data) {
|
||||
@@ -1007,6 +1063,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
timeout is empty (this would cause a flicker bug normally
|
||||
in the page. There is also no point in performing an animation
|
||||
that only has a delay and no duration */
|
||||
var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
|
||||
var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
|
||||
if(maxDuration === 0) {
|
||||
element.removeClass(className);
|
||||
@@ -1016,13 +1073,9 @@ angular.module('ngAnimate', ['ng'])
|
||||
//temporarily disable the transition so that the enter styles
|
||||
//don't animate twice (this is here to avoid a bug in Chrome/FF).
|
||||
var activeClassName = '';
|
||||
if(timings.transitionDuration > 0) {
|
||||
element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
|
||||
activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' ';
|
||||
blockTransitions(element);
|
||||
} else {
|
||||
timings.transitionDuration > 0 ?
|
||||
blockTransitions(element) :
|
||||
blockKeyframeAnimations(element);
|
||||
}
|
||||
|
||||
forEach(className.split(' '), function(klass, i) {
|
||||
activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
|
||||
@@ -1032,6 +1085,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
className : className,
|
||||
activeClassName : activeClassName,
|
||||
maxDuration : maxDuration,
|
||||
maxDelay : maxDelay,
|
||||
classes : className + ' ' + activeClassName,
|
||||
timings : timings,
|
||||
stagger : stagger,
|
||||
@@ -1066,30 +1120,28 @@ angular.module('ngAnimate', ['ng'])
|
||||
}
|
||||
|
||||
function animateRun(element, className, activeAnimationComplete) {
|
||||
var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
||||
var node = extractElementNode(element);
|
||||
if(node.className.indexOf(className) == -1 || !data) {
|
||||
if(node.className.indexOf(className) == -1 || !elementData) {
|
||||
activeAnimationComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
var timings = data.timings;
|
||||
var stagger = data.stagger;
|
||||
var maxDuration = data.maxDuration;
|
||||
var activeClassName = data.activeClassName;
|
||||
var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * 1000;
|
||||
var timings = elementData.timings;
|
||||
var stagger = elementData.stagger;
|
||||
var maxDuration = elementData.maxDuration;
|
||||
var activeClassName = elementData.activeClassName;
|
||||
var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * ONE_SECOND;
|
||||
var startTime = Date.now();
|
||||
var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
|
||||
var ii = data.ii;
|
||||
var ii = elementData.ii;
|
||||
|
||||
var applyFallbackStyle, style = '', appliedStyles = [];
|
||||
var style = '', appliedStyles = [];
|
||||
if(timings.transitionDuration > 0) {
|
||||
var propertyStyle = timings.transitionPropertyStyle;
|
||||
if(propertyStyle.indexOf('all') == -1) {
|
||||
applyFallbackStyle = true;
|
||||
var fallbackProperty = $sniffer.msie ? '-ms-zoom' : 'border-spacing';
|
||||
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; ';
|
||||
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; ';
|
||||
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ';';
|
||||
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + 's;';
|
||||
appliedStyles.push(CSS_PREFIX + 'transition-property');
|
||||
appliedStyles.push(CSS_PREFIX + 'transition-duration');
|
||||
}
|
||||
@@ -1098,10 +1150,6 @@ angular.module('ngAnimate', ['ng'])
|
||||
if(ii > 0) {
|
||||
if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
|
||||
var delayStyle = timings.transitionDelayStyle;
|
||||
if(applyFallbackStyle) {
|
||||
delayStyle += ', ' + timings.transitionDelay + 's';
|
||||
}
|
||||
|
||||
style += CSS_PREFIX + 'transition-delay: ' +
|
||||
prepareStaggerDelay(delayStyle, stagger.transitionDelay, ii) + '; ';
|
||||
appliedStyles.push(CSS_PREFIX + 'transition-delay');
|
||||
@@ -1124,11 +1172,16 @@ angular.module('ngAnimate', ['ng'])
|
||||
|
||||
element.on(css3AnimationEvents, onAnimationProgress);
|
||||
element.addClass(activeClassName);
|
||||
elementData.closeAnimationFn = function() {
|
||||
onEnd();
|
||||
activeAnimationComplete();
|
||||
};
|
||||
return onEnd;
|
||||
|
||||
// This will automatically be called by $animate so
|
||||
// there is no need to attach this internally to the
|
||||
// timeout done method.
|
||||
return function onEnd(cancelled) {
|
||||
function onEnd(cancelled) {
|
||||
element.off(css3AnimationEvents, onAnimationProgress);
|
||||
element.removeClass(activeClassName);
|
||||
animateClose(element, className);
|
||||
@@ -1136,7 +1189,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
for (var i in appliedStyles) {
|
||||
node.style.removeProperty(appliedStyles[i]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function onAnimationProgress(event) {
|
||||
event.stopPropagation();
|
||||
@@ -1202,7 +1255,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
//data from the element which will not make the 2nd animation
|
||||
//happen in the first place
|
||||
var cancel = preReflowCancellation;
|
||||
afterReflow(function() {
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element);
|
||||
unblockKeyframeAnimations(element);
|
||||
//once the reflow is complete then we point cancel to
|
||||
@@ -1218,7 +1271,6 @@ angular.module('ngAnimate', ['ng'])
|
||||
|
||||
function animateClose(element, className) {
|
||||
element.removeClass(className);
|
||||
element.removeClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
|
||||
element.removeData(NG_ANIMATE_CSS_DATA_KEY);
|
||||
}
|
||||
|
||||
@@ -1268,7 +1320,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
beforeAddClass : function(element, className, animationCompleted) {
|
||||
var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'));
|
||||
if(cancellationMethod) {
|
||||
afterReflow(function() {
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element);
|
||||
unblockKeyframeAnimations(element);
|
||||
animationCompleted();
|
||||
@@ -1285,7 +1337,7 @@ angular.module('ngAnimate', ['ng'])
|
||||
beforeRemoveClass : function(element, className, animationCompleted) {
|
||||
var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'));
|
||||
if(cancellationMethod) {
|
||||
afterReflow(function() {
|
||||
afterReflow(element, function() {
|
||||
unblockTransitions(element);
|
||||
unblockKeyframeAnimations(element);
|
||||
animationCompleted();
|
||||
|
||||
@@ -35,7 +35,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
});
|
||||
|
||||
for (var key in src) {
|
||||
if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
|
||||
if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
* when a param value needs to be obtained for a request (unless the param was overridden).
|
||||
*
|
||||
* Each key value in the parameter object is first bound to url template if present and then any
|
||||
* excess keys are appended to the url search query after the `?`.
|
||||
* excess keys are appended to the url seapph query after the `?`.
|
||||
*
|
||||
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
|
||||
* URL `/path/greet?salutation=Hello`.
|
||||
@@ -237,7 +237,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
newCard.name = "Mike Smith";
|
||||
newCard.$save();
|
||||
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
|
||||
// server returns: {id:789, number:'01234', name: 'Mike Smith'};
|
||||
// server returns: {id:789, number:'0123', name: 'Mike Smith'};
|
||||
expect(newCard.id).toEqual(789);
|
||||
* </pre>
|
||||
*
|
||||
@@ -272,6 +272,35 @@ function shallowClearAndCopy(src, dst) {
|
||||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
* # Creating a custom 'PUT' request
|
||||
* In this example we create a custom method on our resource to make a PUT request
|
||||
* <pre>
|
||||
* var app = angular.module('app', ['ngResource', 'ngRoute']);
|
||||
*
|
||||
* // Some APIs expect a PUT request in the format URL/object/ID
|
||||
* // Here we are creating an 'update' method
|
||||
* app.factory('Notes', ['$resource', function($resource) {
|
||||
* return $resource('/notes/:id', null,
|
||||
* {
|
||||
* 'update': { method:'PUT' }
|
||||
* });
|
||||
* }]);
|
||||
*
|
||||
* // In our controller we get the ID from the URL using ngRoute and $routeParams
|
||||
* // We pass in $routeParams and our Notes factory along with $scope
|
||||
* app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
|
||||
function($scope, $routeParams, Notes) {
|
||||
* // First get a note object from the factory
|
||||
* var note = Notes.get({ id:$routeParams.id });
|
||||
* $id = note.id;
|
||||
*
|
||||
* // Now call update passing in the ID first then the object you are updating
|
||||
* Notes.update({ id:$id }, note);
|
||||
*
|
||||
* // This will PUT /notes/ID with the note object in the request payload
|
||||
* }]);
|
||||
* </pre>
|
||||
*/
|
||||
angular.module('ngResource', ['ng']).
|
||||
factory('$resource', ['$http', '$q', function($http, $q) {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
./version.js --minor-bump
|
||||
VERSION=`./version.js --curent`
|
||||
git commit -a -m "chore(relase): start v$VERSION iteration"
|
||||
@@ -504,6 +504,21 @@ describe('angular', function() {
|
||||
expect(log).toEqual(['0:a', '1:c']);
|
||||
});
|
||||
|
||||
if (document.querySelectorAll) {
|
||||
it('should handle the result of querySelectorAll in IE8 as it has no hasOwnProperty function', function() {
|
||||
document.body.innerHTML = "<p>" +
|
||||
"<a name='x'>a</a>" +
|
||||
"<a name='y'>b</a>" +
|
||||
"<a name='x'>c</a>" +
|
||||
"</p>";
|
||||
|
||||
var htmlCollection = document.querySelectorAll('[name="x"]'),
|
||||
log = [];
|
||||
|
||||
forEach(htmlCollection, function(value, key) { log.push(key + ':' + value.innerHTML)});
|
||||
expect(log).toEqual(['0:a', '1:c']);
|
||||
});
|
||||
}
|
||||
|
||||
it('should handle arguments objects like arrays', function() {
|
||||
var args,
|
||||
|
||||
@@ -1120,6 +1120,26 @@ describe('jqLite', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should deregister specific listener within the listener and call subsequent listeners', function() {
|
||||
var aElem = jqLite(a),
|
||||
clickSpy = jasmine.createSpy('click'),
|
||||
clickOnceSpy = jasmine.createSpy('clickOnce').andCallFake(function() {
|
||||
aElem.off('click', clickOnceSpy);
|
||||
});
|
||||
|
||||
aElem.on('click', clickOnceSpy);
|
||||
aElem.on('click', clickSpy);
|
||||
|
||||
browserTrigger(a, 'click');
|
||||
expect(clickOnceSpy).toHaveBeenCalledOnce();
|
||||
expect(clickSpy).toHaveBeenCalledOnce();
|
||||
|
||||
browserTrigger(a, 'click');
|
||||
expect(clickOnceSpy).toHaveBeenCalledOnce();
|
||||
expect(clickSpy.callCount).toBe(2);
|
||||
});
|
||||
|
||||
|
||||
it('should deregister specific listener for multiple types separated by spaces', function() {
|
||||
var aElem = jqLite(a),
|
||||
masterSpy = jasmine.createSpy('master'),
|
||||
@@ -1157,6 +1177,63 @@ describe('jqLite', function() {
|
||||
}
|
||||
});
|
||||
|
||||
describe('one', function() {
|
||||
|
||||
it('should only fire the callback once', function() {
|
||||
var element = jqLite(a);
|
||||
var spy = jasmine.createSpy('click');
|
||||
|
||||
element.one('click', spy);
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
expect(spy).toHaveBeenCalledOnce();
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
expect(spy).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('should deregister when off is called', function() {
|
||||
var element = jqLite(a);
|
||||
var spy = jasmine.createSpy('click');
|
||||
|
||||
element.one('click', spy);
|
||||
element.off('click', spy);
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return the same event object just as on() does', function() {
|
||||
var element = jqLite(a);
|
||||
var eventA, eventB;
|
||||
element.on('click', function(event) {
|
||||
eventA = event;
|
||||
});
|
||||
element.one('click', function(event) {
|
||||
eventB = event;
|
||||
});
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
expect(eventA).toEqual(eventB);
|
||||
});
|
||||
|
||||
it('should not remove other event handlers of the same type after execution', function() {
|
||||
var element = jqLite(a);
|
||||
var calls = [];
|
||||
element.one('click', function(event) {
|
||||
calls.push('one');
|
||||
});
|
||||
element.on('click', function(event) {
|
||||
calls.push('on');
|
||||
});
|
||||
|
||||
browserTrigger(element, 'click');
|
||||
browserTrigger(element, 'click');
|
||||
|
||||
expect(calls).toEqual(['one','on','on']);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('replaceWith', function() {
|
||||
it('should replaceWith', function() {
|
||||
|
||||
@@ -4243,7 +4243,13 @@ describe('$compile', function() {
|
||||
expect(element.attr('test2')).toBe('Misko');
|
||||
expect(element.attr('test3')).toBe('Misko');
|
||||
}));
|
||||
|
||||
|
||||
it('should work with the "href" attribute', inject(function($compile, $rootScope) {
|
||||
$rootScope.value = 'test';
|
||||
element = $compile('<a ng-attr-href="test/{{value}}"></a>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('href')).toBe('test/test');
|
||||
}));
|
||||
|
||||
it('should work if they are prefixed with x- or data-', inject(function($compile, $rootScope) {
|
||||
$rootScope.name = "Misko";
|
||||
|
||||
@@ -477,19 +477,37 @@ describe('input', function() {
|
||||
expect(scope.name).toEqual('adam');
|
||||
});
|
||||
|
||||
it('should not update the model between "compositionstart" and "compositionend"', function() {
|
||||
compileInput('<input type="text" ng-model="name" name="alias"" />');
|
||||
changeInputValueTo('a');
|
||||
expect(scope.name).toEqual('a');
|
||||
if (!(msie < 9)) {
|
||||
browserTrigger(inputElm, 'compositionstart');
|
||||
changeInputValueTo('adam');
|
||||
expect(scope.name).toEqual('a');
|
||||
browserTrigger(inputElm, 'compositionend');
|
||||
}
|
||||
changeInputValueTo('adam');
|
||||
expect(scope.name).toEqual('adam');
|
||||
});
|
||||
if (!(msie < 9)) {
|
||||
describe('compositionevents', function() {
|
||||
it('should not update the model between "compositionstart" and "compositionend" on non android', inject(function($sniffer) {
|
||||
$sniffer.android = false;
|
||||
|
||||
compileInput('<input type="text" ng-model="name" name="alias"" />');
|
||||
changeInputValueTo('a');
|
||||
expect(scope.name).toEqual('a');
|
||||
browserTrigger(inputElm, 'compositionstart');
|
||||
changeInputValueTo('adam');
|
||||
expect(scope.name).toEqual('a');
|
||||
browserTrigger(inputElm, 'compositionend');
|
||||
changeInputValueTo('adam');
|
||||
expect(scope.name).toEqual('adam');
|
||||
}));
|
||||
|
||||
it('should update the model between "compositionstart" and "compositionend" on android', inject(function($sniffer) {
|
||||
$sniffer.android = true;
|
||||
|
||||
compileInput('<input type="text" ng-model="name" name="alias"" />');
|
||||
changeInputValueTo('a');
|
||||
expect(scope.name).toEqual('a');
|
||||
browserTrigger(inputElm, 'compositionstart');
|
||||
changeInputValueTo('adam');
|
||||
expect(scope.name).toEqual('adam');
|
||||
browserTrigger(inputElm, 'compositionend');
|
||||
changeInputValueTo('adam2');
|
||||
expect(scope.name).toEqual('adam2');
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
describe('"change" event', function() {
|
||||
function assertBrowserSupportsChangeEvent(inputEventSupported) {
|
||||
|
||||
@@ -177,6 +177,22 @@ describe('ngRepeat', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should allow expressions over multiple lines', function() {
|
||||
scope.isTrue = function() {
|
||||
return true;
|
||||
};
|
||||
element = $compile(
|
||||
'<ul>' +
|
||||
'<li ng-repeat="item in items\n' +
|
||||
'| filter:isTrue">{{item.name}}</li>' +
|
||||
'</ul>')(scope);
|
||||
scope.items = [{name: 'igor'}];
|
||||
scope.$digest();
|
||||
|
||||
expect(element.find('li').text()).toBe('igor');
|
||||
});
|
||||
|
||||
|
||||
it('should track using provided function when a filter is present', function() {
|
||||
scope.newArray = function (items) {
|
||||
var newArray = [];
|
||||
|
||||
@@ -1215,6 +1215,30 @@ describe('select', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should treat an empty array as invalid when `multiple` attribute used', function() {
|
||||
createSelect({
|
||||
'ng-model': 'value',
|
||||
'ng-options': 'item.name for item in values',
|
||||
'ng-required': 'required',
|
||||
'multiple': ''
|
||||
}, true);
|
||||
|
||||
scope.$apply(function() {
|
||||
scope.value = [];
|
||||
scope.values = [{name: 'A', id: 1}, {name: 'B', id: 2}];
|
||||
scope.required = true;
|
||||
});
|
||||
expect(element).toBeInvalid();
|
||||
|
||||
scope.$apply(function() {
|
||||
// ngModelWatch does not set objectEquality flag
|
||||
// array must be replaced in order to trigger $formatters
|
||||
scope.value = [scope.values[0]];
|
||||
});
|
||||
expect(element).toBeValid();
|
||||
});
|
||||
|
||||
|
||||
it('should allow falsy values as values', function() {
|
||||
createSelect({
|
||||
'ng-model': 'value',
|
||||
|
||||
@@ -1229,6 +1229,31 @@ describe('$location', function() {
|
||||
});
|
||||
browserTrigger(button, 'click');
|
||||
}));
|
||||
|
||||
|
||||
it('should not throw when clicking an SVGAElement link', function() {
|
||||
var base;
|
||||
module(function($locationProvider) {
|
||||
return function($browser) {
|
||||
window.location.hash = '!someHash';
|
||||
$browser.url(base = window.location.href);
|
||||
base = base.split('#')[0];
|
||||
$locationProvider.hashPrefix('!');
|
||||
}
|
||||
});
|
||||
inject(function($rootScope, $compile, $browser, $rootElement, $document, $location) {
|
||||
// we need to do this otherwise we can't simulate events
|
||||
$document.find('body').append($rootElement);
|
||||
var template = '<svg><g><a xlink:href="#!/view1"><circle r="50"></circle></a></g></svg>';
|
||||
var element = $compile(template)($rootScope);
|
||||
|
||||
$rootElement.append(element);
|
||||
var av1 = $rootElement.find('a').eq(0);
|
||||
expect(function() {
|
||||
browserTrigger(av1, 'click');
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -906,6 +906,7 @@ describe('parser', function() {
|
||||
expect($parse('a.b')({a: {b: 0}}, {a: {b:1}})).toEqual(1);
|
||||
expect($parse('a.b')({a: null}, {a: {b:1}})).toEqual(1);
|
||||
expect($parse('a.b')({a: {b: 0}}, {a: null})).toEqual(undefined);
|
||||
expect($parse('a.b.c')({a: null}, {a: {b: {c: 1}}})).toEqual(1);
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -976,6 +977,55 @@ describe('parser', function() {
|
||||
expect($parse('"name" + id').constant).toBe(false);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('nulls in expressions', function() {
|
||||
// simpleGetterFn1
|
||||
it('should return null for `a` where `a` is null', inject(function($rootScope) {
|
||||
$rootScope.a = null;
|
||||
expect($rootScope.$eval('a')).toBe(null);
|
||||
}));
|
||||
|
||||
it('should return undefined for `a` where `a` is undefined', inject(function($rootScope) {
|
||||
expect($rootScope.$eval('a')).toBeUndefined();
|
||||
}));
|
||||
|
||||
// simpleGetterFn2
|
||||
it('should return undefined for properties of `null` constant', inject(function($rootScope) {
|
||||
expect($rootScope.$eval('null.a')).toBeUndefined();
|
||||
}));
|
||||
|
||||
it('should return undefined for properties of `null` values', inject(function($rootScope) {
|
||||
$rootScope.a = null;
|
||||
expect($rootScope.$eval('a.b')).toBeUndefined();
|
||||
}));
|
||||
|
||||
it('should return null for `a.b` where `b` is null', inject(function($rootScope) {
|
||||
$rootScope.a = { b: null };
|
||||
expect($rootScope.$eval('a.b')).toBe(null);
|
||||
}));
|
||||
|
||||
// cspSafeGetter && pathKeys.length < 6 || pathKeys.length > 2
|
||||
it('should return null for `a.b.c.d.e` where `e` is null', inject(function($rootScope) {
|
||||
$rootScope.a = { b: { c: { d: { e: null } } } };
|
||||
expect($rootScope.$eval('a.b.c.d.e')).toBe(null);
|
||||
}));
|
||||
|
||||
it('should return undefined for `a.b.c.d.e` where `d` is null', inject(function($rootScope) {
|
||||
$rootScope.a = { b: { c: { d: null } } };
|
||||
expect($rootScope.$eval('a.b.c.d.e')).toBeUndefined();
|
||||
}));
|
||||
|
||||
// cspSafeGetter || pathKeys.length > 6
|
||||
it('should return null for `a.b.c.d.e.f.g` where `g` is null', inject(function($rootScope) {
|
||||
$rootScope.a = { b: { c: { d: { e: { f: { g: null } } } } } };
|
||||
expect($rootScope.$eval('a.b.c.d.e.f.g')).toBe(null);
|
||||
}));
|
||||
|
||||
it('should return undefined for `a.b.c.d.e.f.g` where `f` is null', inject(function($rootScope) {
|
||||
$rootScope.a = { b: { c: { d: { e: { f: null } } } } };
|
||||
expect($rootScope.$eval('a.b.c.d.e.f.g')).toBeUndefined();
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -334,6 +334,21 @@ describe('$sniffer', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should provide the android version', function() {
|
||||
module(function($provide) {
|
||||
var win = {
|
||||
navigator: {
|
||||
userAgent: 'android 2'
|
||||
}
|
||||
};
|
||||
$provide.value('$document', jqLite({}));
|
||||
$provide.value('$window', win);
|
||||
});
|
||||
inject(function($sniffer) {
|
||||
expect($sniffer.android).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the internal msie flag', inject(function($sniffer) {
|
||||
expect(isNaN($sniffer.msie)).toBe(isNaN(msie));
|
||||
if (msie) {
|
||||
|
||||
+195
-124
@@ -4,6 +4,7 @@ describe("ngAnimate", function() {
|
||||
|
||||
beforeEach(module('ngAnimate'));
|
||||
|
||||
|
||||
it("should disable animations on bootstrap for structural animations even after the first digest has passed", function() {
|
||||
var hasBeenAnimated = false;
|
||||
module(function($animateProvider) {
|
||||
@@ -37,10 +38,12 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//we use another describe block because the before/after operations below
|
||||
//are used across all animations tests and we don't want that same behavior
|
||||
//to be used on the root describe block at the start of the animateSpec.js file
|
||||
describe('', function() {
|
||||
|
||||
var ss, body;
|
||||
beforeEach(module(function() {
|
||||
body = jqLite(document.body);
|
||||
@@ -61,6 +64,7 @@ describe("ngAnimate", function() {
|
||||
dealoc(body);
|
||||
});
|
||||
|
||||
|
||||
describe("$animate", function() {
|
||||
|
||||
var element, $rootElement;
|
||||
@@ -85,6 +89,7 @@ describe("ngAnimate", function() {
|
||||
expect($animate.enabled()).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should place a hard disable on all child animations', function() {
|
||||
var count = 0;
|
||||
module(function($animateProvider) {
|
||||
@@ -132,6 +137,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should skip animations if the element is attached to the $rootElement', function() {
|
||||
var count = 0;
|
||||
module(function($animateProvider) {
|
||||
@@ -154,6 +160,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should check enable/disable animations up until the $rootElement element', function() {
|
||||
var rootElm = jqLite('<div></div>');
|
||||
|
||||
@@ -195,6 +202,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("with polyfill", function() {
|
||||
|
||||
var child, after;
|
||||
@@ -262,6 +270,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
it("should animate the enter animation event",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
element[0].removeChild(child[0]);
|
||||
@@ -280,6 +289,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.contents().length).toBe(1);
|
||||
}));
|
||||
|
||||
|
||||
it("should animate the leave animation event",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
|
||||
@@ -297,6 +307,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.contents().length).toBe(0);
|
||||
}));
|
||||
|
||||
|
||||
it("should animate the move animation event",
|
||||
inject(function($animate, $compile, $rootScope, $timeout, $sniffer) {
|
||||
|
||||
@@ -316,6 +327,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.text()).toBe('21');
|
||||
}));
|
||||
|
||||
|
||||
it("should animate the show animation event",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
|
||||
@@ -334,6 +346,7 @@ describe("ngAnimate", function() {
|
||||
expect(child).toBeShown();
|
||||
}));
|
||||
|
||||
|
||||
it("should animate the hide animation event",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
|
||||
@@ -349,6 +362,7 @@ describe("ngAnimate", function() {
|
||||
expect(child).toBeHidden();
|
||||
}));
|
||||
|
||||
|
||||
it("should assign the ng-event className to all animation events when transitions/keyframes are used",
|
||||
inject(function($animate, $sniffer, $rootScope, $timeout) {
|
||||
|
||||
@@ -401,6 +415,7 @@ describe("ngAnimate", function() {
|
||||
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
|
||||
}));
|
||||
|
||||
|
||||
it("should not run if animations are disabled",
|
||||
inject(function($animate, $rootScope, $timeout, $sniffer) {
|
||||
|
||||
@@ -425,6 +440,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.text()).toBe('memento');
|
||||
}));
|
||||
|
||||
|
||||
it("should only call done() once and right away if another animation takes place in between",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
|
||||
@@ -457,6 +473,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.children().length).toBe(0);
|
||||
}));
|
||||
|
||||
|
||||
it("should retain existing styles of the animated element",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
|
||||
@@ -478,6 +495,7 @@ describe("ngAnimate", function() {
|
||||
expect(child.attr('style')).toMatch(/width: 20px/i);
|
||||
}));
|
||||
|
||||
|
||||
it("should call the cancel callback when another animation is called on the same element",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
|
||||
@@ -495,6 +513,7 @@ describe("ngAnimate", function() {
|
||||
expect(child.hasClass('animation-cancelled')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should skip a class-based animation if the same element already has an ongoing structural animation",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
|
||||
@@ -519,6 +538,7 @@ describe("ngAnimate", function() {
|
||||
expect(completed).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should fire the cancel/end function with the correct flag in the parameters",
|
||||
inject(function($animate, $rootScope, $sniffer, $timeout) {
|
||||
|
||||
@@ -557,6 +577,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.hasClass('custom-long-delay')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should allow both multiple JS and CSS animations which run in parallel",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, _$rootElement_) {
|
||||
$rootElement = _$rootElement_;
|
||||
@@ -588,7 +609,9 @@ describe("ngAnimate", function() {
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe("with CSS3", function() {
|
||||
|
||||
beforeEach(function() {
|
||||
module(function() {
|
||||
return function(_$rootElement_) {
|
||||
@@ -597,7 +620,9 @@ describe("ngAnimate", function() {
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
describe("Animations", function() {
|
||||
|
||||
it("should properly detect and make use of CSS Animations",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
|
||||
@@ -621,6 +646,7 @@ describe("ngAnimate", function() {
|
||||
expect(element).toBeShown();
|
||||
}));
|
||||
|
||||
|
||||
it("should properly detect and make use of CSS Animations with multiple iterations",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
|
||||
@@ -645,29 +671,6 @@ describe("ngAnimate", function() {
|
||||
expect(element).toBeShown();
|
||||
}));
|
||||
|
||||
it("should fallback to the animation duration if an infinite iteration is provided",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
|
||||
var style = '-webkit-animation-duration: 2s;' +
|
||||
'-webkit-animation-iteration-count: infinite;' +
|
||||
'animation-duration: 2s;' +
|
||||
'animation-iteration-count: infinite;';
|
||||
|
||||
ss.addRule('.ng-hide-add', style);
|
||||
ss.addRule('.ng-hide-remove', style);
|
||||
|
||||
element = $compile(html('<div>1</div>'))($rootScope);
|
||||
|
||||
element.addClass('ng-hide');
|
||||
expect(element).toBeHidden();
|
||||
|
||||
$animate.removeClass(element, 'ng-hide');
|
||||
if ($sniffer.animations) {
|
||||
$timeout.flush();
|
||||
browserTrigger(element,'animationend', { timeStamp: Date.now() + 2000, elapsedTime: 2 });
|
||||
}
|
||||
expect(element).toBeShown();
|
||||
}));
|
||||
|
||||
it("should not consider the animation delay is provided",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
@@ -695,6 +698,7 @@ describe("ngAnimate", function() {
|
||||
expect(element).toBeShown();
|
||||
}));
|
||||
|
||||
|
||||
it("should skip animations if disabled and run when enabled",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
$animate.enabled(false);
|
||||
@@ -711,6 +715,7 @@ describe("ngAnimate", function() {
|
||||
expect(element).toBeShown();
|
||||
}));
|
||||
|
||||
|
||||
it("should finish the previous animation when a new animation is started",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
var style = '-webkit-animation: some_animation 2s linear 0s 1 alternate;' +
|
||||
@@ -745,6 +750,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.hasClass('ng-hide-remove-active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it("should stagger the items when the correct CSS class is provided",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, $document, $rootElement) {
|
||||
|
||||
@@ -805,6 +811,7 @@ describe("ngAnimate", function() {
|
||||
expect(elements[4].attr('style')).not.toMatch(/animation-delay: 0\.4\d*s/);
|
||||
}));
|
||||
|
||||
|
||||
it("should stagger items when multiple animation durations/delays are defined",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, $document, $rootElement) {
|
||||
|
||||
@@ -838,108 +845,11 @@ describe("ngAnimate", function() {
|
||||
expect(elements[2].attr('style')).toMatch(/animation-delay: 1\.2\d*s,\s*2\.2\d*s/);
|
||||
expect(elements[3].attr('style')).toMatch(/animation-delay: 1\.3\d*s,\s*2\.3\d*s/);
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("Transitions", function() {
|
||||
it("should only apply the fallback transition property unless all properties are being animated",
|
||||
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
|
||||
if (!$sniffer.animations) return;
|
||||
|
||||
ss.addRule('.all.ng-enter', '-webkit-transition:1s linear all;' +
|
||||
'transition:1s linear all');
|
||||
|
||||
ss.addRule('.one.ng-enter', '-webkit-transition:1s linear color;' +
|
||||
'transition:1s linear color');
|
||||
|
||||
var element = $compile('<div></div>')($rootScope);
|
||||
var child = $compile('<div class="all">...</div>')($rootScope);
|
||||
$rootElement.append(element);
|
||||
var body = jqLite($document[0].body);
|
||||
body.append($rootElement);
|
||||
|
||||
$animate.enter(child, element);
|
||||
$rootScope.$digest();
|
||||
$timeout.flush();
|
||||
|
||||
expect(child.attr('style') || '').not.toContain('transition-property');
|
||||
expect(child.hasClass('ng-animate-start')).toBe(true);
|
||||
expect(child.hasClass('ng-animate-active')).toBe(true);
|
||||
|
||||
browserTrigger(child,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1000 });
|
||||
$timeout.flush();
|
||||
|
||||
expect(child.hasClass('ng-animate')).toBe(false);
|
||||
expect(child.hasClass('ng-animate-active')).toBe(false);
|
||||
|
||||
child.remove();
|
||||
|
||||
var child2 = $compile('<div class="one">...</div>')($rootScope);
|
||||
|
||||
$animate.enter(child2, element);
|
||||
$rootScope.$digest();
|
||||
$timeout.flush();
|
||||
|
||||
//IE removes the -ms- prefix when placed on the style
|
||||
var fallbackProperty = $sniffer.msie ? 'zoom' : 'border-spacing';
|
||||
var regExp = new RegExp("transition-property:\\s+color\\s*,\\s*" + fallbackProperty + "\\s*;");
|
||||
expect(child2.attr('style') || '').toMatch(regExp);
|
||||
expect(child2.hasClass('ng-animate')).toBe(true);
|
||||
expect(child2.hasClass('ng-animate-active')).toBe(true);
|
||||
|
||||
browserTrigger(child2,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1000 });
|
||||
$timeout.flush();
|
||||
|
||||
expect(child2.hasClass('ng-animate')).toBe(false);
|
||||
expect(child2.hasClass('ng-animate-active')).toBe(false);
|
||||
}));
|
||||
|
||||
it("should not apply the fallback classes if no animations are going on or if CSS animations are going on",
|
||||
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
|
||||
if (!$sniffer.animations) return;
|
||||
|
||||
ss.addRule('.transitions', '-webkit-transition:1s linear all;' +
|
||||
'transition:1s linear all');
|
||||
|
||||
ss.addRule('.keyframes', '-webkit-animation:my_animation 1s;' +
|
||||
'animation:my_animation 1s');
|
||||
|
||||
var element = $compile('<div class="transitions">...</div>')($rootScope);
|
||||
$rootElement.append(element);
|
||||
jqLite($document[0].body).append($rootElement);
|
||||
|
||||
$animate.enabled(false);
|
||||
|
||||
$animate.addClass(element, 'klass');
|
||||
|
||||
expect(element.hasClass('ng-animate-start')).toBe(false);
|
||||
|
||||
element.removeClass('klass');
|
||||
|
||||
$animate.enabled(true);
|
||||
|
||||
$animate.addClass(element, 'klass');
|
||||
|
||||
$timeout.flush();
|
||||
|
||||
expect(element.hasClass('ng-animate-start')).toBe(true);
|
||||
expect(element.hasClass('ng-animate-active')).toBe(true);
|
||||
|
||||
browserTrigger(element,'transitionend', { timeStamp: Date.now() + 1000, elapsedTime: 1 });
|
||||
|
||||
expect(element.hasClass('ng-animate-start')).toBe(false);
|
||||
expect(element.hasClass('ng-animate-active')).toBe(false);
|
||||
|
||||
element.attr('class', 'keyframes');
|
||||
|
||||
$animate.addClass(element, 'klass2');
|
||||
|
||||
$timeout.flush();
|
||||
|
||||
expect(element.hasClass('ng-animate-start')).toBe(false);
|
||||
expect(element.hasClass('ng-animate-active')).toBe(false);
|
||||
}));
|
||||
|
||||
it("should skip transitions if disabled and run when enabled",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
@@ -971,6 +881,7 @@ describe("ngAnimate", function() {
|
||||
expect(element).toBeShown();
|
||||
}));
|
||||
|
||||
|
||||
it("should skip animations if disabled and run when enabled picking the longest specified duration",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
|
||||
@@ -998,6 +909,7 @@ describe("ngAnimate", function() {
|
||||
expect(element).toBeShown();
|
||||
}));
|
||||
|
||||
|
||||
it("should skip animations if disabled and run when enabled picking the longest specified duration/delay combination",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
$animate.enabled(false);
|
||||
@@ -1033,6 +945,7 @@ describe("ngAnimate", function() {
|
||||
expect(element).toBeShown();
|
||||
}));
|
||||
|
||||
|
||||
it("should NOT overwrite styles with outdated values when animation completes",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
|
||||
@@ -1062,6 +975,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.css('width')).toBe("200px");
|
||||
}));
|
||||
|
||||
|
||||
it("should animate for the highest duration",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
var style = '-webkit-transition:1s linear all 2s;' +
|
||||
@@ -1083,12 +997,13 @@ describe("ngAnimate", function() {
|
||||
}
|
||||
expect(element).toBeShown();
|
||||
if ($sniffer.transitions) {
|
||||
expect(element.hasClass('ng-animate-active')).toBe(true);
|
||||
expect(element.hasClass('ng-hide-remove-active')).toBe(true);
|
||||
browserTrigger(element,'animationend', { timeStamp: Date.now() + 11000, elapsedTime: 11 });
|
||||
expect(element.hasClass('ng-animate-active')).toBe(false);
|
||||
expect(element.hasClass('ng-hide-remove-active')).toBe(false);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
it("should finish the previous transition when a new animation is started",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
var style = '-webkit-transition: 1s linear all;' +
|
||||
@@ -1121,6 +1036,7 @@ describe("ngAnimate", function() {
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
it("should stagger the items when the correct CSS class is provided",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, $document, $rootElement) {
|
||||
|
||||
@@ -1181,6 +1097,7 @@ describe("ngAnimate", function() {
|
||||
expect(elements[4].attr('style')).not.toMatch(/transition-delay: 0\.4\d*s/);
|
||||
}));
|
||||
|
||||
|
||||
it("should stagger items when multiple transition durations/delays are defined",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, $document, $rootElement) {
|
||||
|
||||
@@ -1214,8 +1131,60 @@ describe("ngAnimate", function() {
|
||||
expect(elements[2].attr('style')).toMatch(/transition-delay: 2\.2\d*s,\s*4\.2\d*s/);
|
||||
expect(elements[3].attr('style')).toMatch(/transition-delay: 2\.3\d*s,\s*4\.3\d*s/);
|
||||
}));
|
||||
|
||||
|
||||
it("apply a closing timeout to close all pending transitions",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
|
||||
if (!$sniffer.transitions) return;
|
||||
|
||||
ss.addRule('.animated-element', '-webkit-transition:5s linear all;' +
|
||||
'transition:5s linear all;');
|
||||
|
||||
element = $compile(html('<div class="animated-element">foo</div>'))($rootScope);
|
||||
|
||||
$animate.addClass(element, 'some-class');
|
||||
|
||||
$timeout.flush(10); //reflow
|
||||
expect(element.hasClass('some-class-add-active')).toBe(true);
|
||||
|
||||
$timeout.flush(7500); //closing timeout
|
||||
expect(element.hasClass('some-class-add-active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it("should not allow the closing animation to close off a successive animation midway",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout) {
|
||||
|
||||
if (!$sniffer.transitions) return;
|
||||
|
||||
ss.addRule('.some-class-add', '-webkit-transition:5s linear all;' +
|
||||
'transition:5s linear all;');
|
||||
ss.addRule('.some-class-remove', '-webkit-transition:10s linear all;' +
|
||||
'transition:10s linear all;');
|
||||
|
||||
element = $compile(html('<div>foo</div>'))($rootScope);
|
||||
|
||||
$animate.addClass(element, 'some-class');
|
||||
|
||||
$timeout.flush(10); //reflow
|
||||
expect(element.hasClass('some-class-add-active')).toBe(true);
|
||||
|
||||
$animate.removeClass(element, 'some-class');
|
||||
|
||||
$timeout.flush(10); //second reflow
|
||||
|
||||
$timeout.flush(7500); //closing timeout for the first animation
|
||||
expect(element.hasClass('some-class-remove-active')).toBe(true);
|
||||
|
||||
$timeout.flush(15000); //closing timeout for the second animation
|
||||
expect(element.hasClass('some-class-remove-active')).toBe(false);
|
||||
|
||||
$timeout.verifyNoPendingTasks();
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
it("should apply staggering to both transitions and keyframe animations when used within the same animation",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, $document, $rootElement) {
|
||||
|
||||
@@ -1263,7 +1232,9 @@ describe("ngAnimate", function() {
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe('animation evaluation', function () {
|
||||
|
||||
it('should re-evaluate the CSS classes for an animation each time',
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout, $compile) {
|
||||
|
||||
@@ -1306,6 +1277,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.hasClass('xyz')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should only append active to the newly append CSS className values',
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1340,7 +1312,9 @@ describe("ngAnimate", function() {
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe("Callbacks", function() {
|
||||
|
||||
beforeEach(function() {
|
||||
module(function($animateProvider) {
|
||||
$animateProvider.register('.custom', function($timeout) {
|
||||
@@ -1360,6 +1334,7 @@ describe("ngAnimate", function() {
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
it("should fire the enter callback",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1379,6 +1354,7 @@ describe("ngAnimate", function() {
|
||||
expect(flag).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should fire the leave callback",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1398,6 +1374,7 @@ describe("ngAnimate", function() {
|
||||
expect(flag).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should fire the move callback",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1419,6 +1396,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.parent().id).toBe(parent2.id);
|
||||
}));
|
||||
|
||||
|
||||
it("should fire the addClass/removeClass callbacks",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1441,6 +1419,7 @@ describe("ngAnimate", function() {
|
||||
expect(signature).toBe('AB');
|
||||
}));
|
||||
|
||||
|
||||
it("should fire a done callback when provided with no animation",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1458,6 +1437,7 @@ describe("ngAnimate", function() {
|
||||
expect(flag).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should fire a done callback when provided with a css animation/transition",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1483,6 +1463,7 @@ describe("ngAnimate", function() {
|
||||
expect(flag).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should fire a done callback when provided with a JS animation",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1501,6 +1482,7 @@ describe("ngAnimate", function() {
|
||||
expect(flag).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should fire the callback right away if another animation is called right after",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1528,7 +1510,9 @@ describe("ngAnimate", function() {
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
describe("addClass / removeClass", function() {
|
||||
|
||||
var captured;
|
||||
beforeEach(function() {
|
||||
module(function($animateProvider, $provide) {
|
||||
@@ -1547,6 +1531,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should not perform an animation, and the followup DOM operation, if the class is " +
|
||||
"already present during addClass or not present during removeClass on the element",
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
|
||||
@@ -1582,6 +1567,7 @@ describe("ngAnimate", function() {
|
||||
expect(captured).toBe('addClass-some-class');
|
||||
}));
|
||||
|
||||
|
||||
it("should add and remove CSS classes after an animation even if no animation is present",
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement) {
|
||||
|
||||
@@ -1601,6 +1587,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.hasClass('klass-remove-active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it("should add and remove CSS classes with a callback",
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1626,6 +1613,7 @@ describe("ngAnimate", function() {
|
||||
expect(signature).toBe('AB');
|
||||
}));
|
||||
|
||||
|
||||
it("should end the current addClass animation, add the CSS class and then run the removeClass animation",
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1675,6 +1663,7 @@ describe("ngAnimate", function() {
|
||||
expect(signature).toBe('12');
|
||||
}));
|
||||
|
||||
|
||||
it("should properly execute JS animations and use callbacks when using addClass / removeClass",
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1704,6 +1693,7 @@ describe("ngAnimate", function() {
|
||||
expect(signature).toBe('XY');
|
||||
}));
|
||||
|
||||
|
||||
it("should properly execute CSS animations/transitions and use callbacks when using addClass / removeClass",
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1754,6 +1744,7 @@ describe("ngAnimate", function() {
|
||||
expect(signature).toBe('db');
|
||||
}));
|
||||
|
||||
|
||||
it("should allow for multiple css classes to be animated plus a callback when added",
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1795,6 +1786,7 @@ describe("ngAnimate", function() {
|
||||
expect(flag).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should allow for multiple css classes to be animated plus a callback when removed",
|
||||
inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
@@ -1858,6 +1850,7 @@ describe("ngAnimate", function() {
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
it("should properly animate and parse CSS3 transitions",
|
||||
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
|
||||
@@ -1881,6 +1874,7 @@ describe("ngAnimate", function() {
|
||||
expect(child.hasClass('ng-enter-active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it("should properly animate and parse CSS3 animations",
|
||||
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
|
||||
@@ -1903,6 +1897,7 @@ describe("ngAnimate", function() {
|
||||
expect(child.hasClass('ng-enter-active')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it("should not set the transition property flag if only CSS animations are used",
|
||||
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
|
||||
@@ -1937,6 +1932,7 @@ describe("ngAnimate", function() {
|
||||
expect(child.css(propertyKey)).not.toBe('background-color');
|
||||
}));
|
||||
|
||||
|
||||
it("should skip animations if the browser does not support CSS3 transitions and CSS3 animations",
|
||||
inject(function($compile, $rootScope, $animate, $sniffer) {
|
||||
|
||||
@@ -1955,6 +1951,7 @@ describe("ngAnimate", function() {
|
||||
expect(child.hasClass('ng-enter')).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
it("should run other defined animations inline with CSS3 animations", function() {
|
||||
module(function($animateProvider) {
|
||||
$animateProvider.register('.custom', function($timeout) {
|
||||
@@ -1990,6 +1987,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should properly cancel CSS transitions or animations if another animation is fired", function() {
|
||||
module(function($animateProvider) {
|
||||
$animateProvider.register('.usurper', function($timeout) {
|
||||
@@ -2036,6 +2034,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should not perform the active class animation if the animation has been cancelled before the reflow occurs", function() {
|
||||
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
if(!$sniffer.transitions) return;
|
||||
@@ -2059,6 +2058,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
// it("should add and remove CSS classes and perform CSS animations during the process",
|
||||
// inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
//
|
||||
@@ -2098,6 +2098,7 @@ describe("ngAnimate", function() {
|
||||
// expect(element.hasClass('on-remove-active')).toBe(false);
|
||||
// }));
|
||||
//
|
||||
//
|
||||
// it("should show and hide elements with CSS & JS animations being performed in the process", function() {
|
||||
// module(function($animateProvider) {
|
||||
// $animateProvider.register('.displayer', function($timeout) {
|
||||
@@ -2158,6 +2159,8 @@ describe("ngAnimate", function() {
|
||||
// expect(element.hasClass('hiding')).toBe(false);
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
it("should remove all the previous classes when the next animation is applied before a reflow", function() {
|
||||
var fn, interceptedClass;
|
||||
module(function($animateProvider) {
|
||||
@@ -2195,6 +2198,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should provide the correct CSS class to the addClass and removeClass callbacks within a JS animation", function() {
|
||||
module(function($animateProvider) {
|
||||
$animateProvider.register('.classify', function() {
|
||||
@@ -2224,6 +2228,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should not skip ngAnimate animations when any pre-existing CSS transitions are present on the element", function() {
|
||||
inject(function($compile, $rootScope, $animate, $timeout, $sniffer) {
|
||||
if(!$sniffer.transitions) return;
|
||||
@@ -2252,6 +2257,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should wait until both the duration and delay are complete to close off the animation",
|
||||
inject(function($compile, $rootScope, $animate, $timeout, $sniffer) {
|
||||
|
||||
@@ -2286,6 +2292,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.contents().length).toBe(1);
|
||||
}));
|
||||
|
||||
|
||||
it("should cancel all child animations when a leave or move animation is triggered on a parent element", function() {
|
||||
|
||||
var step, animationState;
|
||||
@@ -2361,6 +2368,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should wait until a queue of animations are complete before performing a reflow",
|
||||
inject(function($rootScope, $compile, $timeout,$sniffer) {
|
||||
|
||||
@@ -2495,6 +2503,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should not disable any child animations when any parent class-based animations are run", function() {
|
||||
var intercepted;
|
||||
module(function($animateProvider) {
|
||||
@@ -2521,6 +2530,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should cache the response from getComputedStyle if each successive element has the same className value and parent until the first reflow hits", function() {
|
||||
var count = 0;
|
||||
module(function($provide) {
|
||||
@@ -2567,6 +2577,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should cancel an ongoing class-based animation only if the new class contains transition/animation CSS code",
|
||||
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
|
||||
@@ -2603,6 +2614,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.hasClass('yellow-add')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it("should cancel and perform the dom operation only after the reflow has run",
|
||||
inject(function($compile, $rootScope, $animate, $sniffer, $timeout) {
|
||||
|
||||
@@ -2633,6 +2645,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.hasClass('red')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should enable and disable animations properly on the root element', function() {
|
||||
var count = 0;
|
||||
module(function($animateProvider) {
|
||||
@@ -2656,6 +2669,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should perform pre and post animations', function() {
|
||||
var steps = [];
|
||||
module(function($animateProvider) {
|
||||
@@ -2684,6 +2698,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should treat the leave event always as a before event and discard the beforeLeave function', function() {
|
||||
var parentID, steps = [];
|
||||
module(function($animateProvider) {
|
||||
@@ -2717,6 +2732,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should only perform the DOM operation once',
|
||||
inject(function($sniffer, $compile, $rootScope, $rootElement, $animate, $timeout) {
|
||||
|
||||
@@ -2751,6 +2767,7 @@ describe("ngAnimate", function() {
|
||||
expect(element.hasClass('base-class')).toBe(true);
|
||||
}));
|
||||
|
||||
|
||||
it('should block and unblock transitions before the dom operation occurs',
|
||||
inject(function($rootScope, $compile, $rootElement, $document, $animate, $sniffer, $timeout) {
|
||||
|
||||
@@ -2784,6 +2801,7 @@ describe("ngAnimate", function() {
|
||||
expect(capturedProperty).not.toBe('none');
|
||||
}));
|
||||
|
||||
|
||||
it('should block and unblock keyframe animations around the reflow operation',
|
||||
inject(function($rootScope, $compile, $rootElement, $document, $animate, $sniffer, $timeout) {
|
||||
|
||||
@@ -2810,6 +2828,7 @@ describe("ngAnimate", function() {
|
||||
expect(node.style[animationKey]).not.toContain('none');
|
||||
}));
|
||||
|
||||
|
||||
it('should block and unblock keyframe animations before the followup JS animation occurs', function() {
|
||||
module(function($animateProvider) {
|
||||
$animateProvider.register('.special', function($sniffer, $window) {
|
||||
@@ -2853,6 +2872,7 @@ describe("ngAnimate", function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should round up long elapsedTime values to close off a CSS3 animation',
|
||||
inject(function($rootScope, $compile, $rootElement, $document, $animate, $sniffer, $timeout, $window) {
|
||||
if (!$sniffer.animations) return;
|
||||
@@ -2874,6 +2894,7 @@ describe("ngAnimate", function() {
|
||||
expect($rootElement.children().length).toBe(0);
|
||||
}));
|
||||
|
||||
|
||||
it('should properly animate elements with compound directives', function() {
|
||||
var capturedAnimation;
|
||||
module(function($animateProvider) {
|
||||
@@ -2926,5 +2947,55 @@ describe("ngAnimate", function() {
|
||||
expect(capturedAnimation).toBe('leave');
|
||||
});
|
||||
});
|
||||
|
||||
it('should animate only the specified CSS className', function() {
|
||||
var captures = {};
|
||||
module(function($animateProvider) {
|
||||
$animateProvider.classNameFilter(/prefixed-animation/);
|
||||
$animateProvider.register('.capture', function() {
|
||||
return {
|
||||
enter : buildFn('enter'),
|
||||
leave : buildFn('leave')
|
||||
};
|
||||
|
||||
function buildFn(key) {
|
||||
return function(element, className, done) {
|
||||
captures[key] = true;
|
||||
(done || className)();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
inject(function($rootScope, $compile, $rootElement, $document, $timeout, $templateCache, $sniffer, $animate) {
|
||||
if(!$sniffer.transitions) return;
|
||||
|
||||
var element = $compile('<div class="capture"></div>')($rootScope);
|
||||
$rootElement.append(element);
|
||||
jqLite($document[0].body).append($rootElement);
|
||||
|
||||
var enterDone = false;
|
||||
$animate.enter(element, $rootElement, null, function() {
|
||||
enterDone = true;
|
||||
});
|
||||
|
||||
$rootScope.$digest();
|
||||
$timeout.flush();
|
||||
|
||||
expect(captures['enter']).toBeUndefined();
|
||||
expect(enterDone).toBe(true);
|
||||
|
||||
element.addClass('prefixed-animation');
|
||||
|
||||
var leaveDone = false;
|
||||
$animate.leave(element, function() {
|
||||
leaveDone = true;
|
||||
});
|
||||
$rootScope.$digest();
|
||||
$timeout.flush();
|
||||
|
||||
expect(captures['leave']).toBe(true);
|
||||
expect(leaveDone).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user