refactor(animations): deport TCB away from animation-land forever (#10892)
* feat(animations): support animation trigger template callbacks * refactor(animations): deport TCB away from animation-land forever
This commit is contained in:
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {ViewType} from '../../core_private';
|
||||
import {CompiledAnimation} from '../animation/animation_compiler';
|
||||
import {CompiledAnimationTriggerResult} from '../animation/animation_compiler';
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMap, CompileIdentifierMetadata, CompilePipeMetadata, CompileTokenMetadata} from '../compile_metadata';
|
||||
import {CompilerConfig} from '../config';
|
||||
import {ListWrapper} from '../facade/collection';
|
||||
@ -71,7 +71,7 @@ export class CompileView implements NameResolver {
|
||||
constructor(
|
||||
public component: CompileDirectiveMetadata, public genConfig: CompilerConfig,
|
||||
public pipeMetas: CompilePipeMetadata[], public styles: o.Expression,
|
||||
public animations: CompiledAnimation[], public viewIndex: number,
|
||||
public animations: CompiledAnimationTriggerResult[], public viewIndex: number,
|
||||
public declarationElement: CompileElement, public templateVariableBindings: string[][]) {
|
||||
this.createMethod = new CompileMethod(this);
|
||||
this.injectorGetMethod = new CompileMethod(this);
|
||||
|
@ -6,10 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AnimationOutput} from '../../core_private';
|
||||
import {CompileDirectiveMetadata} from '../compile_metadata';
|
||||
import {ListWrapper, StringMapWrapper} from '../facade/collection';
|
||||
import {StringWrapper, isBlank, isPresent} from '../facade/lang';
|
||||
import {identifierToken} from '../identifiers';
|
||||
import {Identifiers, identifierToken} from '../identifiers';
|
||||
import * as o from '../output/output_ast';
|
||||
import {BoundEventAst, DirectiveAst} from '../template_parser/template_ast';
|
||||
|
||||
@ -19,6 +20,10 @@ import {CompileMethod} from './compile_method';
|
||||
import {EventHandlerVars, ViewProperties} from './constants';
|
||||
import {convertCdStatementToIr} from './expression_converter';
|
||||
|
||||
export class CompileElementAnimationOutput {
|
||||
constructor(public listener: CompileEventListener, public output: AnimationOutput) {}
|
||||
}
|
||||
|
||||
export class CompileEventListener {
|
||||
private _method: CompileMethod;
|
||||
private _hasComponentHostListener: boolean = false;
|
||||
@ -39,6 +44,8 @@ export class CompileEventListener {
|
||||
return listener;
|
||||
}
|
||||
|
||||
get methodName() { return this._methodName; }
|
||||
|
||||
constructor(
|
||||
public compileElement: CompileElement, public eventTarget: string, public eventName: string,
|
||||
listenerIndex: number) {
|
||||
@ -112,6 +119,26 @@ export class CompileEventListener {
|
||||
disposable.set(listenExpr).toDeclStmt(o.FUNCTION_TYPE, [o.StmtModifier.Private]));
|
||||
}
|
||||
|
||||
listenToAnimation(output: AnimationOutput) {
|
||||
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
|
||||
.callMethod(
|
||||
'registerAnimationOutput',
|
||||
[
|
||||
this.compileElement.renderNode,
|
||||
o.importExpr(Identifiers.AnimationOutput).instantiate([
|
||||
o.literal(output.name), o.literal(output.phase)
|
||||
]),
|
||||
outputListener
|
||||
])
|
||||
.toStmt();
|
||||
this.compileElement.view.createMethod.addStmt(stmt);
|
||||
}
|
||||
|
||||
listenToDirective(directiveInstance: o.Expression, observablePropName: string) {
|
||||
var subscription = o.variable(`subscription_${this.compileElement.view.subscriptions.length}`);
|
||||
this.compileElement.view.subscriptions.push(subscription);
|
||||
@ -166,6 +193,10 @@ export function bindRenderOutputs(eventListeners: CompileEventListener[]) {
|
||||
eventListeners.forEach(listener => listener.listenToRenderer());
|
||||
}
|
||||
|
||||
export function bindAnimationOutputs(eventListeners: CompileElementAnimationOutput[]) {
|
||||
eventListeners.forEach(entry => { entry.listener.listenToAnimation(entry.output); });
|
||||
}
|
||||
|
||||
function convertStmtIntoExpression(stmt: o.Statement): o.Expression {
|
||||
if (stmt instanceof o.ExpressionStatement) {
|
||||
return stmt.expr;
|
||||
|
@ -5,19 +5,20 @@
|
||||
* 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 {AnimationOutput} from '../../core_private';
|
||||
import {ListWrapper} from '../facade/collection';
|
||||
import {identifierToken} from '../identifiers';
|
||||
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
|
||||
|
||||
import {CompileElement, CompileNode} from './compile_element';
|
||||
import {CompileView} from './compile_view';
|
||||
import {bindDirectiveOutputs, bindRenderOutputs, collectEventListeners} from './event_binder';
|
||||
import {CompileElementAnimationOutput, CompileEventListener, bindAnimationOutputs, bindDirectiveOutputs, bindRenderOutputs, collectEventListeners} from './event_binder';
|
||||
import {bindDirectiveAfterContentLifecycleCallbacks, bindDirectiveAfterViewLifecycleCallbacks, bindDirectiveDetectChangesLifecycleCallbacks, bindInjectableDestroyLifecycleCallbacks, bindPipeDestroyLifecycleCallbacks} from './lifecycle_binder';
|
||||
import {bindDirectiveHostProps, bindDirectiveInputs, bindRenderInputs, bindRenderText} from './property_binder';
|
||||
|
||||
export function bindView(view: CompileView, parsedTemplate: TemplateAst[]): void {
|
||||
var visitor = new ViewBinderVisitor(view);
|
||||
export function bindView(
|
||||
view: CompileView, parsedTemplate: TemplateAst[], animationOutputs: AnimationOutput[]): void {
|
||||
var visitor = new ViewBinderVisitor(view, animationOutputs);
|
||||
templateVisitAll(visitor, parsedTemplate);
|
||||
view.pipes.forEach(
|
||||
(pipe) => { bindPipeDestroyLifecycleCallbacks(pipe.meta, pipe.instance, pipe.view); });
|
||||
@ -25,8 +26,12 @@ export function bindView(view: CompileView, parsedTemplate: TemplateAst[]): void
|
||||
|
||||
class ViewBinderVisitor implements TemplateAstVisitor {
|
||||
private _nodeIndex: number = 0;
|
||||
private _animationOutputsMap: {[key: string]: AnimationOutput} = {};
|
||||
|
||||
constructor(public view: CompileView) {}
|
||||
constructor(public view: CompileView, animationOutputs: AnimationOutput[]) {
|
||||
animationOutputs.forEach(
|
||||
entry => { this._animationOutputsMap[entry.fullPropertyName] = entry; });
|
||||
}
|
||||
|
||||
visitBoundText(ast: BoundTextAst, parent: CompileElement): any {
|
||||
var node = this.view.nodes[this._nodeIndex++];
|
||||
@ -42,7 +47,23 @@ class ViewBinderVisitor implements TemplateAstVisitor {
|
||||
|
||||
visitElement(ast: ElementAst, parent: CompileElement): any {
|
||||
var compileElement = <CompileElement>this.view.nodes[this._nodeIndex++];
|
||||
var eventListeners = collectEventListeners(ast.outputs, ast.directives, compileElement);
|
||||
var eventListeners: CompileEventListener[] = [];
|
||||
var animationEventListeners: CompileElementAnimationOutput[] = [];
|
||||
collectEventListeners(ast.outputs, ast.directives, compileElement).forEach(entry => {
|
||||
// TODO: figure out how to abstract this `if` statement elsewhere
|
||||
if (entry.eventName[0] == '@') {
|
||||
let animationOutputName = entry.eventName.substr(1);
|
||||
let output = this._animationOutputsMap[animationOutputName];
|
||||
// no need to report an error here since the parser will
|
||||
// have caught the missing animation trigger definition
|
||||
if (output) {
|
||||
animationEventListeners.push(new CompileElementAnimationOutput(entry, output));
|
||||
}
|
||||
} else {
|
||||
eventListeners.push(entry);
|
||||
}
|
||||
});
|
||||
bindAnimationOutputs(animationEventListeners);
|
||||
bindRenderInputs(ast.inputs, compileElement);
|
||||
bindRenderOutputs(eventListeners);
|
||||
ast.directives.forEach((directiveAst) => {
|
||||
@ -90,7 +111,7 @@ class ViewBinderVisitor implements TemplateAstVisitor {
|
||||
var providerInstance = compileElement.instances.get(providerAst.token);
|
||||
bindInjectableDestroyLifecycleCallbacks(providerAst, providerInstance, compileElement);
|
||||
});
|
||||
bindView(compileElement.embeddedView, ast.children);
|
||||
bindView(compileElement.embeddedView, ast.children, []);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||
this.nestedViewCount++;
|
||||
var embeddedView = new CompileView(
|
||||
this.view.component, this.view.genConfig, this.view.pipeMetas, o.NULL_EXPR,
|
||||
compiledAnimations, this.view.viewIndex + this.nestedViewCount, compileElement,
|
||||
compiledAnimations.triggers, this.view.viewIndex + this.nestedViewCount, compileElement,
|
||||
templateVariableBindings);
|
||||
this.nestedViewCount += buildView(embeddedView, ast.children, this.targetDependencies);
|
||||
|
||||
|
@ -38,17 +38,18 @@ export class ViewCompiler {
|
||||
var dependencies: Array<ViewFactoryDependency|ComponentFactoryDependency> = [];
|
||||
var compiledAnimations = this._animationCompiler.compileComponent(component, template);
|
||||
var statements: o.Statement[] = [];
|
||||
compiledAnimations.map(entry => {
|
||||
var animationTriggers = compiledAnimations.triggers;
|
||||
animationTriggers.forEach(entry => {
|
||||
statements.push(entry.statesMapStatement);
|
||||
statements.push(entry.fnStatement);
|
||||
});
|
||||
var view = new CompileView(
|
||||
component, this._genConfig, pipes, styles, compiledAnimations, 0,
|
||||
component, this._genConfig, pipes, styles, animationTriggers, 0,
|
||||
CompileElement.createNull(), []);
|
||||
buildView(view, template, dependencies);
|
||||
// Need to separate binding from creation to be able to refer to
|
||||
// variables that have been declared after usage.
|
||||
bindView(view, template);
|
||||
bindView(view, template, compiledAnimations.outputs);
|
||||
finishView(view, statements);
|
||||
|
||||
return new ViewCompileResult(statements, view.viewFactory.name, dependencies);
|
||||
|
Reference in New Issue
Block a user