diff --git a/modules/@angular/compiler-cli/integrationtest/src/animate.ts b/modules/@angular/compiler-cli/integrationtest/src/animate.ts
new file mode 100644
index 0000000000..2044716dd1
--- /dev/null
+++ b/modules/@angular/compiler-cli/integrationtest/src/animate.ts
@@ -0,0 +1,34 @@
+import {Component, trigger, state, animate, transition, style} from '@angular/core';
+
+@Component({
+ selector: "animate-cmp",
+ animations: [
+ trigger('openClose', [
+ state('closed, void',
+ style({ height:"0px", color: "maroon", borderColor: "maroon" })),
+ state('open',
+ style({ height:"*", borderColor:"green", color:"green" })),
+ transition("* => *", animate(500))
+ ])
+ ],
+ template: `
+
+
+
+
+ Look at this box
+
+ `
+})
+export class AnimateCmp {
+ stateExpression:string;
+ constructor() {
+ this.setAsClosed();
+ }
+ setAsOpen() {
+ this.stateExpression = 'open';
+ }
+ setAsClosed() {
+ this.stateExpression = 'closed';
+ }
+}
diff --git a/modules/@angular/compiler-cli/integrationtest/test/animate_spec.ts b/modules/@angular/compiler-cli/integrationtest/test/animate_spec.ts
new file mode 100644
index 0000000000..8c2f8ed1ca
--- /dev/null
+++ b/modules/@angular/compiler-cli/integrationtest/test/animate_spec.ts
@@ -0,0 +1,40 @@
+require('reflect-metadata');
+require('@angular/platform-server/src/parse5_adapter.js').Parse5DomAdapter.makeCurrent();
+require('zone.js/dist/zone-node.js');
+require('zone.js/dist/long-stack-trace-zone.js');
+
+import {AnimateCmpNgFactory} from '../src/animate.ngfactory';
+import {AUTO_STYLE, ReflectiveInjector, DebugElement, getDebugNode} from '@angular/core';
+import {browserPlatform, BROWSER_APP_PROVIDERS} from '@angular/platform-browser';
+
+describe("template codegen output", () => {
+ it("should apply the animate states to the element", (done) => {
+ const appInjector = ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS,
+ browserPlatform().injector);
+ var comp = AnimateCmpNgFactory.create(appInjector);
+ var debugElement = getDebugNode(comp.location.nativeElement);
+
+ // the open-close-container is a child of the main container
+ // if the template changes then please update the location below
+ var targetDebugElement = debugElement.children[3];
+
+ comp.instance.setAsOpen();
+ comp.changeDetectorRef.detectChanges();
+
+ setTimeout(() => {
+ expect(targetDebugElement.styles['height']).toEqual(AUTO_STYLE);
+ expect(targetDebugElement.styles['borderColor']).toEqual('green');
+ expect(targetDebugElement.styles['color']).toEqual('green');
+
+ comp.instance.setAsClosed();
+ comp.changeDetectorRef.detectChanges();
+
+ setTimeout(() => {
+ expect(targetDebugElement.styles['height']).toEqual("0px");
+ expect(targetDebugElement.styles['borderColor']).toEqual('maroon');
+ expect(targetDebugElement.styles['color']).toEqual('maroon');
+ done();
+ }, 0);
+ }, 0);
+ });
+});
diff --git a/modules/@angular/compiler-cli/src/reflector_host.ts b/modules/@angular/compiler-cli/src/reflector_host.ts
index 35b5c1aaf8..69bcb4bfbe 100644
--- a/modules/@angular/compiler-cli/src/reflector_host.ts
+++ b/modules/@angular/compiler-cli/src/reflector_host.ts
@@ -19,6 +19,7 @@ export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator {
coreDecorators: '@angular/core/src/metadata',
diDecorators: '@angular/core/src/di/decorators',
diMetadata: '@angular/core/src/di/metadata',
+ animationMetadata: '@angular/core/src/animation/metadata',
provider: '@angular/core/src/di/provider'
};
}
diff --git a/modules/@angular/compiler-cli/src/static_reflector.ts b/modules/@angular/compiler-cli/src/static_reflector.ts
index cb9e61c32f..f5ec5cd615 100644
--- a/modules/@angular/compiler-cli/src/static_reflector.ts
+++ b/modules/@angular/compiler-cli/src/static_reflector.ts
@@ -20,6 +20,14 @@ import {
SelfMetadata,
SkipSelfMetadata,
InjectMetadata,
+ trigger,
+ state,
+ transition,
+ sequence,
+ group,
+ animate,
+ style,
+ keyframes
} from "@angular/core";
import {ReflectorReader} from "./core_private";
@@ -50,7 +58,7 @@ export interface StaticReflectorHost {
getStaticSymbol(declarationFile: string, name: string): StaticSymbol;
angularImportLocations():
- {coreDecorators: string, diDecorators: string, diMetadata: string, provider: string};
+ {coreDecorators: string, diDecorators: string, diMetadata: string, animationMetadata: string, provider: string};
}
/**
@@ -181,8 +189,19 @@ export class StaticReflector implements ReflectorReader {
});
}
+ private registerFunction(type: StaticSymbol, fn: any): void {
+ this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => {
+ let argValues: any[] = [];
+ args.forEach((arg, index) => {
+ let argValue = this.simplify(context, arg);
+ argValues.push(argValue);
+ });
+ return fn.apply(null, argValues);
+ });
+ }
+
private initializeConversionMap(): void {
- const {coreDecorators, diDecorators, diMetadata, provider} = this.host.angularImportLocations();
+ const {coreDecorators, diDecorators, diMetadata, animationMetadata, provider} = this.host.angularImportLocations();
this.registerDecoratorOrConstructor(this.host.findDeclaration(provider, 'Provider'), Provider);
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'),
@@ -235,6 +254,15 @@ export class StaticReflector implements ReflectorReader {
SkipSelfMetadata);
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'OptionalMetadata'),
OptionalMetadata);
+
+ this.registerFunction(this.host.findDeclaration(animationMetadata, 'trigger'), trigger);
+ this.registerFunction(this.host.findDeclaration(animationMetadata, 'state'), state);
+ this.registerFunction(this.host.findDeclaration(animationMetadata, 'transition'), transition);
+ this.registerFunction(this.host.findDeclaration(animationMetadata, 'style'), style);
+ this.registerFunction(this.host.findDeclaration(animationMetadata, 'animate'), animate);
+ this.registerFunction(this.host.findDeclaration(animationMetadata, 'keyframes'), keyframes);
+ this.registerFunction(this.host.findDeclaration(animationMetadata, 'sequence'), sequence);
+ this.registerFunction(this.host.findDeclaration(animationMetadata, 'group'), group);
}
/** @internal */
diff --git a/modules/@angular/compiler-cli/test/static_reflector_spec.ts b/modules/@angular/compiler-cli/test/static_reflector_spec.ts
index 70bc017d4b..d1c75ba09f 100644
--- a/modules/@angular/compiler-cli/test/static_reflector_spec.ts
+++ b/modules/@angular/compiler-cli/test/static_reflector_spec.ts
@@ -15,6 +15,8 @@ import {
StaticSymbol
} from '@angular/compiler-cli/src/static_reflector';
+import {transition, sequence, group, trigger, state, style, animate, keyframes} from '@angular/core';
+
describe('StaticReflector', () => {
let noContext = new StaticSymbol('', '');
let host: StaticReflectorHost;
@@ -62,6 +64,19 @@ describe('StaticReflector', () => {
expect(annotation.selector).toEqual('my-hero-detail');
expect(annotation.directives)
.toEqual([[host.findDeclaration('angular2/src/common/directives/ng_for', 'NgFor')]]);
+ expect(annotation.animations).toEqual([
+ trigger("myAnimation", [
+ state("state1", style({ "background": "white" })),
+ transition("* => *", sequence([
+ group([
+ animate("1s 0.5s", keyframes([
+ style({ "background": "blue"}),
+ style({ "background": "red"})
+ ]))
+ ])
+ ]))
+ ])
+ ]);
});
it('should throw and exception for unsupported metadata versions', () => {
@@ -252,6 +267,7 @@ class MockReflectorHost implements StaticReflectorHost {
coreDecorators: 'angular2/src/core/metadata',
diDecorators: 'angular2/src/core/di/decorators',
diMetadata: 'angular2/src/core/di/metadata',
+ animationMetadata: 'angular2/src/core/animation/metadata',
provider: 'angular2/src/core/di/provider'
};
}
@@ -405,11 +421,100 @@ class MockReflectorHost implements StaticReflectorHost {
"name": "FORM_DIRECTIVES",
"module": "angular2/src/common/forms/directives"
}
+ ],
+ "animations": [{
+ "__symbolic": "call",
+ "expression": {
+ "__symbolic": "reference",
+ "name": "trigger",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments": [
+ "myAnimation",
+ [{ "__symbolic": "call",
+ "expression": {
+ "__symbolic": "reference",
+ "name": "state",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments": [
+ "state1",
+ { "__symbolic": "call",
+ "expression": {
+ "__symbolic": "reference",
+ "name": "style",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments": [
+ { "background":"white" }
+ ]
+ }
+ ]
+ }, {
+ "__symbolic": "call",
+ "expression": {
+ "__symbolic":"reference",
+ "name":"transition",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments": [
+ "* => *",
+ {
+ "__symbolic":"call",
+ "expression":{
+ "__symbolic":"reference",
+ "name":"sequence",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments":[[{ "__symbolic": "call",
+ "expression": {
+ "__symbolic":"reference",
+ "name":"group",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments":[[{
+ "__symbolic": "call",
+ "expression": {
+ "__symbolic":"reference",
+ "name":"animate",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments":[
+ "1s 0.5s",
+ { "__symbolic": "call",
+ "expression": {
+ "__symbolic":"reference",
+ "name":"keyframes",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments":[[{ "__symbolic": "call",
+ "expression": {
+ "__symbolic":"reference",
+ "name":"style",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments":[ { "background": "blue"} ]
+ }, {
+ "__symbolic": "call",
+ "expression": {
+ "__symbolic":"reference",
+ "name":"style",
+ "module": "angular2/src/core/animation/metadata"
+ },
+ "arguments":[ { "background": "red"} ]
+ }]]
+ }
+ ]
+ }]]
+ }]]
+ }
+ ]
+ }
+ ]
]
- }
- ]
- }
- ],
+ }]
+ }]
+ }],
"members": {
"hero": [
{
diff --git a/modules/@angular/compiler/core_private.ts b/modules/@angular/compiler/core_private.ts
index f63d28e797..9151e5de27 100644
--- a/modules/@angular/compiler/core_private.ts
+++ b/modules/@angular/compiler/core_private.ts
@@ -74,10 +74,13 @@ export type AnimationGroupPlayer = t.AnimationGroupPlayer;
export var AnimationGroupPlayer: typeof t.AnimationGroupPlayer = r.AnimationGroupPlayer;
export type AnimationKeyframe = t.AnimationKeyframe;
export var AnimationKeyframe: typeof t.AnimationKeyframe = r.AnimationKeyframe;
-export type AnimationStyleUtil = t.AnimationStyleUtil;
-export var AnimationStyleUtil: typeof t.AnimationStyleUtil = r.AnimationStyleUtil;
-export type AnimationStylrs = t.AnimationStyles;
+export type AnimationStyles = t.AnimationStyles;
export var AnimationStyles: typeof t.AnimationStyles = r.AnimationStyles;
export var ANY_STATE = r.ANY_STATE;
export var EMPTY_STATE = r.EMPTY_STATE;
export var FILL_STYLE_FLAG = r.FILL_STYLE_FLAG;
+export var balanceAnimationStyles: typeof t.balanceAnimationStyles = r.balanceAnimationStyles;
+export var balanceAnimationKeyframes: typeof t.balanceAnimationKeyframes = r.balanceAnimationKeyframes;
+export var flattenStyles: typeof t.flattenStyles = r.flattenStyles;
+export var clearStyles: typeof t.clearStyles = r.clearStyles;
+export var collectAndResolveStyles: typeof r.collectAndResolveStyles = r.collectAndResolveStyles;
diff --git a/modules/@angular/compiler/src/animation/animation_compiler.ts b/modules/@angular/compiler/src/animation/animation_compiler.ts
index fc8cc3d0ca..e29e2c12ac 100644
--- a/modules/@angular/compiler/src/animation/animation_compiler.ts
+++ b/modules/@angular/compiler/src/animation/animation_compiler.ts
@@ -249,7 +249,7 @@ class _AnimationBuilder implements AnimationAstVisitor {
statements.push(
_ANIMATION_FACTORY_RENDERER_VAR.callMethod('setElementStyles', [
_ANIMATION_FACTORY_ELEMENT_VAR,
- o.importExpr(Identifiers.clearAnimationStyles).callFn([_ANIMATION_START_STATE_STYLES_VAR])
+ o.importExpr(Identifiers.clearStyles).callFn([_ANIMATION_START_STATE_STYLES_VAR])
]).toStmt());
ast.stateTransitions.forEach(transAst => statements.push(transAst.visit(this, context)));
@@ -287,7 +287,7 @@ class _AnimationBuilder implements AnimationAstVisitor {
]).toStmt());
return o.fn([
- new o.FnParam(_ANIMATION_FACTORY_VIEW_VAR.name, o.importType(Identifiers.AppView)),
+ new o.FnParam(_ANIMATION_FACTORY_VIEW_VAR.name, o.importType(Identifiers.AppView, [o.DYNAMIC_TYPE])),
new o.FnParam(_ANIMATION_FACTORY_ELEMENT_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(_ANIMATION_CURRENT_STATE_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(_ANIMATION_NEXT_STATE_VAR.name, o.DYNAMIC_TYPE)
diff --git a/modules/@angular/compiler/src/identifiers.ts b/modules/@angular/compiler/src/identifiers.ts
index d656002a71..a880f9abf9 100644
--- a/modules/@angular/compiler/src/identifiers.ts
+++ b/modules/@angular/compiler/src/identifiers.ts
@@ -45,7 +45,10 @@ import {
NoOpAnimationPlayer as NoOpAnimationPlayer_,
AnimationGroupPlayer as AnimationGroupPlayer_,
AnimationSequencePlayer as AnimationSequencePlayer_,
- AnimationStyleUtil,
+ balanceAnimationStyles as impBalanceAnimationStyles,
+ balanceAnimationKeyframes as impBalanceAnimationKeyframes,
+ clearStyles as impClearStyles,
+ collectAndResolveStyles as impCollectAndResolveStyles,
SecurityContext
} from '../core_private';
@@ -245,22 +248,22 @@ export class Identifiers {
static balanceAnimationStyles = new CompileIdentifierMetadata({
name: 'balanceAnimationStyles',
moduleUrl: ANIMATION_STYLE_UTIL_ASSET_URL,
- runtime: AnimationStyleUtil.balanceStyles
+ runtime: impBalanceAnimationStyles
});
static balanceAnimationKeyframes = new CompileIdentifierMetadata({
name: 'balanceAnimationKeyframes',
moduleUrl: ANIMATION_STYLE_UTIL_ASSET_URL,
- runtime: AnimationStyleUtil.balanceKeyframes
+ runtime: impBalanceAnimationKeyframes
});
- static clearAnimationStyles = new CompileIdentifierMetadata({
- name: 'clearAnimationStyles',
+ static clearStyles = new CompileIdentifierMetadata({
+ name: 'clearStyles',
moduleUrl: ANIMATION_STYLE_UTIL_ASSET_URL,
- runtime: AnimationStyleUtil.clearStyles
+ runtime: impClearStyles
});
static collectAndResolveStyles = new CompileIdentifierMetadata({
name: 'collectAndResolveStyles',
moduleUrl: ANIMATION_STYLE_UTIL_ASSET_URL,
- runtime: AnimationStyleUtil.collectAndResolveStyles
+ runtime: impCollectAndResolveStyles
});
}
diff --git a/modules/@angular/compiler/test/animation/animation_parser_spec.ts b/modules/@angular/compiler/test/animation/animation_parser_spec.ts
index 9b37b5831e..f44e7a77e0 100644
--- a/modules/@angular/compiler/test/animation/animation_parser_spec.ts
+++ b/modules/@angular/compiler/test/animation/animation_parser_spec.ts
@@ -44,7 +44,7 @@ import {
AnimationStepAst
} from '../../src/animation/animation_ast';
-import {FILL_STYLE_FLAG, AnimationStyleUtil} from '../../core_private';
+import {FILL_STYLE_FLAG, flattenStyles} from '../../core_private';
import {StringMapWrapper} from '../../src/facade/collection';
@@ -348,7 +348,7 @@ export function main() {
var kf1 = keyframesStep.keyframes[0];
var kf2 = keyframesStep.keyframes[1];
- expect(AnimationStyleUtil.flattenStyles(kf1.styles.styles)).toEqual({
+ expect(flattenStyles(kf1.styles.styles)).toEqual({
"color": "red",
"background": FILL_STYLE_FLAG
});
@@ -368,7 +368,7 @@ export function main() {
var kf2 = keyframesStep.keyframes[1];
var kf3 = keyframesStep.keyframes[2];
- expect(AnimationStyleUtil.flattenStyles(kf3.styles.styles)).toEqual({
+ expect(flattenStyles(kf3.styles.styles)).toEqual({
"background": "blue",
"color": "red",
"border-color": "white"
@@ -390,7 +390,7 @@ export function main() {
var kf3 = keyframesStep.keyframes[2];
expect(kf1.offset).toEqual(0);
- expect(AnimationStyleUtil.flattenStyles(kf1.styles.styles)).toEqual({
+ expect(flattenStyles(kf1.styles.styles)).toEqual({
"font-size": FILL_STYLE_FLAG,
"background": FILL_STYLE_FLAG,
"color": FILL_STYLE_FLAG
@@ -412,7 +412,7 @@ export function main() {
var kf3 = keyframesStep.keyframes[2];
expect(kf3.offset).toEqual(1);
- expect(AnimationStyleUtil.flattenStyles(kf3.styles.styles)).toEqual({
+ expect(flattenStyles(kf3.styles.styles)).toEqual({
"color": "orange",
"background": "red",
"transform": "rotate(360deg)",
diff --git a/modules/@angular/core/private_export.ts b/modules/@angular/core/private_export.ts
index c9db551a98..5a72553425 100644
--- a/modules/@angular/core/private_export.ts
+++ b/modules/@angular/core/private_export.ts
@@ -35,8 +35,8 @@ import {
import {AnimationSequencePlayer as AnimationSequencePlayer_} from './src/animation/animation_sequence_player';
import {AnimationGroupPlayer as AnimationGroupPlayer_} from './src/animation/animation_group_player';
import {AnimationKeyframe as AnimationKeyframe_} from './src/animation/animation_keyframe';
-import {AnimationStyleUtil as AnimationStyleUtil_} from './src/animation/animation_style_util';
import {AnimationStyles as AnimationStyles_} from './src/animation/animation_styles';
+import * as animationUtils from './src/animation/animation_style_util';
import {
ANY_STATE as ANY_STATE_,
EMPTY_STATE as EMPTY_STATE_,
@@ -121,8 +121,11 @@ export declare namespace __core_private_types__ {
export var AnimationGroupPlayer: typeof AnimationGroupPlayer_;
export type AnimationKeyframe = AnimationKeyframe_;
export var AnimationKeyframe: typeof AnimationKeyframe_;
- export type AnimationStyleUtil = AnimationStyleUtil_;
- export var AnimationStyleUtil: typeof AnimationStyleUtil_;
+ export var balanceAnimationStyles: typeof animationUtils.balanceAnimationStyles;
+ export var balanceAnimationKeyframes: typeof animationUtils.balanceAnimationKeyframes;
+ export var flattenStyles: typeof animationUtils.flattenStyles;
+ export var clearStyles: typeof animationUtils.clearStyles;
+ export var collectAndResolveStyles: typeof animationUtils.collectAndResolveStyles;
export type AnimationStyles = AnimationStyles_;
export var AnimationStyles: typeof AnimationStyles_;
export var ANY_STATE: typeof ANY_STATE_;
@@ -187,7 +190,11 @@ export var __core_private__ = {
AnimationSequencePlayer: AnimationSequencePlayer_,
AnimationGroupPlayer: AnimationGroupPlayer_,
AnimationKeyframe: AnimationKeyframe_,
- AnimationStyleUtil: AnimationStyleUtil_,
+ balanceAnimationStyles: animationUtils.balanceAnimationStyles,
+ balanceAnimationKeyframes: animationUtils.balanceAnimationKeyframes,
+ flattenStyles: animationUtils.flattenStyles,
+ clearStyles: animationUtils.clearStyles,
+ collectAndResolveStyles: animationUtils.collectAndResolveStyles,
AnimationStyles: AnimationStyles_,
ANY_STATE: ANY_STATE_,
EMPTY_STATE: EMPTY_STATE_,
diff --git a/modules/@angular/core/src/animation/animation_style_util.ts b/modules/@angular/core/src/animation/animation_style_util.ts
index 03ef5cf8d7..c05dbed583 100644
--- a/modules/@angular/core/src/animation/animation_style_util.ts
+++ b/modules/@angular/core/src/animation/animation_style_util.ts
@@ -3,111 +3,110 @@ import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {AUTO_STYLE} from './metadata';
import {FILL_STYLE_FLAG} from './animation_constants';
-export class AnimationStyleUtil {
- static balanceStyles(previousStyles: {[key: string]: string|number},
- newStyles: {[key: string]: string|number},
- nullValue = null): {[key: string]: string|number} {
- var finalStyles: {[key: string]: string|number} = {};
+export function balanceAnimationStyles(previousStyles: {[key: string]: string|number},
+ newStyles: {[key: string]: string|number},
+ nullValue = null): {[key: string]: string} {
+ var finalStyles: {[key: string]: string} = {};
- StringMapWrapper.forEach(newStyles, (value, prop) => {
+ StringMapWrapper.forEach(newStyles, (value, prop) => {
+ finalStyles[prop] = value.toString();
+ });
+
+ StringMapWrapper.forEach(previousStyles, (value, 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[] {
+ var limit = keyframes.length - 1;
+ var firstKeyframe = keyframes[0];
+
+ // phase 1: copy all the styles from the first keyframe into the lookup map
+ var flatenedFirstKeyframeStyles = flattenStyles(firstKeyframe.styles.styles);
+
+ var extraFirstKeyframeStyles = {};
+ var hasExtraFirstStyles = false;
+ StringMapWrapper.forEach(collectedStyles, (value, prop) => {
+ // if the style is already defined in the first keyframe then
+ // we do not replace it.
+ if (!flatenedFirstKeyframeStyles[prop]) {
+ flatenedFirstKeyframeStyles[prop] = value;
+ extraFirstKeyframeStyles[prop] = value;
+ hasExtraFirstStyles = true;
+ }
+ });
+
+ var keyframeCollectedStyles = StringMapWrapper.merge({}, flatenedFirstKeyframeStyles);
+
+ // phase 2: normalize the final keyframe
+ var finalKeyframe = keyframes[limit];
+ ListWrapper.insert(finalKeyframe.styles.styles, 0, finalStateStyles);
+
+ var flatenedFinalKeyframeStyles = flattenStyles(finalKeyframe.styles.styles);
+ var extraFinalKeyframeStyles = {};
+ var hasExtraFinalStyles = false;
+ StringMapWrapper.forEach(keyframeCollectedStyles, (value, prop) => {
+ if (!isPresent(flatenedFinalKeyframeStyles[prop])) {
+ extraFinalKeyframeStyles[prop] = AUTO_STYLE;
+ hasExtraFinalStyles = true;
+ }
+ });
+
+ if (hasExtraFinalStyles) {
+ finalKeyframe.styles.styles.push(extraFinalKeyframeStyles);
+ }
+
+ StringMapWrapper.forEach(flatenedFinalKeyframeStyles, (value, prop) => {
+ if (!isPresent(flatenedFirstKeyframeStyles[prop])) {
+ extraFirstKeyframeStyles[prop] = AUTO_STYLE;
+ hasExtraFirstStyles = true;
+ }
+ });
+
+ if (hasExtraFirstStyles) {
+ firstKeyframe.styles.styles.push(extraFirstKeyframeStyles);
+ }
+
+ return keyframes;
+}
+
+export function clearStyles(styles: {[key: string]: string|number}): {[key: string]: string} {
+ var finalStyles: {[key: string]: string} = {};
+ StringMapWrapper.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 => {
+ var stylesObj = {};
+ StringMapWrapper.forEach(entry, (value, prop) => {
+ if (value == FILL_STYLE_FLAG) {
+ value = collection[prop];
+ if (!isPresent(value)) {
+ value = AUTO_STYLE;
+ }
+ }
+ collection[prop] = value;
+ stylesObj[prop] = value;
+ });
+ return stylesObj;
+ });
+}
+
+export function flattenStyles(styles: {[key: string]: string|number}[]) {
+ var finalStyles = {};
+ styles.forEach(entry => {
+ StringMapWrapper.forEach(entry, (value, prop) => {
finalStyles[prop] = value;
});
-
- StringMapWrapper.forEach(previousStyles, (value, prop) => {
- if (!isPresent(finalStyles[prop])) {
- finalStyles[prop] = nullValue;
- }
- });
-
- return finalStyles;
- }
- static balanceKeyframes(collectedStyles: {[key: string]: string|number},
- finalStateStyles: {[key: string]: string|number},
- keyframes: any[]): any[] {
- var limit = keyframes.length - 1;
- var firstKeyframe = keyframes[0];
-
- // phase 1: copy all the styles from the first keyframe into the lookup map
- var flatenedFirstKeyframeStyles = AnimationStyleUtil.flattenStyles(firstKeyframe.styles.styles);
-
- var extraFirstKeyframeStyles = {};
- var hasExtraFirstStyles = false;
- StringMapWrapper.forEach(collectedStyles, (value, prop) => {
- // if the style is already defined in the first keyframe then
- // we do not replace it.
- if (!flatenedFirstKeyframeStyles[prop]) {
- flatenedFirstKeyframeStyles[prop] = value;
- extraFirstKeyframeStyles[prop] = value;
- hasExtraFirstStyles = true;
- }
- });
-
- var keyframeCollectedStyles = StringMapWrapper.merge({}, flatenedFirstKeyframeStyles);
-
- // phase 2: normalize the final keyframe
- var finalKeyframe = keyframes[limit];
- ListWrapper.insert(finalKeyframe.styles.styles, 0, finalStateStyles);
-
- var flatenedFinalKeyframeStyles = AnimationStyleUtil.flattenStyles(finalKeyframe.styles.styles);
- var extraFinalKeyframeStyles = {};
- var hasExtraFinalStyles = false;
- StringMapWrapper.forEach(keyframeCollectedStyles, (value, prop) => {
- if (!isPresent(flatenedFinalKeyframeStyles[prop])) {
- extraFinalKeyframeStyles[prop] = AUTO_STYLE;
- hasExtraFinalStyles = true;
- }
- });
-
- if (hasExtraFinalStyles) {
- finalKeyframe.styles.styles.push(extraFinalKeyframeStyles);
- }
-
- StringMapWrapper.forEach(flatenedFinalKeyframeStyles, (value, prop) => {
- if (!isPresent(flatenedFirstKeyframeStyles[prop])) {
- extraFirstKeyframeStyles[prop] = AUTO_STYLE;
- hasExtraFirstStyles = true;
- }
- });
-
- if (hasExtraFirstStyles) {
- firstKeyframe.styles.styles.push(extraFirstKeyframeStyles);
- }
-
- return keyframes;
- }
-
- static clearStyles(styles: {[key: string]: string|number}): {[key: string]: string|number} {
- var finalStyles: {[key: string]: string|number} = {};
- StringMapWrapper.keys(styles).forEach(key => {
- finalStyles[key] = null;
- });
- return finalStyles;
- }
-
- static collectAndResolveStyles(collection: {[key: string]: string|number}, styles: {[key: string]: string|number}[]) {
- return styles.map(entry => {
- var stylesObj = {};
- StringMapWrapper.forEach(entry, (value, prop) => {
- if (value == FILL_STYLE_FLAG) {
- value = collection[prop];
- if (!isPresent(value)) {
- value = AUTO_STYLE;
- }
- }
- collection[prop] = value;
- stylesObj[prop] = value;
- });
- return stylesObj;
- });
- }
-
- static flattenStyles(styles: {[key: string]: string|number}[]) {
- var finalStyles = {};
- styles.forEach(entry => {
- StringMapWrapper.forEach(entry, (value, prop) => {
- finalStyles[prop] = value;
- });
- });
- return finalStyles;
- }
+ });
+ return finalStyles;
}
diff --git a/modules/@angular/core/test/animation/animation_integration_spec.ts b/modules/@angular/core/test/animation/animation_integration_spec.ts
index c2ab427e8d..a7e1623980 100644
--- a/modules/@angular/core/test/animation/animation_integration_spec.ts
+++ b/modules/@angular/core/test/animation/animation_integration_spec.ts
@@ -33,8 +33,6 @@ import {AnimationDriver} from '../../src/animation/animation_driver';
import {MockAnimationDriver} from '../../testing/animation/mock_animation_driver';
import {trigger, state, transition, keyframes, style, animate, group, sequence, AnimationEntryMetadata} from '../../src/animation/metadata';
-import {AnimationStyleUtil} from '../../src/animation/animation_style_util';
-
import {AUTO_STYLE} from '../../src/animation/metadata';
export function main() {
diff --git a/modules/@angular/core/test/animation/animation_style_util_spec.ts b/modules/@angular/core/test/animation/animation_style_util_spec.ts
index 474b452abd..bb320e7ee6 100644
--- a/modules/@angular/core/test/animation/animation_style_util_spec.ts
+++ b/modules/@angular/core/test/animation/animation_style_util_spec.ts
@@ -21,7 +21,7 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {isPresent} from '../../src/facade/lang';
import {MockAnimationPlayer} from '../../testing/animation/mock_animation_player';
-import {AnimationStyleUtil} from '../../src/animation/animation_style_util';
+import * as animationUtils from '../../src/animation/animation_style_util';
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
import {AnimationStyles} from '../../src/animation/animation_styles';
@@ -29,14 +29,14 @@ import {FILL_STYLE_FLAG} from '../../src/animation/animation_constants';
import {AUTO_STYLE} from '../../src/animation/metadata';
export function main() {
- describe('AnimationStyleUtil', function() {
+ describe('Animation Style Utils', function() {
- describe('balanceStyles', () => {
+ describe('balanceAnimationStyles', () => {
it('should set all non-shared styles to the provided null value between the two sets of styles', () => {
var styles = { opacity: 0, color: 'red' };
var newStyles = { background: 'red' };
var flag = '*';
- var result = AnimationStyleUtil.balanceStyles(styles, newStyles, flag);
+ var result = animationUtils.balanceAnimationStyles(styles, newStyles, flag);
expect(result).toEqual({
opacity:flag,
color:flag,
@@ -47,17 +47,17 @@ export function main() {
it('should handle an empty set of styles', () => {
var value = '*';
- expect(AnimationStyleUtil.balanceStyles({}, { opacity: 0 }, value)).toEqual({
- opacity: 0
+ expect(animationUtils.balanceAnimationStyles({}, { opacity: '0' }, value)).toEqual({
+ opacity: '0'
});
- expect(AnimationStyleUtil.balanceStyles({ opacity: 0 }, {}, value)).toEqual({
+ expect(animationUtils.balanceAnimationStyles({ opacity: '0' }, {}, value)).toEqual({
opacity: value
});
});
});
- describe('balanceKeyframes', () => {
+ describe('balanceAnimationKeyframes', () => {
it('should balance both the starting and final keyframes with thep provided styles', () => {
var collectedStyles = {
width: 100,
@@ -74,9 +74,9 @@ export function main() {
new AnimationKeyframe(1, new AnimationStyles([{ background: 'blue', left: '100px', top: '100px' }]))
];
- var result = AnimationStyleUtil.balanceKeyframes(collectedStyles, finalStyles, keyframes);
+ var result = animationUtils.balanceAnimationKeyframes(collectedStyles, finalStyles, keyframes);
- expect(AnimationStyleUtil.flattenStyles(result[0].styles.styles)).toEqual({
+ expect(animationUtils.flattenStyles(result[0].styles.styles)).toEqual({
"width": 100,
"height": 100,
"opacity": 1,
@@ -86,7 +86,7 @@ export function main() {
"top": '*'
});
- expect(AnimationStyleUtil.flattenStyles(result[1].styles.styles)).toEqual({
+ expect(animationUtils.flattenStyles(result[1].styles.styles)).toEqual({
"width": '*',
"height": '*',
"opacity": '*',
@@ -103,15 +103,15 @@ export function main() {
new AnimationKeyframe(1, new AnimationStyles([{ width: 100 }]))
];
- var result = AnimationStyleUtil.balanceKeyframes({}, {}, keyframes);
+ var result = animationUtils.balanceAnimationKeyframes({}, {}, keyframes);
- expect(AnimationStyleUtil.flattenStyles(result[0].styles.styles)).toEqual({
+ expect(animationUtils.flattenStyles(result[0].styles.styles)).toEqual({
"height": 100,
"opacity": 1,
"width": "*"
});
- expect(AnimationStyleUtil.flattenStyles(result[1].styles.styles)).toEqual({
+ expect(animationUtils.flattenStyles(result[1].styles.styles)).toEqual({
"width": 100,
"height": "*",
"opacity": "*"
@@ -131,11 +131,11 @@ export function main() {
"width": null,
"color": null
};
- expect(AnimationStyleUtil.clearStyles(styles)).toEqual(expectedResult);
+ expect(animationUtils.clearStyles(styles)).toEqual(expectedResult);
});
it('should handle an empty set of styles', () => {
- expect(AnimationStyleUtil.clearStyles({})).toEqual({});
+ expect(animationUtils.clearStyles({})).toEqual({});
});
});
@@ -153,13 +153,13 @@ export function main() {
var collection: {[key: string]: string|number} = {};
- expect(AnimationStyleUtil.collectAndResolveStyles(collection, styles1)).toEqual(styles1);
+ expect(animationUtils.collectAndResolveStyles(collection, styles1)).toEqual(styles1);
expect(collection).toEqual({
"opacity": 0,
"width": 100
});
- expect(AnimationStyleUtil.collectAndResolveStyles(collection, styles2)).toEqual(styles2);
+ expect(animationUtils.collectAndResolveStyles(collection, styles2)).toEqual(styles2);
expect(collection).toEqual({
"opacity": 1,
"width": 100,
@@ -180,12 +180,12 @@ export function main() {
var collection = {};
- expect(AnimationStyleUtil.collectAndResolveStyles(collection, styles1)).toEqual([{
+ expect(animationUtils.collectAndResolveStyles(collection, styles1)).toEqual([{
"opacity": 0,
"width": AUTO_STYLE
}]);
- expect(AnimationStyleUtil.collectAndResolveStyles(collection, styles2)).toEqual([{
+ expect(animationUtils.collectAndResolveStyles(collection, styles2)).toEqual([{
"opacity": 0,
"height": 999
}]);
diff --git a/modules/@angular/platform-browser/core_private.ts b/modules/@angular/platform-browser/core_private.ts
index a87fe807ae..38ff8a0823 100644
--- a/modules/@angular/platform-browser/core_private.ts
+++ b/modules/@angular/platform-browser/core_private.ts
@@ -28,7 +28,10 @@ export type AnimationGroupPlayer = t.AnimationGroupPlayer;
export var AnimationGroupPlayer: typeof t.AnimationGroupPlayer = r.AnimationGroupPlayer;
export type AnimationKeyframe = t.AnimationKeyframe;
export var AnimationKeyframe: typeof t.AnimationKeyframe = r.AnimationKeyframe;
-export type AnimationStyleUtil = t.AnimationStyleUtil;
-export var AnimationStyleUtil: typeof t.AnimationStyleUtil = r.AnimationStyleUtil;
export type AnimationStyles = t.AnimationStyles;
export var AnimationStyles: typeof t.AnimationStyles = r.AnimationStyles;
+export var balanceAnimationStyles: typeof t.balanceAnimationStyles = r.balanceAnimationStyles;
+export var balanceAnimationKeyframes: typeof t.balanceAnimationKeyframes = r.balanceAnimationKeyframes;
+export var flattenStyles: typeof t.flattenStyles = r.flattenStyles;
+export var clearStyles: typeof t.clearStyles = r.clearStyles;
+export var collectAndResolveStyles: typeof r.collectAndResolveStyles = r.collectAndResolveStyles;
diff --git a/modules/@angular/platform-server/src/parse5_adapter.ts b/modules/@angular/platform-server/src/parse5_adapter.ts
index 44e2d5915c..b72cc0fb81 100644
--- a/modules/@angular/platform-server/src/parse5_adapter.ts
+++ b/modules/@angular/platform-server/src/parse5_adapter.ts
@@ -553,7 +553,7 @@ export class Parse5DomAdapter extends DomAdapter {
setGlobalVar(path: string, value: any) { setValueOnPath(global, path, value); }
requestAnimationFrame(callback): number { return setTimeout(callback, 0); }
cancelAnimationFrame(id: number) { clearTimeout(id); }
- supportsWebAnimation(): boolean { return true; }
+ supportsWebAnimation(): boolean { return false; }
performanceNow(): number { return DateWrapper.toMillis(DateWrapper.now()); }
getAnimationPrefix(): string { return ''; }
getTransitionEnd(): string { return 'transitionend'; }
@@ -567,6 +567,7 @@ export class Parse5DomAdapter extends DomAdapter {
supportsCookies(): boolean { return false; }
getCookie(name: string): string { throw new Error('not implemented'); }
setCookie(name: string, value: string) { throw new Error('not implemented'); }
+ animate(element: any, keyframes: any[], options: any): any { throw new Error('not implemented'); }
}
// TODO: build a proper list, this one is all the keys of a HTMLInputElement
diff --git a/tools/public_api_guard/public_api_spec.ts b/tools/public_api_guard/public_api_spec.ts
index c2977b675e..30e88fc8df 100644
--- a/tools/public_api_guard/public_api_spec.ts
+++ b/tools/public_api_guard/public_api_spec.ts
@@ -181,6 +181,7 @@ const CORE = [
'DebugElement.queryAll(predicate:Predicate):DebugElement[]',
'DebugElement.queryAllNodes(predicate:Predicate):DebugNode[]',
'DebugElement.removeChild(child:DebugNode):any',
+ 'DebugElement.styles:{[key:string]:string}',
'DebugElement.triggerEventHandler(eventName:string, eventObj:any):any',
'DebugNode',
'DebugNode.componentInstance:any',
@@ -1651,6 +1652,7 @@ const PLATFORM_SERVER = [
'Parse5DomAdapter',
'Parse5DomAdapter.addClass(element:any, className:string):any',
'Parse5DomAdapter.adoptNode(node:any):any',
+ 'Parse5DomAdapter.animate(element:any, keyframes:any[], options:any):any',
'Parse5DomAdapter.appendChild(el:any, node:any):any',
'Parse5DomAdapter.attrToPropMap:any',
'Parse5DomAdapter.attributeMap(element:any):Map',