feat(animations): provide support for offline compilation

This commit is contained in:
Matias Niemelä
2016-05-31 09:15:17 -07:00
parent 155b88213c
commit fa0718ba9a
16 changed files with 380 additions and 156 deletions

View File

@ -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';
}
}

View File

@ -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);
});
});

View File

@ -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'
};
}

View File

@ -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 */

View File

@ -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": [
{