fix(compiler): changed the compiler to set up event listeners and host properties on host view elements
Closes #1584
This commit is contained in:
parent
414e58edb5
commit
e3c11045bf
|
@ -90,7 +90,9 @@ export class Compiler {
|
||||||
compileInHost(componentTypeOrBinding:any):Promise<AppProtoView> {
|
compileInHost(componentTypeOrBinding:any):Promise<AppProtoView> {
|
||||||
var componentBinding = this._bindDirective(componentTypeOrBinding);
|
var componentBinding = this._bindDirective(componentTypeOrBinding);
|
||||||
this._assertTypeIsComponent(componentBinding);
|
this._assertTypeIsComponent(componentBinding);
|
||||||
return this._renderer.createHostProtoView('host').then( (hostRenderPv) => {
|
|
||||||
|
var directiveMetadata = Compiler.buildRenderDirective(componentBinding);
|
||||||
|
return this._renderer.createHostProtoView(directiveMetadata).then( (hostRenderPv) => {
|
||||||
return this._compileNestedProtoViews(null, hostRenderPv, [componentBinding], true);
|
return this._compileNestedProtoViews(null, hostRenderPv, [componentBinding], true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,9 @@ import {Injectable} from 'angular2/di';
|
||||||
|
|
||||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
import {BaseException} from 'angular2/src/facade/lang';
|
import {BaseException} from 'angular2/src/facade/lang';
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
import {ViewDefinition, ProtoViewDto} from '../../api';
|
import {ViewDefinition, ProtoViewDto, DirectiveMetadata} from '../../api';
|
||||||
import {CompilePipeline} from './compile_pipeline';
|
import {CompilePipeline} from './compile_pipeline';
|
||||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||||
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
|
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
|
||||||
|
@ -32,12 +33,21 @@ export class Compiler {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_compileTemplate(template: ViewDefinition, tplElement):Promise<ProtoViewDto> {
|
compileHost(directiveMetadata: DirectiveMetadata):Promise<ProtoViewDto> {
|
||||||
var subTaskPromises = [];
|
var hostViewDef = new ViewDefinition({
|
||||||
var pipeline = new CompilePipeline(this._stepFactory.createSteps(template, subTaskPromises));
|
componentId: directiveMetadata.id,
|
||||||
var compileElements;
|
absUrl: null,
|
||||||
|
template: null,
|
||||||
|
directives: [directiveMetadata]
|
||||||
|
});
|
||||||
|
var element = DOM.createElement(directiveMetadata.selector);
|
||||||
|
return this._compileTemplate(hostViewDef, element);
|
||||||
|
}
|
||||||
|
|
||||||
compileElements = pipeline.process(tplElement, template.componentId);
|
_compileTemplate(viewDef: ViewDefinition, tplElement):Promise<ProtoViewDto> {
|
||||||
|
var subTaskPromises = [];
|
||||||
|
var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef, subTaskPromises));
|
||||||
|
var compileElements = pipeline.process(tplElement, viewDef.componentId);
|
||||||
|
|
||||||
var protoView = compileElements[0].inheritedProtoView.build();
|
var protoView = compileElements[0].inheritedProtoView.build();
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,20 @@ export class DirectiveParser extends CompileStep {
|
||||||
this._selectorMatcher = new SelectorMatcher();
|
this._selectorMatcher = new SelectorMatcher();
|
||||||
this._directives = directives;
|
this._directives = directives;
|
||||||
for (var i=0; i<directives.length; i++) {
|
for (var i=0; i<directives.length; i++) {
|
||||||
var selector = CssSelector.parse(directives[i].selector);
|
var directive = directives[i];
|
||||||
|
var selector = CssSelector.parse(directive.selector);
|
||||||
|
this._ensureComponentOnlyHasElementSelector(selector, directive);
|
||||||
this._selectorMatcher.addSelectables(selector, i);
|
this._selectorMatcher.addSelectables(selector, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ensureComponentOnlyHasElementSelector(selector, directive) {
|
||||||
|
var isElementSelector = selector.length === 1 && selector[0].isElementSelector();
|
||||||
|
if (! isElementSelector && directive.type === DirectiveMetadata.COMPONENT_TYPE) {
|
||||||
|
throw new BaseException(`Component '${directive.id}' can only have an element selector, but had '${directive.selector}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||||
var attrs = current.attrs();
|
var attrs = current.attrs();
|
||||||
var classList = current.classList();
|
var classList = current.classList();
|
||||||
|
|
|
@ -69,6 +69,13 @@ export class CssSelector {
|
||||||
this.notSelector = null;
|
this.notSelector = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isElementSelector():boolean {
|
||||||
|
return isPresent(this.element) &&
|
||||||
|
ListWrapper.isEmpty(this.classNames) &&
|
||||||
|
ListWrapper.isEmpty(this.attrs) &&
|
||||||
|
isBlank(this.notSelector);
|
||||||
|
}
|
||||||
|
|
||||||
setElement(element:string = null) {
|
setElement(element:string = null) {
|
||||||
if (isPresent(element)) {
|
if (isPresent(element)) {
|
||||||
element = element.toLowerCase();
|
element = element.toLowerCase();
|
||||||
|
|
|
@ -11,7 +11,6 @@ import {RenderViewHydrator} from './view/view_hydrator';
|
||||||
import {Compiler} from './compiler/compiler';
|
import {Compiler} from './compiler/compiler';
|
||||||
import {ShadowDomStrategy} from './shadow_dom/shadow_dom_strategy';
|
import {ShadowDomStrategy} from './shadow_dom/shadow_dom_strategy';
|
||||||
import {ProtoViewBuilder} from './view/proto_view_builder';
|
import {ProtoViewBuilder} from './view/proto_view_builder';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
||||||
import {ViewContainer} from './view/view_container';
|
import {ViewContainer} from './view/view_container';
|
||||||
|
|
||||||
function _resolveViewContainer(vc:api.RenderViewContainerRef) {
|
function _resolveViewContainer(vc:api.RenderViewContainerRef) {
|
||||||
|
@ -80,15 +79,8 @@ export class DirectDomRenderer extends api.Renderer {
|
||||||
this._shadowDomStrategy = shadowDomStrategy;
|
this._shadowDomStrategy = shadowDomStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
createHostProtoView(componentId):Promise<api.ProtoViewDto> {
|
createHostProtoView(directiveMetadata:api.DirectiveMetadata):Promise<api.ProtoViewDto> {
|
||||||
var rootElement = DOM.createElement('div');
|
return this._compiler.compileHost(directiveMetadata);
|
||||||
var hostProtoViewBuilder = new ProtoViewBuilder(rootElement);
|
|
||||||
var elBinder = hostProtoViewBuilder.bindElement(rootElement, 'root element');
|
|
||||||
elBinder.setComponentId(componentId);
|
|
||||||
elBinder.bindDirective(0);
|
|
||||||
|
|
||||||
this._shadowDomStrategy.processElement(null, componentId, rootElement);
|
|
||||||
return PromiseWrapper.resolve(hostProtoViewBuilder.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createImperativeComponentProtoView(rendererId):Promise<api.ProtoViewDto> {
|
createImperativeComponentProtoView(rendererId):Promise<api.ProtoViewDto> {
|
||||||
|
@ -97,10 +89,10 @@ export class DirectDomRenderer extends api.Renderer {
|
||||||
return PromiseWrapper.resolve(protoViewBuilder.build());
|
return PromiseWrapper.resolve(protoViewBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
compile(template:api.ViewDefinition):Promise<api.ProtoViewDto> {
|
compile(view:api.ViewDefinition):Promise<api.ProtoViewDto> {
|
||||||
// Note: compiler already uses a DirectDomProtoViewRef, so we don't
|
// Note: compiler already uses a DirectDomProtoViewRef, so we don't
|
||||||
// need to do anything here
|
// need to do anything here
|
||||||
return this._compiler.compile(template);
|
return this._compiler.compile(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
mergeChildComponentProtoViews(protoViewRef:api.ProtoViewRef, protoViewRefs:List<api.ProtoViewRef>) {
|
mergeChildComponentProtoViews(protoViewRef:api.ProtoViewRef, protoViewRefs:List<api.ProtoViewRef>) {
|
||||||
|
|
|
@ -22,6 +22,8 @@ import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_compone
|
||||||
import {ElementRef} from 'angular2/src/core/compiler/element_injector';
|
import {ElementRef} from 'angular2/src/core/compiler/element_injector';
|
||||||
import {If} from 'angular2/src/directives/if';
|
import {If} from 'angular2/src/directives/if';
|
||||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('DynamicComponentLoader', function () {
|
describe('DynamicComponentLoader', function () {
|
||||||
|
@ -134,6 +136,29 @@ export function main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should update host properties', inject([DynamicComponentLoader, TestBed, AsyncTestCompleter],
|
||||||
|
(loader, tb, async) => {
|
||||||
|
tb.overrideView(MyComp, new View({
|
||||||
|
template: '<div><location #loc></location></div>',
|
||||||
|
directives: [Location]
|
||||||
|
}));
|
||||||
|
|
||||||
|
tb.createView(MyComp).then((view) => {
|
||||||
|
var location = view.rawView.locals.get("loc");
|
||||||
|
|
||||||
|
loader.loadNextToExistingLocation(DynamicallyLoadedWithHostProps, location.elementRef).then(ref => {
|
||||||
|
ref.instance.id = "new value";
|
||||||
|
|
||||||
|
view.detectChanges();
|
||||||
|
|
||||||
|
var newlyInsertedElement = DOM.childNodesAsList(view.rootNodes[0])[1];
|
||||||
|
expect(newlyInsertedElement.id).toEqual("new value")
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('loading into a new location', () => {
|
describe('loading into a new location', () => {
|
||||||
|
@ -242,6 +267,19 @@ class DynamicallyLoaded {
|
||||||
class DynamicallyLoaded2 {
|
class DynamicallyLoaded2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'dummy',
|
||||||
|
hostProperties: {'id' : 'id'}
|
||||||
|
})
|
||||||
|
@View({template: "DynamicallyLoadedWithHostProps;"})
|
||||||
|
class DynamicallyLoadedWithHostProps {
|
||||||
|
id:string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.id = "default";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'location'
|
selector: 'location'
|
||||||
})
|
})
|
||||||
|
@ -254,7 +292,9 @@ class Location {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component()
|
@Component({
|
||||||
|
selector: 'my-comp'
|
||||||
|
})
|
||||||
@View({
|
@View({
|
||||||
directives: []
|
directives: []
|
||||||
})
|
})
|
||||||
|
|
|
@ -255,20 +255,19 @@ export function main() {
|
||||||
tb.overrideView(MyComp,
|
tb.overrideView(MyComp,
|
||||||
new View({
|
new View({
|
||||||
template: '<p [id]="ctxProp"></p>',
|
template: '<p [id]="ctxProp"></p>',
|
||||||
directives: [IdComponent]
|
directives: [IdDir]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||||
|
var idDir = view.rawView.elementInjectors[0].get(IdDir);
|
||||||
|
|
||||||
ctx.ctxProp = 'some_id';
|
ctx.ctxProp = 'some_id';
|
||||||
view.detectChanges();
|
view.detectChanges();
|
||||||
expect(view.rootNodes[0].id).toEqual('some_id');
|
expect(idDir.id).toEqual('some_id');
|
||||||
expect(view.rootNodes).toHaveText('Matched on id with some_id');
|
|
||||||
|
|
||||||
ctx.ctxProp = 'other_id';
|
ctx.ctxProp = 'other_id';
|
||||||
view.detectChanges();
|
view.detectChanges();
|
||||||
expect(view.rootNodes[0].id).toEqual('other_id');
|
expect(idDir.id).toEqual('other_id');
|
||||||
expect(view.rootNodes).toHaveText('Matched on id with other_id');
|
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -932,7 +931,9 @@ class PushCmpWithRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component()
|
@Component({
|
||||||
|
selector: 'my-comp'
|
||||||
|
})
|
||||||
@View({directives: [
|
@View({directives: [
|
||||||
]})
|
]})
|
||||||
class MyComp {
|
class MyComp {
|
||||||
|
@ -1192,14 +1193,11 @@ class DecoratorListeningDomEventNoPrevent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Decorator({
|
||||||
selector: '[id]',
|
selector: '[id]',
|
||||||
properties: {'id': 'id'}
|
properties: {'id': 'id'}
|
||||||
})
|
})
|
||||||
@View({
|
class IdDir {
|
||||||
template: '<div>Matched on id with {{id}}</div>'
|
|
||||||
})
|
|
||||||
class IdComponent {
|
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* Runs compiler tests using in-browser DOM adapter.
|
* Runs compiler tests using in-browser DOM adapter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang';
|
||||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
import {Compiler, CompilerCache} from 'angular2/src/render/dom/compiler/compiler';
|
import {Compiler, CompilerCache} from 'angular2/src/render/dom/compiler/compiler';
|
||||||
import {ProtoViewDto, ViewDefinition} from 'angular2/src/render/api';
|
import {ProtoViewDto, ViewDefinition, DirectiveMetadata} from 'angular2/src/render/api';
|
||||||
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
|
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
|
||||||
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step'
|
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step'
|
||||||
import {CompileStepFactory} from 'angular2/src/render/dom/compiler/compile_step_factory';
|
import {CompileStepFactory} from 'angular2/src/render/dom/compiler/compile_step_factory';
|
||||||
|
@ -54,6 +54,22 @@ export function runCompilerCommonTests() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should run the steps and build the proto view', inject([AsyncTestCompleter], (async) => {
|
||||||
|
var compiler = createCompiler((parent, current, control) => {
|
||||||
|
current.inheritedProtoView.bindVariable('b', 'a');
|
||||||
|
});
|
||||||
|
|
||||||
|
var dirMetadata = new DirectiveMetadata({id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE});
|
||||||
|
compiler.compileHost(dirMetadata).then( (protoView) => {
|
||||||
|
expect(DOM.tagName(protoView.render.delegate.element)).toEqual('CUSTOM')
|
||||||
|
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
|
||||||
|
expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
|
||||||
|
'a': 'b'
|
||||||
|
}));
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should use the inline template and compile in sync', inject([AsyncTestCompleter], (async) => {
|
it('should use the inline template and compile in sync', inject([AsyncTestCompleter], (async) => {
|
||||||
var compiler = createCompiler(EMPTY_STEP);
|
var compiler = createCompiler(EMPTY_STEP);
|
||||||
compiler.compile(new ViewDefinition({
|
compiler.compile(new ViewDefinition({
|
||||||
|
@ -124,11 +140,14 @@ export function runCompilerCommonTests() {
|
||||||
class MockStepFactory extends CompileStepFactory {
|
class MockStepFactory extends CompileStepFactory {
|
||||||
steps:List<CompileStep>;
|
steps:List<CompileStep>;
|
||||||
subTaskPromises:List<Promise>;
|
subTaskPromises:List<Promise>;
|
||||||
|
viewDef:ViewDefinition;
|
||||||
|
|
||||||
constructor(steps) {
|
constructor(steps) {
|
||||||
super();
|
super();
|
||||||
this.steps = steps;
|
this.steps = steps;
|
||||||
}
|
}
|
||||||
createSteps(template, subTaskPromises) {
|
createSteps(viewDef, subTaskPromises) {
|
||||||
|
this.viewDef = viewDef;
|
||||||
this.subTaskPromises = subTaskPromises;
|
this.subTaskPromises = subTaskPromises;
|
||||||
ListWrapper.forEach(this.subTaskPromises, (p) => ListWrapper.push(subTaskPromises, p) );
|
ListWrapper.forEach(this.subTaskPromises, (p) => ListWrapper.push(subTaskPromises, p) );
|
||||||
return this.steps;
|
return this.steps;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {describe, beforeEach, it, xit, expect, iit, ddescribe, el} from 'angular2/test_lib';
|
import {describe, beforeEach, it, xit, expect, iit, ddescribe, el} from 'angular2/test_lib';
|
||||||
import {isPresent, assertionsEnabled} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank, assertionsEnabled} from 'angular2/src/facade/lang';
|
||||||
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {DirectiveParser} from 'angular2/src/render/dom/compiler/directive_parser';
|
import {DirectiveParser} from 'angular2/src/render/dom/compiler/directive_parser';
|
||||||
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
|
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
|
||||||
|
@ -17,11 +17,11 @@ export function main() {
|
||||||
annotatedDirectives = [
|
annotatedDirectives = [
|
||||||
someComponent,
|
someComponent,
|
||||||
someComponent2,
|
someComponent2,
|
||||||
someComponent3,
|
|
||||||
someViewport,
|
someViewport,
|
||||||
someViewport2,
|
someViewport2,
|
||||||
someDecorator,
|
someDecorator,
|
||||||
someDecoratorIgnoringChildren,
|
someDecoratorIgnoringChildren,
|
||||||
|
decoratorWithMultipleAttrs,
|
||||||
someDecoratorWithProps,
|
someDecoratorWithProps,
|
||||||
someDecoratorWithHostProperties,
|
someDecoratorWithHostProperties,
|
||||||
someDecoratorWithEvents,
|
someDecoratorWithEvents,
|
||||||
|
@ -30,7 +30,9 @@ export function main() {
|
||||||
parser = new Parser(new Lexer());
|
parser = new Parser(new Lexer());
|
||||||
});
|
});
|
||||||
|
|
||||||
function createPipeline(propertyBindings = null) {
|
function createPipeline(propertyBindings = null, directives = null) {
|
||||||
|
if (isBlank(directives)) directives = annotatedDirectives;
|
||||||
|
|
||||||
return new CompilePipeline([
|
return new CompilePipeline([
|
||||||
new MockStep( (parent, current, control) => {
|
new MockStep( (parent, current, control) => {
|
||||||
if (isPresent(propertyBindings)) {
|
if (isPresent(propertyBindings)) {
|
||||||
|
@ -39,12 +41,12 @@ export function main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new DirectiveParser(parser, annotatedDirectives)
|
new DirectiveParser(parser, directives)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function process(el, propertyBindings = null) {
|
function process(el, propertyBindings = null, directives = null) {
|
||||||
var pipeline = createPipeline(propertyBindings);
|
var pipeline = createPipeline(propertyBindings, directives);
|
||||||
return ListWrapper.map(pipeline.process(el), (ce) => ce.inheritedElementBinder );
|
return ListWrapper.map(pipeline.process(el), (ce) => ce.inheritedElementBinder );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +65,7 @@ export function main() {
|
||||||
it('should detect directives with multiple attributes', () => {
|
it('should detect directives with multiple attributes', () => {
|
||||||
var results = process(el('<input type=text control=one></input>'));
|
var results = process(el('<input type=text control=one></input>'));
|
||||||
expect(results[0].directives[0].directiveIndex).toBe(
|
expect(results[0].directives[0].directiveIndex).toBe(
|
||||||
annotatedDirectives.indexOf(someComponent3)
|
annotatedDirectives.indexOf(decoratorWithMultipleAttrs)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -176,30 +178,27 @@ export function main() {
|
||||||
describe('component directives', () => {
|
describe('component directives', () => {
|
||||||
it('should save the component id', () => {
|
it('should save the component id', () => {
|
||||||
var results = process(
|
var results = process(
|
||||||
el('<div some-comp></div>')
|
el('<some-comp></some-comp>')
|
||||||
);
|
);
|
||||||
expect(results[0].componentId).toEqual('someComponent');
|
expect(results[0].componentId).toEqual('someComponent');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw when the provided selector is not an element selector', () => {
|
||||||
|
expect( () => {
|
||||||
|
createPipeline(null, [componentWithNonElementSelector]);
|
||||||
|
}).toThrowError(`Component 'componentWithNonElementSelector' can only have an element selector, but had '[attr]'`);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not allow multiple component directives on the same element', () => {
|
it('should not allow multiple component directives on the same element', () => {
|
||||||
expect( () => {
|
expect( () => {
|
||||||
process(
|
process(
|
||||||
el('<div some-comp some-comp2></div>')
|
el('<some-comp></some-comp>'),
|
||||||
|
null,
|
||||||
|
[someComponent, someComponentDup]
|
||||||
);
|
);
|
||||||
}).toThrowError('Only one component directive is allowed per element - check '
|
}).toThrowError(new RegExp('Only one component directive is allowed per element' ));
|
||||||
+ (assertionsEnabled() ? '<div some-comp some-comp2>' : 'null'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow component directives on <template> elements', () => {
|
|
||||||
expect( () => {
|
|
||||||
process(
|
|
||||||
el('<template some-comp></template>')
|
|
||||||
);
|
|
||||||
}).toThrowError('Only template directives are allowed on template elements - check '
|
|
||||||
+ (assertionsEnabled() ? '<template some-comp>' : 'null'));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,20 +214,20 @@ class MockStep extends CompileStep {
|
||||||
}
|
}
|
||||||
|
|
||||||
var someComponent = new DirectiveMetadata({
|
var someComponent = new DirectiveMetadata({
|
||||||
selector: '[some-comp]',
|
selector: 'some-comp',
|
||||||
id: 'someComponent',
|
id: 'someComponent',
|
||||||
type: DirectiveMetadata.COMPONENT_TYPE
|
type: DirectiveMetadata.COMPONENT_TYPE
|
||||||
});
|
});
|
||||||
|
|
||||||
var someComponent2 = new DirectiveMetadata({
|
var someComponentDup = new DirectiveMetadata({
|
||||||
selector: '[some-comp2]',
|
selector: 'some-comp',
|
||||||
id: 'someComponent2',
|
id: 'someComponentDup',
|
||||||
type: DirectiveMetadata.COMPONENT_TYPE
|
type: DirectiveMetadata.COMPONENT_TYPE
|
||||||
});
|
});
|
||||||
|
|
||||||
var someComponent3 = new DirectiveMetadata({
|
var someComponent2 = new DirectiveMetadata({
|
||||||
selector: 'input[type=text][control]',
|
selector: 'some-comp2',
|
||||||
id: 'someComponent3',
|
id: 'someComponent2',
|
||||||
type: DirectiveMetadata.COMPONENT_TYPE
|
type: DirectiveMetadata.COMPONENT_TYPE
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -245,12 +244,21 @@ var someViewport2 = new DirectiveMetadata({
|
||||||
});
|
});
|
||||||
|
|
||||||
var someDecorator = new DirectiveMetadata({
|
var someDecorator = new DirectiveMetadata({
|
||||||
selector: '[some-decor]'
|
selector: '[some-decor]',
|
||||||
|
type: DirectiveMetadata.DECORATOR_TYPE
|
||||||
});
|
});
|
||||||
|
|
||||||
var someDecoratorIgnoringChildren = new DirectiveMetadata({
|
var someDecoratorIgnoringChildren = new DirectiveMetadata({
|
||||||
selector: '[some-decor-ignoring-children]',
|
selector: '[some-decor-ignoring-children]',
|
||||||
compileChildren: false
|
compileChildren: false,
|
||||||
|
type: DirectiveMetadata.DECORATOR_TYPE
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var decoratorWithMultipleAttrs = new DirectiveMetadata({
|
||||||
|
selector: 'input[type=text][control]',
|
||||||
|
id: 'decoratorWithMultipleAttrs',
|
||||||
|
type: DirectiveMetadata.DECORATOR_TYPE
|
||||||
});
|
});
|
||||||
|
|
||||||
var someDecoratorWithProps = new DirectiveMetadata({
|
var someDecoratorWithProps = new DirectiveMetadata({
|
||||||
|
@ -282,3 +290,9 @@ var someDecoratorWithGlobalEvents = new DirectiveMetadata({
|
||||||
'window:resize': 'doItGlobal()'
|
'window:resize': 'doItGlobal()'
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var componentWithNonElementSelector = new DirectiveMetadata({
|
||||||
|
id: 'componentWithNonElementSelector',
|
||||||
|
selector: '[attr]',
|
||||||
|
type: DirectiveMetadata.COMPONENT_TYPE
|
||||||
|
});
|
||||||
|
|
|
@ -41,7 +41,7 @@ export function main() {
|
||||||
|
|
||||||
it('should create host views while using the given elements in place', inject([AsyncTestCompleter], (async) => {
|
it('should create host views while using the given elements in place', inject([AsyncTestCompleter], (async) => {
|
||||||
createRenderer();
|
createRenderer();
|
||||||
renderer.createHostProtoView('someComponentId').then( (rootProtoView) => {
|
renderer.createHostProtoView(someComponent).then( (rootProtoView) => {
|
||||||
expect(rootProtoView.elementBinders[0].directives[0].directiveIndex).toBe(0);
|
expect(rootProtoView.elementBinders[0].directives[0].directiveIndex).toBe(0);
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
||||||
expect(viewRefs.length).toBe(1);
|
expect(viewRefs.length).toBe(1);
|
||||||
|
@ -62,7 +62,7 @@ export function main() {
|
||||||
|
|
||||||
it('should add a static component', inject([AsyncTestCompleter], (async) => {
|
it('should add a static component', inject([AsyncTestCompleter], (async) => {
|
||||||
createRenderer();
|
createRenderer();
|
||||||
renderer.createHostProtoView('someComponentId').then( (rootProtoView) => {
|
renderer.createHostProtoView(someComponent).then( (rootProtoView) => {
|
||||||
var template = new ViewDefinition({
|
var template = new ViewDefinition({
|
||||||
componentId: 'someComponent',
|
componentId: 'someComponent',
|
||||||
template: 'hello',
|
template: 'hello',
|
||||||
|
@ -79,7 +79,7 @@ export function main() {
|
||||||
|
|
||||||
it('should add a a dynamic component', inject([AsyncTestCompleter], (async) => {
|
it('should add a a dynamic component', inject([AsyncTestCompleter], (async) => {
|
||||||
createRenderer();
|
createRenderer();
|
||||||
renderer.createHostProtoView('someComponentId').then( (rootProtoView) => {
|
renderer.createHostProtoView(someComponent).then( (rootProtoView) => {
|
||||||
var template = new ViewDefinition({
|
var template = new ViewDefinition({
|
||||||
componentId: 'someComponent',
|
componentId: 'someComponent',
|
||||||
template: 'hello',
|
template: 'hello',
|
||||||
|
@ -102,7 +102,7 @@ export function main() {
|
||||||
directives: []
|
directives: []
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('someComponent').then( (rootProtoView) => {
|
compileRoot(someComponent).then( (rootProtoView) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
||||||
renderer.setText(viewRefs[1], 0, 'hello');
|
renderer.setText(viewRefs[1], 0, 'hello');
|
||||||
expect(rootEl).toHaveText('hello');
|
expect(rootEl).toHaveText('hello');
|
||||||
|
@ -118,7 +118,7 @@ export function main() {
|
||||||
directives: []
|
directives: []
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('someComponent').then( (rootProtoView) => {
|
compileRoot(someComponent).then( (rootProtoView) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
||||||
renderer.setElementProperty(viewRefs[1], 0, 'value', 'hello');
|
renderer.setElementProperty(viewRefs[1], 0, 'value', 'hello');
|
||||||
expect(DOM.childNodes(rootEl)[0].value).toEqual('hello');
|
expect(DOM.childNodes(rootEl)[0].value).toEqual('hello');
|
||||||
|
@ -134,7 +134,7 @@ export function main() {
|
||||||
directives: []
|
directives: []
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('someComponent').then( (rootProtoView) => {
|
compileRoot(someComponent).then( (rootProtoView) => {
|
||||||
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
||||||
var vcProtoViewRef = rootProtoView.elementBinders[0]
|
var vcProtoViewRef = rootProtoView.elementBinders[0]
|
||||||
.nestedProtoView.elementBinders[0].nestedProtoView.render;
|
.nestedProtoView.elementBinders[0].nestedProtoView.render;
|
||||||
|
@ -162,7 +162,7 @@ export function main() {
|
||||||
})],
|
})],
|
||||||
viewCacheCapacity: 2
|
viewCacheCapacity: 2
|
||||||
});
|
});
|
||||||
compileRoot('someComponent').then( (rootProtoView) => {
|
compileRoot(someComponent).then( (rootProtoView) => {
|
||||||
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
||||||
var vcProtoViewRef = rootProtoView.elementBinders[0]
|
var vcProtoViewRef = rootProtoView.elementBinders[0]
|
||||||
.nestedProtoView.elementBinders[0].nestedProtoView.render;
|
.nestedProtoView.elementBinders[0].nestedProtoView.render;
|
||||||
|
@ -189,7 +189,7 @@ export function main() {
|
||||||
directives: []
|
directives: []
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('someComponent').then( (rootProtoView) => {
|
compileRoot(someComponent).then( (rootProtoView) => {
|
||||||
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
||||||
var dispatcher = new LoggingEventDispatcher();
|
var dispatcher = new LoggingEventDispatcher();
|
||||||
renderer.setEventDispatcher(viewRef, dispatcher);
|
renderer.setEventDispatcher(viewRef, dispatcher);
|
||||||
|
|
|
@ -50,14 +50,9 @@ export class IntegrationTestbed {
|
||||||
this.renderer = new DirectDomRenderer(compiler, viewFactory, viewHydrator, shadowDomStrategy);
|
this.renderer = new DirectDomRenderer(compiler, viewFactory, viewHydrator, shadowDomStrategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileRoot(componentId):Promise<ProtoViewDto> {
|
compileRoot(componentMetadata):Promise<ProtoViewDto> {
|
||||||
return this.renderer.createHostProtoView(componentId).then( (rootProtoView) => {
|
return this.renderer.createHostProtoView(componentMetadata).then( (rootProtoView) => {
|
||||||
return this._compileNestedProtoViews(rootProtoView, [
|
return this._compileNestedProtoViews(rootProtoView, [componentMetadata]);
|
||||||
new DirectiveMetadata({
|
|
||||||
type: DirectiveMetadata.COMPONENT_TYPE,
|
|
||||||
id: componentId
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ export function main() {
|
||||||
directives: [simple]
|
directives: [simple]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('SIMPLE(A)');
|
expect(rootEl).toHaveText('SIMPLE(A)');
|
||||||
|
@ -98,7 +98,7 @@ export function main() {
|
||||||
directives: [empty]
|
directives: [empty]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('');
|
expect(rootEl).toHaveText('');
|
||||||
|
@ -117,7 +117,7 @@ export function main() {
|
||||||
directives: [dynamicComponent]
|
directives: [dynamicComponent]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (rootPv) => {
|
compileRoot(mainDir).then( (rootPv) => {
|
||||||
compile('simple').then( (simplePv) => {
|
compile('simple').then( (simplePv) => {
|
||||||
var views = renderer.createInPlaceHostView(null, rootEl, rootPv.render);
|
var views = renderer.createInPlaceHostView(null, rootEl, rootPv.render);
|
||||||
renderer.createDynamicComponentView(views[1], 0, simplePv.render);
|
renderer.createDynamicComponentView(views[1], 0, simplePv.render);
|
||||||
|
@ -141,7 +141,7 @@ export function main() {
|
||||||
directives: [multipleContentTagsComponent]
|
directives: [multipleContentTagsComponent]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(A, BC)');
|
expect(rootEl).toHaveText('(A, BC)');
|
||||||
|
@ -161,7 +161,7 @@ export function main() {
|
||||||
directives: [multipleContentTagsComponent]
|
directives: [multipleContentTagsComponent]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(, BAC)');
|
expect(rootEl).toHaveText('(, BAC)');
|
||||||
|
@ -181,7 +181,7 @@ export function main() {
|
||||||
directives: [multipleContentTagsComponent, manualViewportDirective]
|
directives: [multipleContentTagsComponent, manualViewportDirective]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
||||||
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
||||||
|
@ -211,7 +211,7 @@ export function main() {
|
||||||
directives: [multipleContentTagsComponent, manualViewportDirective]
|
directives: [multipleContentTagsComponent, manualViewportDirective]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
||||||
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
||||||
|
@ -241,7 +241,7 @@ export function main() {
|
||||||
directives: [outerWithIndirectNestedComponent]
|
directives: [outerWithIndirectNestedComponent]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('OUTER(SIMPLE(AB))');
|
expect(rootEl).toHaveText('OUTER(SIMPLE(AB))');
|
||||||
|
@ -262,7 +262,7 @@ export function main() {
|
||||||
directives: [outerComponent, manualViewportDirective]
|
directives: [outerComponent, manualViewportDirective]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
||||||
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
||||||
|
@ -288,7 +288,7 @@ export function main() {
|
||||||
directives: [conditionalContentComponent]
|
directives: [conditionalContentComponent]
|
||||||
})]
|
})]
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
var vcRef = new RenderViewContainerRef(viewRefs[2], 0);
|
var vcRef = new RenderViewContainerRef(viewRefs[2], 0);
|
||||||
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
||||||
|
@ -321,7 +321,7 @@ export function main() {
|
||||||
})],
|
})],
|
||||||
viewCacheCapacity: 5
|
viewCacheCapacity: 5
|
||||||
});
|
});
|
||||||
compileRoot('main').then( (pv) => {
|
compileRoot(mainDir).then( (pv) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
||||||
var vcRef0 = new RenderViewContainerRef(viewRefs[2], 0);
|
var vcRef0 = new RenderViewContainerRef(viewRefs[2], 0);
|
||||||
var vcRef1 = new RenderViewContainerRef(viewRefs[3], 0);
|
var vcRef1 = new RenderViewContainerRef(viewRefs[3], 0);
|
||||||
|
@ -372,6 +372,12 @@ export function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var mainDir = new DirectiveMetadata({
|
||||||
|
selector: 'main',
|
||||||
|
id: 'main',
|
||||||
|
type: DirectiveMetadata.COMPONENT_TYPE
|
||||||
|
});
|
||||||
|
|
||||||
var simple = new DirectiveMetadata({
|
var simple = new DirectiveMetadata({
|
||||||
selector: 'simple',
|
selector: 'simple',
|
||||||
id: 'simple',
|
id: 'simple',
|
||||||
|
|
|
@ -150,7 +150,9 @@ class ParentCmp {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component()
|
@Component({
|
||||||
|
selector: 'my-comp'
|
||||||
|
})
|
||||||
class MyComp {
|
class MyComp {
|
||||||
name;
|
name;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue