fix(animations): report correct totalTime value even during noOp animations (#22225)
This patch ensures that if the NoopAnimationsModule is used then it will correctly report the associated `totalTime` property within the emitted AnimationEvent instance when an animation event trigger is fired. BREAKING CHANGE: When animation is trigged within a disabled zone, the associated event (which an instance of AnimationEvent) will no longer report the totalTime as 0 (it will emit the actual time of the animation). To detect if an animation event is reporting a disabled animation then the `event.disabled` property can be used instead. PR Close #22225
This commit is contained in:

committed by
Victor Berchet

parent
884de18cba
commit
e1bf067090
@ -59,10 +59,13 @@ export class AnimationTransitionFactory {
|
||||
driver, element, this.ast.animation, enterClassName, leaveClassName, currentStateStyles,
|
||||
nextStateStyles, animationOptions, subInstructions, errors);
|
||||
|
||||
let totalTime = 0;
|
||||
timelines.forEach(tl => { totalTime = Math.max(tl.duration + tl.delay, totalTime); });
|
||||
|
||||
if (errors.length) {
|
||||
return createTransitionInstruction(
|
||||
element, this._triggerName, currentState, nextState, isRemoval, currentStateStyles,
|
||||
nextStateStyles, [], [], preStyleMap, postStyleMap, errors);
|
||||
nextStateStyles, [], [], preStyleMap, postStyleMap, totalTime, errors);
|
||||
}
|
||||
|
||||
timelines.forEach(tl => {
|
||||
@ -81,7 +84,7 @@ export class AnimationTransitionFactory {
|
||||
const queriedElementsList = iteratorToArray(queriedElements.values());
|
||||
return createTransitionInstruction(
|
||||
element, this._triggerName, currentState, nextState, isRemoval, currentStateStyles,
|
||||
nextStateStyles, timelines, queriedElementsList, preStyleMap, postStyleMap);
|
||||
nextStateStyles, timelines, queriedElementsList, preStyleMap, postStyleMap, totalTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ export interface AnimationTransitionInstruction extends AnimationEngineInstructi
|
||||
queriedElements: any[];
|
||||
preStyleProps: Map<any, {[prop: string]: boolean}>;
|
||||
postStyleProps: Map<any, {[prop: string]: boolean}>;
|
||||
totalTime: number;
|
||||
errors?: any[];
|
||||
}
|
||||
|
||||
@ -29,7 +30,7 @@ export function createTransitionInstruction(
|
||||
isRemovalTransition: boolean, fromStyles: ɵStyleData, toStyles: ɵStyleData,
|
||||
timelines: AnimationTimelineInstruction[], queriedElements: any[],
|
||||
preStyleProps: Map<any, {[prop: string]: boolean}>,
|
||||
postStyleProps: Map<any, {[prop: string]: boolean}>,
|
||||
postStyleProps: Map<any, {[prop: string]: boolean}>, totalTime: number,
|
||||
errors?: any[]): AnimationTransitionInstruction {
|
||||
return {
|
||||
type: AnimationTransitionInstructionType.TransitionAnimation,
|
||||
@ -44,6 +45,7 @@ export function createTransitionInstruction(
|
||||
queriedElements,
|
||||
preStyleProps,
|
||||
postStyleProps,
|
||||
totalTime,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ export class NoopAnimationDriver implements AnimationDriver {
|
||||
animate(
|
||||
element: any, keyframes: {[key: string]: string | number}[], duration: number, delay: number,
|
||||
easing: string, previousPlayers: any[] = []): AnimationPlayer {
|
||||
return new NoopAnimationPlayer();
|
||||
return new NoopAnimationPlayer(duration, delay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,23 +75,24 @@ export function listenOnPlayer(
|
||||
callback: (event: any) => any) {
|
||||
switch (eventName) {
|
||||
case 'start':
|
||||
player.onStart(() => callback(event && copyAnimationEvent(event, 'start', player.totalTime)));
|
||||
player.onStart(() => callback(event && copyAnimationEvent(event, 'start', player)));
|
||||
break;
|
||||
case 'done':
|
||||
player.onDone(() => callback(event && copyAnimationEvent(event, 'done', player.totalTime)));
|
||||
player.onDone(() => callback(event && copyAnimationEvent(event, 'done', player)));
|
||||
break;
|
||||
case 'destroy':
|
||||
player.onDestroy(
|
||||
() => callback(event && copyAnimationEvent(event, 'destroy', player.totalTime)));
|
||||
player.onDestroy(() => callback(event && copyAnimationEvent(event, 'destroy', player)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function copyAnimationEvent(
|
||||
e: AnimationEvent, phaseName?: string, totalTime?: number): AnimationEvent {
|
||||
e: AnimationEvent, phaseName: string, player: AnimationPlayer): AnimationEvent {
|
||||
const totalTime = player.totalTime;
|
||||
const disabled = (player as any).disabled ? true : false;
|
||||
const event = makeAnimationEvent(
|
||||
e.element, e.triggerName, e.fromState, e.toState, phaseName || e.phaseName,
|
||||
totalTime == undefined ? e.totalTime : totalTime);
|
||||
totalTime == undefined ? e.totalTime : totalTime, disabled);
|
||||
const data = (e as any)['_data'];
|
||||
if (data != null) {
|
||||
(event as any)['_data'] = data;
|
||||
@ -101,8 +102,8 @@ export function copyAnimationEvent(
|
||||
|
||||
export function makeAnimationEvent(
|
||||
element: any, triggerName: string, fromState: string, toState: string, phaseName: string = '',
|
||||
totalTime: number = 0): AnimationEvent {
|
||||
return {element, triggerName, fromState, toState, phaseName, totalTime};
|
||||
totalTime: number = 0, disabled?: boolean): AnimationEvent {
|
||||
return {element, triggerName, fromState, toState, phaseName, totalTime, disabled: !!disabled};
|
||||
}
|
||||
|
||||
export function getOrSetAsInMap(
|
||||
|
@ -1081,6 +1081,8 @@ export class TransitionAnimationEngine {
|
||||
if (subTimelines.has(element)) {
|
||||
if (disabledElementsSet.has(element)) {
|
||||
player.onDestroy(() => setStyles(element, instruction.toStyles));
|
||||
player.disabled = true;
|
||||
player.overrideTotalTime(instruction.totalTime);
|
||||
skippedPlayers.push(player);
|
||||
return;
|
||||
}
|
||||
@ -1311,7 +1313,8 @@ export class TransitionAnimationEngine {
|
||||
|
||||
// FIXME (matsko): make sure to-be-removed animations are removed properly
|
||||
const details = element[REMOVAL_FLAG];
|
||||
if (details && details.removedBeforeQueried) return new NoopAnimationPlayer();
|
||||
if (details && details.removedBeforeQueried)
|
||||
return new NoopAnimationPlayer(timelineInstruction.duration, timelineInstruction.delay);
|
||||
|
||||
const isQueriedElement = element !== rootElement;
|
||||
const previousPlayers =
|
||||
@ -1379,7 +1382,7 @@ export class TransitionAnimationEngine {
|
||||
|
||||
// special case for when an empty transition|definition is provided
|
||||
// ... there is no point in rendering an empty animation
|
||||
return new NoopAnimationPlayer();
|
||||
return new NoopAnimationPlayer(instruction.duration, instruction.delay);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1392,8 +1395,10 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
|
||||
public parentPlayer: AnimationPlayer;
|
||||
|
||||
public markedForDestroy: boolean = false;
|
||||
public disabled = false;
|
||||
|
||||
readonly queued: boolean = true;
|
||||
public readonly totalTime: number = 0;
|
||||
|
||||
constructor(public namespaceId: string, public triggerName: string, public element: any) {}
|
||||
|
||||
@ -1407,15 +1412,18 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
|
||||
});
|
||||
this._queuedCallbacks = {};
|
||||
this._containsRealPlayer = true;
|
||||
this.overrideTotalTime(player.totalTime);
|
||||
(this as{queued: boolean}).queued = false;
|
||||
}
|
||||
|
||||
getRealPlayer() { return this._player; }
|
||||
|
||||
overrideTotalTime(totalTime: number) { (this as any).totalTime = totalTime; }
|
||||
|
||||
syncPlayerEvents(player: AnimationPlayer) {
|
||||
const p = this._player as any;
|
||||
if (p.triggerCallback) {
|
||||
player.onStart(() => p.triggerCallback('start'));
|
||||
player.onStart(() => p.triggerCallback !('start'));
|
||||
}
|
||||
player.onDone(() => this.finish());
|
||||
player.onDestroy(() => this.destroy());
|
||||
@ -1473,8 +1481,6 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
|
||||
|
||||
getPosition(): number { return this.queued ? 0 : this._player.getPosition(); }
|
||||
|
||||
get totalTime(): number { return this._player.totalTime; }
|
||||
|
||||
/* @internal */
|
||||
triggerCallback(phaseName: string): void {
|
||||
const p = this._player as any;
|
||||
|
@ -299,7 +299,8 @@ const DEFAULT_NAMESPACE_ID = 'id';
|
||||
phaseName: 'start',
|
||||
fromState: '123',
|
||||
toState: '456',
|
||||
totalTime: 1234
|
||||
totalTime: 1234,
|
||||
disabled: false
|
||||
});
|
||||
|
||||
capture = null !;
|
||||
@ -313,7 +314,8 @@ const DEFAULT_NAMESPACE_ID = 'id';
|
||||
phaseName: 'done',
|
||||
fromState: '123',
|
||||
toState: '456',
|
||||
totalTime: 1234
|
||||
totalTime: 1234,
|
||||
disabled: false
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -58,7 +58,7 @@ export class MockAnimationPlayer extends NoopAnimationPlayer {
|
||||
public element: any, public keyframes: {[key: string]: string | number}[],
|
||||
public duration: number, public delay: number, public easing: string,
|
||||
public previousPlayers: any[]) {
|
||||
super();
|
||||
super(duration, delay);
|
||||
|
||||
if (allowPreviousPlayerStylesMerge(duration, delay)) {
|
||||
previousPlayers.forEach(player => {
|
||||
@ -68,8 +68,6 @@ export class MockAnimationPlayer extends NoopAnimationPlayer {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.totalTime = delay + duration;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
Reference in New Issue
Block a user