angular/packages/animations/browser/src/render/animation_engine_next.ts
2017-07-31 15:47:57 -07:00

104 lines
4.0 KiB
TypeScript

/**
* @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 {AnimationMetadata, AnimationPlayer, AnimationTriggerMetadata} from '@angular/animations';
import {TriggerAst} from '../dsl/animation_ast';
import {buildAnimationAst} from '../dsl/animation_ast_builder';
import {AnimationTrigger, buildTrigger} from '../dsl/animation_trigger';
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
import {AnimationDriver} from './animation_driver';
import {parseTimelineCommand} from './shared';
import {TimelineAnimationEngine} from './timeline_animation_engine';
import {TransitionAnimationEngine} from './transition_animation_engine';
export class AnimationEngine {
private _transitionEngine: TransitionAnimationEngine;
private _timelineEngine: TimelineAnimationEngine;
private _triggerCache: {[key: string]: AnimationTrigger} = {};
// this method is designed to be overridden by the code that uses this engine
public onRemovalComplete = (element: any, context: any) => {};
constructor(driver: AnimationDriver, normalizer: AnimationStyleNormalizer) {
this._transitionEngine = new TransitionAnimationEngine(driver, normalizer);
this._timelineEngine = new TimelineAnimationEngine(driver, normalizer);
this._transitionEngine.onRemovalComplete = (element: any, context: any) =>
this.onRemovalComplete(element, context);
}
registerTrigger(
componentId: string, namespaceId: string, hostElement: any, name: string,
metadata: AnimationTriggerMetadata): void {
const cacheKey = componentId + '-' + name;
let trigger = this._triggerCache[cacheKey];
if (!trigger) {
const errors: any[] = [];
const ast = buildAnimationAst(metadata as AnimationMetadata, errors) as TriggerAst;
if (errors.length) {
throw new Error(
`The animation trigger "${name}" has failed to build due to the following errors:\n - ${errors.join("\n - ")}`);
}
trigger = buildTrigger(name, ast);
this._triggerCache[cacheKey] = trigger;
}
this._transitionEngine.registerTrigger(namespaceId, name, trigger);
}
register(namespaceId: string, hostElement: any) {
this._transitionEngine.register(namespaceId, hostElement);
}
destroy(namespaceId: string, context: any) {
this._transitionEngine.destroy(namespaceId, context);
}
onInsert(namespaceId: string, element: any, parent: any, insertBefore: boolean): void {
this._transitionEngine.insertNode(namespaceId, element, parent, insertBefore);
}
onRemove(namespaceId: string, element: any, context: any): void {
this._transitionEngine.removeNode(namespaceId, element, context);
}
disableAnimations(element: any, disable: boolean) {
this._transitionEngine.markElementAsDisabled(element, disable);
}
process(namespaceId: string, element: any, property: string, value: any) {
if (property.charAt(0) == '@') {
const [id, action] = parseTimelineCommand(property);
const args = value as any[];
this._timelineEngine.command(id, element, action, args);
} else {
this._transitionEngine.trigger(namespaceId, element, property, value);
}
}
listen(
namespaceId: string, element: any, eventName: string, eventPhase: string,
callback: (event: any) => any): () => any {
// @@listen
if (eventName.charAt(0) == '@') {
const [id, action] = parseTimelineCommand(eventName);
return this._timelineEngine.listen(id, element, action, callback);
}
return this._transitionEngine.listen(namespaceId, element, eventName, eventPhase, callback);
}
flush(microtaskId: number = -1): void { this._transitionEngine.flush(microtaskId); }
get players(): AnimationPlayer[] {
return (this._transitionEngine.players as AnimationPlayer[])
.concat(this._timelineEngine.players as AnimationPlayer[]);
}
whenRenderingDone(): Promise<any> { return this._transitionEngine.whenRenderingDone(); }
}