@ -0,0 +1,57 @@
|
||||
import {AnimationPlayer} from './animation_player';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {ListWrapper, StringMapWrapper, Map} from '../facade/collection';
|
||||
|
||||
export class ActiveAnimationPlayersMap {
|
||||
private _map = new Map<any, {[key: string]: AnimationPlayer}>();
|
||||
private _allPlayers: AnimationPlayer[] = [];
|
||||
|
||||
get length(): number {
|
||||
return this.getAllPlayers().length;
|
||||
}
|
||||
|
||||
find(element: any, animationName: string): AnimationPlayer {
|
||||
var playersByAnimation = this._map.get(element);
|
||||
if (isPresent(playersByAnimation)) {
|
||||
return playersByAnimation[animationName];
|
||||
}
|
||||
}
|
||||
|
||||
findAllPlayersByElement(element: any): AnimationPlayer[] {
|
||||
var players = [];
|
||||
StringMapWrapper.forEach(this._map.get(element), player => players.push(player));
|
||||
return players;
|
||||
}
|
||||
|
||||
set(element: any, animationName: string, player: AnimationPlayer): void {
|
||||
var playersByAnimation = this._map.get(element);
|
||||
if (!isPresent(playersByAnimation)) {
|
||||
playersByAnimation = {};
|
||||
}
|
||||
var existingEntry = playersByAnimation[animationName];
|
||||
if (isPresent(existingEntry)) {
|
||||
this.remove(element, animationName);
|
||||
}
|
||||
playersByAnimation[animationName] = player;
|
||||
this._allPlayers.push(player);
|
||||
this._map.set(element, playersByAnimation);
|
||||
}
|
||||
|
||||
getAllPlayers(): AnimationPlayer[] {
|
||||
return this._allPlayers;
|
||||
}
|
||||
|
||||
remove(element: any, animationName: string): void {
|
||||
var playersByAnimation = this._map.get(element);
|
||||
if (isPresent(playersByAnimation)) {
|
||||
var player = playersByAnimation[animationName];
|
||||
delete playersByAnimation[animationName];
|
||||
var index = this._allPlayers.indexOf(player);
|
||||
ListWrapper.removeAt(this._allPlayers, index);
|
||||
|
||||
if (StringMapWrapper.isEmpty(playersByAnimation)) {
|
||||
this._map.delete(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
export const FILL_STYLE_FLAG = 'true'; // TODO (matsko): change to boolean
|
||||
export const ANY_STATE = '*';
|
||||
export const EMPTY_STATE = 'void';
|
15
modules/@angular/core/src/animation/animation_driver.ts
Normal file
15
modules/@angular/core/src/animation/animation_driver.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {NoOpAnimationPlayer, AnimationPlayer} from './animation_player';
|
||||
import {AnimationKeyframe} from './animation_keyframe';
|
||||
import {AnimationStyles} from './animation_styles';
|
||||
|
||||
export abstract class AnimationDriver {
|
||||
abstract animate(element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[], duration: number, delay: number,
|
||||
easing: string): AnimationPlayer;
|
||||
}
|
||||
|
||||
export class NoOpAnimationDriver extends AnimationDriver {
|
||||
animate(element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[], duration: number, delay: number,
|
||||
easing: string): AnimationPlayer {
|
||||
return new NoOpAnimationPlayer();
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
import {AnimationPlayer} from './animation_player';
|
||||
import {isPresent, scheduleMicroTask} from '../facade/lang';
|
||||
import {Math} from '../facade/math';
|
||||
|
||||
export class AnimationGroupPlayer implements AnimationPlayer {
|
||||
private _subscriptions: Function[] = [];
|
||||
private _finished = false;
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
|
||||
constructor(private _players: AnimationPlayer[]) {
|
||||
var count = 0;
|
||||
var total = this._players.length;
|
||||
if (total == 0) {
|
||||
scheduleMicroTask(() => this._onFinish());
|
||||
} else {
|
||||
this._players.forEach(player => {
|
||||
player.parentPlayer = this;
|
||||
player.onDone(() => {
|
||||
if (++count >= total) {
|
||||
this._onFinish();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _onFinish() {
|
||||
if (!this._finished) {
|
||||
this._finished = true;
|
||||
if (!isPresent(this.parentPlayer)) {
|
||||
this.destroy();
|
||||
}
|
||||
this._subscriptions.forEach(subscription => subscription());
|
||||
this._subscriptions = [];
|
||||
}
|
||||
}
|
||||
|
||||
onDone(fn: Function): void { this._subscriptions.push(fn); }
|
||||
|
||||
play() { this._players.forEach(player => player.play()); }
|
||||
|
||||
pause(): void { this._players.forEach(player => player.pause()); }
|
||||
|
||||
restart(): void { this._players.forEach(player => player.restart()); }
|
||||
|
||||
finish(): void {
|
||||
this._onFinish();
|
||||
this._players.forEach(player => player.finish());
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this._onFinish();
|
||||
this._players.forEach(player => player.destroy());
|
||||
}
|
||||
|
||||
reset(): void { this._players.forEach(player => player.reset()); }
|
||||
|
||||
setPosition(p): void {
|
||||
this._players.forEach(player => {
|
||||
player.setPosition(p);
|
||||
});
|
||||
}
|
||||
|
||||
getPosition(): number {
|
||||
var min = 0;
|
||||
this._players.forEach(player => {
|
||||
var p = player.getPosition();
|
||||
min = Math.min(p, min);
|
||||
});
|
||||
return min;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
import {AnimationStyles} from './animation_styles';
|
||||
|
||||
export class AnimationKeyframe {
|
||||
constructor(public offset: number, public styles: AnimationStyles) {}
|
||||
}
|
39
modules/@angular/core/src/animation/animation_player.ts
Normal file
39
modules/@angular/core/src/animation/animation_player.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import {scheduleMicroTask} from '../facade/lang';
|
||||
import {BaseException} from '../facade/exceptions';
|
||||
|
||||
export abstract class AnimationPlayer {
|
||||
abstract onDone(fn: Function): void;
|
||||
abstract play(): void;
|
||||
abstract pause(): void;
|
||||
abstract restart(): void;
|
||||
abstract finish(): void;
|
||||
abstract destroy(): void;
|
||||
abstract reset(): void;
|
||||
abstract setPosition(p): void;
|
||||
abstract getPosition(): number;
|
||||
get parentPlayer(): AnimationPlayer { throw new BaseException('NOT IMPLEMENTED: Base Class'); }
|
||||
set parentPlayer(player: AnimationPlayer) { throw new BaseException('NOT IMPLEMENTED: Base Class'); }
|
||||
}
|
||||
|
||||
export class NoOpAnimationPlayer implements AnimationPlayer {
|
||||
private _subscriptions = [];
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
constructor() {
|
||||
scheduleMicroTask(() => this._onFinish());
|
||||
}
|
||||
_onFinish() {
|
||||
this._subscriptions.forEach(entry => { entry(); });
|
||||
this._subscriptions = [];
|
||||
}
|
||||
onDone(fn: Function): void { this._subscriptions.push(fn); }
|
||||
play(): void {}
|
||||
pause(): void {}
|
||||
restart(): void {}
|
||||
finish(): void {
|
||||
this._onFinish();
|
||||
}
|
||||
destroy(): void {}
|
||||
reset(): void {}
|
||||
setPosition(p): void {}
|
||||
getPosition(): number { return 0; }
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {NoOpAnimationPlayer, AnimationPlayer} from './animation_player';
|
||||
import {scheduleMicroTask} from '../facade/lang';
|
||||
|
||||
export class AnimationSequencePlayer implements AnimationPlayer {
|
||||
private _currentIndex: number = 0;
|
||||
private _activePlayer: AnimationPlayer;
|
||||
private _subscriptions: Function[] = [];
|
||||
private _finished = false;
|
||||
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
|
||||
constructor(private _players: AnimationPlayer[]) {
|
||||
this._players.forEach(player => {
|
||||
player.parentPlayer = this;
|
||||
});
|
||||
this._onNext(false);
|
||||
}
|
||||
|
||||
private _onNext(start: boolean) {
|
||||
if (this._finished) return;
|
||||
|
||||
if (this._players.length == 0) {
|
||||
this._activePlayer = new NoOpAnimationPlayer();
|
||||
scheduleMicroTask(() => this._onFinish());
|
||||
} else if (this._currentIndex >= this._players.length) {
|
||||
this._activePlayer = new NoOpAnimationPlayer();
|
||||
this._onFinish();
|
||||
} else {
|
||||
var player = this._players[this._currentIndex++];
|
||||
player.onDone(() => this._onNext(true));
|
||||
|
||||
this._activePlayer = player;
|
||||
if (start) {
|
||||
player.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _onFinish() {
|
||||
if (!this._finished) {
|
||||
this._finished = true;
|
||||
if (!isPresent(this.parentPlayer)) {
|
||||
this.destroy();
|
||||
}
|
||||
this._subscriptions.forEach(subscription => subscription());
|
||||
this._subscriptions = [];
|
||||
}
|
||||
}
|
||||
|
||||
onDone(fn: Function): void { this._subscriptions.push(fn); }
|
||||
|
||||
play(): void { this._activePlayer.play(); }
|
||||
|
||||
pause(): void { this._activePlayer.pause(); }
|
||||
|
||||
restart(): void {
|
||||
if (this._players.length > 0) {
|
||||
this.reset();
|
||||
this._players[0].restart();
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void { this._players.forEach(player => player.reset()); }
|
||||
|
||||
finish(): void {
|
||||
this._onFinish();
|
||||
this._players.forEach(player => player.finish());
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this._onFinish();
|
||||
this._players.forEach(player => player.destroy());
|
||||
}
|
||||
|
||||
setPosition(p): void {
|
||||
this._players[0].setPosition(p);
|
||||
}
|
||||
|
||||
getPosition(): number {
|
||||
return this._players[0].getPosition();
|
||||
}
|
||||
}
|
113
modules/@angular/core/src/animation/animation_style_util.ts
Normal file
113
modules/@angular/core/src/animation/animation_style_util.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import {isPresent, isArray} from '../facade/lang';
|
||||
import {ListWrapper, StringMapWrapper} from '../facade/collection';
|
||||
import {AUTO_STYLE} from './metadata';
|
||||
import {FILL_STYLE_FLAG} from './animation_constants';
|
||||
|
||||
export class AnimationStyleUtil {
|
||||
static balanceStyles(previousStyles: {[key: string]: string|number},
|
||||
newStyles: {[key: string]: string|number},
|
||||
nullValue = null): {[key: string]: string|number} {
|
||||
var finalStyles: {[key: string]: string|number} = {};
|
||||
|
||||
StringMapWrapper.forEach(newStyles, (value, prop) => {
|
||||
finalStyles[prop] = value;
|
||||
});
|
||||
|
||||
StringMapWrapper.forEach(previousStyles, (value, prop) => {
|
||||
if (!isPresent(finalStyles[prop])) {
|
||||
finalStyles[prop] = nullValue;
|
||||
}
|
||||
});
|
||||
|
||||
return finalStyles;
|
||||
}
|
||||
static balanceKeyframes(collectedStyles: {[key: string]: string|number},
|
||||
finalStateStyles: {[key: string]: string|number},
|
||||
keyframes: any[]): any[] {
|
||||
var limit = keyframes.length - 1;
|
||||
var firstKeyframe = keyframes[0];
|
||||
|
||||
// phase 1: copy all the styles from the first keyframe into the lookup map
|
||||
var flatenedFirstKeyframeStyles = AnimationStyleUtil.flattenStyles(firstKeyframe.styles.styles);
|
||||
|
||||
var extraFirstKeyframeStyles = {};
|
||||
var hasExtraFirstStyles = false;
|
||||
StringMapWrapper.forEach(collectedStyles, (value, prop) => {
|
||||
// if the style is already defined in the first keyframe then
|
||||
// we do not replace it.
|
||||
if (!flatenedFirstKeyframeStyles[prop]) {
|
||||
flatenedFirstKeyframeStyles[prop] = value;
|
||||
extraFirstKeyframeStyles[prop] = value;
|
||||
hasExtraFirstStyles = true;
|
||||
}
|
||||
});
|
||||
|
||||
var keyframeCollectedStyles = StringMapWrapper.merge({}, flatenedFirstKeyframeStyles);
|
||||
|
||||
// phase 2: normalize the final keyframe
|
||||
var finalKeyframe = keyframes[limit];
|
||||
ListWrapper.insert(finalKeyframe.styles.styles, 0, finalStateStyles);
|
||||
|
||||
var flatenedFinalKeyframeStyles = AnimationStyleUtil.flattenStyles(finalKeyframe.styles.styles);
|
||||
var extraFinalKeyframeStyles = {};
|
||||
var hasExtraFinalStyles = false;
|
||||
StringMapWrapper.forEach(keyframeCollectedStyles, (value, prop) => {
|
||||
if (!isPresent(flatenedFinalKeyframeStyles[prop])) {
|
||||
extraFinalKeyframeStyles[prop] = AUTO_STYLE;
|
||||
hasExtraFinalStyles = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasExtraFinalStyles) {
|
||||
finalKeyframe.styles.styles.push(extraFinalKeyframeStyles);
|
||||
}
|
||||
|
||||
StringMapWrapper.forEach(flatenedFinalKeyframeStyles, (value, prop) => {
|
||||
if (!isPresent(flatenedFirstKeyframeStyles[prop])) {
|
||||
extraFirstKeyframeStyles[prop] = AUTO_STYLE;
|
||||
hasExtraFirstStyles = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasExtraFirstStyles) {
|
||||
firstKeyframe.styles.styles.push(extraFirstKeyframeStyles);
|
||||
}
|
||||
|
||||
return keyframes;
|
||||
}
|
||||
|
||||
static clearStyles(styles: {[key: string]: string|number}): {[key: string]: string|number} {
|
||||
var finalStyles: {[key: string]: string|number} = {};
|
||||
StringMapWrapper.keys(styles).forEach(key => {
|
||||
finalStyles[key] = null;
|
||||
});
|
||||
return finalStyles;
|
||||
}
|
||||
|
||||
static collectAndResolveStyles(collection: {[key: string]: string|number}, styles: {[key: string]: string|number}[]) {
|
||||
return styles.map(entry => {
|
||||
var stylesObj = {};
|
||||
StringMapWrapper.forEach(entry, (value, prop) => {
|
||||
if (value == FILL_STYLE_FLAG) {
|
||||
value = collection[prop];
|
||||
if (!isPresent(value)) {
|
||||
value = AUTO_STYLE;
|
||||
}
|
||||
}
|
||||
collection[prop] = value;
|
||||
stylesObj[prop] = value;
|
||||
});
|
||||
return stylesObj;
|
||||
});
|
||||
}
|
||||
|
||||
static flattenStyles(styles: {[key: string]: string|number}[]) {
|
||||
var finalStyles = {};
|
||||
styles.forEach(entry => {
|
||||
StringMapWrapper.forEach(entry, (value, prop) => {
|
||||
finalStyles[prop] = value;
|
||||
});
|
||||
});
|
||||
return finalStyles;
|
||||
}
|
||||
}
|
3
modules/@angular/core/src/animation/animation_styles.ts
Normal file
3
modules/@angular/core/src/animation/animation_styles.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export class AnimationStyles {
|
||||
constructor(public styles: {[key: string]: string | number}[]) {}
|
||||
}
|
116
modules/@angular/core/src/animation/metadata.ts
Normal file
116
modules/@angular/core/src/animation/metadata.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import {isPresent, isArray, isString, isStringMap, NumberWrapper} from '../facade/lang';
|
||||
import {BaseException} from '../facade/exceptions';
|
||||
|
||||
export const AUTO_STYLE = "*";
|
||||
|
||||
export class AnimationEntryMetadata {
|
||||
constructor(public name: string, public definitions: AnimationStateMetadata[]) {}
|
||||
}
|
||||
|
||||
export abstract class AnimationStateMetadata {}
|
||||
|
||||
export class AnimationStateDeclarationMetadata extends AnimationStateMetadata {
|
||||
constructor(public stateNameExpr: string, public styles: AnimationStyleMetadata) { super(); }
|
||||
}
|
||||
|
||||
export class AnimationStateTransitionMetadata extends AnimationStateMetadata {
|
||||
constructor(public stateChangeExpr: string, public animation: AnimationMetadata) { super(); }
|
||||
}
|
||||
|
||||
export abstract class AnimationMetadata {}
|
||||
|
||||
export class AnimationKeyframesSequenceMetadata extends AnimationMetadata {
|
||||
constructor(public steps: AnimationStyleMetadata[]) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
export class AnimationStyleMetadata extends AnimationMetadata {
|
||||
constructor(public styles: Array<string|{[key: string]: string | number}>, public offset: number = null) { super(); }
|
||||
}
|
||||
|
||||
export class AnimationAnimateMetadata extends AnimationMetadata {
|
||||
constructor(public timings: string | number,
|
||||
public styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AnimationWithStepsMetadata extends AnimationMetadata {
|
||||
constructor() { super(); }
|
||||
get steps(): AnimationMetadata[] { throw new BaseException('NOT IMPLEMENTED: Base Class'); }
|
||||
}
|
||||
|
||||
export class AnimationSequenceMetadata extends AnimationWithStepsMetadata {
|
||||
constructor(private _steps: AnimationMetadata[]) { super(); }
|
||||
get steps(): AnimationMetadata[] { return this._steps; }
|
||||
}
|
||||
|
||||
export class AnimationGroupMetadata extends AnimationWithStepsMetadata {
|
||||
constructor(private _steps: AnimationMetadata[]) { super(); }
|
||||
get steps(): AnimationMetadata[] { return this._steps; }
|
||||
}
|
||||
|
||||
export function animate(timing: string | number,
|
||||
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata = null): AnimationAnimateMetadata {
|
||||
var stylesEntry = styles;
|
||||
if (!isPresent(stylesEntry)) {
|
||||
var EMPTY_STYLE: {[key: string]: string|number} = {};
|
||||
stylesEntry = new AnimationStyleMetadata([EMPTY_STYLE], 1);
|
||||
}
|
||||
return new AnimationAnimateMetadata(timing, stylesEntry);
|
||||
}
|
||||
|
||||
export function group(steps: AnimationMetadata[]): AnimationGroupMetadata {
|
||||
return new AnimationGroupMetadata(steps);
|
||||
}
|
||||
|
||||
export function sequence(steps: AnimationMetadata[]): AnimationSequenceMetadata {
|
||||
return new AnimationSequenceMetadata(steps);
|
||||
}
|
||||
|
||||
export function style(tokens: string|{[key: string]: string | number}|Array<string|{[key: string]: string | number}>): AnimationStyleMetadata {
|
||||
var input: Array<{[key: string]: string | number}|string>;
|
||||
var offset: number = null;
|
||||
if (isString(tokens)) {
|
||||
input = [<string>tokens];
|
||||
} else {
|
||||
if (isArray(tokens)) {
|
||||
input = <Array<{[key: string]: string | number}>>tokens;
|
||||
} else {
|
||||
input = [<{[key: string]: string | number}>tokens];
|
||||
}
|
||||
input.forEach(entry => {
|
||||
var entryOffset = entry['offset'];
|
||||
if (isPresent(entryOffset)) {
|
||||
offset = offset == null ? NumberWrapper.parseFloat(entryOffset) : offset;
|
||||
}
|
||||
});
|
||||
}
|
||||
return new AnimationStyleMetadata(input, offset);
|
||||
}
|
||||
|
||||
export function state(stateNameExpr: string, styles: AnimationStyleMetadata): AnimationStateDeclarationMetadata {
|
||||
return new AnimationStateDeclarationMetadata(stateNameExpr, styles);
|
||||
}
|
||||
|
||||
export function keyframes(steps: AnimationStyleMetadata|AnimationStyleMetadata[]): AnimationKeyframesSequenceMetadata {
|
||||
var stepData = isArray(steps)
|
||||
? <AnimationStyleMetadata[]>steps
|
||||
: [<AnimationStyleMetadata>steps];
|
||||
return new AnimationKeyframesSequenceMetadata(stepData);
|
||||
}
|
||||
|
||||
export function transition(stateChangeExpr: string, animationData: AnimationMetadata|AnimationMetadata[]): AnimationStateTransitionMetadata {
|
||||
var animation = isArray(animationData)
|
||||
? new AnimationSequenceMetadata(<AnimationMetadata[]>animationData)
|
||||
: <AnimationMetadata>animationData;
|
||||
return new AnimationStateTransitionMetadata(stateChangeExpr, animation);
|
||||
}
|
||||
|
||||
export function trigger(name: string, animation: AnimationMetadata|AnimationMetadata[]): AnimationEntryMetadata {
|
||||
var entry = isArray(animation)
|
||||
? <AnimationMetadata[]>animation
|
||||
: [<AnimationMetadata>animation];
|
||||
return new AnimationEntryMetadata(name, entry);
|
||||
}
|
@ -9,6 +9,10 @@ import {
|
||||
removeDebugNodeFromIndex
|
||||
} from './debug_node';
|
||||
|
||||
import {AnimationKeyframe} from '../animation/animation_keyframe';
|
||||
import {AnimationStyles} from '../animation/animation_styles';
|
||||
import {AnimationPlayer} from '../animation/animation_player';
|
||||
|
||||
export class DebugDomRootRenderer implements RootRenderer {
|
||||
constructor(private _delegate: RootRenderer) {}
|
||||
|
||||
@ -137,4 +141,8 @@ export class DebugDomRenderer implements Renderer {
|
||||
}
|
||||
|
||||
setText(renderNode: any, text: string) { this._delegate.setText(renderNode, text); }
|
||||
|
||||
animate(element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[], duration: number, delay: number, easing: string): AnimationPlayer {
|
||||
return this._delegate.animate(element, startingStyles, keyframes, duration, delay, easing);
|
||||
}
|
||||
}
|
||||
|
@ -81,8 +81,7 @@ export class AppElement {
|
||||
if (view.type === ViewType.COMPONENT) {
|
||||
throw new BaseException(`Component views can't be moved!`);
|
||||
}
|
||||
|
||||
view.renderer.detachView(view.flatRootNodes);
|
||||
view.detach();
|
||||
|
||||
view.removeFromContentChildren(this);
|
||||
return view;
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {
|
||||
ListWrapper,
|
||||
StringMapWrapper,
|
||||
} from '../../src/facade/collection';
|
||||
Map,
|
||||
MapWrapper
|
||||
} from '../facade/collection';
|
||||
|
||||
import {AppElement} from './element';
|
||||
import {
|
||||
@ -14,9 +16,9 @@ import {
|
||||
stringify,
|
||||
isPrimitive,
|
||||
isString
|
||||
} from '../../src/facade/lang';
|
||||
} from '../facade/lang';
|
||||
|
||||
import {ObservableWrapper} from '../../src/facade/async';
|
||||
import {ObservableWrapper} from '../facade/async';
|
||||
import {Renderer, RootRenderer, RenderComponentType, RenderDebugInfo} from '../render/api';
|
||||
import {ViewRef_} from './view_ref';
|
||||
|
||||
@ -43,6 +45,14 @@ import {StaticNodeDebugInfo, DebugContext} from './debug_context';
|
||||
import {ElementInjector} from './element_injector';
|
||||
import {Injector} from '../di/injector';
|
||||
|
||||
import {AUTO_STYLE} from '../animation/metadata';
|
||||
import {AnimationPlayer} from '../animation/animation_player';
|
||||
import {AnimationGroupPlayer} from '../animation/animation_group_player';
|
||||
import {AnimationKeyframe} from '../animation/animation_keyframe';
|
||||
import {AnimationStyles} from '../animation/animation_styles';
|
||||
import {AnimationDriver} from '../animation/animation_driver';
|
||||
import {ActiveAnimationPlayersMap} from '../animation/active_animation_players_map';
|
||||
|
||||
var _scope_check: WtfScopeFn = wtfCreateScope(`AppView#check(ascii id)`);
|
||||
|
||||
/**
|
||||
@ -71,6 +81,8 @@ export abstract class AppView<T> {
|
||||
|
||||
private _hasExternalHostElement: boolean;
|
||||
|
||||
public activeAnimationPlayers = new ActiveAnimationPlayersMap();
|
||||
|
||||
public context: T;
|
||||
|
||||
constructor(public clazz: any, public componentType: RenderComponentType, public type: ViewType,
|
||||
@ -84,6 +96,25 @@ export abstract class AppView<T> {
|
||||
}
|
||||
}
|
||||
|
||||
cancelActiveAnimation(element: any, animationName: string, removeAllAnimations: boolean = false) {
|
||||
if (removeAllAnimations) {
|
||||
this.activeAnimationPlayers.findAllPlayersByElement(element).forEach(player => player.destroy());
|
||||
} else {
|
||||
var player = this.activeAnimationPlayers.find(element, animationName);
|
||||
if (isPresent(player)) {
|
||||
player.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAndStartAnimation(element: any, animationName: string, player: AnimationPlayer): void {
|
||||
this.activeAnimationPlayers.set(element, animationName, player);
|
||||
player.onDone(() => {
|
||||
this.activeAnimationPlayers.remove(element, animationName);
|
||||
});
|
||||
player.play();
|
||||
}
|
||||
|
||||
create(context: T, givenProjectableNodes: Array<any | any[]>,
|
||||
rootSelectorOrNode: string | any): AppElement {
|
||||
this.context = context;
|
||||
@ -193,7 +224,15 @@ export abstract class AppView<T> {
|
||||
}
|
||||
this.destroyInternal();
|
||||
this.dirtyParentQueriesInternal();
|
||||
this.renderer.destroyView(hostElement, this.allNodes);
|
||||
|
||||
if (this.activeAnimationPlayers.length == 0) {
|
||||
this.renderer.destroyView(hostElement, this.allNodes);
|
||||
} else {
|
||||
var player = new AnimationGroupPlayer(this.activeAnimationPlayers.getAllPlayers());
|
||||
player.onDone(() => {
|
||||
this.renderer.destroyView(hostElement, this.allNodes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -201,6 +240,23 @@ export abstract class AppView<T> {
|
||||
*/
|
||||
destroyInternal(): void {}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
detachInternal(): void {}
|
||||
|
||||
detach(): void {
|
||||
this.detachInternal();
|
||||
if (this.activeAnimationPlayers.length == 0) {
|
||||
this.renderer.detachView(this.flatRootNodes);
|
||||
} else {
|
||||
var player = new AnimationGroupPlayer(this.activeAnimationPlayers.getAllPlayers());
|
||||
player.onDone(() => {
|
||||
this.renderer.detachView(this.flatRootNodes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get changeDetectorRef(): ChangeDetectorRef { return this.ref; }
|
||||
|
||||
get parent(): AppView<any> {
|
||||
@ -319,6 +375,16 @@ export class DebugAppView<T> extends AppView<T> {
|
||||
}
|
||||
}
|
||||
|
||||
detach(): void {
|
||||
this._resetDebug();
|
||||
try {
|
||||
super.detach();
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e, e.stack);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
destroyLocal() {
|
||||
this._resetDebug();
|
||||
try {
|
||||
|
@ -5,6 +5,7 @@ import 'package:angular2/src/core/change_detection/change_detection.dart';
|
||||
import './metadata/di.dart';
|
||||
import './metadata/directives.dart';
|
||||
import './metadata/view.dart';
|
||||
import './metadata/animations.dart' show AnimationEntryMetadata;
|
||||
|
||||
export './metadata/di.dart';
|
||||
export './metadata/directives.dart';
|
||||
@ -72,7 +73,8 @@ class Component extends ComponentMetadata {
|
||||
dynamic pipes,
|
||||
ViewEncapsulation encapsulation,
|
||||
List<String> styles,
|
||||
List<String> styleUrls})
|
||||
List<String> styleUrls,
|
||||
List<AnimationEntryMetadata> animations})
|
||||
: super(
|
||||
selector: selector,
|
||||
inputs: inputs,
|
||||
@ -92,7 +94,8 @@ class Component extends ComponentMetadata {
|
||||
pipes: pipes,
|
||||
encapsulation: encapsulation,
|
||||
styles: styles,
|
||||
styleUrls: styleUrls);
|
||||
styleUrls: styleUrls,
|
||||
animations: animations);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,7 +109,8 @@ class View extends ViewMetadata {
|
||||
dynamic pipes,
|
||||
ViewEncapsulation encapsulation,
|
||||
List<String> styles,
|
||||
List<String> styleUrls})
|
||||
List<String> styleUrls,
|
||||
List<AnimationEntryMetadata> animations})
|
||||
: super(
|
||||
templateUrl: templateUrl,
|
||||
template: template,
|
||||
@ -114,7 +118,8 @@ class View extends ViewMetadata {
|
||||
pipes: pipes,
|
||||
encapsulation: encapsulation,
|
||||
styles: styles,
|
||||
styleUrls: styleUrls);
|
||||
styleUrls: styleUrls,
|
||||
animations: animations);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,7 +57,8 @@ import {
|
||||
} from './metadata/directives';
|
||||
|
||||
import {ViewMetadata, ViewEncapsulation} from './metadata/view';
|
||||
import {ChangeDetectionStrategy} from './change_detection/change_detection';
|
||||
import {AnimationEntryMetadata} from './animation/metadata';
|
||||
import {ChangeDetectionStrategy} from '../src/change_detection/change_detection';
|
||||
|
||||
import {
|
||||
makeDecorator,
|
||||
@ -91,6 +92,7 @@ export interface ComponentDecorator extends TypeDecorator {
|
||||
renderer?: string,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[]
|
||||
}): ViewDecorator;
|
||||
}
|
||||
|
||||
@ -111,6 +113,7 @@ export interface ViewDecorator extends TypeDecorator {
|
||||
renderer?: string,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[]
|
||||
}): ViewDecorator;
|
||||
}
|
||||
|
||||
@ -219,6 +222,7 @@ export interface ComponentMetadataFactory {
|
||||
template?: string,
|
||||
styleUrls?: string[],
|
||||
styles?: string[],
|
||||
animations?: AnimationEntryMetadata[],
|
||||
directives?: Array<Type | any[]>,
|
||||
pipes?: Array<Type | any[]>,
|
||||
encapsulation?: ViewEncapsulation
|
||||
@ -240,6 +244,7 @@ export interface ComponentMetadataFactory {
|
||||
template?: string,
|
||||
styleUrls?: string[],
|
||||
styles?: string[],
|
||||
animations?: AnimationEntryMetadata[],
|
||||
directives?: Array<Type | any[]>,
|
||||
pipes?: Array<Type | any[]>,
|
||||
encapsulation?: ViewEncapsulation
|
||||
@ -297,6 +302,7 @@ export interface ViewMetadataFactory {
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[]
|
||||
}): ViewDecorator;
|
||||
new (obj: {
|
||||
templateUrl?: string,
|
||||
@ -306,6 +312,7 @@ export interface ViewMetadataFactory {
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[]
|
||||
}): ViewMetadata;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ import {isPresent, Type} from '../../src/facade/lang';
|
||||
import {InjectableMetadata} from '../di/metadata';
|
||||
import {ViewEncapsulation} from './view';
|
||||
import {ChangeDetectionStrategy} from '../change_detection/constants';
|
||||
import {AnimationEntryMetadata} from '../animation/metadata';
|
||||
|
||||
/**
|
||||
* Directives allow you to attach behavior to elements in the DOM.
|
||||
@ -872,6 +873,8 @@ export class ComponentMetadata extends DirectiveMetadata {
|
||||
|
||||
styles: string[];
|
||||
|
||||
animations: AnimationEntryMetadata[];
|
||||
|
||||
directives: Array<Type | any[]>;
|
||||
|
||||
pipes: Array<Type | any[]>;
|
||||
@ -881,7 +884,7 @@ export class ComponentMetadata extends DirectiveMetadata {
|
||||
constructor({selector, inputs, outputs, properties, events, host, exportAs, moduleId,
|
||||
providers, viewProviders,
|
||||
changeDetection = ChangeDetectionStrategy.Default, queries, templateUrl, template,
|
||||
styleUrls, styles, directives, pipes, encapsulation}: {
|
||||
styleUrls, styles, animations, directives, pipes, encapsulation}: {
|
||||
selector?: string,
|
||||
inputs?: string[],
|
||||
outputs?: string[],
|
||||
@ -898,6 +901,7 @@ export class ComponentMetadata extends DirectiveMetadata {
|
||||
template?: string,
|
||||
styleUrls?: string[],
|
||||
styles?: string[],
|
||||
animations?: AnimationEntryMetadata[],
|
||||
directives?: Array<Type | any[]>,
|
||||
pipes?: Array<Type | any[]>,
|
||||
encapsulation?: ViewEncapsulation
|
||||
@ -924,6 +928,7 @@ export class ComponentMetadata extends DirectiveMetadata {
|
||||
this.pipes = pipes;
|
||||
this.encapsulation = encapsulation;
|
||||
this.moduleId = moduleId;
|
||||
this.animations = animations;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {Type} from '../../src/facade/lang';
|
||||
import {AnimationEntryMetadata} from '../animation/metadata';
|
||||
|
||||
/**
|
||||
* Defines template and style encapsulation options available for Component's {@link View}.
|
||||
@ -123,7 +124,10 @@ export class ViewMetadata {
|
||||
*/
|
||||
encapsulation: ViewEncapsulation;
|
||||
|
||||
constructor({templateUrl, template, directives, pipes, encapsulation, styles, styleUrls}: {
|
||||
animations: AnimationEntryMetadata[];
|
||||
|
||||
constructor({templateUrl, template, directives, pipes, encapsulation, styles, styleUrls,
|
||||
animations}: {
|
||||
templateUrl?: string,
|
||||
template?: string,
|
||||
directives?: Array<Type | any[]>,
|
||||
@ -131,6 +135,7 @@ export class ViewMetadata {
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[]
|
||||
} = {}) {
|
||||
this.templateUrl = templateUrl;
|
||||
this.template = template;
|
||||
@ -139,5 +144,6 @@ export class ViewMetadata {
|
||||
this.directives = directives;
|
||||
this.pipes = pipes;
|
||||
this.encapsulation = encapsulation;
|
||||
this.animations = animations;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import {unimplemented} from '../../src/facade/exceptions';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
import {Injector} from '../di/injector';
|
||||
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
|
||||
import {AnimationPlayer} from '../../src/animation/animation_player';
|
||||
import {AnimationStyles} from '../../src/animation/animation_styles';
|
||||
|
||||
export class RenderComponentType {
|
||||
constructor(public id: string, public templateUrl: string, public slotCount: number,
|
||||
@ -59,6 +62,8 @@ export abstract class Renderer {
|
||||
abstract invokeElementMethod(renderElement: any, methodName: string, args: any[]);
|
||||
|
||||
abstract setText(renderNode: any, text: string);
|
||||
|
||||
abstract animate(element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[], duration: number, delay: number, easing: string): AnimationPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user