perf: delete pre-view-engine core, compiler, platform-browser, etc code (#14788)
After the introduction of the view engine, we can drop a lot of code that is not used any more. This should reduce the size of the app bundles because a lot of this code was not being properly tree-shaken by today's tools even though it was dead code.
This commit is contained in:
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
export const FILL_STYLE_FLAG = 'true'; // TODO (matsko): change to boolean
|
||||
export const ANY_STATE = '*';
|
||||
export const DEFAULT_STATE = '*';
|
||||
export const EMPTY_STATE = 'void';
|
@ -1,110 +0,0 @@
|
||||
/**
|
||||
* @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 {isPresent, scheduleMicroTask} from '../facade/lang';
|
||||
|
||||
import {AnimationPlayer} from './animation_player';
|
||||
|
||||
export class AnimationGroupPlayer implements AnimationPlayer {
|
||||
private _onDoneFns: Function[] = [];
|
||||
private _onStartFns: Function[] = [];
|
||||
private _finished = false;
|
||||
private _started = false;
|
||||
private _destroyed = false;
|
||||
private _onDestroyFns: Function[] = [];
|
||||
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
|
||||
constructor(private _players: AnimationPlayer[]) {
|
||||
let count = 0;
|
||||
const 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;
|
||||
this._onDoneFns.forEach(fn => fn());
|
||||
this._onDoneFns = [];
|
||||
}
|
||||
}
|
||||
|
||||
init(): void { this._players.forEach(player => player.init()); }
|
||||
|
||||
onStart(fn: () => void): void { this._onStartFns.push(fn); }
|
||||
|
||||
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
|
||||
|
||||
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
|
||||
|
||||
hasStarted() { return this._started; }
|
||||
|
||||
play() {
|
||||
if (!isPresent(this.parentPlayer)) {
|
||||
this.init();
|
||||
}
|
||||
if (!this.hasStarted()) {
|
||||
this._onStartFns.forEach(fn => fn());
|
||||
this._onStartFns = [];
|
||||
this._started = true;
|
||||
}
|
||||
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 {
|
||||
if (!this._destroyed) {
|
||||
this._onFinish();
|
||||
this._players.forEach(player => player.destroy());
|
||||
this._destroyed = true;
|
||||
this._onDestroyFns.forEach(fn => fn());
|
||||
this._onDestroyFns = [];
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._players.forEach(player => player.reset());
|
||||
this._destroyed = false;
|
||||
this._finished = false;
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
setPosition(p: number): void {
|
||||
this._players.forEach(player => { player.setPosition(p); });
|
||||
}
|
||||
|
||||
getPosition(): number {
|
||||
let min = 0;
|
||||
this._players.forEach(player => {
|
||||
const p = player.getPosition();
|
||||
min = Math.min(p, min);
|
||||
});
|
||||
return min;
|
||||
}
|
||||
|
||||
get players(): AnimationPlayer[] { return this._players; }
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* @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 {AnimationStyles} from './animation_styles';
|
||||
|
||||
/**
|
||||
* `AnimationKeyframe` consists of a series of styles (contained within {@link AnimationStyles
|
||||
* `AnimationStyles`})
|
||||
* and an offset value indicating when those styles are applied within the `duration/delay/easing`
|
||||
* timings.
|
||||
* `AnimationKeyframe` is mostly an internal class which is designed to be used alongside {@link
|
||||
* Renderer#animate-anchor `Renderer.animate`}.
|
||||
*
|
||||
* @experimental Animation support is experimental
|
||||
*/
|
||||
export class AnimationKeyframe {
|
||||
constructor(public offset: number, public styles: AnimationStyles) {}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/**
|
||||
* @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 {scheduleMicroTask} from '../facade/lang';
|
||||
|
||||
|
||||
/**
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export abstract class AnimationPlayer {
|
||||
abstract onDone(fn: () => void): void;
|
||||
abstract onStart(fn: () => void): void;
|
||||
abstract onDestroy(fn: () => void): void;
|
||||
abstract init(): void;
|
||||
abstract hasStarted(): boolean;
|
||||
abstract play(): void;
|
||||
abstract pause(): void;
|
||||
abstract restart(): void;
|
||||
abstract finish(): void;
|
||||
abstract destroy(): void;
|
||||
abstract reset(): void;
|
||||
abstract setPosition(p: any /** TODO #9100 */): void;
|
||||
abstract getPosition(): number;
|
||||
get parentPlayer(): AnimationPlayer { throw new Error('NOT IMPLEMENTED: Base Class'); }
|
||||
set parentPlayer(player: AnimationPlayer) { throw new Error('NOT IMPLEMENTED: Base Class'); }
|
||||
}
|
||||
|
||||
export class NoOpAnimationPlayer implements AnimationPlayer {
|
||||
private _onDoneFns: Function[] = [];
|
||||
private _onStartFns: Function[] = [];
|
||||
private _onDestroyFns: Function[] = [];
|
||||
private _started = false;
|
||||
private _destroyed = false;
|
||||
private _finished = false;
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
constructor() { scheduleMicroTask(() => this._onFinish()); }
|
||||
private _onFinish() {
|
||||
if (!this._finished) {
|
||||
this._finished = true;
|
||||
this._onDoneFns.forEach(fn => fn());
|
||||
this._onDoneFns = [];
|
||||
}
|
||||
}
|
||||
onStart(fn: () => void): void { this._onStartFns.push(fn); }
|
||||
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
|
||||
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
|
||||
hasStarted(): boolean { return this._started; }
|
||||
init(): void {}
|
||||
play(): void {
|
||||
if (!this.hasStarted()) {
|
||||
this._onStartFns.forEach(fn => fn());
|
||||
this._onStartFns = [];
|
||||
}
|
||||
this._started = true;
|
||||
}
|
||||
pause(): void {}
|
||||
restart(): void {}
|
||||
finish(): void { this._onFinish(); }
|
||||
destroy(): void {
|
||||
if (!this._destroyed) {
|
||||
this._destroyed = true;
|
||||
this.finish();
|
||||
this._onDestroyFns.forEach(fn => fn());
|
||||
this._onDestroyFns = [];
|
||||
}
|
||||
}
|
||||
reset(): void {}
|
||||
setPosition(p: number): void {}
|
||||
getPosition(): number { return 0; }
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* @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 {Injectable} from '../di/metadata';
|
||||
import {NgZone} from '../zone/ng_zone';
|
||||
import {AnimationPlayer} from './animation_player';
|
||||
|
||||
@Injectable()
|
||||
export class AnimationQueue {
|
||||
public entries: AnimationPlayer[] = [];
|
||||
|
||||
constructor(private _zone: NgZone) {}
|
||||
|
||||
enqueue(player: AnimationPlayer) { this.entries.push(player); }
|
||||
|
||||
flush() {
|
||||
// given that each animation player may set aside
|
||||
// microtasks and rely on DOM-based events, this
|
||||
// will cause Angular to run change detection after
|
||||
// each request. This sidesteps the issue. If a user
|
||||
// hooks into an animation via (@anim.start) or (@anim.done)
|
||||
// then those methods will automatically trigger change
|
||||
// detection by wrapping themselves inside of a zone
|
||||
if (this.entries.length) {
|
||||
this._zone.runOutsideAngular(() => {
|
||||
// this code is wrapped into a single promise such that the
|
||||
// onStart and onDone player callbacks are triggered outside
|
||||
// of the digest cycle of animations
|
||||
Promise.resolve(null).then(() => this._triggerAnimations());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _triggerAnimations() {
|
||||
NgZone.assertNotInAngularZone();
|
||||
|
||||
while (this.entries.length) {
|
||||
const player = this.entries.shift();
|
||||
// in the event that an animation throws an error then we do
|
||||
// not want to re-run animations on any previous animations
|
||||
// if they have already been kicked off beforehand
|
||||
if (!player.hasStarted()) {
|
||||
player.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/**
|
||||
* @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 {isPresent, scheduleMicroTask} from '../facade/lang';
|
||||
|
||||
import {AnimationPlayer, NoOpAnimationPlayer} from './animation_player';
|
||||
|
||||
export class AnimationSequencePlayer implements AnimationPlayer {
|
||||
private _currentIndex: number = 0;
|
||||
private _activePlayer: AnimationPlayer;
|
||||
private _onDoneFns: Function[] = [];
|
||||
private _onStartFns: Function[] = [];
|
||||
private _onDestroyFns: Function[] = [];
|
||||
private _finished = false;
|
||||
private _started = false;
|
||||
private _destroyed = 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 {
|
||||
const 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;
|
||||
this._onDoneFns.forEach(fn => fn());
|
||||
this._onDoneFns = [];
|
||||
}
|
||||
}
|
||||
|
||||
init(): void { this._players.forEach(player => player.init()); }
|
||||
|
||||
onStart(fn: () => void): void { this._onStartFns.push(fn); }
|
||||
|
||||
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
|
||||
|
||||
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
|
||||
|
||||
hasStarted() { return this._started; }
|
||||
|
||||
play(): void {
|
||||
if (!isPresent(this.parentPlayer)) {
|
||||
this.init();
|
||||
}
|
||||
if (!this.hasStarted()) {
|
||||
this._onStartFns.forEach(fn => fn());
|
||||
this._onStartFns = [];
|
||||
this._started = true;
|
||||
}
|
||||
this._activePlayer.play();
|
||||
}
|
||||
|
||||
pause(): void { this._activePlayer.pause(); }
|
||||
|
||||
restart(): void {
|
||||
this.reset();
|
||||
if (this._players.length > 0) {
|
||||
this._players[0].restart();
|
||||
}
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._players.forEach(player => player.reset());
|
||||
this._destroyed = false;
|
||||
this._finished = false;
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
finish(): void {
|
||||
this._onFinish();
|
||||
this._players.forEach(player => player.finish());
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
if (!this._destroyed) {
|
||||
this._onFinish();
|
||||
this._players.forEach(player => player.destroy());
|
||||
this._destroyed = true;
|
||||
this._activePlayer = new NoOpAnimationPlayer();
|
||||
this._onDestroyFns.forEach(fn => fn());
|
||||
this._onDestroyFns = [];
|
||||
}
|
||||
}
|
||||
|
||||
setPosition(p: number): void { this._players[0].setPosition(p); }
|
||||
|
||||
getPosition(): number { return this._players[0].getPosition(); }
|
||||
|
||||
get players(): AnimationPlayer[] { return this._players; }
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
/**
|
||||
* @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 {StringMapWrapper} from '../facade/collection';
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
||||
import {FILL_STYLE_FLAG} from './animation_constants';
|
||||
import {AUTO_STYLE} from './metadata';
|
||||
|
||||
export function prepareFinalAnimationStyles(
|
||||
previousStyles: {[key: string]: string | number}, newStyles: {[key: string]: string | number},
|
||||
nullValue: string = null): {[key: string]: string} {
|
||||
const finalStyles: {[key: string]: string} = {};
|
||||
|
||||
Object.keys(newStyles).forEach(prop => {
|
||||
const value = newStyles[prop];
|
||||
finalStyles[prop] = value == AUTO_STYLE ? nullValue : value.toString();
|
||||
});
|
||||
|
||||
Object.keys(previousStyles).forEach(prop => {
|
||||
if (!isPresent(finalStyles[prop])) {
|
||||
finalStyles[prop] = nullValue;
|
||||
}
|
||||
});
|
||||
|
||||
return finalStyles;
|
||||
}
|
||||
|
||||
export function balanceAnimationKeyframes(
|
||||
collectedStyles: {[key: string]: string | number},
|
||||
finalStateStyles: {[key: string]: string | number}, keyframes: any[]): any[] {
|
||||
const limit = keyframes.length - 1;
|
||||
const firstKeyframe = keyframes[0];
|
||||
|
||||
// phase 1: copy all the styles from the first keyframe into the lookup map
|
||||
const flatenedFirstKeyframeStyles = flattenStyles(firstKeyframe.styles.styles);
|
||||
|
||||
const extraFirstKeyframeStyles: {[key: string]: string} = {};
|
||||
let hasExtraFirstStyles = false;
|
||||
Object.keys(collectedStyles).forEach(prop => {
|
||||
const value = collectedStyles[prop] as string;
|
||||
// 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;
|
||||
}
|
||||
});
|
||||
|
||||
const keyframeCollectedStyles = StringMapWrapper.merge({}, flatenedFirstKeyframeStyles);
|
||||
|
||||
// phase 2: normalize the final keyframe
|
||||
const finalKeyframe = keyframes[limit];
|
||||
finalKeyframe.styles.styles.unshift(finalStateStyles);
|
||||
|
||||
const flatenedFinalKeyframeStyles = flattenStyles(finalKeyframe.styles.styles);
|
||||
const extraFinalKeyframeStyles: {[key: string]: string} = {};
|
||||
let hasExtraFinalStyles = false;
|
||||
Object.keys(keyframeCollectedStyles).forEach(prop => {
|
||||
if (!isPresent(flatenedFinalKeyframeStyles[prop])) {
|
||||
extraFinalKeyframeStyles[prop] = AUTO_STYLE;
|
||||
hasExtraFinalStyles = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasExtraFinalStyles) {
|
||||
finalKeyframe.styles.styles.push(extraFinalKeyframeStyles);
|
||||
}
|
||||
|
||||
Object.keys(flatenedFinalKeyframeStyles).forEach(prop => {
|
||||
if (!isPresent(flatenedFirstKeyframeStyles[prop])) {
|
||||
extraFirstKeyframeStyles[prop] = AUTO_STYLE;
|
||||
hasExtraFirstStyles = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasExtraFirstStyles) {
|
||||
firstKeyframe.styles.styles.push(extraFirstKeyframeStyles);
|
||||
}
|
||||
|
||||
collectAndResolveStyles(collectedStyles, [finalStateStyles]);
|
||||
|
||||
return keyframes;
|
||||
}
|
||||
|
||||
export function clearStyles(styles: {[key: string]: string | number}): {[key: string]: string} {
|
||||
const finalStyles: {[key: string]: string} = {};
|
||||
Object.keys(styles).forEach(key => { finalStyles[key] = null; });
|
||||
return finalStyles;
|
||||
}
|
||||
|
||||
export function collectAndResolveStyles(
|
||||
collection: {[key: string]: string | number}, styles: {[key: string]: string | number}[]) {
|
||||
return styles.map(entry => {
|
||||
const stylesObj: {[key: string]: string | number} = {};
|
||||
Object.keys(entry).forEach(prop => {
|
||||
let value = entry[prop];
|
||||
if (value == FILL_STYLE_FLAG) {
|
||||
value = collection[prop];
|
||||
if (!isPresent(value)) {
|
||||
value = AUTO_STYLE;
|
||||
}
|
||||
}
|
||||
collection[prop] = value;
|
||||
stylesObj[prop] = value;
|
||||
});
|
||||
return stylesObj;
|
||||
});
|
||||
}
|
||||
|
||||
export function renderStyles(
|
||||
element: any, renderer: any, styles: {[key: string]: string | number}): void {
|
||||
Object.keys(styles).forEach(prop => { renderer.setElementStyle(element, prop, styles[prop]); });
|
||||
}
|
||||
|
||||
export function flattenStyles(styles: {[key: string]: string | number}[]): {[key: string]: string} {
|
||||
const finalStyles: {[key: string]: string} = {};
|
||||
styles.forEach(entry => {
|
||||
Object.keys(entry).forEach(prop => { finalStyles[prop] = entry[prop] as string; });
|
||||
});
|
||||
return finalStyles;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
// having an import prevents dgeni from truncating out
|
||||
// the class description in the docs. DO NOT REMOVE.
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
||||
/**
|
||||
* `AnimationStyles` consists of a collection of key/value maps containing CSS-based style data
|
||||
* that can either be used as initial styling data or apart of a series of keyframes within an
|
||||
* animation.
|
||||
* This class is mostly internal, and it is designed to be used alongside
|
||||
* {@link AnimationKeyframe `AnimationKeyframe`} and {@link Renderer#animate-anchor
|
||||
* `Renderer.animate`}.
|
||||
*
|
||||
* @experimental Animation support is experimental
|
||||
*/
|
||||
export class AnimationStyles {
|
||||
constructor(public styles: {[key: string]: string | number}[]) {}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/**
|
||||
* @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 {ElementRef} from '../linker/element_ref';
|
||||
|
||||
import {AnimationPlayer} from './animation_player';
|
||||
import {AnimationTransitionEvent} from './animation_transition_event';
|
||||
|
||||
export class AnimationTransition {
|
||||
constructor(
|
||||
private _player: AnimationPlayer, private _element: ElementRef, private _triggerName: string,
|
||||
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,
|
||||
element: this._element,
|
||||
triggerName: this._triggerName
|
||||
});
|
||||
}
|
||||
|
||||
onStart(callback: (event: AnimationTransitionEvent) => any): void {
|
||||
const fn =
|
||||
<() => void>Zone.current.wrap(() => callback(this._createEvent('start')), 'player.onStart');
|
||||
this._player.onStart(fn);
|
||||
}
|
||||
|
||||
onDone(callback: (event: AnimationTransitionEvent) => any): void {
|
||||
const fn =
|
||||
<() => void>Zone.current.wrap(() => callback(this._createEvent('done')), 'player.onDone');
|
||||
this._player.onDone(fn);
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/**
|
||||
* @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 {ElementRef} from '../linker/element_ref';
|
||||
|
||||
/**
|
||||
* An instance of this class is returned as an event parameter when an animation
|
||||
* callback is captured for an animation either during the start or done phase.
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* host: {
|
||||
* '[@myAnimationTrigger]': 'someExpression',
|
||||
* '(@myAnimationTrigger.start)': 'captureStartEvent($event)',
|
||||
* '(@myAnimationTrigger.done)': 'captureDoneEvent($event)',
|
||||
* },
|
||||
* animations: [
|
||||
* trigger("myAnimationTrigger", [
|
||||
* // ...
|
||||
* ])
|
||||
* ]
|
||||
* })
|
||||
* class MyComponent {
|
||||
* someExpression: any = false;
|
||||
* captureStartEvent(event: AnimationTransitionEvent) {
|
||||
* // the toState, fromState and totalTime data is accessible from the event variable
|
||||
* }
|
||||
*
|
||||
* captureDoneEvent(event: AnimationTransitionEvent) {
|
||||
* // the toState, fromState and totalTime data is accessible from the event variable
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationTransitionEvent {
|
||||
public fromState: string;
|
||||
public toState: string;
|
||||
public totalTime: number;
|
||||
public phaseName: string;
|
||||
public element: ElementRef;
|
||||
public triggerName: string;
|
||||
|
||||
constructor({fromState, toState, totalTime, phaseName, element, triggerName}: {
|
||||
fromState: string,
|
||||
toState: string,
|
||||
totalTime: number,
|
||||
phaseName: string,
|
||||
element: any,
|
||||
triggerName: string
|
||||
}) {
|
||||
this.fromState = fromState;
|
||||
this.toState = toState;
|
||||
this.totalTime = totalTime;
|
||||
this.phaseName = phaseName;
|
||||
this.element = new ElementRef(element);
|
||||
this.triggerName = triggerName;
|
||||
}
|
||||
}
|
@ -1,644 +0,0 @@
|
||||
/**
|
||||
* @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 {isPresent} from '../facade/lang';
|
||||
|
||||
/**
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export const AUTO_STYLE = '*';
|
||||
|
||||
/**
|
||||
* Metadata representing the entry of animations.
|
||||
* Instances of this class are provided via the animation DSL when the {@link trigger trigger
|
||||
* animation function} is called.
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationEntryMetadata {
|
||||
constructor(public name: string, public definitions: AnimationStateMetadata[]) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export abstract class AnimationStateMetadata {}
|
||||
|
||||
/**
|
||||
* Metadata representing the entry of animations.
|
||||
* Instances of this class are provided via the animation DSL when the {@link state state animation
|
||||
* function} is called.
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationStateDeclarationMetadata extends AnimationStateMetadata {
|
||||
constructor(public stateNameExpr: string, public styles: AnimationStyleMetadata) { super(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata representing the entry of animations.
|
||||
* Instances of this class are provided via the animation DSL when the
|
||||
* {@link transition transition animation function} is called.
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationStateTransitionMetadata extends AnimationStateMetadata {
|
||||
constructor(
|
||||
public stateChangeExpr: string|((fromState: string, toState: string) => boolean),
|
||||
public steps: AnimationMetadata) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export abstract class AnimationMetadata {}
|
||||
|
||||
/**
|
||||
* Metadata representing the entry of animations.
|
||||
* Instances of this class are provided via the animation DSL when the {@link keyframes keyframes
|
||||
* animation function} is called.
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationKeyframesSequenceMetadata extends AnimationMetadata {
|
||||
constructor(public steps: AnimationStyleMetadata[]) { super(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata representing the entry of animations.
|
||||
* Instances of this class are provided via the animation DSL when the {@link style style animation
|
||||
* function} is called.
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationStyleMetadata extends AnimationMetadata {
|
||||
constructor(
|
||||
public styles: Array<string|{[key: string]: string | number}>, public offset: number = null) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata representing the entry of animations.
|
||||
* Instances of this class are provided via the animation DSL when the {@link animate animate
|
||||
* animation function} is called.
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationAnimateMetadata extends AnimationMetadata {
|
||||
constructor(
|
||||
public timings: string|number,
|
||||
public styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export abstract class AnimationWithStepsMetadata extends AnimationMetadata {
|
||||
constructor() { super(); }
|
||||
get steps(): AnimationMetadata[] { throw new Error('NOT IMPLEMENTED: Base Class'); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata representing the entry of animations.
|
||||
* Instances of this class are provided via the animation DSL when the {@link sequence sequence
|
||||
* animation function} is called.
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationSequenceMetadata extends AnimationWithStepsMetadata {
|
||||
constructor(private _steps: AnimationMetadata[]) { super(); }
|
||||
get steps(): AnimationMetadata[] { return this._steps; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata representing the entry of animations.
|
||||
* Instances of this class are provided via the animation DSL when the {@link group group animation
|
||||
* function} is called.
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export class AnimationGroupMetadata extends AnimationWithStepsMetadata {
|
||||
constructor(private _steps: AnimationMetadata[]) { super(); }
|
||||
get steps(): AnimationMetadata[] { return this._steps; }
|
||||
}
|
||||
|
||||
/**
|
||||
* `animate` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* animation
|
||||
* DSL language. If this information is new, please navigate to the
|
||||
* {@link Component#animations-anchor component animations metadata
|
||||
* page} to gain a better understanding of how animations in Angular2 are used.
|
||||
*
|
||||
* `animate` specifies an animation step that will apply the provided `styles` data for a given
|
||||
* amount of
|
||||
* time based on the provided `timing` expression value. Calls to `animate` are expected to be
|
||||
* used within {@link sequence an animation sequence}, {@link group group}, or {@link transition
|
||||
* transition}.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* The `animate` function accepts two input parameters: `timing` and `styles`:
|
||||
*
|
||||
* - `timing` is a string based value that can be a combination of a duration with optional
|
||||
* delay and easing values. The format for the expression breaks down to `duration delay easing`
|
||||
* (therefore a value such as `1s 100ms ease-out` will be parse itself into `duration=1000,
|
||||
* delay=100, easing=ease-out`.
|
||||
* If a numeric value is provided then that will be used as the `duration` value in millisecond
|
||||
* form.
|
||||
* - `styles` is the style input data which can either be a call to {@link style style} or {@link
|
||||
* keyframes keyframes}.
|
||||
* If left empty then the styles from the destination state will be collected and used (this is
|
||||
* useful when
|
||||
* describing an animation step that will complete an animation by {@link
|
||||
* transition#the-final-animate-call animating to the final state}).
|
||||
*
|
||||
* ```typescript
|
||||
* // various functions for specifying timing data
|
||||
* animate(500, style(...))
|
||||
* animate("1s", style(...))
|
||||
* animate("100ms 0.5s", style(...))
|
||||
* animate("5s ease", style(...))
|
||||
* animate("5s 10ms cubic-bezier(.17,.67,.88,.1)", style(...))
|
||||
*
|
||||
* // either style() of keyframes() can be used
|
||||
* animate(500, style({ background: "red" }))
|
||||
* animate(500, keyframes([
|
||||
* style({ background: "blue" })),
|
||||
* style({ background: "red" }))
|
||||
* ])
|
||||
* ```
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
|
||||
*
|
||||
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function animate(
|
||||
timing: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata =
|
||||
null): AnimationAnimateMetadata {
|
||||
let stylesEntry = styles;
|
||||
if (!isPresent(stylesEntry)) {
|
||||
const EMPTY_STYLE: {[key: string]: string | number} = {};
|
||||
stylesEntry = new AnimationStyleMetadata([EMPTY_STYLE], 1);
|
||||
}
|
||||
return new AnimationAnimateMetadata(timing, stylesEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* `group` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* animation
|
||||
* DSL language. If this information is new, please navigate to the
|
||||
* {@link Component#animations-anchor component animations metadata
|
||||
* page} to gain a better understanding of how animations in Angular2 are used.
|
||||
*
|
||||
* `group` specifies a list of animation steps that are all run in parallel. Grouped animations
|
||||
* are useful when a series of styles must be animated/closed off
|
||||
* at different statrting/ending times.
|
||||
*
|
||||
* The `group` function can either be used within a {@link sequence sequence} or a {@link transition
|
||||
* transition}
|
||||
* and it will only continue to the next instruction once all of the inner animation steps
|
||||
* have completed.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* The `steps` data that is passed into the `group` animation function can either consist
|
||||
* of {@link style style} or {@link animate animate} function calls. Each call to `style()` or
|
||||
* `animate()`
|
||||
* within a group will be executed instantly (use {@link keyframes keyframes} or a
|
||||
* {@link animate#usage animate() with a delay value} to offset styles to be applied at a later
|
||||
* time).
|
||||
*
|
||||
* ```typescript
|
||||
* group([
|
||||
* animate("1s", { background: "black" }))
|
||||
* animate("2s", { color: "white" }))
|
||||
* ])
|
||||
* ```
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
|
||||
*
|
||||
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function group(steps: AnimationMetadata[]): AnimationGroupMetadata {
|
||||
return new AnimationGroupMetadata(steps);
|
||||
}
|
||||
|
||||
/**
|
||||
* `sequence` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* animation
|
||||
* DSL language. If this information is new, please navigate to the
|
||||
* {@link Component#animations-anchor component animations metadata
|
||||
* page} to gain a better understanding of how animations in Angular2 are used.
|
||||
*
|
||||
* `sequence` Specifies a list of animation steps that are run one by one. (`sequence` is used
|
||||
* by default when an array is passed as animation data into {@link transition transition}.)
|
||||
*
|
||||
* The `sequence` function can either be used within a {@link group group} or a {@link transition
|
||||
* transition}
|
||||
* and it will only continue to the next instruction once each of the inner animation steps
|
||||
* have completed.
|
||||
*
|
||||
* To perform animation styling in parallel with other animation steps then
|
||||
* have a look at the {@link group group} animation function.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* The `steps` data that is passed into the `sequence` animation function can either consist
|
||||
* of {@link style style} or {@link animate animate} function calls. A call to `style()` will apply
|
||||
* the
|
||||
* provided styling data immediately while a call to `animate()` will apply its styling
|
||||
* data over a given time depending on its timing data.
|
||||
*
|
||||
* ```typescript
|
||||
* sequence([
|
||||
* style({ opacity: 0 })),
|
||||
* animate("1s", { opacity: 1 }))
|
||||
* ])
|
||||
* ```
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
|
||||
*
|
||||
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function sequence(steps: AnimationMetadata[]): AnimationSequenceMetadata {
|
||||
return new AnimationSequenceMetadata(steps);
|
||||
}
|
||||
|
||||
/**
|
||||
* `style` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* animation
|
||||
* DSL language. If this information is new, please navigate to the
|
||||
* {@link Component#animations-anchor component animations metadata
|
||||
* page} to gain a better understanding of how animations in Angular2 are used.
|
||||
*
|
||||
* `style` declares a key/value object containing CSS properties/styles that can then
|
||||
* be used for {@link state animation states}, within an {@link sequence animation sequence}, or as
|
||||
* styling data for both {@link animate animate} and {@link keyframes keyframes}.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* `style` takes in a key/value string map as data and expects one or more CSS property/value
|
||||
* pairs to be defined.
|
||||
*
|
||||
* ```typescript
|
||||
* // string values are used for css properties
|
||||
* style({ background: "red", color: "blue" })
|
||||
*
|
||||
* // numerical (pixel) values are also supported
|
||||
* style({ width: 100, height: 0 })
|
||||
* ```
|
||||
*
|
||||
* #### Auto-styles (using `*`)
|
||||
*
|
||||
* When an asterix (`*`) character is used as a value then it will be detected from the element
|
||||
* being animated
|
||||
* and applied as animation data when the animation starts.
|
||||
*
|
||||
* This feature proves useful for a state depending on layout and/or environment factors; in such
|
||||
* cases
|
||||
* the styles are calculated just before the animation starts.
|
||||
*
|
||||
* ```typescript
|
||||
* // the steps below will animate from 0 to the
|
||||
* // actual height of the element
|
||||
* style({ height: 0 }),
|
||||
* animate("1s", style({ height: "*" }))
|
||||
* ```
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
|
||||
*
|
||||
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function style(
|
||||
tokens: string | {[key: string]: string | number} |
|
||||
Array<string|{[key: string]: string | number}>): AnimationStyleMetadata {
|
||||
let input: Array<{[key: string]: string | number}|string>;
|
||||
let offset: number = null;
|
||||
if (typeof tokens === 'string') {
|
||||
input = [<string>tokens];
|
||||
} else {
|
||||
if (Array.isArray(tokens)) {
|
||||
input = <Array<{[key: string]: string | number}>>tokens;
|
||||
} else {
|
||||
input = [<{[key: string]: string | number}>tokens];
|
||||
}
|
||||
input.forEach(entry => {
|
||||
const entryOffset = (entry as any /** TODO #9100 */)['offset'];
|
||||
if (isPresent(entryOffset)) {
|
||||
offset = offset == null ? parseFloat(entryOffset) : offset;
|
||||
}
|
||||
});
|
||||
}
|
||||
return new AnimationStyleMetadata(input, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* `state` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* animation
|
||||
* DSL language. If this information is new, please navigate to the
|
||||
* {@link Component#animations-anchor component animations metadata
|
||||
* page} to gain a better understanding of how animations in Angular2 are used.
|
||||
*
|
||||
* `state` declares an animation state within the given trigger. When a state is
|
||||
* active within a component then its associated styles will persist on
|
||||
* the element that the trigger is attached to (even when the animation ends).
|
||||
*
|
||||
* To animate between states, have a look at the animation {@link transition transition}
|
||||
* DSL function. To register states to an animation trigger please have a look
|
||||
* at the {@link trigger trigger} function.
|
||||
*
|
||||
* #### The `void` state
|
||||
*
|
||||
* The `void` state value is a reserved word that angular uses to determine when the element is not
|
||||
* apart
|
||||
* of the application anymore (e.g. when an `ngIf` evaluates to false then the state of the
|
||||
* associated element
|
||||
* is void).
|
||||
*
|
||||
* #### The `*` (default) state
|
||||
*
|
||||
* The `*` state (when styled) is a fallback state that will be used if
|
||||
* the state that is being animated is not declared within the trigger.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* `state` will declare an animation state with its associated styles
|
||||
* within the given trigger.
|
||||
*
|
||||
* - `stateNameExpr` can be one or more state names separated by commas.
|
||||
* - `styles` refers to the {@link style styling data} that will be persisted on the element once
|
||||
* the state
|
||||
* has been reached.
|
||||
*
|
||||
* ```typescript
|
||||
* // "void" is a reserved name for a state and is used to represent
|
||||
* // the state in which an element is detached from from the application.
|
||||
* state("void", style({ height: 0 }))
|
||||
*
|
||||
* // user-defined states
|
||||
* state("closed", style({ height: 0 }))
|
||||
* state("open, visible", style({ height: "*" }))
|
||||
* ```
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
|
||||
*
|
||||
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function state(
|
||||
stateNameExpr: string, styles: AnimationStyleMetadata): AnimationStateDeclarationMetadata {
|
||||
return new AnimationStateDeclarationMetadata(stateNameExpr, styles);
|
||||
}
|
||||
|
||||
/**
|
||||
* `keyframes` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* animation
|
||||
* DSL language. If this information is new, please navigate to the
|
||||
* {@link Component#animations-anchor component animations metadata
|
||||
* page} to gain a better understanding of how animations in Angular2 are used.
|
||||
*
|
||||
* `keyframes` specifies a collection of {@link style style} entries each optionally characterized
|
||||
* by an `offset` value.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* The `keyframes` animation function is designed to be used alongside the {@link animate animate}
|
||||
* animation function. Instead of applying animations from where they are
|
||||
* currently to their destination, keyframes can describe how each style entry is applied
|
||||
* and at what point within the animation arc (much like CSS Keyframe Animations do).
|
||||
*
|
||||
* For each `style()` entry an `offset` value can be set. Doing so allows to specifiy at
|
||||
* what percentage of the animate time the styles will be applied.
|
||||
*
|
||||
* ```typescript
|
||||
* // the provided offset values describe when each backgroundColor value is applied.
|
||||
* animate("5s", keyframes([
|
||||
* style({ backgroundColor: "red", offset: 0 }),
|
||||
* style({ backgroundColor: "blue", offset: 0.2 }),
|
||||
* style({ backgroundColor: "orange", offset: 0.3 }),
|
||||
* style({ backgroundColor: "black", offset: 1 })
|
||||
* ]))
|
||||
* ```
|
||||
*
|
||||
* Alternatively, if there are no `offset` values used within the style entries then the offsets
|
||||
* will
|
||||
* be calculated automatically.
|
||||
*
|
||||
* ```typescript
|
||||
* animate("5s", keyframes([
|
||||
* style({ backgroundColor: "red" }) // offset = 0
|
||||
* style({ backgroundColor: "blue" }) // offset = 0.33
|
||||
* style({ backgroundColor: "orange" }) // offset = 0.66
|
||||
* style({ backgroundColor: "black" }) // offset = 1
|
||||
* ]))
|
||||
* ```
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
|
||||
*
|
||||
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSequenceMetadata {
|
||||
return new AnimationKeyframesSequenceMetadata(steps);
|
||||
}
|
||||
|
||||
/**
|
||||
* `transition` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* animation
|
||||
* DSL language. If this information is new, please navigate to the
|
||||
* {@link Component#animations-anchor component animations metadata
|
||||
* page} to gain a better understanding of how animations in Angular2 are used.
|
||||
*
|
||||
* `transition` declares the {@link sequence sequence of animation steps} that will be run when the
|
||||
* provided
|
||||
* `stateChangeExpr` value is satisfied. The `stateChangeExpr` consists of a `state1 => state2`
|
||||
* which consists
|
||||
* of two known states (use an asterix (`*`) to refer to a dynamic starting and/or ending state).
|
||||
*
|
||||
* A function can also be provided as the `stateChangeExpr` argument for a transition and this
|
||||
* function will be executed each time a state change occurs. If the value returned within the
|
||||
* function is true then the associated animation will be run.
|
||||
*
|
||||
* Animation transitions are placed within an {@link trigger animation trigger}. For an transition
|
||||
* to animate to
|
||||
* a state value and persist its styles then one or more {@link state animation states} is expected
|
||||
* to be defined.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* An animation transition is kicked off the `stateChangeExpr` predicate evaluates to true based on
|
||||
* what the
|
||||
* previous state is and what the current state has become. In other words, if a transition is
|
||||
* defined that
|
||||
* matches the old/current state criteria then the associated animation will be triggered.
|
||||
*
|
||||
* ```typescript
|
||||
* // all transition/state changes are defined within an animation trigger
|
||||
* trigger("myAnimationTrigger", [
|
||||
* // if a state is defined then its styles will be persisted when the
|
||||
* // animation has fully completed itself
|
||||
* state("on", style({ background: "green" })),
|
||||
* state("off", style({ background: "grey" })),
|
||||
*
|
||||
* // a transition animation that will be kicked off when the state value
|
||||
* // bound to "myAnimationTrigger" changes from "on" to "off"
|
||||
* transition("on => off", animate(500)),
|
||||
*
|
||||
* // it is also possible to do run the same animation for both directions
|
||||
* transition("on <=> off", animate(500)),
|
||||
*
|
||||
* // or to define multiple states pairs separated by commas
|
||||
* transition("on => off, off => void", animate(500)),
|
||||
*
|
||||
* // this is a catch-all state change for when an element is inserted into
|
||||
* // the page and the destination state is unknown
|
||||
* transition("void => *", [
|
||||
* style({ opacity: 0 }),
|
||||
* animate(500)
|
||||
* ]),
|
||||
*
|
||||
* // this will capture a state change between any states
|
||||
* transition("* => *", animate("1s 0s")),
|
||||
*
|
||||
* // you can also go full out and include a function
|
||||
* transition((fromState, toState) => {
|
||||
* // when `true` then it will allow the animation below to be invoked
|
||||
* return fromState == "off" && toState == "on";
|
||||
* }, animate("1s 0s"))
|
||||
* ])
|
||||
* ```
|
||||
*
|
||||
* The template associated with this component will make use of the `myAnimationTrigger`
|
||||
* animation trigger by binding to an element within its template code.
|
||||
*
|
||||
* ```html
|
||||
* <!-- somewhere inside of my-component-tpl.html -->
|
||||
* <div [@myAnimationTrigger]="myStatusExp">...</div>
|
||||
* ```
|
||||
*
|
||||
* #### The final `animate` call
|
||||
*
|
||||
* If the final step within the transition steps is a call to `animate()` that **only**
|
||||
* uses a timing value with **no style data** then it will be automatically used as the final
|
||||
* animation
|
||||
* arc for the element to animate itself to the final state. This involves an automatic mix of
|
||||
* adding/removing CSS styles so that the element will be in the exact state it should be for the
|
||||
* applied state to be presented correctly.
|
||||
*
|
||||
* ```
|
||||
* // start off by hiding the element, but make sure that it animates properly to whatever state
|
||||
* // is currently active for "myAnimationTrigger"
|
||||
* transition("void => *", [
|
||||
* style({ opacity: 0 }),
|
||||
* animate(500)
|
||||
* ])
|
||||
* ```
|
||||
*
|
||||
* ### Transition Aliases (`:enter` and `:leave`)
|
||||
*
|
||||
* Given that enter (insertion) and leave (removal) animations are so common,
|
||||
* the `transition` function accepts both `:enter` and `:leave` values which
|
||||
* are aliases for the `void => *` and `* => void` state changes.
|
||||
*
|
||||
* ```
|
||||
* transition(":enter", [
|
||||
* style({ opacity: 0 }),
|
||||
* animate(500, style({ opacity: 1 }))
|
||||
* ])
|
||||
* transition(":leave", [
|
||||
* animate(500, style({ opacity: 0 }))
|
||||
* ])
|
||||
* ```
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
|
||||
*
|
||||
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function transition(
|
||||
stateChangeExpr: string | ((fromState: string, toState: string) => boolean),
|
||||
steps: AnimationMetadata | AnimationMetadata[]): AnimationStateTransitionMetadata {
|
||||
const animationData = Array.isArray(steps) ? new AnimationSequenceMetadata(steps) : steps;
|
||||
return new AnimationStateTransitionMetadata(stateChangeExpr, animationData);
|
||||
}
|
||||
|
||||
/**
|
||||
* `trigger` is an animation-specific function that is designed to be used inside of Angular2's
|
||||
* animation
|
||||
* DSL language. If this information is new, please navigate to the
|
||||
* {@link Component#animations-anchor component animations metadata
|
||||
* page} to gain a better understanding of how animations in Angular2 are used.
|
||||
*
|
||||
* `trigger` Creates an animation trigger which will a list of {@link state state} and {@link
|
||||
* transition transition}
|
||||
* entries that will be evaluated when the expression bound to the trigger changes.
|
||||
*
|
||||
* Triggers are registered within the component annotation data under the
|
||||
* {@link Component#animations-anchor animations section}. An animation trigger can
|
||||
* be placed on an element within a template by referencing the name of the
|
||||
* trigger followed by the expression value that the trigger is bound to
|
||||
* (in the form of `[@triggerName]="expression"`.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* `trigger` will create an animation trigger reference based on the provided `name` value.
|
||||
* The provided `animation` value is expected to be an array consisting of {@link state state} and
|
||||
* {@link transition transition}
|
||||
* declarations.
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-component',
|
||||
* templateUrl: 'my-component-tpl.html',
|
||||
* animations: [
|
||||
* trigger("myAnimationTrigger", [
|
||||
* state(...),
|
||||
* state(...),
|
||||
* transition(...),
|
||||
* transition(...)
|
||||
* ])
|
||||
* ]
|
||||
* })
|
||||
* class MyComponent {
|
||||
* myStatusExp = "something";
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The template associated with this component will make use of the `myAnimationTrigger`
|
||||
* animation trigger by binding to an element within its template code.
|
||||
*
|
||||
* ```html
|
||||
* <!-- somewhere inside of my-component-tpl.html -->
|
||||
* <div [@myAnimationTrigger]="myStatusExp">...</div>
|
||||
* ```
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/Kez8XGWBxWue7qP7nNvF?p=preview))
|
||||
*
|
||||
* {@example core/animation/ts/dsl/animation_example.ts region='Component'}
|
||||
*
|
||||
* @experimental Animation support is experimental.
|
||||
*/
|
||||
export function trigger(name: string, animation: AnimationMetadata[]): AnimationEntryMetadata {
|
||||
return new AnimationEntryMetadata(name, animation);
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/**
|
||||
* @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 {isPresent} from '../facade/lang';
|
||||
|
||||
import {AnimationPlayer} from './animation_player';
|
||||
|
||||
export class ViewAnimationMap {
|
||||
private _map = new Map<any, {[key: string]: AnimationPlayer}>();
|
||||
private _allPlayers: AnimationPlayer[] = [];
|
||||
|
||||
find(element: any, animationName: string): AnimationPlayer {
|
||||
const playersByAnimation = this._map.get(element);
|
||||
if (isPresent(playersByAnimation)) {
|
||||
return playersByAnimation[animationName];
|
||||
}
|
||||
}
|
||||
|
||||
findAllPlayersByElement(element: any): AnimationPlayer[] {
|
||||
const el = this._map.get(element);
|
||||
|
||||
return el ? Object.keys(el).map(k => el[k]) : [];
|
||||
}
|
||||
|
||||
set(element: any, animationName: string, player: AnimationPlayer): void {
|
||||
let playersByAnimation = this._map.get(element);
|
||||
if (!isPresent(playersByAnimation)) {
|
||||
playersByAnimation = {};
|
||||
}
|
||||
const 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, targetPlayer: AnimationPlayer = null): void {
|
||||
const playersByAnimation = this._map.get(element);
|
||||
if (playersByAnimation) {
|
||||
const player = playersByAnimation[animationName];
|
||||
if (!targetPlayer || player === targetPlayer) {
|
||||
delete playersByAnimation[animationName];
|
||||
const index = this._allPlayers.indexOf(player);
|
||||
this._allPlayers.splice(index, 1);
|
||||
|
||||
if (Object.keys(playersByAnimation).length === 0) {
|
||||
this._map.delete(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AnimationQueue} from './animation/animation_queue';
|
||||
import {APP_INITIALIZER, ApplicationInitStatus} from './application_init';
|
||||
import {ApplicationRef, ApplicationRef_} from './application_ref';
|
||||
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
|
||||
@ -14,7 +13,6 @@ import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValu
|
||||
import {Inject, Optional, SkipSelf} from './di/metadata';
|
||||
import {LOCALE_ID} from './i18n/tokens';
|
||||
import {Compiler} from './linker/compiler';
|
||||
import {ViewUtils} from './linker/view_utils';
|
||||
import {NgModule} from './metadata';
|
||||
import {initServicesIfNeeded} from './view/index';
|
||||
|
||||
@ -47,8 +45,6 @@ export function _initViewEngine() {
|
||||
ApplicationInitStatus,
|
||||
Compiler,
|
||||
APP_ID_RANDOM_PROVIDER,
|
||||
ViewUtils,
|
||||
AnimationQueue,
|
||||
{provide: IterableDiffers, useFactory: _iterableDiffersFactory},
|
||||
{provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory},
|
||||
{
|
||||
|
@ -26,7 +26,6 @@ import {CompilerFactory, CompilerOptions} from './linker/compiler';
|
||||
import {ComponentFactory, ComponentRef} from './linker/component_factory';
|
||||
import {ComponentFactoryResolver} from './linker/component_factory_resolver';
|
||||
import {NgModuleFactory, NgModuleInjector, NgModuleRef} from './linker/ng_module_factory';
|
||||
import {AppView} from './linker/view';
|
||||
import {InternalViewRef, ViewRef} from './linker/view_ref';
|
||||
import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile';
|
||||
import {Testability, TestabilityRegistry} from './testability/testability';
|
||||
|
@ -6,24 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export {AnimationGroupPlayer as ɵAnimationGroupPlayer} from './animation/animation_group_player';
|
||||
export {AnimationKeyframe as ɵAnimationKeyframe} from './animation/animation_keyframe';
|
||||
export {NoOpAnimationPlayer as ɵNoOpAnimationPlayer} from './animation/animation_player';
|
||||
export {AnimationSequencePlayer as ɵAnimationSequencePlayer} from './animation/animation_sequence_player';
|
||||
export {balanceAnimationKeyframes as ɵbalanceAnimationKeyframes, clearStyles as ɵclearStyles, collectAndResolveStyles as ɵcollectAndResolveStyles, prepareFinalAnimationStyles as ɵprepareFinalAnimationStyles, renderStyles as ɵrenderStyles} from './animation/animation_style_util';
|
||||
export {AnimationStyles as ɵAnimationStyles} from './animation/animation_styles';
|
||||
export {AnimationTransition as ɵAnimationTransition} from './animation/animation_transition';
|
||||
export {ValueUnwrapper as ɵValueUnwrapper, devModeEqual as ɵdevModeEqual} from './change_detection/change_detection_util';
|
||||
export {ChangeDetectorStatus as ɵChangeDetectorStatus} from './change_detection/constants';
|
||||
export {ComponentRef_ as ɵComponentRef_} from './linker/component_factory';
|
||||
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
|
||||
export {DebugContext as ɵDebugContext, StaticNodeDebugInfo as ɵStaticNodeDebugInfo} from './linker/debug_context';
|
||||
export {NgModuleInjector as ɵNgModuleInjector} from './linker/ng_module_factory';
|
||||
export {registerModuleFactory as ɵregisterModuleFactory} from './linker/ng_module_factory_loader';
|
||||
export {TemplateRef_ as ɵTemplateRef_} from './linker/template_ref';
|
||||
export {AppView as ɵAppView, DebugAppView as ɵDebugAppView} from './linker/view';
|
||||
export {ViewContainer as ɵViewContainer} from './linker/view_container';
|
||||
export {ViewType as ɵViewType} from './linker/view_type';
|
||||
export {EMPTY_ARRAY as ɵEMPTY_ARRAY, EMPTY_INLINE_ARRAY as ɵEMPTY_INLINE_ARRAY, EMPTY_MAP as ɵEMPTY_MAP, InlineArray16 as ɵInlineArray16, InlineArray2 as ɵInlineArray2, InlineArray4 as ɵInlineArray4, InlineArray8 as ɵInlineArray8, InlineArrayDynamic as ɵInlineArrayDynamic, ViewUtils as ɵViewUtils, castByValue as ɵcastByValue, checkBinding as ɵcheckBinding, checkBindingChange as ɵcheckBindingChange, checkRenderAttribute as ɵcheckRenderAttribute, checkRenderClass as ɵcheckRenderClass, checkRenderProperty as ɵcheckRenderProperty, checkRenderStyle as ɵcheckRenderStyle, checkRenderText as ɵcheckRenderText, createRenderComponentType as ɵcreateRenderComponentType, createRenderElement as ɵcreateRenderElement, getComponentFactoryViewClass as ɵgetComponentFactoryViewClass, inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate, noop as ɵnoop, pureProxy1 as ɵpureProxy1, pureProxy10 as ɵpureProxy10, pureProxy2 as ɵpureProxy2, pureProxy3 as ɵpureProxy3, pureProxy4 as ɵpureProxy4, pureProxy5 as ɵpureProxy5, pureProxy6 as ɵpureProxy6, pureProxy7 as ɵpureProxy7, pureProxy8 as ɵpureProxy8, pureProxy9 as ɵpureProxy9, selectOrCreateRenderHostElement as ɵselectOrCreateRenderHostElement, setBindingDebugInfo as ɵsetBindingDebugInfo, setBindingDebugInfoForChanges as ɵsetBindingDebugInfoForChanges, subscribeToRenderElement as ɵsubscribeToRenderElement} from './linker/view_utils';
|
||||
export {reflector as ɵreflector} from './reflection/reflection';
|
||||
export {ArgumentType as ɵArgumentType, BindingType as ɵBindingType, DepFlags as ɵDepFlags, NodeFlags as ɵNodeFlags, QueryBindingType as ɵQueryBindingType, QueryValueType as ɵQueryValueType, ViewDefinition as ɵViewDefinition, ViewFlags as ɵViewFlags, anchorDef as ɵand, createComponentFactory as ɵccf, createRendererTypeV2 as ɵcrt, directiveDef as ɵdid, elementDef as ɵeld, elementEventFullName as ɵelementEventFullName, ngContentDef as ɵncd, nodeValue as ɵnov, pipeDef as ɵpid, providerDef as ɵprd, pureArrayDef as ɵpad, pureObjectDef as ɵpod, purePipeDef as ɵppd, queryDef as ɵqud, textDef as ɵted, unwrapValue as ɵunv, viewDef as ɵvid} from './view/index';
|
||||
export {ArgumentType as ɵArgumentType, BindingType as ɵBindingType, DepFlags as ɵDepFlags, EMPTY_ARRAY as ɵEMPTY_ARRAY, EMPTY_MAP as ɵEMPTY_MAP, NodeFlags as ɵNodeFlags, QueryBindingType as ɵQueryBindingType, QueryValueType as ɵQueryValueType, ViewDefinition as ɵViewDefinition, ViewFlags as ɵViewFlags, anchorDef as ɵand, createComponentFactory as ɵccf, createRendererTypeV2 as ɵcrt, directiveDef as ɵdid, elementDef as ɵeld, elementEventFullName as ɵelementEventFullName, getComponentViewDefinitionFactory as ɵgetComponentViewDefinitionFactory, inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate, ngContentDef as ɵncd, nodeValue as ɵnov, pipeDef as ɵpid, providerDef as ɵprd, pureArrayDef as ɵpad, pureObjectDef as ɵpod, purePipeDef as ɵppd, queryDef as ɵqud, textDef as ɵted, unwrapValue as ɵunv, viewDef as ɵvid} from './view/index';
|
||||
|
@ -32,20 +32,31 @@ export {Type} from './type';
|
||||
export {EventEmitter} from './facade/async';
|
||||
export {ErrorHandler} from './error_handler';
|
||||
export * from './core_private_export';
|
||||
export {AnimationPlayer} from './animation/animation_player';
|
||||
export {AnimationStyles} from './animation/animation_styles';
|
||||
export {AnimationKeyframe} from './animation/animation_keyframe';
|
||||
export {Sanitizer, SecurityContext} from './security';
|
||||
export * from './codegen_private_exports';
|
||||
|
||||
export * from './animation_next/animation_metadata_wrapped';
|
||||
export * from './animation/animation_metadata_wrapped';
|
||||
import {AnimationTriggerMetadata} from './animation/animation_metadata_wrapped';
|
||||
|
||||
|
||||
// For backwards compatibility.
|
||||
/**
|
||||
* @deprecated
|
||||
* @deprecated from v4
|
||||
*/
|
||||
export type AnimationEntryMetadata = any;
|
||||
/**
|
||||
* @deprecated
|
||||
* @deprecated from v4
|
||||
*/
|
||||
export type AnimationStateTransitionMetadata = any;
|
||||
/**
|
||||
* @deprecated from v4
|
||||
*/
|
||||
export type AnimationPlayer = any;
|
||||
/**
|
||||
* @deprecated from v4
|
||||
*/
|
||||
export type AnimationStyles = any;
|
||||
/**
|
||||
* @deprecated from v4
|
||||
*/
|
||||
export type AnimationKeyframe = any;
|
@ -6,27 +6,14 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export {ANY_STATE as ɵANY_STATE, DEFAULT_STATE as ɵDEFAULT_STATE, EMPTY_STATE as ɵEMPTY_STATE, FILL_STYLE_FLAG as ɵFILL_STYLE_FLAG} from './animation/animation_constants';
|
||||
export {AnimationGroupPlayer as ɵAnimationGroupPlayer} from './animation/animation_group_player';
|
||||
export {AnimationKeyframe as ɵAnimationKeyframe} from './animation/animation_keyframe';
|
||||
export {AnimationPlayer as ɵAnimationPlayer, NoOpAnimationPlayer as ɵNoOpAnimationPlayer} from './animation/animation_player';
|
||||
export {AnimationSequencePlayer as ɵAnimationSequencePlayer} from './animation/animation_sequence_player';
|
||||
export {balanceAnimationKeyframes as ɵbalanceAnimationKeyframes, clearStyles as ɵclearStyles, collectAndResolveStyles as ɵcollectAndResolveStyles, flattenStyles as ɵflattenStyles, prepareFinalAnimationStyles as ɵprepareFinalAnimationStyles, renderStyles as ɵrenderStyles} from './animation/animation_style_util';
|
||||
export {AnimationStyles as ɵAnimationStyles} from './animation/animation_styles';
|
||||
export {AnimationTransition as ɵAnimationTransition} from './animation/animation_transition';
|
||||
export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS} from './application_ref';
|
||||
export {APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER} from './application_tokens';
|
||||
export {ValueUnwrapper as ɵValueUnwrapper, devModeEqual as ɵdevModeEqual} from './change_detection/change_detection_util';
|
||||
export {ChangeDetectorStatus as ɵChangeDetectorStatus, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy} from './change_detection/constants';
|
||||
export {Console as ɵConsole} from './console';
|
||||
export {DebugDomRootRenderer as ɵDebugDomRootRenderer} from './debug/debug_renderer';
|
||||
export {ERROR_COMPONENT_TYPE as ɵERROR_COMPONENT_TYPE} from './errors';
|
||||
export {ComponentFactory as ɵComponentFactory} from './linker/component_factory';
|
||||
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
|
||||
export {DebugContext as ɵDebugContext, StaticNodeDebugInfo as ɵStaticNodeDebugInfo} from './linker/debug_context';
|
||||
export {AppView as ɵAppView, DebugAppView as ɵDebugAppView} from './linker/view';
|
||||
export {ViewContainer as ɵViewContainer} from './linker/view_container';
|
||||
export {ViewType as ɵViewType} from './linker/view_type';
|
||||
export {LIFECYCLE_HOOKS_VALUES as ɵLIFECYCLE_HOOKS_VALUES, LifecycleHooks as ɵLifecycleHooks} from './metadata/lifecycle_hooks';
|
||||
export {ViewMetadata as ɵViewMetadata} from './metadata/view';
|
||||
export {Reflector as ɵReflector, reflector as ɵreflector} from './reflection/reflection';
|
||||
|
@ -1,161 +0,0 @@
|
||||
/**
|
||||
* @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 {AnimationKeyframe} from '../animation/animation_keyframe';
|
||||
import {AnimationPlayer} from '../animation/animation_player';
|
||||
import {AnimationStyles} from '../animation/animation_styles';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
||||
|
||||
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from './debug_node';
|
||||
|
||||
export class DebugDomRootRenderer implements RootRenderer {
|
||||
constructor(private _delegate: RootRenderer) {
|
||||
throw new Error(
|
||||
'RootRenderer is no longer supported. Please use the `RendererFactoryV2` instead!');
|
||||
}
|
||||
|
||||
renderComponent(componentProto: RenderComponentType): Renderer {
|
||||
return new DebugDomRenderer(this._delegate.renderComponent(componentProto));
|
||||
}
|
||||
}
|
||||
|
||||
export class DebugDomRenderer implements Renderer {
|
||||
constructor(private _delegate: Renderer) {}
|
||||
|
||||
selectRootElement(selectorOrNode: string|any, debugInfo?: RenderDebugInfo): any {
|
||||
const nativeEl = this._delegate.selectRootElement(selectorOrNode, debugInfo);
|
||||
const debugEl = new DebugElement(nativeEl, null, debugInfo);
|
||||
indexDebugNode(debugEl);
|
||||
return nativeEl;
|
||||
}
|
||||
|
||||
createElement(parentElement: any, name: string, debugInfo?: RenderDebugInfo): any {
|
||||
const nativeEl = this._delegate.createElement(parentElement, name, debugInfo);
|
||||
const debugEl = new DebugElement(nativeEl, getDebugNode(parentElement), debugInfo);
|
||||
debugEl.name = name;
|
||||
indexDebugNode(debugEl);
|
||||
return nativeEl;
|
||||
}
|
||||
|
||||
createViewRoot(hostElement: any): any { return this._delegate.createViewRoot(hostElement); }
|
||||
|
||||
createTemplateAnchor(parentElement: any, debugInfo?: RenderDebugInfo): any {
|
||||
const comment = this._delegate.createTemplateAnchor(parentElement, debugInfo);
|
||||
const debugEl = new DebugNode(comment, getDebugNode(parentElement), debugInfo);
|
||||
indexDebugNode(debugEl);
|
||||
return comment;
|
||||
}
|
||||
|
||||
createText(parentElement: any, value: string, debugInfo?: RenderDebugInfo): any {
|
||||
const text = this._delegate.createText(parentElement, value, debugInfo);
|
||||
const debugEl = new DebugNode(text, getDebugNode(parentElement), debugInfo);
|
||||
indexDebugNode(debugEl);
|
||||
return text;
|
||||
}
|
||||
|
||||
projectNodes(parentElement: any, nodes: any[]) {
|
||||
const debugParent = getDebugNode(parentElement);
|
||||
if (isPresent(debugParent) && debugParent instanceof DebugElement) {
|
||||
const debugElement = debugParent;
|
||||
nodes.forEach((node) => { debugElement.addChild(getDebugNode(node)); });
|
||||
}
|
||||
this._delegate.projectNodes(parentElement, nodes);
|
||||
}
|
||||
|
||||
attachViewAfter(node: any, viewRootNodes: any[]) {
|
||||
const debugNode = getDebugNode(node);
|
||||
if (isPresent(debugNode)) {
|
||||
const debugParent = debugNode.parent;
|
||||
if (viewRootNodes.length > 0 && isPresent(debugParent)) {
|
||||
const debugViewRootNodes: DebugNode[] = [];
|
||||
viewRootNodes.forEach((rootNode) => debugViewRootNodes.push(getDebugNode(rootNode)));
|
||||
debugParent.insertChildrenAfter(debugNode, debugViewRootNodes);
|
||||
}
|
||||
}
|
||||
this._delegate.attachViewAfter(node, viewRootNodes);
|
||||
}
|
||||
|
||||
detachView(viewRootNodes: any[]) {
|
||||
viewRootNodes.forEach((node) => {
|
||||
const debugNode = getDebugNode(node);
|
||||
if (debugNode && debugNode.parent) {
|
||||
debugNode.parent.removeChild(debugNode);
|
||||
}
|
||||
});
|
||||
this._delegate.detachView(viewRootNodes);
|
||||
}
|
||||
|
||||
destroyView(hostElement: any, viewAllNodes: any[]) {
|
||||
viewAllNodes = viewAllNodes || [];
|
||||
viewAllNodes.forEach((node) => { removeDebugNodeFromIndex(getDebugNode(node)); });
|
||||
this._delegate.destroyView(hostElement, viewAllNodes);
|
||||
}
|
||||
|
||||
listen(renderElement: any, name: string, callback: Function): Function {
|
||||
const debugEl = getDebugNode(renderElement);
|
||||
if (isPresent(debugEl)) {
|
||||
debugEl.listeners.push(new EventListener(name, callback));
|
||||
}
|
||||
return this._delegate.listen(renderElement, name, callback);
|
||||
}
|
||||
|
||||
listenGlobal(target: string, name: string, callback: Function): Function {
|
||||
return this._delegate.listenGlobal(target, name, callback);
|
||||
}
|
||||
|
||||
setElementProperty(renderElement: any, propertyName: string, propertyValue: any) {
|
||||
const debugEl = getDebugNode(renderElement);
|
||||
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
|
||||
debugEl.properties[propertyName] = propertyValue;
|
||||
}
|
||||
this._delegate.setElementProperty(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
setElementAttribute(renderElement: any, attributeName: string, attributeValue: string) {
|
||||
const debugEl = getDebugNode(renderElement);
|
||||
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
|
||||
debugEl.attributes[attributeName] = attributeValue;
|
||||
}
|
||||
this._delegate.setElementAttribute(renderElement, attributeName, attributeValue);
|
||||
}
|
||||
|
||||
setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string) {
|
||||
this._delegate.setBindingDebugInfo(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
setElementClass(renderElement: any, className: string, isAdd: boolean) {
|
||||
const debugEl = getDebugNode(renderElement);
|
||||
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
|
||||
debugEl.classes[className] = isAdd;
|
||||
}
|
||||
this._delegate.setElementClass(renderElement, className, isAdd);
|
||||
}
|
||||
|
||||
setElementStyle(renderElement: any, styleName: string, styleValue: string) {
|
||||
const debugEl = getDebugNode(renderElement);
|
||||
if (isPresent(debugEl) && debugEl instanceof DebugElement) {
|
||||
debugEl.styles[styleName] = styleValue;
|
||||
}
|
||||
this._delegate.setElementStyle(renderElement, styleName, styleValue);
|
||||
}
|
||||
|
||||
invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {
|
||||
this._delegate.invokeElementMethod(renderElement, methodName, args);
|
||||
}
|
||||
|
||||
setText(renderNode: any, text: string) { this._delegate.setText(renderNode, text); }
|
||||
|
||||
animate(
|
||||
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||
duration: number, delay: number, easing: string,
|
||||
previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
|
||||
return this._delegate.animate(
|
||||
element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/**
|
||||
* @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 {AnimationGroupPlayer} from '../animation/animation_group_player';
|
||||
import {AnimationPlayer} from '../animation/animation_player';
|
||||
import {AnimationQueue} from '../animation/animation_queue';
|
||||
import {AnimationSequencePlayer} from '../animation/animation_sequence_player';
|
||||
import {ViewAnimationMap} from '../animation/view_animation_map';
|
||||
|
||||
export class AnimationViewContext {
|
||||
private _players = new ViewAnimationMap();
|
||||
|
||||
constructor(private _animationQueue: AnimationQueue) {}
|
||||
|
||||
onAllActiveAnimationsDone(callback: () => any): void {
|
||||
const activeAnimationPlayers = this._players.getAllPlayers();
|
||||
// we check for the length to avoid having GroupAnimationPlayer
|
||||
// issue an unnecessary microtask when zero players are passed in
|
||||
if (activeAnimationPlayers.length) {
|
||||
new AnimationGroupPlayer(activeAnimationPlayers).onDone(() => callback());
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
queueAnimation(element: any, animationName: string, player: AnimationPlayer): void {
|
||||
this._animationQueue.enqueue(player);
|
||||
this._players.set(element, animationName, player);
|
||||
player.onDone(() => this._players.remove(element, animationName, player));
|
||||
}
|
||||
|
||||
getAnimationPlayers(element: any, animationName: string = null): AnimationPlayer[] {
|
||||
const players: AnimationPlayer[] = [];
|
||||
if (animationName) {
|
||||
const currentPlayer = this._players.find(element, animationName);
|
||||
if (currentPlayer) {
|
||||
_recursePlayers(currentPlayer, players);
|
||||
}
|
||||
} else {
|
||||
this._players.findAllPlayersByElement(element).forEach(
|
||||
player => _recursePlayers(player, players));
|
||||
}
|
||||
return players;
|
||||
}
|
||||
}
|
||||
|
||||
function _recursePlayers(player: AnimationPlayer, collectedPlayers: AnimationPlayer[]) {
|
||||
if ((player instanceof AnimationGroupPlayer) || (player instanceof AnimationSequencePlayer)) {
|
||||
player.players.forEach(player => _recursePlayers(player, collectedPlayers));
|
||||
} else {
|
||||
collectedPlayers.push(player);
|
||||
}
|
||||
}
|
@ -11,11 +11,7 @@ import {Injector} from '../di/injector';
|
||||
import {Type} from '../type';
|
||||
|
||||
import {ElementRef} from './element_ref';
|
||||
import {AppView} from './view';
|
||||
import {ViewRef} from './view_ref';
|
||||
import {ViewUtils} from './view_utils';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Represents an instance of a Component created via a {@link ComponentFactory}.
|
||||
@ -67,53 +63,15 @@ export abstract class ComponentRef<C> {
|
||||
abstract onDestroy(callback: Function): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* workaround https://github.com/angular/tsickle/issues/350
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
export class ComponentRef_<C> extends ComponentRef<C> {
|
||||
constructor(
|
||||
private _index: number, private _parentView: AppView<any>, private _nativeElement: any,
|
||||
private _component: C) {
|
||||
super();
|
||||
}
|
||||
get location(): ElementRef { return new ElementRef(this._nativeElement); }
|
||||
get injector(): Injector { return this._parentView.injector(this._index); }
|
||||
get instance(): C { return this._component; };
|
||||
get hostView(): ViewRef { return this._parentView.ref; };
|
||||
get changeDetectorRef(): ChangeDetectorRef { return this._parentView.ref; };
|
||||
get componentType(): Type<any> { return <any>this._component.constructor; }
|
||||
|
||||
destroy(): void { this._parentView.detachAndDestroy(); }
|
||||
onDestroy(callback: Function): void { this.hostView.onDestroy(callback); }
|
||||
}
|
||||
|
||||
/**
|
||||
* @stable
|
||||
*/
|
||||
export class ComponentFactory<C> {
|
||||
/**
|
||||
* TODO(tbosch): type this properly to ViewDefinitionFactory again once the view engine
|
||||
* is the default.
|
||||
* @internal
|
||||
*/
|
||||
_viewClass: any;
|
||||
constructor(
|
||||
public selector: string, _viewClass: Type<AppView<any>>, public componentType: Type<any>) {
|
||||
this._viewClass = _viewClass;
|
||||
}
|
||||
|
||||
export abstract class ComponentFactory<C> {
|
||||
abstract get selector(): string;
|
||||
abstract get componentType(): Type<any>;
|
||||
/**
|
||||
* Creates a new component.
|
||||
*/
|
||||
create(
|
||||
injector: Injector, projectableNodes: any[][] = null,
|
||||
rootSelectorOrNode: string|any = null): ComponentRef<C> {
|
||||
const vu: ViewUtils = injector.get(ViewUtils);
|
||||
if (!projectableNodes) {
|
||||
projectableNodes = [];
|
||||
}
|
||||
const hostView: AppView<any> = new this._viewClass(vu, null, null, null);
|
||||
return hostView.createHostView(rootSelectorOrNode, injector, projectableNodes);
|
||||
}
|
||||
abstract create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string|any):
|
||||
ComponentRef<C>;
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
/**
|
||||
* @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 {Injector} from '../di';
|
||||
import {isBlank, isPresent} from '../facade/lang';
|
||||
import {RenderDebugInfo} from '../render/api';
|
||||
|
||||
import {DebugAppView} from './view';
|
||||
import {ViewType} from './view_type';
|
||||
|
||||
|
||||
export class StaticNodeDebugInfo {
|
||||
constructor(
|
||||
public providerTokens: any[], public componentToken: any,
|
||||
public refTokens: {[key: string]: any}) {}
|
||||
}
|
||||
|
||||
export class DebugContext implements RenderDebugInfo {
|
||||
constructor(
|
||||
private _view: DebugAppView<any>, private _nodeIndex: number, private _tplRow: number,
|
||||
private _tplCol: number) {}
|
||||
|
||||
private get _staticNodeInfo(): StaticNodeDebugInfo {
|
||||
return isPresent(this._nodeIndex) ? this._view.staticNodeDebugInfos[this._nodeIndex] : null;
|
||||
}
|
||||
|
||||
get context() { return this._view.context; }
|
||||
get component() {
|
||||
const staticNodeInfo = this._staticNodeInfo;
|
||||
if (isPresent(staticNodeInfo) && isPresent(staticNodeInfo.componentToken)) {
|
||||
return this.injector.get(staticNodeInfo.componentToken);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
get componentRenderElement() {
|
||||
let componentView = this._view;
|
||||
while (isPresent(componentView.parentView) && componentView.type !== ViewType.COMPONENT) {
|
||||
componentView = <DebugAppView<any>>componentView.parentView;
|
||||
}
|
||||
return componentView.parentElement;
|
||||
}
|
||||
get injector(): Injector { return this._view.injector(this._nodeIndex); }
|
||||
get renderNode(): any {
|
||||
if (isPresent(this._nodeIndex) && this._view.allNodes) {
|
||||
return this._view.allNodes[this._nodeIndex];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
get providerTokens(): any[] {
|
||||
const staticNodeInfo = this._staticNodeInfo;
|
||||
return isPresent(staticNodeInfo) ? staticNodeInfo.providerTokens : null;
|
||||
}
|
||||
get source(): string {
|
||||
return `${this._view.componentType.templateUrl}:${this._tplRow}:${this._tplCol}`;
|
||||
}
|
||||
get references(): {[key: string]: any} {
|
||||
const varValues: {[key: string]: string} = {};
|
||||
const staticNodeInfo = this._staticNodeInfo;
|
||||
if (isPresent(staticNodeInfo)) {
|
||||
const refs = staticNodeInfo.refTokens;
|
||||
Object.keys(refs).forEach(refName => {
|
||||
const refToken = refs[refName];
|
||||
let varValue: any;
|
||||
if (isBlank(refToken)) {
|
||||
varValue = this._view.allNodes ? this._view.allNodes[this._nodeIndex] : null;
|
||||
} else {
|
||||
varValue = this._view.injectorGet(refToken, this._nodeIndex, null);
|
||||
}
|
||||
varValues[refName] = varValue;
|
||||
});
|
||||
}
|
||||
return varValues;
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/**
|
||||
* @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 {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
||||
import {AppView} from './view';
|
||||
|
||||
export class ElementInjector extends Injector {
|
||||
constructor(private _view: AppView<any>, private _nodeIndex: number) { super(); }
|
||||
|
||||
get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any {
|
||||
return this._view.injectorGet(token, this._nodeIndex, notFoundValue);
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/**
|
||||
* @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 {wrappedError} from '../error_handler';
|
||||
import {ERROR_DEBUG_CONTEXT, ERROR_TYPE} from '../errors';
|
||||
import {DebugContext} from './debug_context';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An error thrown if application changes model breaking the top-down data flow.
|
||||
*
|
||||
* This exception is only thrown in dev mode.
|
||||
*
|
||||
* <!-- TODO: Add a link once the dev mode option is configurable -->
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'parent',
|
||||
* template: '<child [prop]="parentProp"></child>',
|
||||
* })
|
||||
* class Parent {
|
||||
* parentProp = 'init';
|
||||
* }
|
||||
*
|
||||
* @Directive({selector: 'child', inputs: ['prop']})
|
||||
* class Child {
|
||||
* constructor(public parent: Parent) {}
|
||||
*
|
||||
* set prop(v) {
|
||||
* // this updates the parent property, which is disallowed during change detection
|
||||
* // this will result in ExpressionChangedAfterItHasBeenCheckedError
|
||||
* this.parent.parentProp = 'updated';
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function expressionChangedAfterItHasBeenCheckedError(
|
||||
oldValue: any, currValue: any, isFirstCheck: boolean) {
|
||||
let msg =
|
||||
`Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`;
|
||||
if (isFirstCheck) {
|
||||
msg +=
|
||||
` It seems like the view has been created after its parent and its children have been dirty checked.` +
|
||||
` Has it been created in a change detection hook ?`;
|
||||
}
|
||||
const error = Error(msg);
|
||||
(error as any)[ERROR_TYPE] = expressionChangedAfterItHasBeenCheckedError;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when an exception was raised during view creation, change detection or destruction.
|
||||
*
|
||||
* This error wraps the original exception to attach additional contextual information that can
|
||||
* be useful for debugging.
|
||||
*/
|
||||
export function viewWrappedError(originalError: any, context: DebugContext): Error {
|
||||
const error = wrappedError(`Error in ${context.source}`, originalError);
|
||||
(error as any)[ERROR_DEBUG_CONTEXT] = context;
|
||||
(error as any)[ERROR_TYPE] = viewWrappedError;
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when a destroyed view is used.
|
||||
*
|
||||
* This error indicates a bug in the framework.
|
||||
*
|
||||
* This is an internal Angular error.
|
||||
*/
|
||||
export function viewDestroyedError(details: string) {
|
||||
return Error(`Attempt to use a destroyed view: ${details}`);
|
||||
}
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import {ElementRef} from './element_ref';
|
||||
import {AppView} from './view';
|
||||
import {EmbeddedViewRef} from './view_ref';
|
||||
|
||||
|
||||
@ -41,22 +40,3 @@ export abstract class TemplateRef<C> {
|
||||
|
||||
abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;
|
||||
}
|
||||
|
||||
/**
|
||||
* workaround https://github.com/angular/tsickle/issues/350
|
||||
* @suppress {checkTypes}
|
||||
*/
|
||||
export class TemplateRef_<C> extends TemplateRef<C> {
|
||||
constructor(
|
||||
private _parentView: AppView<any>, private _nodeIndex: number, private _nativeElement: any) {
|
||||
super();
|
||||
}
|
||||
|
||||
createEmbeddedView(context: C): EmbeddedViewRef<C> {
|
||||
const view = this._parentView.createEmbeddedViewInternal(this._nodeIndex);
|
||||
view.create(context || <any>{});
|
||||
return view.ref;
|
||||
}
|
||||
|
||||
get elementRef(): ElementRef { return new ElementRef(this._nativeElement); }
|
||||
}
|
||||
|
@ -1,472 +0,0 @@
|
||||
/**
|
||||
* @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 {ApplicationRef} from '../application_ref';
|
||||
import {ChangeDetectorRef, ChangeDetectorStatus} from '../change_detection/change_detection';
|
||||
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
||||
import {getType} from '../errors';
|
||||
import {isPresent} from '../facade/lang';
|
||||
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
|
||||
import {DirectRenderer, RenderComponentType, Renderer} from '../render/api';
|
||||
|
||||
import {AnimationViewContext} from './animation_view_context';
|
||||
import {ComponentRef} from './component_factory';
|
||||
import {DebugContext, StaticNodeDebugInfo} from './debug_context';
|
||||
import {ElementInjector} from './element_injector';
|
||||
import {expressionChangedAfterItHasBeenCheckedError, viewDestroyedError, viewWrappedError} from './errors';
|
||||
import {ViewContainer} from './view_container';
|
||||
import {ViewRef_} from './view_ref';
|
||||
import {ViewType} from './view_type';
|
||||
import {ViewUtils, addToArray} from './view_utils';
|
||||
|
||||
const _scope_check: WtfScopeFn = wtfCreateScope(`AppView#check(ascii id)`);
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
const EMPTY_CONTEXT = new Object();
|
||||
|
||||
const UNDEFINED = new Object();
|
||||
|
||||
/**
|
||||
* Cost of making objects: http://jsperf.com/instantiate-size-of-object
|
||||
*
|
||||
*/
|
||||
export abstract class AppView<T> {
|
||||
ref: ViewRef_<T>;
|
||||
lastRootNode: any;
|
||||
allNodes: any[];
|
||||
disposables: Function[];
|
||||
viewContainer: ViewContainer;
|
||||
// This will be set if a view is directly attached to an ApplicationRef
|
||||
// and not to a view container.
|
||||
appRef: ApplicationRef;
|
||||
|
||||
numberOfChecks: number = 0;
|
||||
throwOnChange: boolean = false;
|
||||
|
||||
renderer: Renderer;
|
||||
|
||||
private _hasExternalHostElement: boolean;
|
||||
private _hostInjector: Injector;
|
||||
private _hostProjectableNodes: any[][];
|
||||
private _animationContext: AnimationViewContext;
|
||||
private _directRenderer: DirectRenderer;
|
||||
|
||||
public context: T;
|
||||
|
||||
constructor(
|
||||
public clazz: any, public componentType: RenderComponentType, public type: ViewType,
|
||||
public viewUtils: ViewUtils, public parentView: AppView<any>, public parentIndex: number,
|
||||
public parentElement: any, public cdMode: ChangeDetectorStatus,
|
||||
public declaredViewContainer: ViewContainer = null) {
|
||||
this.ref = new ViewRef_(this, viewUtils.animationQueue);
|
||||
if (type === ViewType.COMPONENT || type === ViewType.HOST) {
|
||||
this.renderer = viewUtils.renderComponent(componentType);
|
||||
} else {
|
||||
this.renderer = parentView.renderer;
|
||||
}
|
||||
this._directRenderer = (this.renderer as any).directRenderer;
|
||||
}
|
||||
|
||||
get animationContext(): AnimationViewContext {
|
||||
if (!this._animationContext) {
|
||||
this._animationContext = new AnimationViewContext(this.viewUtils.animationQueue);
|
||||
}
|
||||
return this._animationContext;
|
||||
}
|
||||
|
||||
get destroyed(): boolean { return this.cdMode === ChangeDetectorStatus.Destroyed; }
|
||||
|
||||
create(context: T) {
|
||||
this.context = context;
|
||||
return this.createInternal(null);
|
||||
}
|
||||
|
||||
createHostView(rootSelectorOrNode: string|any, hostInjector: Injector, projectableNodes: any[][]):
|
||||
ComponentRef<any> {
|
||||
this.context = <any>EMPTY_CONTEXT;
|
||||
this._hasExternalHostElement = isPresent(rootSelectorOrNode);
|
||||
this._hostInjector = hostInjector;
|
||||
this._hostProjectableNodes = projectableNodes;
|
||||
return this.createInternal(rootSelectorOrNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations.
|
||||
* Returns the ComponentRef for the host element for ViewType.HOST.
|
||||
*/
|
||||
createInternal(rootSelectorOrNode: string|any): ComponentRef<any> { return null; }
|
||||
|
||||
/**
|
||||
* Overwritten by implementations.
|
||||
*/
|
||||
createEmbeddedViewInternal(templateNodeIndex: number): AppView<any> { return null; }
|
||||
|
||||
init(lastRootNode: any, allNodes: any[], disposables: Function[]) {
|
||||
this.lastRootNode = lastRootNode;
|
||||
this.allNodes = allNodes;
|
||||
this.disposables = disposables;
|
||||
if (this.type === ViewType.COMPONENT) {
|
||||
this.dirtyParentQueriesInternal();
|
||||
}
|
||||
}
|
||||
|
||||
injectorGet(token: any, nodeIndex: number, notFoundValue: any = THROW_IF_NOT_FOUND): any {
|
||||
let result = UNDEFINED;
|
||||
let view: AppView<any> = this;
|
||||
while (result === UNDEFINED) {
|
||||
if (isPresent(nodeIndex)) {
|
||||
result = view.injectorGetInternal(token, nodeIndex, UNDEFINED);
|
||||
}
|
||||
if (result === UNDEFINED && view.type === ViewType.HOST) {
|
||||
result = view._hostInjector.get(token, notFoundValue);
|
||||
}
|
||||
nodeIndex = view.parentIndex;
|
||||
view = view.parentView;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
injectorGetInternal(token: any, nodeIndex: number, notFoundResult: any): any {
|
||||
return notFoundResult;
|
||||
}
|
||||
|
||||
injector(nodeIndex: number): Injector { return new ElementInjector(this, nodeIndex); }
|
||||
|
||||
detachAndDestroy() {
|
||||
if (this.viewContainer) {
|
||||
this.viewContainer.detachView(this.viewContainer.nestedViews.indexOf(this));
|
||||
} else if (this.appRef) {
|
||||
this.appRef.detachView(this.ref);
|
||||
} else if (this._hasExternalHostElement) {
|
||||
this.detach();
|
||||
}
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.cdMode === ChangeDetectorStatus.Destroyed) {
|
||||
return;
|
||||
}
|
||||
const hostElement = this.type === ViewType.COMPONENT ? this.parentElement : null;
|
||||
if (this.disposables) {
|
||||
for (let i = 0; i < this.disposables.length; i++) {
|
||||
this.disposables[i]();
|
||||
}
|
||||
}
|
||||
this.destroyInternal();
|
||||
this.dirtyParentQueriesInternal();
|
||||
|
||||
if (this._animationContext) {
|
||||
this._animationContext.onAllActiveAnimationsDone(
|
||||
() => this.renderer.destroyView(hostElement, this.allNodes));
|
||||
} else {
|
||||
this.renderer.destroyView(hostElement, this.allNodes);
|
||||
}
|
||||
|
||||
this.cdMode = ChangeDetectorStatus.Destroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
destroyInternal(): void {}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
detachInternal(): void {}
|
||||
|
||||
detach(): void {
|
||||
this.detachInternal();
|
||||
if (this._animationContext) {
|
||||
this._animationContext.onAllActiveAnimationsDone(() => this._renderDetach());
|
||||
} else {
|
||||
this._renderDetach();
|
||||
}
|
||||
if (this.declaredViewContainer && this.declaredViewContainer !== this.viewContainer &&
|
||||
this.declaredViewContainer.projectedViews) {
|
||||
const projectedViews = this.declaredViewContainer.projectedViews;
|
||||
const index = projectedViews.indexOf(this);
|
||||
// perf: pop is faster than splice!
|
||||
if (index >= projectedViews.length - 1) {
|
||||
projectedViews.pop();
|
||||
} else {
|
||||
projectedViews.splice(index, 1);
|
||||
}
|
||||
}
|
||||
this.appRef = null;
|
||||
this.viewContainer = null;
|
||||
this.dirtyParentQueriesInternal();
|
||||
}
|
||||
|
||||
private _renderDetach() {
|
||||
if (this._directRenderer) {
|
||||
this.visitRootNodesInternal(this._directRenderer.remove, null);
|
||||
} else {
|
||||
this.renderer.detachView(this.flatRootNodes);
|
||||
}
|
||||
}
|
||||
|
||||
attachToAppRef(appRef: ApplicationRef) {
|
||||
if (this.viewContainer) {
|
||||
throw new Error('This view is already attached to a ViewContainer!');
|
||||
}
|
||||
this.appRef = appRef;
|
||||
this.dirtyParentQueriesInternal();
|
||||
}
|
||||
|
||||
attachAfter(viewContainer: ViewContainer, prevView: AppView<any>) {
|
||||
if (this.appRef) {
|
||||
throw new Error('This view is already attached directly to the ApplicationRef!');
|
||||
}
|
||||
this._renderAttach(viewContainer, prevView);
|
||||
this.viewContainer = viewContainer;
|
||||
if (this.declaredViewContainer && this.declaredViewContainer !== viewContainer) {
|
||||
if (!this.declaredViewContainer.projectedViews) {
|
||||
this.declaredViewContainer.projectedViews = [];
|
||||
}
|
||||
this.declaredViewContainer.projectedViews.push(this);
|
||||
}
|
||||
this.dirtyParentQueriesInternal();
|
||||
}
|
||||
|
||||
moveAfter(viewContainer: ViewContainer, prevView: AppView<any>) {
|
||||
this._renderAttach(viewContainer, prevView);
|
||||
this.dirtyParentQueriesInternal();
|
||||
}
|
||||
|
||||
private _renderAttach(viewContainer: ViewContainer, prevView: AppView<any>) {
|
||||
const prevNode = prevView ? prevView.lastRootNode : viewContainer.nativeElement;
|
||||
if (this._directRenderer) {
|
||||
const nextSibling = this._directRenderer.nextSibling(prevNode);
|
||||
if (nextSibling) {
|
||||
this.visitRootNodesInternal(this._directRenderer.insertBefore, nextSibling);
|
||||
} else {
|
||||
const parentElement = this._directRenderer.parentElement(prevNode);
|
||||
if (parentElement) {
|
||||
this.visitRootNodesInternal(this._directRenderer.appendChild, parentElement);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.renderer.attachViewAfter(prevNode, this.flatRootNodes);
|
||||
}
|
||||
}
|
||||
|
||||
get changeDetectorRef(): ChangeDetectorRef { return this.ref; }
|
||||
|
||||
get flatRootNodes(): any[] {
|
||||
const nodes: any[] = [];
|
||||
this.visitRootNodesInternal(addToArray, nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
projectNodes(parentElement: any, ngContentIndex: number) {
|
||||
if (this._directRenderer) {
|
||||
this.visitProjectedNodes(ngContentIndex, this._directRenderer.appendChild, parentElement);
|
||||
} else {
|
||||
const nodes: any[] = [];
|
||||
this.visitProjectedNodes(ngContentIndex, addToArray, nodes);
|
||||
this.renderer.projectNodes(parentElement, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
visitProjectedNodes<C>(ngContentIndex: number, cb: (node: any, ctx: C) => void, c: C): void {
|
||||
switch (this.type) {
|
||||
case ViewType.EMBEDDED:
|
||||
this.parentView.visitProjectedNodes(ngContentIndex, cb, c);
|
||||
break;
|
||||
case ViewType.COMPONENT:
|
||||
if (this.parentView.type === ViewType.HOST) {
|
||||
const nodes = this.parentView._hostProjectableNodes[ngContentIndex] || [];
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
cb(nodes[i], c);
|
||||
}
|
||||
} else {
|
||||
this.parentView.visitProjectableNodesInternal(this.parentIndex, ngContentIndex, cb, c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
visitRootNodesInternal<C>(cb: (node: any, ctx: C) => void, c: C): void {}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
visitProjectableNodesInternal<C>(
|
||||
nodeIndex: number, ngContentIndex: number, cb: (node: any, ctx: C) => void, c: C): void {}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
dirtyParentQueriesInternal(): void {}
|
||||
|
||||
internalDetectChanges(throwOnChange: boolean): void {
|
||||
if (this.cdMode !== ChangeDetectorStatus.Detached) {
|
||||
this.detectChanges(throwOnChange);
|
||||
}
|
||||
}
|
||||
|
||||
detectChanges(throwOnChange: boolean): void {
|
||||
const s = _scope_check(this.clazz);
|
||||
if (this.cdMode === ChangeDetectorStatus.Checked ||
|
||||
this.cdMode === ChangeDetectorStatus.Errored)
|
||||
return;
|
||||
if (this.cdMode === ChangeDetectorStatus.Destroyed) {
|
||||
this.throwDestroyedError('detectChanges');
|
||||
}
|
||||
this.throwOnChange = throwOnChange;
|
||||
this.detectChangesInternal();
|
||||
if (this.cdMode === ChangeDetectorStatus.CheckOnce) this.cdMode = ChangeDetectorStatus.Checked;
|
||||
|
||||
this.numberOfChecks++;
|
||||
wtfLeave(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten by implementations
|
||||
*/
|
||||
detectChangesInternal(): void {}
|
||||
|
||||
markAsCheckOnce(): void { this.cdMode = ChangeDetectorStatus.CheckOnce; }
|
||||
|
||||
markPathToRootAsCheckOnce(): void {
|
||||
let c: AppView<any> = this;
|
||||
while (isPresent(c) && c.cdMode !== ChangeDetectorStatus.Detached) {
|
||||
if (c.cdMode === ChangeDetectorStatus.Checked) {
|
||||
c.cdMode = ChangeDetectorStatus.CheckOnce;
|
||||
}
|
||||
if (c.type === ViewType.COMPONENT) {
|
||||
c = c.parentView;
|
||||
} else {
|
||||
c = c.viewContainer ? c.viewContainer.parentView : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eventHandler<E, R>(cb: (eventName: string, event?: E) => R): (eventName: string, event?: E) => R {
|
||||
return cb;
|
||||
}
|
||||
|
||||
throwDestroyedError(details: string): void { throw viewDestroyedError(details); }
|
||||
}
|
||||
|
||||
export class DebugAppView<T> extends AppView<T> {
|
||||
private _currentDebugContext: DebugContext = null;
|
||||
|
||||
constructor(
|
||||
clazz: any, componentType: RenderComponentType, type: ViewType, viewUtils: ViewUtils,
|
||||
parentView: AppView<any>, parentIndex: number, parentNode: any, cdMode: ChangeDetectorStatus,
|
||||
public staticNodeDebugInfos: StaticNodeDebugInfo[],
|
||||
declaredViewContainer: ViewContainer = null) {
|
||||
super(
|
||||
clazz, componentType, type, viewUtils, parentView, parentIndex, parentNode, cdMode,
|
||||
declaredViewContainer);
|
||||
}
|
||||
|
||||
create(context: T) {
|
||||
this._resetDebug();
|
||||
try {
|
||||
return super.create(context);
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
createHostView(
|
||||
rootSelectorOrNode: string|any, injector: Injector,
|
||||
projectableNodes: any[][] = null): ComponentRef<any> {
|
||||
this._resetDebug();
|
||||
try {
|
||||
return super.createHostView(rootSelectorOrNode, injector, projectableNodes);
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
injectorGet(token: any, nodeIndex: number, notFoundResult?: any): any {
|
||||
this._resetDebug();
|
||||
try {
|
||||
return super.injectorGet(token, nodeIndex, notFoundResult);
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
detach(): void {
|
||||
this._resetDebug();
|
||||
try {
|
||||
super.detach();
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._resetDebug();
|
||||
try {
|
||||
super.destroy();
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
detectChanges(throwOnChange: boolean): void {
|
||||
this._resetDebug();
|
||||
try {
|
||||
super.detectChanges(throwOnChange);
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private _resetDebug() { this._currentDebugContext = null; }
|
||||
|
||||
debug(nodeIndex: number, rowNum: number, colNum: number): DebugContext {
|
||||
return this._currentDebugContext = new DebugContext(this, nodeIndex, rowNum, colNum);
|
||||
}
|
||||
|
||||
private _rethrowWithContext(e: any) {
|
||||
if (!(getType(e) == viewWrappedError)) {
|
||||
if (!(getType(e) == expressionChangedAfterItHasBeenCheckedError)) {
|
||||
this.cdMode = ChangeDetectorStatus.Errored;
|
||||
}
|
||||
if (isPresent(this._currentDebugContext)) {
|
||||
throw viewWrappedError(e, this._currentDebugContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eventHandler<E, R>(cb: (eventName: string, event?: E) => R): (eventName: string, event?: E) => R {
|
||||
const superHandler = super.eventHandler(cb);
|
||||
return (eventName: string, event?: any) => {
|
||||
this._resetDebug();
|
||||
try {
|
||||
return superHandler.call(this, eventName, event);
|
||||
} catch (e) {
|
||||
this._rethrowWithContext(e);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
/**
|
||||
* @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 {Injector} from '../di/injector';
|
||||
|
||||
import {ElementRef} from './element_ref';
|
||||
import {AppView} from './view';
|
||||
import {ViewContainerRef_} from './view_container_ref';
|
||||
import {ViewType} from './view_type';
|
||||
|
||||
|
||||
/**
|
||||
* A ViewContainer is created for elements that have a ViewContainerRef
|
||||
* to keep track of the nested views.
|
||||
*/
|
||||
export class ViewContainer {
|
||||
public nestedViews: AppView<any>[];
|
||||
// views that have been declared at the place of this view container,
|
||||
// but inserted into another view container
|
||||
public projectedViews: AppView<any>[];
|
||||
|
||||
constructor(
|
||||
public index: number, public parentIndex: number, public parentView: AppView<any>,
|
||||
public nativeElement: any) {}
|
||||
|
||||
get elementRef(): ElementRef { return new ElementRef(this.nativeElement); }
|
||||
|
||||
get vcRef(): ViewContainerRef_ { return new ViewContainerRef_(this); }
|
||||
|
||||
get parentInjector(): Injector { return this.parentView.injector(this.parentIndex); }
|
||||
get injector(): Injector { return this.parentView.injector(this.index); }
|
||||
|
||||
detectChangesInNestedViews(throwOnChange: boolean): void {
|
||||
if (this.nestedViews) {
|
||||
for (let i = 0; i < this.nestedViews.length; i++) {
|
||||
this.nestedViews[i].detectChanges(throwOnChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destroyNestedViews(): void {
|
||||
if (this.nestedViews) {
|
||||
for (let i = 0; i < this.nestedViews.length; i++) {
|
||||
this.nestedViews[i].destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visitNestedViewRootNodes<C>(cb: (node: any, ctx: C) => void, c: C): void {
|
||||
if (this.nestedViews) {
|
||||
for (let i = 0; i < this.nestedViews.length; i++) {
|
||||
this.nestedViews[i].visitRootNodesInternal(cb, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapNestedViews(nestedViewClass: any, callback: Function): any[] {
|
||||
const result: any[] = [];
|
||||
if (this.nestedViews) {
|
||||
for (let i = 0; i < this.nestedViews.length; i++) {
|
||||
const nestedView = this.nestedViews[i];
|
||||
if (nestedView.clazz === nestedViewClass) {
|
||||
result.push(callback(nestedView));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.projectedViews) {
|
||||
for (let i = 0; i < this.projectedViews.length; i++) {
|
||||
const projectedView = this.projectedViews[i];
|
||||
if (projectedView.clazz === nestedViewClass) {
|
||||
result.push(callback(projectedView));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
moveView(view: AppView<any>, toIndex: number) {
|
||||
const fromIndex = this.nestedViews.indexOf(view);
|
||||
if (view.type === ViewType.COMPONENT) {
|
||||
throw new Error(`Component views can't be moved!`);
|
||||
}
|
||||
let nestedViews = this.nestedViews;
|
||||
if (nestedViews == null) {
|
||||
nestedViews = [];
|
||||
this.nestedViews = nestedViews;
|
||||
}
|
||||
nestedViews.splice(fromIndex, 1);
|
||||
nestedViews.splice(toIndex, 0, view);
|
||||
const prevView = toIndex > 0 ? nestedViews[toIndex - 1] : null;
|
||||
view.moveAfter(this, prevView);
|
||||
}
|
||||
|
||||
attachView(view: AppView<any>, viewIndex: number) {
|
||||
if (view.type === ViewType.COMPONENT) {
|
||||
throw new Error(`Component views can't be moved!`);
|
||||
}
|
||||
let nestedViews = this.nestedViews;
|
||||
if (nestedViews == null) {
|
||||
nestedViews = [];
|
||||
this.nestedViews = nestedViews;
|
||||
}
|
||||
// perf: array.push is faster than array.splice!
|
||||
if (viewIndex >= nestedViews.length) {
|
||||
nestedViews.push(view);
|
||||
} else {
|
||||
nestedViews.splice(viewIndex, 0, view);
|
||||
}
|
||||
const prevView = viewIndex > 0 ? nestedViews[viewIndex - 1] : null;
|
||||
view.attachAfter(this, prevView);
|
||||
}
|
||||
|
||||
detachView(viewIndex: number): AppView<any> {
|
||||
const view = this.nestedViews[viewIndex];
|
||||
// perf: array.pop is faster than array.splice!
|
||||
if (viewIndex >= this.nestedViews.length - 1) {
|
||||
this.nestedViews.pop();
|
||||
} else {
|
||||
this.nestedViews.splice(viewIndex, 1);
|
||||
}
|
||||
if (view.type === ViewType.COMPONENT) {
|
||||
throw new Error(`Component views can't be moved!`);
|
||||
}
|
||||
view.detach();
|
||||
return view;
|
||||
}
|
||||
}
|
@ -7,14 +7,10 @@
|
||||
*/
|
||||
|
||||
import {Injector} from '../di/injector';
|
||||
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
|
||||
|
||||
import {ComponentFactory, ComponentRef} from './component_factory';
|
||||
import {ElementRef} from './element_ref';
|
||||
import {TemplateRef} from './template_ref';
|
||||
import {ViewContainer} from './view_container';
|
||||
import {EmbeddedViewRef, ViewRef, ViewRef_} from './view_ref';
|
||||
|
||||
import {EmbeddedViewRef, ViewRef} from './view_ref';
|
||||
|
||||
|
||||
/**
|
||||
@ -125,97 +121,3 @@ export abstract class ViewContainerRef {
|
||||
*/
|
||||
abstract detach(index?: number): ViewRef;
|
||||
}
|
||||
|
||||
export class ViewContainerRef_ implements ViewContainerRef {
|
||||
constructor(private _element: ViewContainer) {}
|
||||
|
||||
get(index: number): ViewRef { return this._element.nestedViews[index].ref; }
|
||||
get length(): number {
|
||||
const views = this._element.nestedViews;
|
||||
return views ? views.length : 0;
|
||||
}
|
||||
|
||||
get element(): ElementRef { return this._element.elementRef; }
|
||||
|
||||
get injector(): Injector { return this._element.injector; }
|
||||
|
||||
get parentInjector(): Injector { return this._element.parentInjector; }
|
||||
|
||||
// TODO(rado): profile and decide whether bounds checks should be added
|
||||
// to the methods below.
|
||||
createEmbeddedView<C>(templateRef: TemplateRef<C>, context: C = null, index: number = -1):
|
||||
EmbeddedViewRef<C> {
|
||||
const viewRef: EmbeddedViewRef<any> = templateRef.createEmbeddedView(context);
|
||||
this.insert(viewRef, index);
|
||||
return viewRef;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_createComponentInContainerScope: WtfScopeFn =
|
||||
wtfCreateScope('ViewContainerRef#createComponent()');
|
||||
|
||||
createComponent<C>(
|
||||
componentFactory: ComponentFactory<C>, index: number = -1, injector: Injector = null,
|
||||
projectableNodes: any[][] = null): ComponentRef<C> {
|
||||
const s = this._createComponentInContainerScope();
|
||||
const contextInjector = injector || this._element.parentInjector;
|
||||
const componentRef = componentFactory.create(contextInjector, projectableNodes);
|
||||
this.insert(componentRef.hostView, index);
|
||||
return wtfLeave(s, componentRef);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_insertScope = wtfCreateScope('ViewContainerRef#insert()');
|
||||
|
||||
// TODO(i): refactor insert+remove into move
|
||||
insert(viewRef: ViewRef, index: number = -1): ViewRef {
|
||||
const s = this._insertScope();
|
||||
if (index == -1) index = this.length;
|
||||
const viewRef_ = <ViewRef_<any>>viewRef;
|
||||
this._element.attachView(viewRef_.internalView, index);
|
||||
return wtfLeave(s, viewRef_);
|
||||
}
|
||||
|
||||
move(viewRef: ViewRef, currentIndex: number): ViewRef {
|
||||
const s = this._insertScope();
|
||||
if (currentIndex == -1) return;
|
||||
const viewRef_ = <ViewRef_<any>>viewRef;
|
||||
this._element.moveView(viewRef_.internalView, currentIndex);
|
||||
return wtfLeave(s, viewRef_);
|
||||
}
|
||||
|
||||
indexOf(viewRef: ViewRef): number {
|
||||
return this.length ? this._element.nestedViews.indexOf((<ViewRef_<any>>viewRef).internalView) :
|
||||
-1;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_removeScope = wtfCreateScope('ViewContainerRef#remove()');
|
||||
|
||||
// TODO(i): rename to destroy
|
||||
remove(index: number = -1): void {
|
||||
const s = this._removeScope();
|
||||
if (index == -1) index = this.length - 1;
|
||||
const view = this._element.detachView(index);
|
||||
view.destroy();
|
||||
// view is intentionally not returned to the client.
|
||||
wtfLeave(s);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
_detachScope = wtfCreateScope('ViewContainerRef#detach()');
|
||||
|
||||
// TODO(i): refactor insert+remove into move
|
||||
detach(index: number = -1): ViewRef {
|
||||
const s = this._detachScope();
|
||||
if (index == -1) index = this.length - 1;
|
||||
const view = this._element.detachView(index);
|
||||
return wtfLeave(s, view.ref);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
for (let i = this.length - 1; i >= 0; i--) {
|
||||
this.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AnimationQueue} from '../animation/animation_queue';
|
||||
import {ApplicationRef} from '../application_ref';
|
||||
import {ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
||||
import {ChangeDetectorStatus} from '../change_detection/constants';
|
||||
|
||||
import {AppView} from './view';
|
||||
|
||||
|
||||
/**
|
||||
@ -92,46 +88,3 @@ export interface InternalViewRef extends ViewRef {
|
||||
detachFromAppRef(): void;
|
||||
attachToAppRef(appRef: ApplicationRef): void;
|
||||
}
|
||||
|
||||
export class ViewRef_<C> implements EmbeddedViewRef<C>, ChangeDetectorRef, InternalViewRef {
|
||||
/** @internal */
|
||||
_originalMode: ChangeDetectorStatus;
|
||||
|
||||
constructor(private _view: AppView<C>, public animationQueue: AnimationQueue) {
|
||||
this._view = _view;
|
||||
this._originalMode = this._view.cdMode;
|
||||
}
|
||||
|
||||
get internalView(): AppView<C> { return this._view; }
|
||||
|
||||
get rootNodes(): any[] { return this._view.flatRootNodes; }
|
||||
|
||||
get context() { return this._view.context; }
|
||||
|
||||
get destroyed(): boolean { return this._view.destroyed; }
|
||||
|
||||
markForCheck(): void { this._view.markPathToRootAsCheckOnce(); }
|
||||
detach(): void { this._view.cdMode = ChangeDetectorStatus.Detached; }
|
||||
detectChanges(): void {
|
||||
this._view.detectChanges(false);
|
||||
this.animationQueue.flush();
|
||||
}
|
||||
checkNoChanges(): void { this._view.detectChanges(true); }
|
||||
reattach(): void {
|
||||
this._view.cdMode = this._originalMode;
|
||||
this.markForCheck();
|
||||
}
|
||||
|
||||
onDestroy(callback: Function) {
|
||||
if (!this._view.disposables) {
|
||||
this._view.disposables = [];
|
||||
}
|
||||
this._view.disposables.push(callback);
|
||||
}
|
||||
|
||||
destroy() { this._view.detachAndDestroy(); }
|
||||
|
||||
detachFromAppRef() { this._view.detach(); }
|
||||
|
||||
attachToAppRef(appRef: ApplicationRef) { this._view.attachToAppRef(appRef); }
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
export enum ViewType {
|
||||
// A view that contains the host element with bound component directive.
|
||||
// Contains a COMPONENT view
|
||||
HOST,
|
||||
// The view of the component can contain 0 to n EMBEDDED views
|
||||
COMPONENT,
|
||||
// A view is embedded into another View via a <ng-template> element inside of a COMPONENT view
|
||||
EMBEDDED
|
||||
}
|
@ -1,736 +0,0 @@
|
||||
/**
|
||||
* @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 {AnimationQueue} from '../animation/animation_queue';
|
||||
import {SimpleChange, devModeEqual} from '../change_detection/change_detection';
|
||||
import {Injectable} from '../di';
|
||||
import {isPresent, looseIdentical} from '../facade/lang';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
||||
import {Sanitizer, SecurityContext} from '../security';
|
||||
import {Type} from '../type';
|
||||
import {VERSION} from '../version';
|
||||
|
||||
import {ComponentFactory} from './component_factory';
|
||||
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||
import {AppView} from './view';
|
||||
|
||||
@Injectable()
|
||||
export class ViewUtils {
|
||||
sanitizer: Sanitizer;
|
||||
|
||||
constructor(
|
||||
private _renderer: RootRenderer, sanitizer: Sanitizer,
|
||||
public animationQueue: AnimationQueue) {
|
||||
this.sanitizer = sanitizer;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
renderComponent(renderComponentType: RenderComponentType): Renderer {
|
||||
return this._renderer.renderComponent(renderComponentType);
|
||||
}
|
||||
}
|
||||
|
||||
let nextRenderComponentTypeId = 0;
|
||||
|
||||
export function createRenderComponentType(
|
||||
templateUrl: string, slotCount: number, encapsulation: ViewEncapsulation,
|
||||
styles: Array<string|any[]>, animations: any): RenderComponentType {
|
||||
return new RenderComponentType(
|
||||
`${nextRenderComponentTypeId++}`, templateUrl, slotCount, encapsulation, styles, animations);
|
||||
}
|
||||
|
||||
export function addToArray(e: any, array: any[]) {
|
||||
array.push(e);
|
||||
}
|
||||
|
||||
export function interpolate(valueCount: number, constAndInterp: string[]): string {
|
||||
let result = '';
|
||||
for (let i = 0; i < valueCount * 2; i = i + 2) {
|
||||
result = result + constAndInterp[i] + _toStringWithNull(constAndInterp[i + 1]);
|
||||
}
|
||||
return result + constAndInterp[valueCount * 2];
|
||||
}
|
||||
|
||||
export function inlineInterpolate(
|
||||
valueCount: number, c0: string, a1: any, c1: string, a2?: any, c2?: string, a3?: any,
|
||||
c3?: string, a4?: any, c4?: string, a5?: any, c5?: string, a6?: any, c6?: string, a7?: any,
|
||||
c7?: string, a8?: any, c8?: string, a9?: any, c9?: string): string {
|
||||
switch (valueCount) {
|
||||
case 1:
|
||||
return c0 + _toStringWithNull(a1) + c1;
|
||||
case 2:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2;
|
||||
case 3:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3;
|
||||
case 4:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4;
|
||||
case 5:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5;
|
||||
case 6:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) + c6;
|
||||
case 7:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
|
||||
c6 + _toStringWithNull(a7) + c7;
|
||||
case 8:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
|
||||
c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8;
|
||||
case 9:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
|
||||
c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8 + _toStringWithNull(a9) + c9;
|
||||
default:
|
||||
throw new Error(`Does not support more than 9 expressions`);
|
||||
}
|
||||
}
|
||||
|
||||
function _toStringWithNull(v: any): string {
|
||||
return v != null ? v.toString() : '';
|
||||
}
|
||||
|
||||
export function checkBinding(
|
||||
view: AppView<any>, oldValue: any, newValue: any, forceUpdate: boolean): boolean {
|
||||
const isFirstCheck = view.numberOfChecks === 0;
|
||||
if (view.throwOnChange) {
|
||||
if (isFirstCheck || !devModeEqual(oldValue, newValue)) {
|
||||
throw expressionChangedAfterItHasBeenCheckedError(oldValue, newValue, isFirstCheck);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return isFirstCheck || forceUpdate || !looseIdentical(oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkBindingChange(
|
||||
view: AppView<any>, oldValue: any, newValue: any, forceUpdate: boolean): SimpleChange {
|
||||
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
|
||||
return new SimpleChange(oldValue, newValue, view.numberOfChecks === 0);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkRenderText(
|
||||
view: AppView<any>, renderElement: any, oldValue: any, newValue: any, forceUpdate: boolean) {
|
||||
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
|
||||
view.renderer.setText(renderElement, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkRenderProperty(
|
||||
view: AppView<any>, renderElement: any, propName: string, oldValue: any, newValue: any,
|
||||
forceUpdate: boolean, securityContext: SecurityContext) {
|
||||
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
|
||||
let renderValue =
|
||||
securityContext ? view.viewUtils.sanitizer.sanitize(securityContext, newValue) : newValue;
|
||||
view.renderer.setElementProperty(renderElement, propName, renderValue);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkRenderAttribute(
|
||||
view: AppView<any>, renderElement: any, attrName: string, oldValue: any, newValue: any,
|
||||
forceUpdate: boolean, securityContext: SecurityContext) {
|
||||
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
|
||||
let renderValue =
|
||||
securityContext ? view.viewUtils.sanitizer.sanitize(securityContext, newValue) : newValue;
|
||||
renderValue = renderValue != null ? renderValue.toString() : null;
|
||||
view.renderer.setElementAttribute(renderElement, attrName, renderValue);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkRenderClass(
|
||||
view: AppView<any>, renderElement: any, className: string, oldValue: any, newValue: any,
|
||||
forceUpdate: boolean) {
|
||||
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
|
||||
view.renderer.setElementClass(renderElement, className, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
export function checkRenderStyle(
|
||||
view: AppView<any>, renderElement: any, styleName: string, unit: string, oldValue: any,
|
||||
newValue: any, forceUpdate: boolean, securityContext: SecurityContext) {
|
||||
if (checkBinding(view, oldValue, newValue, forceUpdate)) {
|
||||
let renderValue =
|
||||
securityContext ? view.viewUtils.sanitizer.sanitize(securityContext, newValue) : newValue;
|
||||
if (renderValue != null) {
|
||||
renderValue = renderValue.toString();
|
||||
if (unit != null) {
|
||||
renderValue = renderValue + unit;
|
||||
}
|
||||
} else {
|
||||
renderValue = null;
|
||||
}
|
||||
view.renderer.setElementStyle(renderElement, styleName, renderValue);
|
||||
}
|
||||
}
|
||||
|
||||
export function castByValue<T>(input: any, value: T): T {
|
||||
return <T>input;
|
||||
}
|
||||
|
||||
export const EMPTY_ARRAY: any[] = [];
|
||||
export const EMPTY_MAP = {};
|
||||
|
||||
export function pureProxy1<P0, R>(fn: (p0: P0) => R): (p0: P0) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any;
|
||||
|
||||
return (p0) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0)) {
|
||||
v0 = p0;
|
||||
result = fn(p0);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function pureProxy2<P0, P1, R>(fn: (p0: P0, p1: P1) => R): (p0: P0, p1: P1) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any;
|
||||
let v1: any;
|
||||
|
||||
return (p0, p1) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
result = fn(p0, p1);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function pureProxy3<P0, P1, P2, R>(fn: (p0: P0, p1: P1, p2: P2) => R): (
|
||||
p0: P0, p1: P1, p2: P2) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any;
|
||||
let v1: any;
|
||||
let v2: any;
|
||||
|
||||
return (p0, p1, p2) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
|
||||
!looseIdentical(v2, p2)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
v2 = p2;
|
||||
result = fn(p0, p1, p2);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function pureProxy4<P0, P1, P2, P3, R>(fn: (p0: P0, p1: P1, p2: P2, p3: P3) => R): (
|
||||
p0: P0, p1: P1, p2: P2, p3: P3) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any, v1: any, v2: any, v3: any;
|
||||
v0 = v1 = v2 = v3;
|
||||
return (p0, p1, p2, p3) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
|
||||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
v2 = p2;
|
||||
v3 = p3;
|
||||
result = fn(p0, p1, p2, p3);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function pureProxy5<P0, P1, P2, P3, P4, R>(
|
||||
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) => R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) =>
|
||||
R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any, v1: any, v2: any, v3: any, v4: any;
|
||||
v0 = v1 = v2 = v3 = v4;
|
||||
return (p0, p1, p2, p3, p4) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
|
||||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
v2 = p2;
|
||||
v3 = p3;
|
||||
v4 = p4;
|
||||
result = fn(p0, p1, p2, p3, p4);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function pureProxy6<P0, P1, P2, P3, P4, P5, R>(
|
||||
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) =>
|
||||
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any;
|
||||
v0 = v1 = v2 = v3 = v4 = v5;
|
||||
return (p0, p1, p2, p3, p4, p5) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
|
||||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
|
||||
!looseIdentical(v5, p5)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
v2 = p2;
|
||||
v3 = p3;
|
||||
v4 = p4;
|
||||
v5 = p5;
|
||||
result = fn(p0, p1, p2, p3, p4, p5);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function pureProxy7<P0, P1, P2, P3, P4, P5, P6, R>(
|
||||
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) =>
|
||||
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any;
|
||||
v0 = v1 = v2 = v3 = v4 = v5 = v6;
|
||||
return (p0, p1, p2, p3, p4, p5, p6) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
|
||||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
|
||||
!looseIdentical(v5, p5) || !looseIdentical(v6, p6)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
v2 = p2;
|
||||
v3 = p3;
|
||||
v4 = p4;
|
||||
v5 = p5;
|
||||
v6 = p6;
|
||||
result = fn(p0, p1, p2, p3, p4, p5, p6);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function pureProxy8<P0, P1, P2, P3, P4, P5, P6, P7, R>(
|
||||
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) =>
|
||||
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any;
|
||||
v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7;
|
||||
return (p0, p1, p2, p3, p4, p5, p6, p7) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
|
||||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
|
||||
!looseIdentical(v5, p5) || !looseIdentical(v6, p6) || !looseIdentical(v7, p7)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
v2 = p2;
|
||||
v3 = p3;
|
||||
v4 = p4;
|
||||
v5 = p5;
|
||||
v6 = p6;
|
||||
v7 = p7;
|
||||
result = fn(p0, p1, p2, p3, p4, p5, p6, p7);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function pureProxy9<P0, P1, P2, P3, P4, P5, P6, P7, P8, R>(
|
||||
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8) =>
|
||||
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any;
|
||||
v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7 = v8;
|
||||
return (p0, p1, p2, p3, p4, p5, p6, p7, p8) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
|
||||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
|
||||
!looseIdentical(v5, p5) || !looseIdentical(v6, p6) || !looseIdentical(v7, p7) ||
|
||||
!looseIdentical(v8, p8)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
v2 = p2;
|
||||
v3 = p3;
|
||||
v4 = p4;
|
||||
v5 = p5;
|
||||
v6 = p6;
|
||||
v7 = p7;
|
||||
v8 = p8;
|
||||
result = fn(p0, p1, p2, p3, p4, p5, p6, p7, p8);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function pureProxy10<P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, R>(
|
||||
fn: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9) =>
|
||||
R): (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9) => R {
|
||||
let numberOfChecks = 0;
|
||||
let result: R;
|
||||
let v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any, v9: any;
|
||||
v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7 = v8 = v9;
|
||||
return (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9) => {
|
||||
if (!numberOfChecks++ || !looseIdentical(v0, p0) || !looseIdentical(v1, p1) ||
|
||||
!looseIdentical(v2, p2) || !looseIdentical(v3, p3) || !looseIdentical(v4, p4) ||
|
||||
!looseIdentical(v5, p5) || !looseIdentical(v6, p6) || !looseIdentical(v7, p7) ||
|
||||
!looseIdentical(v8, p8) || !looseIdentical(v9, p9)) {
|
||||
v0 = p0;
|
||||
v1 = p1;
|
||||
v2 = p2;
|
||||
v3 = p3;
|
||||
v4 = p4;
|
||||
v5 = p5;
|
||||
v6 = p6;
|
||||
v7 = p7;
|
||||
v8 = p8;
|
||||
v9 = p9;
|
||||
result = fn(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function setBindingDebugInfoForChanges(
|
||||
renderer: Renderer, el: any, changes: {[key: string]: SimpleChange}) {
|
||||
Object.keys(changes).forEach((propName) => {
|
||||
setBindingDebugInfo(renderer, el, propName, changes[propName].currentValue);
|
||||
});
|
||||
}
|
||||
|
||||
export function setBindingDebugInfo(renderer: Renderer, el: any, propName: string, value: any) {
|
||||
try {
|
||||
renderer.setBindingDebugInfo(
|
||||
el, `ng-reflect-${camelCaseToDashCase(propName)}`, value ? value.toString() : null);
|
||||
} catch (e) {
|
||||
renderer.setBindingDebugInfo(
|
||||
el, `ng-reflect-${camelCaseToDashCase(propName)}`,
|
||||
'[ERROR] Exception while trying to serialize the value');
|
||||
}
|
||||
}
|
||||
|
||||
const CAMEL_CASE_REGEXP = /([A-Z])/g;
|
||||
|
||||
function camelCaseToDashCase(input: string): string {
|
||||
return input.replace(CAMEL_CASE_REGEXP, (...m: any[]) => '-' + m[1].toLowerCase());
|
||||
}
|
||||
|
||||
export function createRenderElement(
|
||||
renderer: Renderer, parentElement: any, name: string, attrs: InlineArray<string>,
|
||||
debugInfo?: RenderDebugInfo): any {
|
||||
const el = renderer.createElement(parentElement, name, debugInfo);
|
||||
for (let i = 0; i < attrs.length; i += 2) {
|
||||
renderer.setElementAttribute(el, attrs.get(i), attrs.get(i + 1));
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
export function selectOrCreateRenderHostElement(
|
||||
renderer: Renderer, elementName: string, attrs: InlineArray<string>,
|
||||
rootSelectorOrNode: string | any, debugInfo?: RenderDebugInfo): any {
|
||||
let hostElement: any;
|
||||
if (isPresent(rootSelectorOrNode)) {
|
||||
hostElement = renderer.selectRootElement(rootSelectorOrNode, debugInfo);
|
||||
for (let i = 0; i < attrs.length; i += 2) {
|
||||
renderer.setElementAttribute(hostElement, attrs.get(i), attrs.get(i + 1));
|
||||
}
|
||||
renderer.setElementAttribute(hostElement, 'ng-version', VERSION.full);
|
||||
} else {
|
||||
hostElement = createRenderElement(renderer, null, elementName, attrs, debugInfo);
|
||||
}
|
||||
return hostElement;
|
||||
}
|
||||
|
||||
export function subscribeToRenderElement(
|
||||
view: AppView<any>, element: any, eventNamesAndTargets: InlineArray<string>,
|
||||
listener: (eventName: string, event: any) => any) {
|
||||
const disposables = createEmptyInlineArray(eventNamesAndTargets.length / 2);
|
||||
for (let i = 0; i < eventNamesAndTargets.length; i += 2) {
|
||||
const eventName = eventNamesAndTargets.get(i);
|
||||
const eventTarget = eventNamesAndTargets.get(i + 1);
|
||||
let disposable: Function;
|
||||
if (eventTarget) {
|
||||
disposable = view.renderer.listenGlobal(
|
||||
eventTarget, eventName, listener.bind(view, `${eventTarget}:${eventName}`));
|
||||
} else {
|
||||
disposable = view.renderer.listen(element, eventName, listener.bind(view, eventName));
|
||||
}
|
||||
disposables.set(i / 2, disposable);
|
||||
}
|
||||
return disposeInlineArray.bind(null, disposables);
|
||||
}
|
||||
|
||||
function disposeInlineArray(disposables: InlineArray<Function>) {
|
||||
for (let i = 0; i < disposables.length; i++) {
|
||||
disposables.get(i)();
|
||||
}
|
||||
}
|
||||
|
||||
export function noop() {}
|
||||
|
||||
export interface InlineArray<T> {
|
||||
length: number;
|
||||
get(index: number): T;
|
||||
set(index: number, value: T): void;
|
||||
}
|
||||
|
||||
function createEmptyInlineArray<T>(length: number): InlineArray<T> {
|
||||
let ctor: any;
|
||||
if (length <= 2) {
|
||||
ctor = InlineArray2;
|
||||
} else if (length <= 4) {
|
||||
ctor = InlineArray4;
|
||||
} else if (length <= 8) {
|
||||
ctor = InlineArray8;
|
||||
} else if (length <= 16) {
|
||||
ctor = InlineArray16;
|
||||
} else {
|
||||
ctor = InlineArrayDynamic;
|
||||
}
|
||||
return new ctor(length);
|
||||
}
|
||||
|
||||
class InlineArray0 implements InlineArray<any> {
|
||||
length = 0;
|
||||
get(index: number): any { return undefined; }
|
||||
set(index: number, value: any): void {}
|
||||
}
|
||||
|
||||
export class InlineArray2<T> implements InlineArray<T> {
|
||||
constructor(public length: number, private _v0?: T, private _v1?: T) {}
|
||||
get(index: number) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return this._v0;
|
||||
case 1:
|
||||
return this._v1;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
set(index: number, value: T) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
this._v0 = value;
|
||||
break;
|
||||
case 1:
|
||||
this._v1 = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class InlineArray4<T> implements InlineArray<T> {
|
||||
constructor(
|
||||
public length: number, private _v0?: T, private _v1?: T, private _v2?: T, private _v3?: T) {}
|
||||
get(index: number) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return this._v0;
|
||||
case 1:
|
||||
return this._v1;
|
||||
case 2:
|
||||
return this._v2;
|
||||
case 3:
|
||||
return this._v3;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
set(index: number, value: T) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
this._v0 = value;
|
||||
break;
|
||||
case 1:
|
||||
this._v1 = value;
|
||||
break;
|
||||
case 2:
|
||||
this._v2 = value;
|
||||
break;
|
||||
case 3:
|
||||
this._v3 = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class InlineArray8<T> implements InlineArray<T> {
|
||||
constructor(
|
||||
public length: number, private _v0?: T, private _v1?: T, private _v2?: T, private _v3?: T,
|
||||
private _v4?: T, private _v5?: T, private _v6?: T, private _v7?: T) {}
|
||||
get(index: number) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return this._v0;
|
||||
case 1:
|
||||
return this._v1;
|
||||
case 2:
|
||||
return this._v2;
|
||||
case 3:
|
||||
return this._v3;
|
||||
case 4:
|
||||
return this._v4;
|
||||
case 5:
|
||||
return this._v5;
|
||||
case 6:
|
||||
return this._v6;
|
||||
case 7:
|
||||
return this._v7;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
set(index: number, value: T) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
this._v0 = value;
|
||||
break;
|
||||
case 1:
|
||||
this._v1 = value;
|
||||
break;
|
||||
case 2:
|
||||
this._v2 = value;
|
||||
break;
|
||||
case 3:
|
||||
this._v3 = value;
|
||||
break;
|
||||
case 4:
|
||||
this._v4 = value;
|
||||
break;
|
||||
case 5:
|
||||
this._v5 = value;
|
||||
break;
|
||||
case 6:
|
||||
this._v6 = value;
|
||||
break;
|
||||
case 7:
|
||||
this._v7 = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class InlineArray16<T> implements InlineArray<T> {
|
||||
constructor(
|
||||
public length: number, private _v0?: T, private _v1?: T, private _v2?: T, private _v3?: T,
|
||||
private _v4?: T, private _v5?: T, private _v6?: T, private _v7?: T, private _v8?: T,
|
||||
private _v9?: T, private _v10?: T, private _v11?: T, private _v12?: T, private _v13?: T,
|
||||
private _v14?: T, private _v15?: T) {}
|
||||
get(index: number) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return this._v0;
|
||||
case 1:
|
||||
return this._v1;
|
||||
case 2:
|
||||
return this._v2;
|
||||
case 3:
|
||||
return this._v3;
|
||||
case 4:
|
||||
return this._v4;
|
||||
case 5:
|
||||
return this._v5;
|
||||
case 6:
|
||||
return this._v6;
|
||||
case 7:
|
||||
return this._v7;
|
||||
case 8:
|
||||
return this._v8;
|
||||
case 9:
|
||||
return this._v9;
|
||||
case 10:
|
||||
return this._v10;
|
||||
case 11:
|
||||
return this._v11;
|
||||
case 12:
|
||||
return this._v12;
|
||||
case 13:
|
||||
return this._v13;
|
||||
case 14:
|
||||
return this._v14;
|
||||
case 15:
|
||||
return this._v15;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
set(index: number, value: T) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
this._v0 = value;
|
||||
break;
|
||||
case 1:
|
||||
this._v1 = value;
|
||||
break;
|
||||
case 2:
|
||||
this._v2 = value;
|
||||
break;
|
||||
case 3:
|
||||
this._v3 = value;
|
||||
break;
|
||||
case 4:
|
||||
this._v4 = value;
|
||||
break;
|
||||
case 5:
|
||||
this._v5 = value;
|
||||
break;
|
||||
case 6:
|
||||
this._v6 = value;
|
||||
break;
|
||||
case 7:
|
||||
this._v7 = value;
|
||||
break;
|
||||
case 8:
|
||||
this._v8 = value;
|
||||
break;
|
||||
case 9:
|
||||
this._v9 = value;
|
||||
break;
|
||||
case 10:
|
||||
this._v10 = value;
|
||||
break;
|
||||
case 11:
|
||||
this._v11 = value;
|
||||
break;
|
||||
case 12:
|
||||
this._v12 = value;
|
||||
break;
|
||||
case 13:
|
||||
this._v13 = value;
|
||||
break;
|
||||
case 14:
|
||||
this._v14 = value;
|
||||
break;
|
||||
case 15:
|
||||
this._v15 = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class InlineArrayDynamic<T> implements InlineArray<T> {
|
||||
private _values: any[];
|
||||
// Note: We still take the length argument so this class can be created
|
||||
// in the same ways as the other classes!
|
||||
constructor(public length: number, ...values: any[]) { this._values = values; }
|
||||
|
||||
get(index: number) { return this._values[index]; }
|
||||
set(index: number, value: T) { this._values[index] = value; }
|
||||
}
|
||||
|
||||
export const EMPTY_INLINE_ARRAY: InlineArray<any> = new InlineArray0();
|
||||
|
||||
/**
|
||||
* This is a private API only used by the compiler to read the view class.
|
||||
*/
|
||||
export function getComponentFactoryViewClass(componentFactory: ComponentFactory<any>): Type<any> {
|
||||
return componentFactory._viewClass;
|
||||
}
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AnimationEntryMetadata} from '../animation/metadata';
|
||||
import {ChangeDetectionStrategy} from '../change_detection/constants';
|
||||
import {Provider} from '../di';
|
||||
import {Type} from '../type';
|
||||
@ -651,7 +650,7 @@ export interface Component extends Directive {
|
||||
* - {@link animate animate()}
|
||||
* - {@link keyframes keyframes()}
|
||||
*/
|
||||
animations?: AnimationEntryMetadata[];
|
||||
animations?: any[];
|
||||
|
||||
/**
|
||||
* Specifies how the template and the styles should be encapsulated:
|
||||
|
@ -6,8 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AnimationEntryMetadata} from '../animation/metadata';
|
||||
|
||||
/**
|
||||
* Defines template and style encapsulation options available for Component's {@link Component}.
|
||||
*
|
||||
@ -74,7 +72,7 @@ export class ViewMetadata {
|
||||
/** {@link Component.encapsulation} */
|
||||
encapsulation: ViewEncapsulation;
|
||||
/** {@link Component.animation} */
|
||||
animations: AnimationEntryMetadata[];
|
||||
animations: any[];
|
||||
/** {@link Component.interpolation} */
|
||||
interpolation: [string, string];
|
||||
|
||||
@ -85,7 +83,7 @@ export class ViewMetadata {
|
||||
encapsulation?: ViewEncapsulation,
|
||||
styles?: string[],
|
||||
styleUrls?: string[],
|
||||
animations?: AnimationEntryMetadata[],
|
||||
animations?: any[],
|
||||
interpolation?: [string, string]
|
||||
} = {}) {
|
||||
this.templateUrl = templateUrl;
|
||||
|
@ -6,9 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
|
||||
import {AnimationPlayer} from '../../src/animation/animation_player';
|
||||
import {AnimationStyles} from '../../src/animation/animation_styles';
|
||||
import {InjectionToken, Injector} from '../di';
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
|
||||
@ -91,9 +88,8 @@ export abstract class Renderer {
|
||||
abstract setText(renderNode: any, text: string): void;
|
||||
|
||||
abstract animate(
|
||||
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||
duration: number, delay: number, easing: string,
|
||||
previousPlayers?: AnimationPlayer[]): AnimationPlayer;
|
||||
element: any, startingStyles: any, keyframes: any[], duration: number, delay: number,
|
||||
easing: string, previousPlayers?: any[]): any;
|
||||
}
|
||||
|
||||
export const RendererV2Interceptor = new InjectionToken<RendererV2[]>('RendererV2Interceptor');
|
||||
|
@ -11,10 +11,10 @@ export {ngContentDef} from './ng_content';
|
||||
export {directiveDef, pipeDef, providerDef} from './provider';
|
||||
export {pureArrayDef, pureObjectDef, purePipeDef} from './pure_expression';
|
||||
export {queryDef} from './query';
|
||||
export {ViewRef_, createComponentFactory, nodeValue} from './refs';
|
||||
export {ViewRef_, createComponentFactory, getComponentViewDefinitionFactory, nodeValue} from './refs';
|
||||
export {initServicesIfNeeded} from './services';
|
||||
export {textDef} from './text';
|
||||
export {createRendererTypeV2, elementEventFullName, rootRenderNodes, unwrapValue} from './util';
|
||||
export {EMPTY_ARRAY, EMPTY_MAP, createRendererTypeV2, elementEventFullName, inlineInterpolate, interpolate, rootRenderNodes, unwrapValue} from './util';
|
||||
export {viewDef} from './view';
|
||||
export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NoOpAnimationPlayer} from '../animation/animation_player';
|
||||
import {ApplicationRef} from '../application_ref';
|
||||
import {ChangeDetectorRef} from '../change_detection/change_detection';
|
||||
import {Injector} from '../di';
|
||||
@ -31,9 +30,22 @@ export function createComponentFactory(
|
||||
return new ComponentFactory_(selector, componentType, viewDefFactory);
|
||||
}
|
||||
|
||||
export function getComponentViewDefinitionFactory(componentFactory: ComponentFactory<any>):
|
||||
ViewDefinitionFactory {
|
||||
return (componentFactory as ComponentFactory_).viewDefFactory;
|
||||
}
|
||||
|
||||
class ComponentFactory_ extends ComponentFactory<any> {
|
||||
constructor(selector: string, componentType: Type<any>, viewDefFactory: ViewDefinitionFactory) {
|
||||
super(selector, <any>viewDefFactory, componentType);
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
viewDefFactory: ViewDefinitionFactory;
|
||||
|
||||
constructor(
|
||||
public selector: string, public componentType: Type<any>,
|
||||
viewDefFactory: ViewDefinitionFactory) {
|
||||
super();
|
||||
this.viewDefFactory = viewDefFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,7 +54,7 @@ class ComponentFactory_ extends ComponentFactory<any> {
|
||||
create(
|
||||
injector: Injector, projectableNodes: any[][] = null,
|
||||
rootSelectorOrNode: string|any = null): ComponentRef<any> {
|
||||
const viewDef = resolveViewDefinition(this._viewClass);
|
||||
const viewDef = resolveViewDefinition(this.viewDefFactory);
|
||||
const componentNodeIndex = viewDef.nodes[0].element.componentProvider.index;
|
||||
const view = Services.createRootView(
|
||||
injector, projectableNodes || [], rootSelectorOrNode, viewDef, EMPTY_CONTEXT);
|
||||
@ -386,5 +398,5 @@ class RendererAdapter implements RendererV1 {
|
||||
|
||||
setText(renderNode: Text, text: string): void { this.delegate.setValue(renderNode, text); }
|
||||
|
||||
animate(): NoOpAnimationPlayer { return new NoOpAnimationPlayer(); }
|
||||
animate(): any { throw new Error('Renderer.animate is no longer supported!'); }
|
||||
}
|
@ -337,3 +337,56 @@ export function splitNamespace(name: string): string[] {
|
||||
}
|
||||
return ['', name];
|
||||
}
|
||||
|
||||
export function interpolate(valueCount: number, constAndInterp: string[]): string {
|
||||
let result = '';
|
||||
for (let i = 0; i < valueCount * 2; i = i + 2) {
|
||||
result = result + constAndInterp[i] + _toStringWithNull(constAndInterp[i + 1]);
|
||||
}
|
||||
return result + constAndInterp[valueCount * 2];
|
||||
}
|
||||
|
||||
export function inlineInterpolate(
|
||||
valueCount: number, c0: string, a1: any, c1: string, a2?: any, c2?: string, a3?: any,
|
||||
c3?: string, a4?: any, c4?: string, a5?: any, c5?: string, a6?: any, c6?: string, a7?: any,
|
||||
c7?: string, a8?: any, c8?: string, a9?: any, c9?: string): string {
|
||||
switch (valueCount) {
|
||||
case 1:
|
||||
return c0 + _toStringWithNull(a1) + c1;
|
||||
case 2:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2;
|
||||
case 3:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3;
|
||||
case 4:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4;
|
||||
case 5:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5;
|
||||
case 6:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) + c6;
|
||||
case 7:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
|
||||
c6 + _toStringWithNull(a7) + c7;
|
||||
case 8:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
|
||||
c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8;
|
||||
case 9:
|
||||
return c0 + _toStringWithNull(a1) + c1 + _toStringWithNull(a2) + c2 + _toStringWithNull(a3) +
|
||||
c3 + _toStringWithNull(a4) + c4 + _toStringWithNull(a5) + c5 + _toStringWithNull(a6) +
|
||||
c6 + _toStringWithNull(a7) + c7 + _toStringWithNull(a8) + c8 + _toStringWithNull(a9) + c9;
|
||||
default:
|
||||
throw new Error(`Does not support more than 9 expressions`);
|
||||
}
|
||||
}
|
||||
|
||||
function _toStringWithNull(v: any): string {
|
||||
return v != null ? v.toString() : '';
|
||||
}
|
||||
|
||||
export const EMPTY_ARRAY: any[] = [];
|
||||
export const EMPTY_MAP: {[key: string]: any} = {};
|
@ -1,76 +0,0 @@
|
||||
/**
|
||||
* @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 {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {el} from '@angular/platform-browser/testing/browser_util';
|
||||
|
||||
import {ViewAnimationMap} from '../../src/animation/view_animation_map';
|
||||
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
|
||||
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
|
||||
|
||||
export function main() {
|
||||
describe('ActiveAnimationsPlayersMap', function() {
|
||||
let playersMap: any /** TODO #9100 */;
|
||||
let elementNode: any /** TODO #9100 */;
|
||||
const animationName = 'animationName';
|
||||
|
||||
beforeEach(() => {
|
||||
playersMap = new ViewAnimationMap();
|
||||
elementNode = el('<div></div>');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
getDOM().remove(elementNode);
|
||||
elementNode = null;
|
||||
});
|
||||
|
||||
it('should register a player an allow it to be accessed', () => {
|
||||
const player = new MockAnimationPlayer();
|
||||
playersMap.set(elementNode, animationName, player);
|
||||
|
||||
expect(playersMap.find(elementNode, animationName)).toBe(player);
|
||||
expect(playersMap.findAllPlayersByElement(elementNode)).toEqual([player]);
|
||||
expect(playersMap.getAllPlayers()).toEqual([player]);
|
||||
expect(countPlayers(playersMap)).toEqual(1);
|
||||
});
|
||||
|
||||
it('should remove a registered player when remove() is called', () => {
|
||||
const player = new MockAnimationPlayer();
|
||||
playersMap.set(elementNode, animationName, player);
|
||||
expect(playersMap.find(elementNode, animationName)).toBe(player);
|
||||
expect(countPlayers(playersMap)).toEqual(1);
|
||||
playersMap.remove(elementNode, animationName);
|
||||
expect(playersMap.find(elementNode, animationName)).not.toBe(player);
|
||||
expect(countPlayers(playersMap)).toEqual(0);
|
||||
});
|
||||
|
||||
it('should allow multiple players to be registered on the same element', () => {
|
||||
const player1 = new MockAnimationPlayer();
|
||||
const player2 = new MockAnimationPlayer();
|
||||
playersMap.set(elementNode, 'myAnimation1', player1);
|
||||
playersMap.set(elementNode, 'myAnimation2', player2);
|
||||
expect(countPlayers(playersMap)).toEqual(2);
|
||||
expect(playersMap.findAllPlayersByElement(elementNode)).toEqual([player1, player2]);
|
||||
});
|
||||
|
||||
it('should only allow one player to be set for a given element/animationName pair', () => {
|
||||
const player1 = new MockAnimationPlayer();
|
||||
const player2 = new MockAnimationPlayer();
|
||||
playersMap.set(elementNode, animationName, player1);
|
||||
expect(playersMap.find(elementNode, animationName)).toBe(player1);
|
||||
expect(countPlayers(playersMap)).toEqual(1);
|
||||
playersMap.set(elementNode, animationName, player2);
|
||||
expect(playersMap.find(elementNode, animationName)).toBe(player2);
|
||||
expect(countPlayers(playersMap)).toEqual(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function countPlayers(map: ViewAnimationMap): number {
|
||||
return map.getAllPlayers().length;
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
/**
|
||||
* @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 {AnimationGroupPlayer} from '../../src/animation/animation_group_player';
|
||||
import {fakeAsync, flushMicrotasks} from '../../testing';
|
||||
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
|
||||
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
|
||||
|
||||
export function main() {
|
||||
describe('AnimationGroupPlayer', function() {
|
||||
let players: any /** TODO #9100 */;
|
||||
beforeEach(() => {
|
||||
players = [
|
||||
new MockAnimationPlayer(),
|
||||
new MockAnimationPlayer(),
|
||||
new MockAnimationPlayer(),
|
||||
];
|
||||
});
|
||||
|
||||
const assertLastStatus =
|
||||
(player: MockAnimationPlayer, status: string, match: boolean, iOffset: number = 0) => {
|
||||
const index = player.log.length - 1 + iOffset;
|
||||
const actual = player.log.length > 0 ? player.log[index] : null;
|
||||
if (match) {
|
||||
expect(actual).toEqual(status);
|
||||
} else {
|
||||
expect(actual).not.toEqual(status);
|
||||
}
|
||||
};
|
||||
|
||||
const assertPlaying = (player: MockAnimationPlayer, isPlaying: boolean) => {
|
||||
assertLastStatus(player, 'play', isPlaying);
|
||||
};
|
||||
|
||||
it('should play and pause all players in parallel', () => {
|
||||
const group = new AnimationGroupPlayer(players);
|
||||
|
||||
assertPlaying(players[0], false);
|
||||
assertPlaying(players[1], false);
|
||||
assertPlaying(players[2], false);
|
||||
|
||||
group.play();
|
||||
|
||||
assertPlaying(players[0], true);
|
||||
assertPlaying(players[1], true);
|
||||
assertPlaying(players[2], true);
|
||||
|
||||
group.pause();
|
||||
|
||||
assertPlaying(players[0], false);
|
||||
assertPlaying(players[1], false);
|
||||
assertPlaying(players[2], false);
|
||||
});
|
||||
|
||||
it('should finish when all players have finished', () => {
|
||||
const group = new AnimationGroupPlayer(players);
|
||||
let completed = false;
|
||||
group.onDone(() => completed = true);
|
||||
|
||||
group.play();
|
||||
|
||||
expect(completed).toBeFalsy();
|
||||
|
||||
players[0].finish();
|
||||
|
||||
expect(completed).toBeFalsy();
|
||||
|
||||
players[1].finish();
|
||||
|
||||
expect(completed).toBeFalsy();
|
||||
|
||||
players[2].finish();
|
||||
|
||||
expect(completed).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should restart all the players', () => {
|
||||
const group = new AnimationGroupPlayer(players);
|
||||
|
||||
group.play();
|
||||
|
||||
assertLastStatus(players[0], 'restart', false);
|
||||
assertLastStatus(players[1], 'restart', false);
|
||||
assertLastStatus(players[2], 'restart', false);
|
||||
|
||||
group.restart();
|
||||
|
||||
assertLastStatus(players[0], 'restart', true);
|
||||
assertLastStatus(players[1], 'restart', true);
|
||||
assertLastStatus(players[2], 'restart', true);
|
||||
});
|
||||
|
||||
it('should not destroy the inner the players when finished', () => {
|
||||
const group = new AnimationGroupPlayer(players);
|
||||
|
||||
let completed = false;
|
||||
group.onDone(() => completed = true);
|
||||
|
||||
expect(completed).toBeFalsy();
|
||||
|
||||
group.play();
|
||||
|
||||
assertLastStatus(players[0], 'finish', false);
|
||||
assertLastStatus(players[1], 'finish', false);
|
||||
assertLastStatus(players[2], 'finish', false);
|
||||
|
||||
expect(completed).toBeFalsy();
|
||||
|
||||
group.finish();
|
||||
|
||||
assertLastStatus(players[0], 'finish', true);
|
||||
assertLastStatus(players[1], 'finish', true);
|
||||
assertLastStatus(players[2], 'finish', true);
|
||||
|
||||
expect(completed).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not call destroy automatically when finished even if a parent player finishes',
|
||||
() => {
|
||||
const group = new AnimationGroupPlayer(players);
|
||||
const parent = new AnimationGroupPlayer([group, new MockAnimationPlayer()]);
|
||||
|
||||
group.play();
|
||||
|
||||
assertLastStatus(players[0], 'destroy', false);
|
||||
assertLastStatus(players[1], 'destroy', false);
|
||||
assertLastStatus(players[2], 'destroy', false);
|
||||
|
||||
group.finish();
|
||||
|
||||
assertLastStatus(players[0], 'destroy', false);
|
||||
assertLastStatus(players[1], 'destroy', false);
|
||||
assertLastStatus(players[2], 'destroy', false);
|
||||
|
||||
parent.finish();
|
||||
|
||||
assertLastStatus(players[0], 'destroy', false);
|
||||
assertLastStatus(players[1], 'destroy', false);
|
||||
assertLastStatus(players[2], 'destroy', false);
|
||||
});
|
||||
|
||||
it('should function without any players', () => {
|
||||
const group = new AnimationGroupPlayer([]);
|
||||
group.onDone(() => {});
|
||||
group.pause();
|
||||
group.play();
|
||||
group.finish();
|
||||
group.restart();
|
||||
group.destroy();
|
||||
});
|
||||
|
||||
it('should run the onStart method when started but only once', () => {
|
||||
const player = new AnimationGroupPlayer([]);
|
||||
let calls = 0;
|
||||
player.onStart(() => calls++);
|
||||
expect(calls).toEqual(0);
|
||||
player.play();
|
||||
expect(calls).toEqual(1);
|
||||
player.pause();
|
||||
player.play();
|
||||
expect(calls).toEqual(1);
|
||||
});
|
||||
|
||||
it('should call onDone after the next microtask if no players are provided', fakeAsync(() => {
|
||||
const group = new AnimationGroupPlayer([]);
|
||||
let completed = false;
|
||||
group.onDone(() => completed = true);
|
||||
expect(completed).toEqual(false);
|
||||
flushMicrotasks();
|
||||
expect(completed).toEqual(true);
|
||||
}));
|
||||
|
||||
it('should not allow the player to be destroyed if it already has been destroyed unless reset',
|
||||
fakeAsync(() => {
|
||||
const p1 = new MockAnimationPlayer();
|
||||
const p2 = new MockAnimationPlayer();
|
||||
const innerPlayers = [p1, p2];
|
||||
|
||||
const groupPlayer = new AnimationGroupPlayer(innerPlayers);
|
||||
expect(p1.log[p1.log.length - 1]).not.toContain('destroy');
|
||||
expect(p2.log[p2.log.length - 1]).not.toContain('destroy');
|
||||
|
||||
groupPlayer.destroy();
|
||||
expect(p1.log[p1.log.length - 1]).toContain('destroy');
|
||||
expect(p2.log[p2.log.length - 1]).toContain('destroy');
|
||||
|
||||
p1.log = p2.log = [];
|
||||
|
||||
groupPlayer.destroy();
|
||||
expect(p1.log[p1.log.length - 1]).not.toContain('destroy');
|
||||
expect(p2.log[p2.log.length - 1]).not.toContain('destroy');
|
||||
|
||||
groupPlayer.reset();
|
||||
groupPlayer.destroy();
|
||||
expect(p1.log[p1.log.length - 1]).toContain('destroy');
|
||||
expect(p2.log[p2.log.length - 1]).toContain('destroy');
|
||||
}));
|
||||
});
|
||||
}
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {AUTO_STYLE, AnimationEvent, animate, keyframes, state, style, transition, trigger} from '@angular/animations';
|
||||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {Component, HostBinding, HostListener, ViewChild} from '@angular/core';
|
||||
import {AnimationDriver, BrowserAnimationsModule, ɵAnimationEngine} from '@angular/platform-browser/animations';
|
||||
import {MockAnimationDriver, MockAnimationPlayer} from '@angular/platform-browser/animations/testing';
|
||||
@ -14,22 +13,6 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {TestBed} from '../../testing';
|
||||
|
||||
export function main() {
|
||||
describe('view engine', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler({
|
||||
useJit: true,
|
||||
providers: [{
|
||||
provide: USE_VIEW_ENGINE,
|
||||
useValue: true,
|
||||
}],
|
||||
});
|
||||
});
|
||||
|
||||
declareTests({useJit: true});
|
||||
});
|
||||
}
|
||||
|
||||
function declareTests({useJit}: {useJit: boolean}) {
|
||||
// these tests are only mean't to be run within the DOM (for now)
|
||||
if (typeof Element == 'undefined') return;
|
||||
|
@ -1,45 +0,0 @@
|
||||
/**
|
||||
* @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 {NoOpAnimationPlayer} from '../../src/animation/animation_player';
|
||||
import {fakeAsync, flushMicrotasks} from '../../testing';
|
||||
import {describe, expect, it} from '../../testing/testing_internal';
|
||||
|
||||
export function main() {
|
||||
describe('NoOpAnimationPlayer', function() {
|
||||
it('should call onDone after the next microtask when constructed', fakeAsync(() => {
|
||||
const player = new NoOpAnimationPlayer();
|
||||
let completed = false;
|
||||
player.onDone(() => completed = true);
|
||||
expect(completed).toEqual(false);
|
||||
flushMicrotasks();
|
||||
expect(completed).toEqual(true);
|
||||
}));
|
||||
|
||||
it('should be able to run each of the player methods', fakeAsync(() => {
|
||||
const player = new NoOpAnimationPlayer();
|
||||
player.pause();
|
||||
player.play();
|
||||
player.finish();
|
||||
player.restart();
|
||||
player.destroy();
|
||||
}));
|
||||
|
||||
it('should run the onStart method when started but only once', fakeAsync(() => {
|
||||
const player = new NoOpAnimationPlayer();
|
||||
let calls = 0;
|
||||
player.onStart(() => calls++);
|
||||
expect(calls).toEqual(0);
|
||||
player.play();
|
||||
expect(calls).toEqual(1);
|
||||
player.pause();
|
||||
player.play();
|
||||
expect(calls).toEqual(1);
|
||||
}));
|
||||
});
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
/**
|
||||
* @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 {AnimationQueue} from '@angular/core/src/animation/animation_queue';
|
||||
|
||||
import {NgZone} from '../../src/zone/ng_zone';
|
||||
import {TestBed, fakeAsync, flushMicrotasks} from '../../testing';
|
||||
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
|
||||
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
|
||||
|
||||
export function main() {
|
||||
describe('AnimationQueue', function() {
|
||||
beforeEach(() => { TestBed.configureTestingModule({declarations: [], imports: []}); });
|
||||
|
||||
it('should queue animation players and run when flushed, but only as the next scheduled microtask',
|
||||
fakeAsync(() => {
|
||||
const zone = TestBed.get(NgZone);
|
||||
const queue = new AnimationQueue(zone);
|
||||
|
||||
const log: string[] = [];
|
||||
const p1 = new MockAnimationPlayer();
|
||||
const p2 = new MockAnimationPlayer();
|
||||
const p3 = new MockAnimationPlayer();
|
||||
|
||||
p1.onStart(() => log.push('1'));
|
||||
p2.onStart(() => log.push('2'));
|
||||
p3.onStart(() => log.push('3'));
|
||||
|
||||
queue.enqueue(p1);
|
||||
queue.enqueue(p2);
|
||||
queue.enqueue(p3);
|
||||
expect(log).toEqual([]);
|
||||
|
||||
queue.flush();
|
||||
expect(log).toEqual([]);
|
||||
|
||||
flushMicrotasks();
|
||||
expect(log).toEqual(['1', '2', '3']);
|
||||
}));
|
||||
|
||||
it('should always run each of the animation players outside of the angular zone on start',
|
||||
fakeAsync(() => {
|
||||
const zone = TestBed.get(NgZone);
|
||||
const queue = new AnimationQueue(zone);
|
||||
|
||||
const player = new MockAnimationPlayer();
|
||||
let eventHasRun = false;
|
||||
player.onStart(() => {
|
||||
NgZone.assertNotInAngularZone();
|
||||
eventHasRun = true;
|
||||
});
|
||||
|
||||
zone.run(() => {
|
||||
NgZone.assertInAngularZone();
|
||||
queue.enqueue(player);
|
||||
queue.flush();
|
||||
flushMicrotasks();
|
||||
});
|
||||
|
||||
expect(eventHasRun).toBe(true);
|
||||
}));
|
||||
|
||||
it('should always run each of the animation players outside of the angular zone on done',
|
||||
fakeAsync(() => {
|
||||
const zone = TestBed.get(NgZone);
|
||||
const queue = new AnimationQueue(zone);
|
||||
|
||||
const player = new MockAnimationPlayer();
|
||||
let eventHasRun = false;
|
||||
player.onDone(() => {
|
||||
NgZone.assertNotInAngularZone();
|
||||
eventHasRun = true;
|
||||
});
|
||||
|
||||
zone.run(() => {
|
||||
NgZone.assertInAngularZone();
|
||||
queue.enqueue(player);
|
||||
queue.flush();
|
||||
flushMicrotasks();
|
||||
});
|
||||
|
||||
expect(eventHasRun).toBe(false);
|
||||
player.finish();
|
||||
expect(eventHasRun).toBe(true);
|
||||
}));
|
||||
|
||||
it('should not run animations again incase an animation midway fails', fakeAsync(() => {
|
||||
const zone = TestBed.get(NgZone);
|
||||
const queue = new AnimationQueue(zone);
|
||||
|
||||
const log: string[] = [];
|
||||
const p1 = new PlayerThatFails(false);
|
||||
const p2 = new PlayerThatFails(true);
|
||||
const p3 = new PlayerThatFails(false);
|
||||
|
||||
p1.onStart(() => log.push('1'));
|
||||
p2.onStart(() => log.push('2'));
|
||||
p3.onStart(() => log.push('3'));
|
||||
|
||||
queue.enqueue(p1);
|
||||
queue.enqueue(p2);
|
||||
queue.enqueue(p3);
|
||||
|
||||
queue.flush();
|
||||
|
||||
expect(() => flushMicrotasks()).toThrowError();
|
||||
|
||||
expect(log).toEqual(['1', '2']);
|
||||
|
||||
// let's reset this so that it gets triggered again
|
||||
p2.reset();
|
||||
p2.onStart(() => log.push('2'));
|
||||
|
||||
queue.flush();
|
||||
|
||||
expect(() => flushMicrotasks()).not.toThrowError();
|
||||
|
||||
expect(log).toEqual(['1', '2', '3']);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
class PlayerThatFails extends MockAnimationPlayer {
|
||||
private _animationStarted = false;
|
||||
|
||||
constructor(public doFail: boolean) { super(); }
|
||||
|
||||
play() {
|
||||
super.play();
|
||||
this._animationStarted = true;
|
||||
if (this.doFail) {
|
||||
throw new Error('Oh nooooo');
|
||||
}
|
||||
}
|
||||
|
||||
reset() { this._animationStarted = false; }
|
||||
|
||||
hasStarted() { return this._animationStarted; }
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
/**
|
||||
* @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 {AnimationSequencePlayer} from '../../src/animation/animation_sequence_player';
|
||||
import {fakeAsync, flushMicrotasks} from '../../testing';
|
||||
import {MockAnimationPlayer} from '../../testing/mock_animation_player';
|
||||
import {beforeEach, describe, expect, it} from '../../testing/testing_internal';
|
||||
|
||||
export function main() {
|
||||
describe('AnimationSequencePlayer', function() {
|
||||
let players: any /** TODO #9100 */;
|
||||
beforeEach(() => {
|
||||
players = [
|
||||
new MockAnimationPlayer(),
|
||||
new MockAnimationPlayer(),
|
||||
new MockAnimationPlayer(),
|
||||
];
|
||||
});
|
||||
|
||||
const assertLastStatus =
|
||||
(player: MockAnimationPlayer, status: string, match: boolean, iOffset: number = 0) => {
|
||||
const index = player.log.length - 1 + iOffset;
|
||||
const actual = player.log.length > 0 ? player.log[index] : null;
|
||||
if (match) {
|
||||
expect(actual).toEqual(status);
|
||||
} else {
|
||||
expect(actual).not.toEqual(status);
|
||||
}
|
||||
};
|
||||
|
||||
const assertPlaying = (player: MockAnimationPlayer, isPlaying: boolean) => {
|
||||
assertLastStatus(player, 'play', isPlaying);
|
||||
};
|
||||
|
||||
it('should pause/play the active player', () => {
|
||||
const sequence = new AnimationSequencePlayer(players);
|
||||
|
||||
assertPlaying(players[0], false);
|
||||
assertPlaying(players[1], false);
|
||||
assertPlaying(players[2], false);
|
||||
|
||||
sequence.play();
|
||||
|
||||
assertPlaying(players[0], true);
|
||||
assertPlaying(players[1], false);
|
||||
assertPlaying(players[2], false);
|
||||
|
||||
sequence.pause();
|
||||
|
||||
assertPlaying(players[0], false);
|
||||
assertPlaying(players[1], false);
|
||||
assertPlaying(players[2], false);
|
||||
|
||||
sequence.play();
|
||||
players[0].finish();
|
||||
|
||||
assertPlaying(players[0], false);
|
||||
assertPlaying(players[1], true);
|
||||
assertPlaying(players[2], false);
|
||||
|
||||
players[1].finish();
|
||||
|
||||
assertPlaying(players[0], false);
|
||||
assertPlaying(players[1], false);
|
||||
assertPlaying(players[2], true);
|
||||
|
||||
players[2].finish();
|
||||
sequence.pause();
|
||||
|
||||
assertPlaying(players[0], false);
|
||||
assertPlaying(players[1], false);
|
||||
assertPlaying(players[2], false);
|
||||
});
|
||||
|
||||
it('should finish when all players have finished', () => {
|
||||
const sequence = new AnimationSequencePlayer(players);
|
||||
|
||||
let completed = false;
|
||||
sequence.onDone(() => completed = true);
|
||||
sequence.play();
|
||||
|
||||
expect(completed).toBeFalsy();
|
||||
|
||||
players[0].finish();
|
||||
|
||||
expect(completed).toBeFalsy();
|
||||
|
||||
players[1].finish();
|
||||
|
||||
expect(completed).toBeFalsy();
|
||||
|
||||
players[2].finish();
|
||||
|
||||
expect(completed).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should restart all the players', () => {
|
||||
const sequence = new AnimationSequencePlayer(players);
|
||||
|
||||
sequence.play();
|
||||
|
||||
assertPlaying(players[0], true);
|
||||
assertPlaying(players[1], false);
|
||||
assertPlaying(players[2], false);
|
||||
|
||||
players[0].finish();
|
||||
|
||||
assertPlaying(players[0], false);
|
||||
assertPlaying(players[1], true);
|
||||
assertPlaying(players[2], false);
|
||||
|
||||
sequence.restart();
|
||||
|
||||
assertLastStatus(players[0], 'restart', true);
|
||||
assertLastStatus(players[1], 'reset', true);
|
||||
assertLastStatus(players[2], 'reset', true);
|
||||
});
|
||||
|
||||
it('should finish all the players', () => {
|
||||
const sequence = new AnimationSequencePlayer(players);
|
||||
|
||||
let completed = false;
|
||||
sequence.onDone(() => completed = true);
|
||||
|
||||
sequence.play();
|
||||
|
||||
assertLastStatus(players[0], 'finish', false);
|
||||
assertLastStatus(players[1], 'finish', false);
|
||||
assertLastStatus(players[2], 'finish', false);
|
||||
|
||||
sequence.finish();
|
||||
|
||||
assertLastStatus(players[0], 'finish', true);
|
||||
assertLastStatus(players[1], 'finish', true);
|
||||
assertLastStatus(players[2], 'finish', true);
|
||||
|
||||
expect(completed).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not call destroy automatically when finished even if a parent player is present',
|
||||
() => {
|
||||
const sequence = new AnimationSequencePlayer(players);
|
||||
const parent = new AnimationSequencePlayer([sequence, new MockAnimationPlayer()]);
|
||||
|
||||
sequence.play();
|
||||
|
||||
assertLastStatus(players[0], 'destroy', false);
|
||||
assertLastStatus(players[1], 'destroy', false);
|
||||
assertLastStatus(players[2], 'destroy', false);
|
||||
|
||||
sequence.finish();
|
||||
|
||||
assertLastStatus(players[0], 'destroy', false);
|
||||
assertLastStatus(players[1], 'destroy', false);
|
||||
assertLastStatus(players[2], 'destroy', false);
|
||||
|
||||
parent.finish();
|
||||
|
||||
assertLastStatus(players[0], 'destroy', false);
|
||||
assertLastStatus(players[1], 'destroy', false);
|
||||
assertLastStatus(players[2], 'destroy', false);
|
||||
});
|
||||
|
||||
it('should function without any players', () => {
|
||||
const sequence = new AnimationSequencePlayer([]);
|
||||
sequence.onDone(() => {});
|
||||
sequence.pause();
|
||||
sequence.play();
|
||||
sequence.finish();
|
||||
sequence.restart();
|
||||
sequence.destroy();
|
||||
});
|
||||
|
||||
it('should run the onStart method when started but only once', () => {
|
||||
const player = new AnimationSequencePlayer([]);
|
||||
let calls = 0;
|
||||
player.onStart(() => calls++);
|
||||
expect(calls).toEqual(0);
|
||||
player.play();
|
||||
expect(calls).toEqual(1);
|
||||
player.pause();
|
||||
player.play();
|
||||
expect(calls).toEqual(1);
|
||||
});
|
||||
|
||||
it('should call onDone after the next microtask if no players are provided', fakeAsync(() => {
|
||||
const sequence = new AnimationSequencePlayer([]);
|
||||
let completed = false;
|
||||
sequence.onDone(() => completed = true);
|
||||
expect(completed).toEqual(false);
|
||||
flushMicrotasks();
|
||||
expect(completed).toEqual(true);
|
||||
}));
|
||||
|
||||
it('should not allow the player to be destroyed if it already has been destroyed unless reset',
|
||||
fakeAsync(() => {
|
||||
const p1 = new MockAnimationPlayer();
|
||||
const p2 = new MockAnimationPlayer();
|
||||
const innerPlayers = [p1, p2];
|
||||
|
||||
const sequencePlayer = new AnimationSequencePlayer(innerPlayers);
|
||||
expect(p1.log[p1.log.length - 1]).not.toContain('destroy');
|
||||
expect(p2.log[p2.log.length - 1]).not.toContain('destroy');
|
||||
|
||||
sequencePlayer.destroy();
|
||||
expect(p1.log[p1.log.length - 1]).toContain('destroy');
|
||||
expect(p2.log[p2.log.length - 1]).toContain('destroy');
|
||||
|
||||
p1.log = p2.log = [];
|
||||
|
||||
sequencePlayer.destroy();
|
||||
expect(p1.log[p1.log.length - 1]).not.toContain('destroy');
|
||||
expect(p2.log[p2.log.length - 1]).not.toContain('destroy');
|
||||
|
||||
sequencePlayer.reset();
|
||||
sequencePlayer.destroy();
|
||||
expect(p1.log[p1.log.length - 1]).toContain('destroy');
|
||||
expect(p2.log[p2.log.length - 1]).toContain('destroy');
|
||||
}));
|
||||
});
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
/**
|
||||
* @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 {FILL_STYLE_FLAG} from '../../src/animation/animation_constants';
|
||||
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
|
||||
import * as animationUtils from '../../src/animation/animation_style_util';
|
||||
import {AnimationStyles} from '../../src/animation/animation_styles';
|
||||
import {AUTO_STYLE} from '../../src/animation/metadata';
|
||||
import {describe, expect, it} from '../../testing/testing_internal';
|
||||
|
||||
export function main() {
|
||||
describe('Animation Style Utils', function() {
|
||||
|
||||
describe('prepareFinalAnimationStyles', () => {
|
||||
it('should set all non-shared styles to the provided null value between the two sets of styles',
|
||||
() => {
|
||||
const styles = {opacity: 0, color: 'red'};
|
||||
const newStyles = {background: 'red'};
|
||||
const flag = '*';
|
||||
const result = animationUtils.prepareFinalAnimationStyles(styles, newStyles, flag);
|
||||
expect(result).toEqual({opacity: flag, color: flag, background: 'red'});
|
||||
});
|
||||
|
||||
it('should handle an empty set of styles', () => {
|
||||
const value = '*';
|
||||
|
||||
expect(animationUtils.prepareFinalAnimationStyles({}, {opacity: '0'}, value)).toEqual({
|
||||
opacity: '0'
|
||||
});
|
||||
|
||||
expect(animationUtils.prepareFinalAnimationStyles({opacity: '0'}, {}, value)).toEqual({
|
||||
opacity: value
|
||||
});
|
||||
});
|
||||
|
||||
it('should set all AUTO styles to the null value', () => {
|
||||
const styles = {opacity: 0};
|
||||
const newStyles = {color: '*', border: '*'};
|
||||
const flag = '*';
|
||||
const result = animationUtils.prepareFinalAnimationStyles(styles, newStyles, null);
|
||||
expect(result).toEqual({opacity: null, color: null, border: null});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('balanceAnimationKeyframes', () => {
|
||||
it('should balance both the starting and final keyframes with thep provided styles', () => {
|
||||
const collectedStyles = {width: 100, height: 200};
|
||||
|
||||
const finalStyles = {background: 'red', border: '1px solid black'};
|
||||
|
||||
const keyframes = [
|
||||
new AnimationKeyframe(0, new AnimationStyles([{height: 100, opacity: 1}])),
|
||||
new AnimationKeyframe(
|
||||
1, new AnimationStyles([{background: 'blue', left: '100px', top: '100px'}]))
|
||||
];
|
||||
|
||||
const result =
|
||||
animationUtils.balanceAnimationKeyframes(collectedStyles, finalStyles, keyframes);
|
||||
|
||||
expect(animationUtils.flattenStyles(result[0].styles.styles)).toEqual({
|
||||
'width': 100,
|
||||
'height': 100,
|
||||
'opacity': 1,
|
||||
'background': '*',
|
||||
'border': '*',
|
||||
'left': '*',
|
||||
'top': '*'
|
||||
});
|
||||
|
||||
expect(animationUtils.flattenStyles(result[1].styles.styles)).toEqual({
|
||||
'width': '*',
|
||||
'height': '*',
|
||||
'opacity': '*',
|
||||
'background': 'blue',
|
||||
'border': '1px solid black',
|
||||
'left': '100px',
|
||||
'top': '100px'
|
||||
});
|
||||
});
|
||||
|
||||
it('should perform balancing when no collected and final styles are provided', () => {
|
||||
const keyframes = [
|
||||
new AnimationKeyframe(0, new AnimationStyles([{height: 100, opacity: 1}])),
|
||||
new AnimationKeyframe(1, new AnimationStyles([{width: 100}]))
|
||||
];
|
||||
|
||||
const result = animationUtils.balanceAnimationKeyframes({}, {}, keyframes);
|
||||
|
||||
expect(animationUtils.flattenStyles(result[0].styles.styles))
|
||||
.toEqual({'height': 100, 'opacity': 1, 'width': '*'});
|
||||
|
||||
expect(animationUtils.flattenStyles(result[1].styles.styles))
|
||||
.toEqual({'width': 100, 'height': '*', 'opacity': '*'});
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearStyles', () => {
|
||||
it('should set all the style values to "null"', () => {
|
||||
const styles: {[key: string]:
|
||||
string | number} = {'opacity': 0, 'width': 100, 'color': 'red'};
|
||||
const expectedResult: {[key: string]: string |
|
||||
number} = {'opacity': null, 'width': null, 'color': null};
|
||||
expect(animationUtils.clearStyles(styles)).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should handle an empty set of styles',
|
||||
() => { expect(animationUtils.clearStyles({})).toEqual({}); });
|
||||
});
|
||||
|
||||
describe('collectAndResolveStyles', () => {
|
||||
it('should keep a record of the styles as they are called', () => {
|
||||
const styles1 = [{'opacity': 0, 'width': 100}];
|
||||
|
||||
const styles2 = [{'height': 999, 'opacity': 1}];
|
||||
|
||||
const collection: {[key: string]: string | number} = {};
|
||||
|
||||
expect(animationUtils.collectAndResolveStyles(collection, styles1)).toEqual(styles1);
|
||||
expect(collection).toEqual({'opacity': 0, 'width': 100});
|
||||
|
||||
expect(animationUtils.collectAndResolveStyles(collection, styles2)).toEqual(styles2);
|
||||
expect(collection).toEqual({'opacity': 1, 'width': 100, 'height': 999});
|
||||
});
|
||||
|
||||
it('should resolve styles if they contain a FILL_STYLE_FLAG value', () => {
|
||||
const styles1 = [{'opacity': 0, 'width': FILL_STYLE_FLAG}];
|
||||
|
||||
const styles2 = [{'height': 999, 'opacity': FILL_STYLE_FLAG}];
|
||||
|
||||
const collection = {};
|
||||
|
||||
expect(animationUtils.collectAndResolveStyles(collection, styles1)).toEqual([
|
||||
{'opacity': 0, 'width': AUTO_STYLE}
|
||||
]);
|
||||
|
||||
expect(animationUtils.collectAndResolveStyles(collection, styles2)).toEqual([
|
||||
{'opacity': 0, 'height': 999}
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -6,9 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ERROR_DEBUG_CONTEXT} from '@angular/core/src/errors';
|
||||
import {DebugContext} from '@angular/core/src/linker/debug_context';
|
||||
import {viewWrappedError} from '@angular/core/src/linker/errors';
|
||||
import {ERROR_DEBUG_CONTEXT, ERROR_TYPE} from '@angular/core/src/errors';
|
||||
|
||||
import {ErrorHandler, wrappedError} from '../src/error_handler';
|
||||
|
||||
@ -99,3 +97,10 @@ Context`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function viewWrappedError(originalError: any, context: any): Error {
|
||||
const error = wrappedError(`Error in ${context.source}`, originalError);
|
||||
(error as any)[ERROR_DEBUG_CONTEXT] = context;
|
||||
(error as any)[ERROR_TYPE] = viewWrappedError;
|
||||
return error;
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
/**
|
||||
* @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 {el} from '@angular/platform-browser/testing/browser_util';
|
||||
|
||||
import {NoOpAnimationPlayer} from '../../src/animation/animation_player';
|
||||
import {AnimationQueue} from '../../src/animation/animation_queue';
|
||||
import {AnimationViewContext} from '../../src/linker/animation_view_context';
|
||||
import {TestBed, fakeAsync, flushMicrotasks} from '../../testing';
|
||||
import {describe, expect, iit, it} from '../../testing/testing_internal';
|
||||
|
||||
export function main() {
|
||||
describe('AnimationViewContext', function() {
|
||||
let elm: any;
|
||||
beforeEach(() => { elm = el('<div></div>'); });
|
||||
|
||||
function getPlayers(vc: any) { return vc.getAnimationPlayers(elm); }
|
||||
|
||||
it('should remove the player from the registry once the animation is complete',
|
||||
fakeAsync(() => {
|
||||
const player = new NoOpAnimationPlayer();
|
||||
const animationQueue = TestBed.get(AnimationQueue) as AnimationQueue;
|
||||
const vc = new AnimationViewContext(animationQueue);
|
||||
|
||||
expect(getPlayers(vc).length).toEqual(0);
|
||||
vc.queueAnimation(elm, 'someAnimation', player);
|
||||
expect(getPlayers(vc).length).toEqual(1);
|
||||
player.finish();
|
||||
expect(getPlayers(vc).length).toEqual(0);
|
||||
}));
|
||||
|
||||
it('should not remove a follow-up player from the registry if another player is queued',
|
||||
fakeAsync(() => {
|
||||
const player1 = new NoOpAnimationPlayer();
|
||||
const player2 = new NoOpAnimationPlayer();
|
||||
const animationQueue = TestBed.get(AnimationQueue) as AnimationQueue;
|
||||
const vc = new AnimationViewContext(animationQueue);
|
||||
|
||||
vc.queueAnimation(elm, 'someAnimation', player1);
|
||||
expect(getPlayers(vc).length).toBe(1);
|
||||
expect(getPlayers(vc)[0]).toBe(player1);
|
||||
|
||||
vc.queueAnimation(elm, 'someAnimation', player2);
|
||||
expect(getPlayers(vc).length).toBe(1);
|
||||
expect(getPlayers(vc)[0]).toBe(player2);
|
||||
|
||||
player1.finish();
|
||||
|
||||
expect(getPlayers(vc).length).toBe(1);
|
||||
expect(getPlayers(vc)[0]).toBe(player2);
|
||||
|
||||
player2.finish();
|
||||
|
||||
expect(getPlayers(vc).length).toBe(0);
|
||||
}));
|
||||
});
|
||||
}
|
@ -6,37 +6,17 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry';
|
||||
import {TEST_COMPILER_PROVIDERS} from '@angular/compiler/testing/test_bindings';
|
||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, DoCheck, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, RenderComponentType, Renderer, RendererFactoryV2, RootRenderer, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core';
|
||||
import {DebugDomRenderer} from '@angular/core/src/debug/debug_renderer';
|
||||
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {DomRootRenderer} from '@angular/platform-browser/src/dom/dom_renderer';
|
||||
|
||||
import {MockSchemaRegistry} from '../../../compiler/testing/index';
|
||||
import {EventEmitter} from '../../src/facade/async';
|
||||
|
||||
export function main() {
|
||||
describe('Current compiler', () => { createTests({viewEngine: false}); });
|
||||
|
||||
describe('View Engine compiler', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler({
|
||||
useJit: true,
|
||||
providers: [
|
||||
{provide: USE_VIEW_ENGINE, useValue: true},
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
createTests({viewEngine: true});
|
||||
});
|
||||
}
|
||||
|
||||
function createTests({viewEngine}: {viewEngine: boolean}) {
|
||||
let elSchema: MockSchemaRegistry;
|
||||
let renderLog: RenderLog;
|
||||
let directiveLog: DirectiveLog;
|
||||
@ -123,7 +103,6 @@ function createTests({viewEngine}: {viewEngine: boolean}) {
|
||||
providers: [
|
||||
RenderLog,
|
||||
DirectiveLog,
|
||||
{provide: RootRenderer, useClass: LoggingRootRenderer},
|
||||
],
|
||||
});
|
||||
});
|
||||
@ -1286,26 +1265,6 @@ class RenderLog {
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class LoggingRootRenderer implements RootRenderer {
|
||||
constructor(private _delegate: DomRootRenderer, private _log: RenderLog) {}
|
||||
|
||||
renderComponent(componentProto: RenderComponentType): Renderer {
|
||||
return new LoggingRenderer(this._delegate.renderComponent(componentProto), this._log);
|
||||
}
|
||||
}
|
||||
|
||||
class LoggingRenderer extends DebugDomRenderer {
|
||||
constructor(delegate: Renderer, private _log: RenderLog) { super(delegate); }
|
||||
|
||||
setElementProperty(renderElement: any, propertyName: string, propertyValue: any) {
|
||||
this._log.setElementProperty(renderElement, propertyName, propertyValue);
|
||||
super.setElementProperty(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
setText(renderNode: any, value: string) { this._log.setText(renderNode, value); }
|
||||
}
|
||||
|
||||
class DirectiveLogEntry {
|
||||
constructor(public directiveName: string, public method: string) {}
|
||||
}
|
||||
|
@ -1,185 +0,0 @@
|
||||
/**
|
||||
* @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 {Component, ContentChild, Injectable, Input, RenderComponentType, Renderer, RootRenderer, TemplateRef} from '@angular/core';
|
||||
import {DebugDomRenderer} from '@angular/core/src/debug/debug_renderer';
|
||||
import {DirectRenderer} from '@angular/core/src/render/api';
|
||||
import {TestBed, inject} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {DIRECT_DOM_RENDERER, DomRootRenderer} from '@angular/platform-browser/src/dom/dom_renderer';
|
||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||
|
||||
let directRenderer: any;
|
||||
let destroyViewLogs: any[];
|
||||
|
||||
export function main() {
|
||||
// Don't run on server...
|
||||
if (!getDOM().supportsDOMEvents()) return;
|
||||
// TODO(tbosch): delete the tests here as they use the old renderer.
|
||||
xdescribe('direct dom integration tests', function() {
|
||||
|
||||
beforeEach(() => {
|
||||
directRenderer = DIRECT_DOM_RENDERER;
|
||||
destroyViewLogs = [];
|
||||
spyOn(directRenderer, 'remove').and.callThrough();
|
||||
spyOn(directRenderer, 'appendChild').and.callThrough();
|
||||
spyOn(directRenderer, 'insertBefore').and.callThrough();
|
||||
|
||||
TestBed.configureTestingModule(
|
||||
{providers: [{provide: RootRenderer, useClass: DirectRootRenderer}]});
|
||||
});
|
||||
|
||||
it('should attach views as last nodes in a parent', () => {
|
||||
@Component({template: '<div *ngIf="true">hello</div>'})
|
||||
class MyComp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
directRenderer.insertBefore.calls.reset();
|
||||
directRenderer.appendChild.calls.reset();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement).toHaveText('hello');
|
||||
expect(directRenderer.insertBefore).not.toHaveBeenCalled();
|
||||
expect(directRenderer.appendChild).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should attach views as non last nodes in a parent', () => {
|
||||
@Component({template: '<div *ngIf="true">hello</div>after'})
|
||||
class MyComp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
|
||||
directRenderer.insertBefore.calls.reset();
|
||||
directRenderer.appendChild.calls.reset();
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement).toHaveText('helloafter');
|
||||
expect(directRenderer.insertBefore).toHaveBeenCalled();
|
||||
expect(directRenderer.appendChild).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should detach views', () => {
|
||||
@Component({template: '<div *ngIf="shown">hello</div>'})
|
||||
class MyComp {
|
||||
shown = true;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
fixture.detectChanges();
|
||||
|
||||
directRenderer.remove.calls.reset();
|
||||
|
||||
fixture.componentInstance.shown = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement).toHaveText('');
|
||||
expect(directRenderer.remove).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should pass null as all nodes to destroyView', () => {
|
||||
@Component({template: '<div *ngIf="shown">hello</div>'})
|
||||
class MyComp {
|
||||
shown = true;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyComp]});
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
fixture.detectChanges();
|
||||
|
||||
destroyViewLogs.length = 0;
|
||||
|
||||
fixture.componentInstance.shown = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(destroyViewLogs).toEqual([[null, null]]);
|
||||
});
|
||||
|
||||
it('should project nodes', () => {
|
||||
@Component({template: '<child>hello</child>'})
|
||||
class Parent {
|
||||
}
|
||||
|
||||
@Component({selector: 'child', template: '(<ng-content></ng-content>)'})
|
||||
class Child {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Parent, Child]});
|
||||
const fixture = TestBed.createComponent(Parent);
|
||||
|
||||
expect(fixture.nativeElement).toHaveText('(hello)');
|
||||
const childHostEl = fixture.nativeElement.children[0];
|
||||
const projectedNode = childHostEl.childNodes[1];
|
||||
expect(directRenderer.appendChild).toHaveBeenCalledWith(projectedNode, childHostEl);
|
||||
});
|
||||
|
||||
it('should support using structural directives with ngTemplateOutlet', () => {
|
||||
@Component({
|
||||
template:
|
||||
'<child [templateCtx]="templateCtx"><ng-template let-shown="shown" #tpl><span *ngIf="shown">hello</span></ng-template></child>'
|
||||
})
|
||||
class Parent {
|
||||
templateCtx = {shown: false};
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'child',
|
||||
template:
|
||||
'(<ng-container [ngTemplateOutlet]="templateRef" [ngOutletContext]="templateCtx"></ng-container>)'
|
||||
})
|
||||
class Child {
|
||||
@Input()
|
||||
templateCtx: any;
|
||||
|
||||
@ContentChild('tpl')
|
||||
templateRef: TemplateRef<any>;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Parent, Child]});
|
||||
|
||||
let fixture = TestBed.createComponent(Parent);
|
||||
fixture.componentInstance.templateCtx.shown = false;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('()');
|
||||
fixture.destroy();
|
||||
|
||||
fixture = TestBed.createComponent(Parent);
|
||||
fixture.componentInstance.templateCtx.shown = true;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('(hello)');
|
||||
|
||||
fixture.componentInstance.templateCtx.shown = false;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement).toHaveText('()');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class DirectRootRenderer implements RootRenderer {
|
||||
constructor(private _delegate: DomRootRenderer) {}
|
||||
renderComponent(componentType: RenderComponentType): Renderer {
|
||||
const renderer = new DebugDomRenderer(this._delegate.renderComponent(componentType));
|
||||
(renderer as any).directRenderer = directRenderer;
|
||||
const originalDestroyView = renderer.destroyView;
|
||||
renderer.destroyView = function(...args: any[]) {
|
||||
destroyViewLogs.push(args);
|
||||
return originalDestroyView.apply(this, args);
|
||||
};
|
||||
return renderer;
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver} from '@angular/core';
|
||||
import {noComponentFactoryError} from '@angular/core/src/linker/component_factory_resolver';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
@ -15,19 +14,6 @@ import {Console} from '../../src/console';
|
||||
|
||||
|
||||
export function main() {
|
||||
describe('Current compiler', () => { createTests({viewEngine: false}); });
|
||||
|
||||
describe('View Engine compiler', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler(
|
||||
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
|
||||
});
|
||||
|
||||
createTests({viewEngine: true});
|
||||
});
|
||||
}
|
||||
|
||||
function createTests({viewEngine}: {viewEngine: boolean}) {
|
||||
describe('jit', () => { declareTests({useJit: true}); });
|
||||
describe('no jit', () => { declareTests({useJit: false}); });
|
||||
}
|
||||
|
@ -7,14 +7,13 @@
|
||||
*/
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {ComponentFactory, Host, Inject, Injectable, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, OnDestroy, ReflectiveInjector, SkipSelf} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection';
|
||||
import {getDebugContext} from '@angular/core/src/errors';
|
||||
import {ComponentFactoryResolver} from '@angular/core/src/linker/component_factory_resolver';
|
||||
import {ElementRef} from '@angular/core/src/linker/element_ref';
|
||||
import {QueryList} from '@angular/core/src/linker/query_list';
|
||||
import {TemplateRef, TemplateRef_} from '@angular/core/src/linker/template_ref';
|
||||
import {TemplateRef} from '@angular/core/src/linker/template_ref';
|
||||
import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
|
||||
import {EmbeddedViewRef} from '@angular/core/src/linker/view_ref';
|
||||
import {Attribute, Component, ContentChildren, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata';
|
||||
@ -30,27 +29,13 @@ import {stringify} from '../../src/facade/lang';
|
||||
const ANCHOR_ELEMENT = new InjectionToken('AnchorElement');
|
||||
|
||||
export function main() {
|
||||
describe('jit', () => { declareTests({useJit: true, viewEngine: false}); });
|
||||
describe('jit', () => { declareTests({useJit: true}); });
|
||||
|
||||
describe('no jit', () => { declareTests({useJit: false, viewEngine: false}); });
|
||||
|
||||
describe('view engine', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler({
|
||||
useJit: true,
|
||||
providers: [{
|
||||
provide: USE_VIEW_ENGINE,
|
||||
useValue: true,
|
||||
}],
|
||||
});
|
||||
});
|
||||
|
||||
declareTests({useJit: true, viewEngine: true});
|
||||
});
|
||||
describe('no jit', () => { declareTests({useJit: false}); });
|
||||
}
|
||||
|
||||
|
||||
function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolean}) {
|
||||
function declareTests({useJit}: {useJit: boolean}) {
|
||||
describe('integration tests', function() {
|
||||
|
||||
beforeEach(() => { TestBed.configureCompiler({useJit}); });
|
||||
@ -1290,7 +1275,7 @@ function declareTests({useJit, viewEngine}: {useJit: boolean, viewEngine: boolea
|
||||
});
|
||||
});
|
||||
|
||||
viewEngine || describe('error handling', () => {
|
||||
describe('error handling', () => {
|
||||
it('should report a meaningful error when a directive is missing annotation', () => {
|
||||
TestBed.configureTestingModule({declarations: [MyComp, SomeDirectiveMissingAnnotation]});
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {Component, Directive, ElementRef, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||
@ -14,19 +13,6 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||
|
||||
export function main() {
|
||||
describe('Current compiler', () => { createTests({viewEngine: false}); });
|
||||
|
||||
describe('View Engine compiler', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler(
|
||||
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
|
||||
});
|
||||
|
||||
createTests({viewEngine: true});
|
||||
});
|
||||
}
|
||||
|
||||
function createTests({viewEngine}: {viewEngine: boolean}) {
|
||||
describe('projection', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({declarations: [MainComp, OtherComp, Simple]}));
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, asNativeElements} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||
@ -14,19 +13,6 @@ import {expect} from '@angular/platform-browser/testing/matchers';
|
||||
import {stringify} from '../../src/facade/lang';
|
||||
|
||||
export function main() {
|
||||
describe('Current compiler', () => { createTests({viewEngine: false}); });
|
||||
|
||||
describe('View Engine compiler', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler(
|
||||
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
|
||||
});
|
||||
|
||||
createTests({viewEngine: true});
|
||||
});
|
||||
}
|
||||
|
||||
function createTests({viewEngine}: {viewEngine: boolean}) {
|
||||
describe('Query API', () => {
|
||||
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {USE_VIEW_ENGINE} from '@angular/compiler/src/config';
|
||||
import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, DebugElement, Directive, ElementRef, Host, Inject, InjectionToken, Input, Optional, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewContainerRef} from '@angular/core';
|
||||
import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
@ -184,19 +183,6 @@ class TestComp {
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe('Current compiler', () => { createTests({viewEngine: false}); });
|
||||
|
||||
describe('View Engine compiler', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler(
|
||||
{useJit: true, providers: [{provide: USE_VIEW_ENGINE, useValue: true}]});
|
||||
});
|
||||
|
||||
createTests({viewEngine: true});
|
||||
});
|
||||
}
|
||||
|
||||
function createTests({viewEngine}: {viewEngine: boolean}) {
|
||||
function createComponentFixture<T>(
|
||||
template: string, providers: Provider[] = null, comp: Type<T> = null): ComponentFixture<T> {
|
||||
if (!comp) {
|
||||
|
@ -1,115 +0,0 @@
|
||||
/**
|
||||
* @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 {AUTO_STYLE, AnimationPlayer} from '@angular/core';
|
||||
|
||||
export class MockAnimationPlayer implements AnimationPlayer {
|
||||
private _onDoneFns: Function[] = [];
|
||||
private _onStartFns: Function[] = [];
|
||||
private _onDestroyFns: Function[] = [];
|
||||
private _finished = false;
|
||||
private _destroyed = false;
|
||||
private _started = false;
|
||||
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
public previousStyles: {[styleName: string]: string | number} = {};
|
||||
|
||||
public log: any[] = [];
|
||||
|
||||
constructor(
|
||||
public startingStyles: {[key: string]: string | number} = {},
|
||||
public keyframes: Array<[number, {[style: string]: string | number}]> = [],
|
||||
previousPlayers: AnimationPlayer[] = []) {
|
||||
previousPlayers.forEach(player => {
|
||||
if (player instanceof MockAnimationPlayer) {
|
||||
const styles = player._captureStyles();
|
||||
Object.keys(styles).forEach(prop => this.previousStyles[prop] = styles[prop]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _onFinish(): void {
|
||||
if (!this._finished) {
|
||||
this._finished = true;
|
||||
this.log.push('finish');
|
||||
|
||||
this._onDoneFns.forEach(fn => fn());
|
||||
this._onDoneFns = [];
|
||||
}
|
||||
}
|
||||
|
||||
init(): void { this.log.push('init'); }
|
||||
|
||||
onDone(fn: () => void): void { this._onDoneFns.push(fn); }
|
||||
|
||||
onStart(fn: () => void): void { this._onStartFns.push(fn); }
|
||||
|
||||
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
|
||||
|
||||
hasStarted() { return this._started; }
|
||||
|
||||
play(): void {
|
||||
if (!this.hasStarted()) {
|
||||
this._onStartFns.forEach(fn => fn());
|
||||
this._onStartFns = [];
|
||||
this._started = true;
|
||||
}
|
||||
this.log.push('play');
|
||||
}
|
||||
|
||||
pause(): void { this.log.push('pause'); }
|
||||
|
||||
restart(): void { this.log.push('restart'); }
|
||||
|
||||
finish(): void { this._onFinish(); }
|
||||
|
||||
reset(): void {
|
||||
this.log.push('reset');
|
||||
this._destroyed = false;
|
||||
this._finished = false;
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
if (!this._destroyed) {
|
||||
this._destroyed = true;
|
||||
this.finish();
|
||||
this.log.push('destroy');
|
||||
this._onDestroyFns.forEach(fn => fn());
|
||||
this._onDestroyFns = [];
|
||||
}
|
||||
}
|
||||
|
||||
setPosition(p: number): void {}
|
||||
getPosition(): number { return 0; }
|
||||
|
||||
private _captureStyles(): {[styleName: string]: string | number} {
|
||||
const captures: {[prop: string]: string | number} = {};
|
||||
|
||||
if (this.hasStarted()) {
|
||||
// when assembling the captured styles, it's important that
|
||||
// we build the keyframe styles in the following order:
|
||||
// {startingStyles, ... other styles within keyframes, ... previousStyles }
|
||||
Object.keys(this.startingStyles).forEach(prop => {
|
||||
captures[prop] = this.startingStyles[prop];
|
||||
});
|
||||
|
||||
this.keyframes.forEach(kf => {
|
||||
const [offset, styles] = kf;
|
||||
const newStyles: {[prop: string]: string | number} = {};
|
||||
Object.keys(styles).forEach(
|
||||
prop => { captures[prop] = this._finished ? styles[prop] : AUTO_STYLE; });
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(this.previousStyles).forEach(prop => {
|
||||
captures[prop] = this.previousStyles[prop];
|
||||
});
|
||||
|
||||
return captures;
|
||||
}
|
||||
}
|
@ -6,5 +6,4 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export {MockAnimationPlayer as ɵMockAnimationPlayer} from './mock_animation_player';
|
||||
export {TestingCompiler as ɵTestingCompiler, TestingCompilerFactory as ɵTestingCompilerFactory} from './test_compiler';
|
||||
|
@ -14,7 +14,6 @@ import {global} from './facade/lang';
|
||||
import {getTestBed, inject} from './test_bed';
|
||||
|
||||
export {AsyncTestCompleter} from './async_test_completer';
|
||||
export {MockAnimationPlayer} from './mock_animation_player';
|
||||
export {inject} from './test_bed';
|
||||
|
||||
export * from './logger';
|
||||
|
Reference in New Issue
Block a user