fix(projection): allow more bound render elements than app elements.

Fixes #3236
Closes #3247
This commit is contained in:
Tobias Bosch 2015-07-23 14:27:49 -07:00
parent b44b06c2c9
commit 46502e4d61
6 changed files with 36 additions and 10 deletions

View File

@ -37,8 +37,8 @@ export class AppProtoViewMergeMapping {
this.renderProtoViewRef = renderProtoViewMergeMapping.mergedProtoViewRef; this.renderProtoViewRef = renderProtoViewMergeMapping.mergedProtoViewRef;
this.renderFragmentCount = renderProtoViewMergeMapping.fragmentCount; this.renderFragmentCount = renderProtoViewMergeMapping.fragmentCount;
this.renderElementIndices = renderProtoViewMergeMapping.mappedElementIndices; this.renderElementIndices = renderProtoViewMergeMapping.mappedElementIndices;
this.renderInverseElementIndices = this.renderInverseElementIndices = inverseIndexMapping(
inverseIndexMapping(this.renderElementIndices, this.renderElementIndices.length); this.renderElementIndices, renderProtoViewMergeMapping.mappedElementCount);
this.renderTextIndices = renderProtoViewMergeMapping.mappedTextIndices; this.renderTextIndices = renderProtoViewMergeMapping.mappedTextIndices;
this.hostElementIndicesByViewIndex = renderProtoViewMergeMapping.hostElementIndicesByViewIndex; this.hostElementIndicesByViewIndex = renderProtoViewMergeMapping.hostElementIndicesByViewIndex;
this.nestedViewIndicesByElementIndex = this.nestedViewIndicesByElementIndex =
@ -48,7 +48,7 @@ export class AppProtoViewMergeMapping {
} }
function inverseIndexMapping(input: number[], resultLength: number): number[] { function inverseIndexMapping(input: number[], resultLength: number): number[] {
var result = ListWrapper.createFixedSize(resultLength); var result = ListWrapper.createGrowableSize(resultLength);
for (var i = 0; i < input.length; i++) { for (var i = 0; i < input.length; i++) {
var value = input[i]; var value = input[i];
if (isPresent(value)) { if (isPresent(value)) {

View File

@ -307,6 +307,10 @@ export class RenderProtoViewMergeMapping {
// Mappings of nested ProtoViews are in depth first order, with all // Mappings of nested ProtoViews are in depth first order, with all
// indices for one ProtoView in a consecuitve block. // indices for one ProtoView in a consecuitve block.
public mappedElementIndices: number[], public mappedElementIndices: number[],
// Number of bound render element.
// Note: This could be more than the original ones
// as we might have bound a new element for projecting bound text nodes.
public mappedElementCount: number,
// Mapping from app text index to render text index. // Mapping from app text index to render text index.
// Mappings of nested ProtoViews are in depth first order, with all // Mappings of nested ProtoViews are in depth first order, with all
// indices for one ProtoView in a consecuitve block. // indices for one ProtoView in a consecuitve block.

View File

@ -56,9 +56,10 @@ export function mergeProtoViewsRecursively(protoViewRefs: List<RenderProtoViewRe
var mergedProtoView = var mergedProtoView =
DomProtoView.create(mainProtoView.original.type, rootElement, fragmentsRootNodeCount, DomProtoView.create(mainProtoView.original.type, rootElement, fragmentsRootNodeCount,
rootTextNodeIndices, mergedElementBinders); rootTextNodeIndices, mergedElementBinders);
return new RenderProtoViewMergeMapping( return new RenderProtoViewMergeMapping(new DomProtoViewRef(mergedProtoView),
new DomProtoViewRef(mergedProtoView), fragmentsRootNodeCount.length, mappedElementIndices, fragmentsRootNodeCount.length, mappedElementIndices,
mappedTextIndices, hostElementIndicesByViewIndex, nestedViewCounts); mergedBoundElements.length, mappedTextIndices,
hostElementIndicesByViewIndex, nestedViewCounts);
} }
function cloneProtoViews(protoViewRefs: List<RenderProtoViewRef | List<any>>, function cloneProtoViews(protoViewRefs: List<RenderProtoViewRef | List<any>>,

View File

@ -74,7 +74,7 @@ export function main() {
renderCompiler.spy('mergeProtoViewsRecursively') renderCompiler.spy('mergeProtoViewsRecursively')
.andCallFake((protoViewRefs: List<renderApi.RenderProtoViewRef | List<any>>) => { .andCallFake((protoViewRefs: List<renderApi.RenderProtoViewRef | List<any>>) => {
return PromiseWrapper.resolve(new renderApi.RenderProtoViewMergeMapping( return PromiseWrapper.resolve(new renderApi.RenderProtoViewMergeMapping(
new MergedRenderProtoViewRef(protoViewRefs), 1, [], [], [], [null])); new MergedRenderProtoViewRef(protoViewRefs), 1, [], 0, [], [], [null]));
}); });
// TODO spy on .compile and return RenderProtoViewRef, same for compileHost // TODO spy on .compile and return RenderProtoViewRef, same for compileHost
rootProtoView = createRootProtoView(directiveResolver, MainComponent); rootProtoView = createRootProtoView(directiveResolver, MainComponent);

View File

@ -92,6 +92,26 @@ export function main() {
}); });
})); }));
it('should support projecting text interpolation to a non bound element with other bound elements after it',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(Simple, new viewAnn.View({
template: 'SIMPLE(<div><ng-content></ng-content></div><div [tab-index]="0">EL</div>)',
directives: []
}))
.overrideView(
MainComp,
new viewAnn.View({template: '<simple>{{text}}</simple>', directives: [Simple]}))
.createAsync(MainComp)
.then((main) => {
main.componentInstance.text = 'A';
main.detectChanges();
expect(main.nativeElement).toHaveText('SIMPLE(AEL)');
async.done();
});
}));
it('should not show the light dom even if there is no content tag', it('should not show the light dom even if there is no content tag',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideView(MainComp, tcb.overrideView(MainComp,

View File

@ -324,9 +324,10 @@ function _createProtoView(type: ViewType, binders: ElementBinder[] = null) {
} }
var hostElementIndicesByViewIndex = calcHostElementIndicesByViewIndex(res); var hostElementIndicesByViewIndex = calcHostElementIndicesByViewIndex(res);
if (type === ViewType.EMBEDDED || type === ViewType.HOST) { if (type === ViewType.EMBEDDED || type === ViewType.HOST) {
res.mergeMapping = new AppProtoViewMergeMapping(new RenderProtoViewMergeMapping( res.mergeMapping = new AppProtoViewMergeMapping(
null, hostElementIndicesByViewIndex.length, mappedElementIndices, [], new RenderProtoViewMergeMapping(null, hostElementIndicesByViewIndex.length,
hostElementIndicesByViewIndex, countNestedProtoViews(res))); mappedElementIndices, mappedElementIndices.length, [],
hostElementIndicesByViewIndex, countNestedProtoViews(res)));
} }
return res; return res;
} }