feat(animations): provide support for offline compilation
This commit is contained in:
parent
155b88213c
commit
fa0718ba9a
|
@ -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: `
|
||||
<button (click)="setAsOpen()">Open</button>
|
||||
<button (click)="setAsClosed()">Closed</button>
|
||||
<hr />
|
||||
<div @openClose="stateExpression">
|
||||
Look at this box
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class AnimateCmp {
|
||||
stateExpression:string;
|
||||
constructor() {
|
||||
this.setAsClosed();
|
||||
}
|
||||
setAsOpen() {
|
||||
this.stateExpression = 'open';
|
||||
}
|
||||
setAsClosed() {
|
||||
this.stateExpression = 'closed';
|
||||
}
|
||||
}
|
|
@ -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 = <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>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);
|
||||
});
|
||||
});
|
|
@ -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'
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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": [
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -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_,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
}]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -181,6 +181,7 @@ const CORE = [
|
|||
'DebugElement.queryAll(predicate:Predicate<DebugElement>):DebugElement[]',
|
||||
'DebugElement.queryAllNodes(predicate:Predicate<DebugNode>):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<string, string>',
|
||||
|
|
Loading…
Reference in New Issue