feat(ngUpgrade): support for content project from ng1->ng2

This commit is contained in:
Misko Hevery
2015-10-09 14:53:04 -07:00
parent 867c08ac84
commit cd90e6ed8f
9 changed files with 93 additions and 28 deletions

View File

@ -50,6 +50,8 @@ export abstract class DomRenderer extends Renderer implements NodeFactory<Node>
abstract destroyView(viewRef: RenderViewRef);
abstract createRootContentInsertionPoint();
getNativeElementSync(location: RenderElementRef): any {
return resolveInternalDomView(location.renderView).boundElements[location.boundElementIndex];
}
@ -282,6 +284,9 @@ export class DomRenderer_ extends DomRenderer {
DOM.setAttribute(node, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
}
}
createRootContentInsertionPoint(): Node {
return DOM.createComment('root-content-insertion-point');
}
createShadowRoot(host: Node, templateId: number): Node {
var sr = DOM.createShadowRoot(host);
var styles = this._nativeShadowStyles.get(templateId);

View File

@ -25,7 +25,7 @@ export class DefaultRenderView<N> extends RenderViewRef {
constructor(public fragments: DefaultRenderFragmentRef<N>[], public boundTextNodes: N[],
public boundElements: N[], public nativeShadowRoots: N[],
public globalEventAdders: Function[]) {
public globalEventAdders: Function[], public rootContentInsertionPoints: N[]) {
super();
}

View File

@ -23,7 +23,8 @@ export function createRenderView(fragmentCmds: RenderTemplateCmd[], inplaceEleme
fragments.push(new DefaultRenderFragmentRef(context.fragments[i]));
}
view = new DefaultRenderView<any>(fragments, context.boundTextNodes, context.boundElements,
context.nativeShadowRoots, context.globalEventAdders);
context.nativeShadowRoots, context.globalEventAdders,
context.rootContentInsertionPoints);
return view;
}
@ -31,6 +32,7 @@ export interface NodeFactory<N> {
resolveComponentTemplate(templateId: number): RenderTemplateCmd[];
createTemplateAnchor(attrNameAndValues: string[]): N;
createElement(name: string, attrNameAndValues: string[]): N;
createRootContentInsertionPoint(): N;
mergeElement(existing: N, attrNameAndValues: string[]);
createShadowRoot(host: N, templateId: number): N;
createText(value: string): N;
@ -41,7 +43,9 @@ export interface NodeFactory<N> {
class BuildContext<N> {
constructor(private _eventDispatcher: Function, public factory: NodeFactory<N>,
private _inplaceElement: N) {}
private _inplaceElement: N) {
this.isHost = isPresent((_inplaceElement));
}
private _builders: RenderViewBuilder<N>[] = [];
globalEventAdders: Function[] = [];
@ -49,6 +53,9 @@ class BuildContext<N> {
boundTextNodes: N[] = [];
nativeShadowRoots: N[] = [];
fragments: N[][] = [];
rootContentInsertionPoints: N[] = [];
componentCount: number = 0;
isHost: boolean;
build(fragmentCmds: RenderTemplateCmd[]) {
this.enqueueFragmentBuilder(null, fragmentCmds);
@ -65,6 +72,7 @@ class BuildContext<N> {
}
enqueueComponentBuilder(component: Component<N>) {
this.componentCount++;
this._builders.push(new RenderViewBuilder<N>(
component, null, this.factory.resolveComponentTemplate(component.cmd.templateId)));
}
@ -131,10 +139,20 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
}
visitNgContent(cmd: RenderNgContentCmd, context: BuildContext<N>): any {
if (isPresent(this.parentComponent)) {
var projectedNodes = this.parentComponent.project(cmd.index);
for (var i = 0; i < projectedNodes.length; i++) {
var node = projectedNodes[i];
this._addChild(node, cmd.ngContentIndex, context);
if (this.parentComponent.isRoot) {
var insertionPoint = context.factory.createRootContentInsertionPoint();
if (this.parent instanceof Component) {
context.factory.appendChild((<Component<N>>this.parent).shadowRoot, insertionPoint);
} else {
context.factory.appendChild(<N>this.parent, insertionPoint);
}
context.rootContentInsertionPoints.push(insertionPoint);
} else {
var projectedNodes = this.parentComponent.project(cmd.index);
for (var i = 0; i < projectedNodes.length; i++) {
var node = projectedNodes[i];
this._addChild(node, cmd.ngContentIndex, context);
}
}
}
return null;
@ -154,7 +172,8 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
root = context.factory.createShadowRoot(el, cmd.templateId);
context.nativeShadowRoots.push(root);
}
var component = new Component(el, root, cmd);
var isRoot = context.componentCount === 0 && context.isHost;
var component = new Component(el, root, cmd, isRoot);
context.enqueueComponentBuilder(component);
this.parentStack.push(component);
return null;
@ -213,7 +232,8 @@ class RenderViewBuilder<N> implements RenderCommandVisitor {
class Component<N> {
private contentNodesByNgContentIndex: N[][] = [];
constructor(public hostElement: N, public shadowRoot: N, public cmd: RenderBeginComponentCmd) {}
constructor(public hostElement: N, public shadowRoot: N, public cmd: RenderBeginComponentCmd,
public isRoot: boolean) {}
addContentNode(ngContentIndex: number, node: N, context: BuildContext<N>) {
if (isBlank(ngContentIndex)) {
if (this.cmd.nativeShadow) {

View File

@ -517,6 +517,16 @@ export function main() {
expect(stringifyFragment(view.fragments[0].nodes))
.toEqual('<a-comp><b-comp>(hello)</b-comp></a-comp>');
});
it('should store content injection points for root component in a view', () => {
componentTemplates.set(0, [ngContent(0, null)]);
var view =
createRenderView([beginComponent('a-comp', [], [], false, null, 0), endComponent()],
DOM.createElement('root'), nodeFactory);
expect(stringifyFragment(view.rootContentInsertionPoints))
.toEqual('<root-content-insertion-point></root-content-insertion-point>');
});
});
});
}
@ -571,6 +581,9 @@ class DomNodeFactory implements NodeFactory<Node> {
return root;
}
createText(value: string): Node { return DOM.createTextNode(isPresent(value) ? value : ''); }
createRootContentInsertionPoint(): Node {
return DOM.createElement('root-content-insertion-point');
}
appendChild(parent: Node, child: Node) { DOM.appendChild(parent, child); }
on(element: Node, eventName: string, callback: Function) {
this._localEventListeners.push(new LocalEventListener(element, eventName, callback));

View File

@ -18,7 +18,7 @@ export function main() {
it('should register global event listeners', () => {
var addCount = 0;
var adder = () => { addCount++ };
var view = new DefaultRenderView<Node>([], [], [], [], [adder]);
var view = new DefaultRenderView<Node>([], [], [], [], [adder], []);
view.hydrate();
expect(addCount).toBe(1);
});
@ -28,7 +28,7 @@ export function main() {
it('should deregister global event listeners', () => {
var removeCount = 0;
var adder = () => () => { removeCount++ };
var view = new DefaultRenderView<Node>([], [], [], [], [adder]);
var view = new DefaultRenderView<Node>([], [], [], [], [adder], []);
view.hydrate();
view.dehydrate();
expect(removeCount).toBe(1);