Permalink
Browse files

fix(animations): generate aot code for animation trigger output events (

#12291)


Closes #11707
Closes #12291
  • Loading branch information...
matsko authored and alxhub committed Oct 19, 2016
1 parent 8409b65 commit 6e5f8b59b369f7ca4719b8709871a2869b9c02d1
@@ -264,23 +264,21 @@ class _AnimationBuilder implements AnimationAstVisitor {
.toStmt()])])
.toStmt());
- var transitionParams = o.literalMap([
- ['toState', _ANIMATION_NEXT_STATE_VAR], ['fromState', _ANIMATION_CURRENT_STATE_VAR],
- ['totalTime', _ANIMATION_TIME_VAR]
- ]);
-
- var transitionEvent = o.importExpr(resolveIdentifier(Identifiers.AnimationTransitionEvent))
- .instantiate([transitionParams]);
-
statements.push(_ANIMATION_FACTORY_VIEW_CONTEXT
.callMethod(
'queueAnimation',
[
_ANIMATION_FACTORY_ELEMENT_VAR, o.literal(this.animationName),
- _ANIMATION_PLAYER_VAR, transitionEvent
+ _ANIMATION_PLAYER_VAR
])
.toStmt());
+ statements.push(new o.ReturnStatement(
+ o.importExpr(resolveIdentifier(Identifiers.AnimationTransition)).instantiate([
+ _ANIMATION_PLAYER_VAR, _ANIMATION_CURRENT_STATE_VAR, _ANIMATION_NEXT_STATE_VAR,
+ _ANIMATION_TIME_VAR
+ ])));
+
return o.fn(
[
new o.FnParam(
@@ -290,7 +288,7 @@ class _AnimationBuilder implements AnimationAstVisitor {
new o.FnParam(_ANIMATION_CURRENT_STATE_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(_ANIMATION_NEXT_STATE_VAR.name, o.DYNAMIC_TYPE)
],
- statements);
+ statements, o.importType(resolveIdentifier(Identifiers.AnimationTransition)));
}
build(ast: AnimationAst): AnimationEntryCompileResult {
@@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {ANALYZE_FOR_ENTRY_COMPONENTS, AnimationTransitionEvent, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, LOCALE_ID as LOCALE_ID_, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT as TRANSLATIONS_FORMAT_, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
+import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, LOCALE_ID as LOCALE_ID_, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT as TRANSLATIONS_FORMAT_, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
-import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AppElement, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes, castByValue, checkBinding, clearStyles, collectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, reflector, registerModuleFactory, renderStyles} from './private_import_core';
+import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AnimationTransition, AppElement, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes, castByValue, checkBinding, clearStyles, collectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, reflector, registerModuleFactory, renderStyles} from './private_import_core';
import {assetUrl} from './util';
var APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view');
@@ -266,10 +266,10 @@ export class Identifiers {
moduleUrl: assetUrl('core', 'i18n/tokens'),
runtime: TRANSLATIONS_FORMAT_
};
- static AnimationTransitionEvent: IdentifierSpec = {
- name: 'AnimationTransitionEvent',
- moduleUrl: assetUrl('core', 'animation/animation_transition_event'),
- runtime: AnimationTransitionEvent
+ static AnimationTransition: IdentifierSpec = {
+ name: 'AnimationTransition',
+ moduleUrl: assetUrl('core', 'animation/animation_transition'),
+ runtime: AnimationTransition
};
}
@@ -90,3 +90,4 @@ export const ViewMetadata: typeof r.ViewMetadata = r.ViewMetadata;
export type ComponentStillLoadingError = typeof r._ComponentStillLoadingError;
export const ComponentStillLoadingError: typeof r.ComponentStillLoadingError =
r.ComponentStillLoadingError;
+export const AnimationTransition: typeof r.AnimationTransition = r.AnimationTransition;
@@ -40,6 +40,7 @@ export class CompileEventListener {
}
get methodName() { return this._methodName; }
+ get isAnimation() { return !!this.eventPhase; }
constructor(
public compileElement: CompileElement, public eventTarget: string, public eventName: string,
@@ -113,21 +114,13 @@ export class CompileEventListener {
disposable.set(listenExpr).toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
}
- listenToAnimation() {
- var outputListener = o.THIS_EXPR.callMethod(
- 'eventHandler',
- [o.THIS_EXPR.prop(this._methodName).callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR])]);
-
- // tie the property callback method to the view animations map
- var stmt = o.THIS_EXPR.prop('animationContext')
- .callMethod(
- 'registerOutputHandler',
- [
- this.compileElement.renderNode, o.literal(this.eventName),
- o.literal(this.eventPhase), outputListener
- ])
- .toStmt();
- this.compileElement.view.createMethod.addStmt(stmt);
+ listenToAnimation(animationTransitionVar: o.ReadVarExpr): o.Statement {
+ const callbackMethod = this.eventPhase == 'start' ? 'onStart' : 'onDone';
+ return animationTransitionVar
+ .callMethod(
+ callbackMethod,
+ [o.THIS_EXPR.prop(this.methodName).callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR])])
+ .toStmt();
}
listenToDirective(directiveInstance: o.Expression, observablePropName: string) {
@@ -185,9 +178,9 @@ export function bindDirectiveOutputs(
export function bindRenderOutputs(eventListeners: CompileEventListener[]) {
eventListeners.forEach(listener => {
- if (listener.eventPhase) {
- listener.listenToAnimation();
- } else {
+ // the animation listeners are handled within property_binder.ts to
+ // allow them to be placed next to the animation factory statements
+ if (!listener.isAnimation) {
listener.listenToRenderer();
}
});
@@ -21,6 +21,7 @@ import {CompileElement, CompileNode} from './compile_element';
import {CompileMethod} from './compile_method';
import {CompileView} from './compile_view';
import {DetectChangesVars, ViewProperties} from './constants';
+import {CompileEventListener} from './event_binder';
import {convertCdExpressionToIr, temporaryDeclaration} from './expression_converter';
function createBindFieldExpr(exprIndex: number): o.ReadPropExpr {
@@ -90,7 +91,7 @@ export function bindRenderText(
function bindAndWriteToRenderer(
boundProps: BoundElementPropertyAst[], context: o.Expression, compileElement: CompileElement,
- isHostProp: boolean) {
+ isHostProp: boolean, eventListeners: CompileEventListener[]) {
var view = compileElement.view;
var renderNode = compileElement.renderNode;
boundProps.forEach((boundProp) => {
@@ -142,41 +143,45 @@ function bindAndWriteToRenderer(
.toStmt());
break;
case PropertyBindingType.Animation:
- var animationName = boundProp.name;
- var targetViewExpr: o.Expression = o.THIS_EXPR;
- if (isHostProp) {
- targetViewExpr = compileElement.appElement.prop('componentView');
- }
-
compileMethod = view.animationBindingsMethod;
+ const detachStmts: o.Statement[] = [];
+
+ const animationName = boundProp.name;
+ const targetViewExpr: o.Expression =
+ isHostProp ? compileElement.appElement.prop('componentView') : o.THIS_EXPR;
- var animationFnExpr =
+ const animationFnExpr =
targetViewExpr.prop('componentType').prop('animations').key(o.literal(animationName));
// it's important to normalize the void value as `void` explicitly
// so that the styles data can be obtained from the stringmap
- var emptyStateValue = o.literal(EMPTY_ANIMATION_STATE);
+ const emptyStateValue = o.literal(EMPTY_ANIMATION_STATE);
+ const unitializedValue = o.importExpr(resolveIdentifier(Identifiers.UNINITIALIZED));
+ const animationTransitionVar = o.variable('animationTransition_' + animationName);
- // void => ...
- var oldRenderVar = o.variable('oldRenderVar');
- updateStmts.push(oldRenderVar.set(oldRenderValue).toDeclStmt());
- updateStmts.push(new o.IfStmt(
- oldRenderVar.equals(o.importExpr(resolveIdentifier(Identifiers.UNINITIALIZED))),
- [oldRenderVar.set(emptyStateValue).toStmt()]));
+ updateStmts.push(
+ animationTransitionVar
+ .set(animationFnExpr.callFn([
+ o.THIS_EXPR, renderNode, oldRenderValue.equals(unitializedValue)
+ .conditional(emptyStateValue, oldRenderValue),
+ renderValue.equals(unitializedValue).conditional(emptyStateValue, renderValue)
+ ]))
+ .toDeclStmt());
- // ... => void
- var newRenderVar = o.variable('newRenderVar');
- updateStmts.push(newRenderVar.set(renderValue).toDeclStmt());
- updateStmts.push(new o.IfStmt(
- newRenderVar.equals(o.importExpr(resolveIdentifier(Identifiers.UNINITIALIZED))),
- [newRenderVar.set(emptyStateValue).toStmt()]));
+ detachStmts.push(animationTransitionVar
+ .set(animationFnExpr.callFn(
+ [o.THIS_EXPR, renderNode, oldRenderValue, emptyStateValue]))
+ .toDeclStmt());
- updateStmts.push(
- animationFnExpr.callFn([o.THIS_EXPR, renderNode, oldRenderVar, newRenderVar]).toStmt());
+ eventListeners.forEach(listener => {
+ if (listener.isAnimation && listener.eventName === animationName) {
+ let animationStmt = listener.listenToAnimation(animationTransitionVar);
+ updateStmts.push(animationStmt);
+ detachStmts.push(animationStmt);
+ }
+ });
- view.detachMethod.addStmt(
- animationFnExpr.callFn([o.THIS_EXPR, renderNode, oldRenderValue, emptyStateValue])
- .toStmt());
+ view.detachMethod.addStmts(detachStmts);
break;
}
@@ -218,14 +223,17 @@ function sanitizedValue(
}
export function bindRenderInputs(
- boundProps: BoundElementPropertyAst[], compileElement: CompileElement): void {
- bindAndWriteToRenderer(boundProps, compileElement.view.componentContext, compileElement, false);
+ boundProps: BoundElementPropertyAst[], compileElement: CompileElement,
+ eventListeners: CompileEventListener[]): void {
+ bindAndWriteToRenderer(
+ boundProps, compileElement.view.componentContext, compileElement, false, eventListeners);
}
export function bindDirectiveHostProps(
- directiveAst: DirectiveAst, directiveInstance: o.Expression,
- compileElement: CompileElement): void {
- bindAndWriteToRenderer(directiveAst.hostProperties, directiveInstance, compileElement, true);
+ directiveAst: DirectiveAst, directiveInstance: o.Expression, compileElement: CompileElement,
+ eventListeners: CompileEventListener[]): void {
+ bindAndWriteToRenderer(
+ directiveAst.hostProperties, directiveInstance, compileElement, true, eventListeners);
}
export function bindDirectiveInputs(
@@ -44,14 +44,14 @@ class ViewBinderVisitor implements TemplateAstVisitor {
collectEventListeners(ast.outputs, ast.directives, compileElement).forEach(entry => {
eventListeners.push(entry);
});
- bindRenderInputs(ast.inputs, compileElement);
+ bindRenderInputs(ast.inputs, compileElement, eventListeners);
bindRenderOutputs(eventListeners);
ast.directives.forEach((directiveAst) => {
var directiveInstance = compileElement.instances.get(directiveAst.directive.type.reference);
bindDirectiveInputs(directiveAst, directiveInstance, compileElement);
bindDirectiveDetectChangesLifecycleCallbacks(directiveAst, directiveInstance, compileElement);
- bindDirectiveHostProps(directiveAst, directiveInstance, compileElement);
+ bindDirectiveHostProps(directiveAst, directiveInstance, compileElement, eventListeners);
bindDirectiveOutputs(directiveAst, directiveInstance, eventListeners);
});
templateVisitAll(this, ast.children, compileElement);
@@ -8,7 +8,7 @@
import {Injectable} from '@angular/core';
-import {AnimationCompiler, AnimationEntryCompileResult} from '../animation/animation_compiler';
+import {AnimationEntryCompileResult} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompilePipeMetadata} from '../compile_metadata';
import {CompilerConfig} from '../config';
import * as o from '../output/output_ast';
@@ -29,7 +29,6 @@ export class ViewCompileResult {
@Injectable()
export class ViewCompiler {
- private _animationCompiler = new AnimationCompiler();
constructor(private _genConfig: CompilerConfig) {}
compileComponent(
@@ -0,0 +1,34 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+import {AnimationPlayer} from './animation_player';
+import {AnimationTransitionEvent} from './animation_transition_event';
+
+export class AnimationTransition {
+ constructor(
+ private _player: AnimationPlayer, private _fromState: string, private _toState: string,
+ private _totalTime: number) {}
+
+ private _createEvent(phaseName: string): AnimationTransitionEvent {
+ return new AnimationTransitionEvent({
+ fromState: this._fromState,
+ toState: this._toState,
+ totalTime: this._totalTime,
+ phaseName: phaseName
+ });
+ }
+
+ onStart(callback: (event: AnimationTransitionEvent) => any): void {
+ const event = this._createEvent('start');
+ this._player.onStart(() => callback(event));
+ }
+
+ onDone(callback: (event: AnimationTransitionEvent) => any): void {
+ const event = this._createEvent('done');
+ this._player.onDone(() => callback(event));
+ }
+}
@@ -41,11 +41,13 @@ export class AnimationTransitionEvent {
public fromState: string;
public toState: string;
public totalTime: number;
+ public phaseName: string;
- constructor({fromState, toState,
- totalTime}: {fromState: string, toState: string, totalTime: number}) {
+ constructor({fromState, toState, totalTime, phaseName}:
+ {fromState: string, toState: string, totalTime: number, phaseName: string}) {
this.fromState = fromState;
this.toState = toState;
this.totalTime = totalTime;
+ this.phaseName = phaseName;
}
}
@@ -13,6 +13,7 @@ import {AnimationPlayer as AnimationPlayer_, NoOpAnimationPlayer as NoOpAnimatio
import {AnimationSequencePlayer as AnimationSequencePlayer_} from './animation/animation_sequence_player';
import * as animationUtils from './animation/animation_style_util';
import {AnimationStyles as AnimationStyles_} from './animation/animation_styles';
+import {AnimationTransition} from './animation/animation_transition';
import * as change_detection_util from './change_detection/change_detection_util';
import * as constants from './change_detection/constants';
import * as console from './console';
@@ -118,7 +119,8 @@ export var __core_private__: {
FILL_STYLE_FLAG: typeof FILL_STYLE_FLAG_,
_ComponentStillLoadingError?: ComponentStillLoadingError,
ComponentStillLoadingError: typeof ComponentStillLoadingError,
- isPromise: typeof isPromise
+ isPromise: typeof isPromise,
+ AnimationTransition: typeof AnimationTransition
} = {
isDefaultChangeDetectionStrategy: constants.isDefaultChangeDetectionStrategy,
ChangeDetectorStatus: constants.ChangeDetectorStatus,
@@ -182,5 +184,6 @@ export var __core_private__: {
EMPTY_STATE: EMPTY_STATE_,
FILL_STYLE_FLAG: FILL_STYLE_FLAG_,
ComponentStillLoadingError: ComponentStillLoadingError,
- isPromise: isPromise
+ isPromise: isPromise,
+ AnimationTransition: AnimationTransition
};
Oops, something went wrong.

0 comments on commit 6e5f8b5

Please sign in to comment.