Skip to content

Commit d892aab

Browse files
kirjsmmalerba
authored andcommitted
Revert "fix(core): Fixes animations in conjunction with content projection (angular#63776)" (angular#64189)
This reverts commit 1cb16fd. PR Close angular#64189
1 parent be0455a commit d892aab

File tree

15 files changed

+91
-427
lines changed

15 files changed

+91
-427
lines changed

packages/core/src/animation/interfaces.ts

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,6 @@ export const ANIMATIONS_DISABLED = new InjectionToken<boolean>(
1818
},
1919
);
2020

21-
export interface AnimationQueue {
22-
queue: Set<Function>;
23-
isScheduled: boolean;
24-
}
25-
26-
/**
27-
* A [DI token](api/core/InjectionToken) for the queue of all animations.
28-
*/
29-
export const ANIMATION_QUEUE = new InjectionToken<AnimationQueue>(
30-
typeof ngDevMode !== 'undefined' && ngDevMode ? 'AnimationQueue' : '',
31-
{
32-
providedIn: 'root',
33-
factory: () => {
34-
return {
35-
queue: new Set(),
36-
isScheduled: false,
37-
};
38-
},
39-
},
40-
);
41-
4221
/**
4322
* The event type for when `animate.enter` and `animate.leave` are used with function
4423
* callbacks.
@@ -99,10 +78,10 @@ export interface LongestAnimation {
9978

10079
export interface AnimationLViewData {
10180
// Enter animations that apply to nodes in this view
102-
enter?: Map<number, Function[]>;
81+
enter?: Function[];
10382

10483
// Leave animations that apply to nodes in this view
105-
leave?: Map<number, Function[]>;
84+
leave?: (() => Promise<void>)[];
10685

10786
// Leave animations that apply to nodes in this view
10887
// We chose to use unknown instead of PromiseSettledResult<void> to avoid requiring the type

packages/core/src/animation/utils.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,17 @@ export function trackLeavingNodes(tNode: TNode, el: HTMLElement): void {
162162
/**
163163
* Retrieves the list of specified enter animations from the lView
164164
*/
165-
export function getLViewEnterAnimations(lView: LView): Map<number, Function[]> {
165+
export function getLViewEnterAnimations(lView: LView): Function[] {
166166
const animationData = (lView[ANIMATIONS] ??= {});
167-
return (animationData.enter ??= new Map<number, Function[]>());
167+
return (animationData.enter ??= []);
168168
}
169169

170170
/**
171171
* Retrieves the list of specified leave animations from the lView
172172
*/
173-
export function getLViewLeaveAnimations(lView: LView): Map<number, Function[]> {
173+
export function getLViewLeaveAnimations(lView: LView): Function[] {
174174
const animationData = (lView[ANIMATIONS] ??= {});
175-
return (animationData.leave ??= new Map<number, Function[]>());
175+
return (animationData.leave ??= []);
176176
}
177177

178178
/**
@@ -244,18 +244,8 @@ export function isLongestAnimation(
244244
}
245245

246246
/**
247-
* Stores a given animation function in the LView's animation map for later execution
248-
*
249-
* @param animations Either the enter or leave animation map from the LView
250-
* @param tNode The TNode the animation is associated with
251-
* @param fn The animation function to be called later
247+
* Determines if a given tNode is a content projection root node.
252248
*/
253-
export function addAnimationToLView(
254-
animations: Map<number, Function[]>,
255-
tNode: TNode,
256-
fn: Function,
257-
) {
258-
const animationFns = animations.get(tNode.index) ?? [];
259-
animationFns.push(fn);
260-
animations.set(tNode.index, animationFns);
249+
export function isTNodeContentProjectionRoot(tNode: TNode): boolean {
250+
return Array.isArray(tNode.projection);
261251
}

packages/core/src/render3/instructions/animation.ts

Lines changed: 25 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,21 @@
77
*/
88

99
import {
10-
ANIMATION_QUEUE,
1110
AnimationCallbackEvent,
1211
AnimationFunction,
1312
MAX_ANIMATION_TIMEOUT,
1413
} from '../../animation/interfaces';
1514
import {getLView, getCurrentTNode} from '../state';
16-
import {RENDERER, INJECTOR, CONTEXT, LView, ANIMATIONS} from '../interfaces/view';
15+
import {RENDERER, INJECTOR, CONTEXT, LView} from '../interfaces/view';
1716
import {getNativeByTNode} from '../util/view_utils';
1817
import {performanceMarkFeature} from '../../util/performance';
1918
import {Renderer} from '../interfaces/renderer';
2019
import {NgZone} from '../../zone';
2120
import {determineLongestAnimation, allLeavingAnimations} from '../../animation/longest_animation';
2221
import {TNode} from '../interfaces/node';
2322
import {promiseWithResolvers} from '../../util/promise_with_resolvers';
24-
import {Injector} from '../../di';
25-
import {afterEveryRender} from '../after_render/hooks';
2623

2724
import {
28-
addAnimationToLView,
2925
areAnimationsDisabled,
3026
areAnimationSupported,
3127
assertAnimationTypes,
@@ -70,16 +66,12 @@ export function ɵɵanimateEnter(value: string | Function): typeof ɵɵanimateEn
7066

7167
cancelLeavingNodes(tNode, lView);
7268

73-
addAnimationToLView(getLViewEnterAnimations(lView), tNode, () =>
74-
runEnterAnimation(lView, tNode, value),
75-
);
76-
77-
queueEnterAnimations(lView);
69+
getLViewEnterAnimations(lView).push(() => runEnterAnimation(lView, tNode, value));
7870

7971
return ɵɵanimateEnter; // For chaining
8072
}
8173

82-
export function runEnterAnimation(lView: LView, tNode: TNode, value: string | Function) {
74+
export function runEnterAnimation(lView: LView, tNode: TNode, value: string | Function): void {
8375
const nativeElement = getNativeByTNode(tNode, lView) as HTMLElement;
8476

8577
ngDevMode && assertElementNodes(nativeElement, 'animate.enter');
@@ -102,7 +94,7 @@ export function runEnterAnimation(lView: LView, tNode: TNode, value: string | Fu
10294

10395
const eventName = event instanceof AnimationEvent ? 'animationend' : 'transitionend';
10496
ngZone.runOutsideAngular(() => {
105-
renderer.listen(nativeElement, eventName, handleEnterAnimationEnd);
97+
cleanupFns.push(renderer.listen(nativeElement, eventName, handleEnterAnimationEnd));
10698
});
10799
};
108100

@@ -126,7 +118,6 @@ export function runEnterAnimation(lView: LView, tNode: TNode, value: string | Fu
126118
for (const klass of activeClasses) {
127119
renderer.addClass(nativeElement, klass);
128120
}
129-
130121
// In the case that the classes added have no animations, we need to remove
131122
// the classes right away. This could happen because someone is intentionally
132123
// preventing an animation via selector specificity.
@@ -191,19 +182,15 @@ export function ɵɵanimateEnterListener(value: AnimationFunction): typeof ɵɵa
191182

192183
cancelLeavingNodes(tNode, lView);
193184

194-
addAnimationToLView(getLViewEnterAnimations(lView), tNode, () =>
195-
runEnterAnimationFunction(lView, tNode, value),
196-
);
197-
198-
queueEnterAnimations(lView);
185+
getLViewEnterAnimations(lView).push(() => runEnterAnimationFunction(lView, tNode, value));
199186

200187
return ɵɵanimateEnterListener;
201188
}
202189

203190
/**
204191
* runs enter animations when a custom function is provided
205192
*/
206-
function runEnterAnimationFunction(lView: LView, tNode: TNode, value: AnimationFunction): void {
193+
function runEnterAnimationFunction(lView: LView, tNode: TNode, value: AnimationFunction) {
207194
const nativeElement = getNativeByTNode(tNode, lView) as HTMLElement;
208195
ngDevMode && assertElementNodes(nativeElement, 'animate.enter');
209196

@@ -237,16 +224,19 @@ export function ɵɵanimateLeave(value: string | Function): typeof ɵɵanimateLe
237224

238225
const tNode = getCurrentTNode()!;
239226

240-
addAnimationToLView(getLViewLeaveAnimations(lView), tNode, () =>
241-
runLeaveAnimations(lView, tNode, value),
227+
getLViewLeaveAnimations(lView).push(() =>
228+
runLeaveAnimations(lView, tNode, value, animationsDisabled),
242229
);
243230

244-
enableAnimationQueueScheduler(lView[INJECTOR]);
245-
246231
return ɵɵanimateLeave; // For chaining
247232
}
248233

249-
function runLeaveAnimations(lView: LView, tNode: TNode, value: string | Function): Promise<void> {
234+
function runLeaveAnimations(
235+
lView: LView,
236+
tNode: TNode,
237+
value: string | Function,
238+
animationsDisabled: boolean,
239+
): Promise<void> {
250240
const {promise, resolve} = promiseWithResolvers<void>();
251241
const nativeElement = getNativeByTNode(tNode, lView) as Element;
252242

@@ -263,6 +253,7 @@ function runLeaveAnimations(lView: LView, tNode: TNode, value: string | Function
263253
tNode,
264254
activeClasses,
265255
renderer,
256+
animationsDisabled,
266257
ngZone,
267258
resolve,
268259
);
@@ -282,11 +273,17 @@ function animateLeaveClassRunner(
282273
tNode: TNode,
283274
classList: string[],
284275
renderer: Renderer,
276+
animationsDisabled: boolean,
285277
ngZone: NgZone,
286278
resolver: VoidFunction,
287279
) {
280+
if (animationsDisabled) {
281+
longestAnimations.delete(el);
282+
resolver();
283+
return;
284+
}
285+
288286
cancelAnimationsIfRunning(el, renderer);
289-
const cleanupFns: Function[] = [];
290287

291288
const handleOutAnimationEnd = (event: AnimationEvent | TransitionEvent | CustomEvent) => {
292289
// this early exit case is to prevent issues with bubbling events that are from child element animations
@@ -310,14 +307,11 @@ function animateLeaveClassRunner(
310307
}
311308
}
312309
resolver();
313-
for (const fn of cleanupFns) {
314-
fn();
315-
}
316310
};
317311

318312
ngZone.runOutsideAngular(() => {
319-
cleanupFns.push(renderer.listen(el, 'animationend', handleOutAnimationEnd));
320-
cleanupFns.push(renderer.listen(el, 'transitionend', handleOutAnimationEnd));
313+
renderer.listen(el, 'animationend', handleOutAnimationEnd);
314+
renderer.listen(el, 'transitionend', handleOutAnimationEnd);
321315
});
322316
trackLeavingNodes(tNode, el);
323317
for (const item of classList) {
@@ -332,9 +326,6 @@ function animateLeaveClassRunner(
332326
if (!longestAnimations.has(el)) {
333327
clearLeavingNodes(tNode, el);
334328
resolver();
335-
for (const fn of cleanupFns) {
336-
fn();
337-
}
338329
}
339330
});
340331
});
@@ -368,11 +359,7 @@ export function ɵɵanimateLeaveListener(value: AnimationFunction): typeof ɵɵa
368359
const tNode = getCurrentTNode()!;
369360
allLeavingAnimations.add(lView);
370361

371-
addAnimationToLView(getLViewLeaveAnimations(lView), tNode, () =>
372-
runLeaveAnimationFunction(lView, tNode, value),
373-
);
374-
375-
enableAnimationQueueScheduler(lView[INJECTOR]);
362+
getLViewLeaveAnimations(lView).push(() => runLeaveAnimationFunction(lView, tNode, value));
376363

377364
return ɵɵanimateLeaveListener; // For chaining
378365
}
@@ -429,38 +416,3 @@ function runLeaveAnimationFunction(
429416
// Ensure cleanup if the LView is destroyed before the animation runs.
430417
return promise;
431418
}
432-
433-
function queueEnterAnimations(lView: LView) {
434-
enableAnimationQueueScheduler(lView[INJECTOR]);
435-
const enterAnimations = lView[ANIMATIONS]?.enter;
436-
if (enterAnimations) {
437-
const animationQueue = lView[INJECTOR].get(ANIMATION_QUEUE);
438-
for (const [_, animateFns] of enterAnimations) {
439-
for (const animateFn of animateFns) {
440-
animationQueue.queue.add(animateFn);
441-
}
442-
}
443-
}
444-
}
445-
446-
function enableAnimationQueueScheduler(injector: Injector) {
447-
const animationQueue = injector.get(ANIMATION_QUEUE);
448-
// We only need to schedule the animation queue runner once per application.
449-
if (!animationQueue.isScheduled) {
450-
afterEveryRender(
451-
() => {
452-
runQueuedAnimations(injector);
453-
},
454-
{injector},
455-
);
456-
animationQueue.isScheduled = true;
457-
}
458-
}
459-
460-
function runQueuedAnimations(injector: Injector) {
461-
const animationQueue = injector.get(ANIMATION_QUEUE);
462-
for (let animateFn of animationQueue.queue) {
463-
animateFn();
464-
}
465-
animationQueue.queue.clear();
466-
}

packages/core/src/render3/instructions/change_detection.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {ComponentTemplate, HostBindingsFunction, RenderFlags} from '../interface
2525
import {
2626
CONTEXT,
2727
EFFECTS_TO_SCHEDULE,
28+
ANIMATIONS,
2829
ENVIRONMENT,
2930
FLAGS,
3031
InitPhaseState,
@@ -231,6 +232,7 @@ export function refreshView<T>(
231232
if (templateFn !== null) {
232233
executeTemplate(tView, lView, templateFn, RenderFlags.Update, context);
233234
}
235+
runEnterAnimations(lView);
234236

235237
const hooksInitPhaseCompleted =
236238
(flags & LViewFlags.InitPhaseStateMask) === InitPhaseState.InitPhaseCompleted;
@@ -372,6 +374,16 @@ export function refreshView<T>(
372374
}
373375
}
374376

377+
function runEnterAnimations(lView: LView) {
378+
const animationData = lView[ANIMATIONS];
379+
if (animationData?.enter) {
380+
for (const animateFn of animationData.enter) {
381+
animateFn();
382+
}
383+
animationData.enter = undefined;
384+
}
385+
}
386+
375387
/**
376388
* Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
377389
* them by executing an associated template function.

0 commit comments

Comments
 (0)