mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
feat($animate): provide support for DOM callbacks
This commit is contained in:
parent
4ae3184c59
commit
dde1b29497
2 changed files with 100 additions and 3 deletions
|
|
@ -317,6 +317,10 @@ angular.module('ngAnimate', ['ng'])
|
|||
return classNameFilter.test(className);
|
||||
};
|
||||
|
||||
function async(fn) {
|
||||
return $timeout(fn, 0, false);
|
||||
}
|
||||
|
||||
function lookup(name) {
|
||||
if (name) {
|
||||
var matches = [],
|
||||
|
|
@ -608,6 +612,8 @@ angular.module('ngAnimate', ['ng'])
|
|||
//best to catch this early on to prevent any animation operations from occurring
|
||||
if(!node || !isAnimatableClassName(classes)) {
|
||||
fireDOMOperation();
|
||||
fireBeforeCallbackAsync();
|
||||
fireAfterCallbackAsync();
|
||||
closeAnimation();
|
||||
return;
|
||||
}
|
||||
|
|
@ -627,6 +633,8 @@ angular.module('ngAnimate', ['ng'])
|
|||
//NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case a NO animation is not found.
|
||||
if (animationsDisabled(element, parentElement) || matches.length === 0) {
|
||||
fireDOMOperation();
|
||||
fireBeforeCallbackAsync();
|
||||
fireAfterCallbackAsync();
|
||||
closeAnimation();
|
||||
return;
|
||||
}
|
||||
|
|
@ -665,6 +673,8 @@ angular.module('ngAnimate', ['ng'])
|
|||
//animation do it's thing and close this one early
|
||||
if(animations.length === 0) {
|
||||
fireDOMOperation();
|
||||
fireBeforeCallbackAsync();
|
||||
fireAfterCallbackAsync();
|
||||
fireDoneCallbackAsync();
|
||||
return;
|
||||
}
|
||||
|
|
@ -718,6 +728,8 @@ angular.module('ngAnimate', ['ng'])
|
|||
if((animationEvent == 'addClass' && futureClassName.indexOf(classNameToken) >= 0) ||
|
||||
(animationEvent == 'removeClass' && futureClassName.indexOf(classNameToken) == -1)) {
|
||||
fireDOMOperation();
|
||||
fireBeforeCallbackAsync();
|
||||
fireAfterCallbackAsync();
|
||||
fireDoneCallbackAsync();
|
||||
return;
|
||||
}
|
||||
|
|
@ -758,6 +770,10 @@ angular.module('ngAnimate', ['ng'])
|
|||
}
|
||||
|
||||
function invokeRegisteredAnimationFns(animations, phase, allAnimationFnsComplete) {
|
||||
phase == 'after' ?
|
||||
fireAfterCallbackAsync() :
|
||||
fireBeforeCallbackAsync();
|
||||
|
||||
var endFnName = phase + 'End';
|
||||
forEach(animations, function(animation, index) {
|
||||
var animationPhaseCompleted = function() {
|
||||
|
|
@ -794,8 +810,27 @@ angular.module('ngAnimate', ['ng'])
|
|||
}
|
||||
}
|
||||
|
||||
function fireDOMCallback(animationPhase) {
|
||||
element.triggerHandler('$animate:' + animationPhase, {
|
||||
event : animationEvent,
|
||||
className : className
|
||||
});
|
||||
}
|
||||
|
||||
function fireBeforeCallbackAsync() {
|
||||
async(function() {
|
||||
fireDOMCallback('before');
|
||||
});
|
||||
}
|
||||
|
||||
function fireAfterCallbackAsync() {
|
||||
async(function() {
|
||||
fireDOMCallback('after');
|
||||
});
|
||||
}
|
||||
|
||||
function fireDoneCallbackAsync() {
|
||||
doneCallback && $timeout(doneCallback, 0, false);
|
||||
doneCallback && async(doneCallback);
|
||||
}
|
||||
|
||||
//it is less complicated to use a flag than managing and cancelling
|
||||
|
|
@ -819,9 +854,9 @@ angular.module('ngAnimate', ['ng'])
|
|||
if(isClassBased) {
|
||||
cleanup(element);
|
||||
} else {
|
||||
data.closeAnimationTimeout = $timeout(function() {
|
||||
data.closeAnimationTimeout = async(function() {
|
||||
cleanup(element);
|
||||
}, 0, false);
|
||||
});
|
||||
element.data(NG_ANIMATE_STATE, data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1496,6 +1496,68 @@ describe("ngAnimate", function() {
|
|||
expect(signature).toBe('AB');
|
||||
}));
|
||||
|
||||
it('should fire DOM callbacks on the element being animated',
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
if(!$sniffer.transitions) return;
|
||||
|
||||
$animate.enabled(true);
|
||||
|
||||
ss.addRule('.klass-add', '-webkit-transition:1s linear all;' +
|
||||
'transition:1s linear all;');
|
||||
|
||||
var element = jqLite('<div></div>');
|
||||
$rootElement.append(element);
|
||||
body.append($rootElement);
|
||||
|
||||
var steps = [];
|
||||
element.on('$animate:before', function(e, data) {
|
||||
steps.push(['before', data.className, data.event]);
|
||||
});
|
||||
|
||||
element.on('$animate:after', function(e, data) {
|
||||
steps.push(['after', data.className, data.event]);
|
||||
});
|
||||
|
||||
$animate.addClass(element, 'klass');
|
||||
|
||||
$timeout.flush(1);
|
||||
|
||||
expect(steps.pop()).toEqual(['before', 'klass', 'addClass']);
|
||||
|
||||
$animate.triggerReflow();
|
||||
$timeout.flush(1);
|
||||
|
||||
expect(steps.pop()).toEqual(['after', 'klass', 'addClass']);
|
||||
}));
|
||||
|
||||
it('should fire the DOM callbacks even if no animation is rendered',
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
||||
$animate.enabled(true);
|
||||
|
||||
var parent = jqLite('<div></div>');
|
||||
var element = jqLite('<div></div>');
|
||||
$rootElement.append(parent);
|
||||
body.append($rootElement);
|
||||
|
||||
var steps = [];
|
||||
element.on('$animate:before', function(e, data) {
|
||||
steps.push(['before', data.className, data.event]);
|
||||
});
|
||||
|
||||
element.on('$animate:after', function(e, data) {
|
||||
steps.push(['after', data.className, data.event]);
|
||||
});
|
||||
|
||||
$animate.enter(element, parent);
|
||||
$rootScope.$digest();
|
||||
|
||||
$timeout.flush(1);
|
||||
|
||||
expect(steps.shift()).toEqual(['before', 'ng-enter', 'enter']);
|
||||
expect(steps.shift()).toEqual(['after', 'ng-enter', 'enter']);
|
||||
}));
|
||||
|
||||
it("should fire a done callback when provided with no animation",
|
||||
inject(function($animate, $rootScope, $compile, $sniffer, $rootElement, $timeout) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue