refactor(render): add DomElement

Replaces the multiple arrays of `DomView`
by a single array with `DomElement`s.

Note: this commit does not show a performance regression
(tested against the tree benchmark locally).
This commit is contained in:
Tobias Bosch 2015-06-02 10:15:16 -07:00
parent 0a50a3f564
commit 827841ec5b
11 changed files with 86 additions and 95 deletions

View File

@ -80,7 +80,7 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
var domView = resolveInternalDomView(componentRef.hostView.render); var domView = resolveInternalDomView(componentRef.hostView.render);
// We need to do this here to ensure that we create Testability and // We need to do this here to ensure that we create Testability and
// it's ready on the window for users. // it's ready on the window for users.
registry.registerApplication(domView.boundElements[0], testability); registry.registerApplication(domView.boundElements[0].element, testability);
return componentRef; return componentRef;
}); });

View File

@ -23,7 +23,9 @@ export class ElementRef {
// We need a more general way to read/write to the DOM element // We need a more general way to read/write to the DOM element
// via a proper abstraction in the render layer // via a proper abstraction in the render layer
get domElement() { get domElement() {
return resolveInternalDomView(this.parentView.render).boundElements[this.boundElementIndex]; return resolveInternalDomView(this.parentView.render)
.boundElements[this.boundElementIndex]
.element;
} }
/** /**

View File

@ -43,7 +43,9 @@ export class DebugElement {
} }
get domElement(): any { get domElement(): any {
return resolveInternalDomView(this._parentView.render).boundElements[this._boundElementIndex]; return resolveInternalDomView(this._parentView.render)
.boundElements[this._boundElementIndex]
.element;
} }
getDirectiveInstance(directiveIndex: number): any { getDirectiveInstance(directiveIndex: number): any {

View File

@ -61,7 +61,7 @@ export class DebugElementViewListener implements AppViewListener {
MapWrapper.set(_allIdsByView, view, viewId); MapWrapper.set(_allIdsByView, view, viewId);
var renderView = resolveInternalDomView(view.render); var renderView = resolveInternalDomView(view.render);
for (var i = 0; i < renderView.boundElements.length; i++) { for (var i = 0; i < renderView.boundElements.length; i++) {
_setElementId(renderView.boundElements[i], [viewId, i]); _setElementId(renderView.boundElements[i].element, [viewId, i]);
} }
} }

View File

@ -16,6 +16,7 @@ import {EventManager} from './events/event_manager';
import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './view/proto_view'; import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './view/proto_view';
import {DomView, DomViewRef, resolveInternalDomView} from './view/view'; import {DomView, DomViewRef, resolveInternalDomView} from './view/view';
import {DomElement} from './view/element';
import {DomViewContainer} from './view/view_container'; import {DomViewContainer} from './view/view_container';
import {NG_BINDING_CLASS_SELECTOR, NG_BINDING_CLASS} from './util'; import {NG_BINDING_CLASS_SELECTOR, NG_BINDING_CLASS} from './util';
@ -65,8 +66,8 @@ export class DomRenderer extends Renderer {
componentViewRef: RenderViewRef) { componentViewRef: RenderViewRef) {
var hostView = resolveInternalDomView(hostViewRef); var hostView = resolveInternalDomView(hostViewRef);
var componentView = resolveInternalDomView(componentViewRef); var componentView = resolveInternalDomView(componentViewRef);
var element = hostView.boundElements[elementIndex]; var element = hostView.boundElements[elementIndex].element;
var lightDom = hostView.lightDoms[elementIndex]; var lightDom = hostView.boundElements[elementIndex].lightDom;
if (isPresent(lightDom)) { if (isPresent(lightDom)) {
lightDom.attachShadowDomView(componentView); lightDom.attachShadowDomView(componentView);
} }
@ -92,7 +93,7 @@ export class DomRenderer extends Renderer {
var hostView = resolveInternalDomView(hostViewRef); var hostView = resolveInternalDomView(hostViewRef);
var componentView = resolveInternalDomView(componentViewRef); var componentView = resolveInternalDomView(componentViewRef);
this._removeViewNodes(componentView); this._removeViewNodes(componentView);
var lightDom = hostView.lightDoms[boundElementIndex]; var lightDom = hostView.boundElements[boundElementIndex].lightDom;
if (isPresent(lightDom)) { if (isPresent(lightDom)) {
lightDom.detachShadowDomView(); lightDom.detachShadowDomView();
} }
@ -108,11 +109,11 @@ export class DomRenderer extends Renderer {
ListWrapper.insert(viewContainer.views, atIndex, view); ListWrapper.insert(viewContainer.views, atIndex, view);
view.hostLightDom = parentView.hostLightDom; view.hostLightDom = parentView.hostLightDom;
var directParentLightDom = parentView.getDirectParentLightDom(boundElementIndex); var directParentLightDom = this._directParentLightDom(parentView, boundElementIndex);
if (isBlank(directParentLightDom)) { if (isBlank(directParentLightDom)) {
var siblingToInsertAfter; var siblingToInsertAfter;
if (atIndex == 0) { if (atIndex == 0) {
siblingToInsertAfter = parentView.boundElements[boundElementIndex]; siblingToInsertAfter = parentView.boundElements[boundElementIndex].element;
} else { } else {
siblingToInsertAfter = ListWrapper.last(viewContainer.views[atIndex - 1].rootNodes); siblingToInsertAfter = ListWrapper.last(viewContainer.views[atIndex - 1].rootNodes);
} }
@ -130,10 +131,10 @@ export class DomRenderer extends Renderer {
viewRef: RenderViewRef) { viewRef: RenderViewRef) {
var parentView = resolveInternalDomView(parentViewRef); var parentView = resolveInternalDomView(parentViewRef);
var view = resolveInternalDomView(viewRef); var view = resolveInternalDomView(viewRef);
var viewContainer = parentView.viewContainers[boundElementIndex]; var viewContainer = parentView.boundElements[boundElementIndex].viewContainer;
var detachedView = viewContainer.views[atIndex]; var detachedView = viewContainer.views[atIndex];
ListWrapper.removeAt(viewContainer.views, atIndex); ListWrapper.removeAt(viewContainer.views, atIndex);
var directParentLightDom = parentView.getDirectParentLightDom(boundElementIndex); var directParentLightDom = this._directParentLightDom(parentView, boundElementIndex);
if (isBlank(directParentLightDom)) { if (isBlank(directParentLightDom)) {
this._removeViewNodes(detachedView); this._removeViewNodes(detachedView);
} else { } else {
@ -151,8 +152,8 @@ export class DomRenderer extends Renderer {
if (view.hydrated) throw new BaseException('The view is already hydrated.'); if (view.hydrated) throw new BaseException('The view is already hydrated.');
view.hydrated = true; view.hydrated = true;
for (var i = 0; i < view.lightDoms.length; ++i) { for (var i = 0; i < view.boundElements.length; ++i) {
var lightDom = view.lightDoms[i]; var lightDom = view.boundElements[i].lightDom;
if (isPresent(lightDom)) { if (isPresent(lightDom)) {
lightDom.redistribute(); lightDom.redistribute();
} }
@ -244,7 +245,6 @@ export class DomRenderer extends Renderer {
var binders = protoView.elementBinders; var binders = protoView.elementBinders;
var boundTextNodes = []; var boundTextNodes = [];
var boundElements = ListWrapper.createFixedSize(binders.length); var boundElements = ListWrapper.createFixedSize(binders.length);
var contentTags = ListWrapper.createFixedSize(binders.length);
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) { for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
var binder = binders[binderIdx]; var binder = binders[binderIdx];
@ -261,7 +261,6 @@ export class DomRenderer extends Renderer {
element = elementsWithBindings[binderIdx - protoView.rootBindingOffset]; element = elementsWithBindings[binderIdx - protoView.rootBindingOffset];
childNodes = DOM.childNodes(element); childNodes = DOM.childNodes(element);
} }
boundElements[binderIdx] = element;
// boundTextNodes // boundTextNodes
var textNodeIndices = binder.textNodeIndices; var textNodeIndices = binder.textNodeIndices;
@ -274,10 +273,10 @@ export class DomRenderer extends Renderer {
if (isPresent(binder.contentTagSelector)) { if (isPresent(binder.contentTagSelector)) {
contentTag = new Content(element, binder.contentTagSelector); contentTag = new Content(element, binder.contentTagSelector);
} }
contentTags[binderIdx] = contentTag; boundElements[binderIdx] = new DomElement(binder, element, contentTag);
} }
var view = new DomView(protoView, viewRootNodes, boundTextNodes, boundElements, contentTags); var view = new DomView(protoView, viewRootNodes, boundTextNodes, boundElements);
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) { for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
var binder = binders[binderIdx]; var binder = binders[binderIdx];
@ -286,21 +285,21 @@ export class DomRenderer extends Renderer {
// lightDoms // lightDoms
var lightDom = null; var lightDom = null;
if (isPresent(binder.componentId)) { if (isPresent(binder.componentId)) {
lightDom = this._shadowDomStrategy.constructLightDom(view, boundElements[binderIdx]); lightDom = this._shadowDomStrategy.constructLightDom(view, element.element);
} }
view.lightDoms[binderIdx] = lightDom; element.lightDom = lightDom;
// init contentTags // init contentTags
var contentTag = contentTags[binderIdx]; var contentTag = element.contentTag;
if (isPresent(contentTag)) { if (isPresent(contentTag)) {
var destLightDom = view.getDirectParentLightDom(binderIdx); var directParentLightDom = this._directParentLightDom(view, binderIdx);
contentTag.init(destLightDom); contentTag.init(directParentLightDom);
} }
// events // events
if (isPresent(binder.eventLocals) && isPresent(binder.localEvents)) { if (isPresent(binder.eventLocals) && isPresent(binder.localEvents)) {
for (var i = 0; i < binder.localEvents.length; i++) { for (var i = 0; i < binder.localEvents.length; i++) {
this._createEventListener(view, element, binderIdx, binder.localEvents[i].name, this._createEventListener(view, element.element, binderIdx, binder.localEvents[i].name,
binder.eventLocals); binder.eventLocals);
} }
} }
@ -337,14 +336,20 @@ export class DomRenderer extends Renderer {
} }
_getOrCreateViewContainer(parentView: DomView, boundElementIndex) { _getOrCreateViewContainer(parentView: DomView, boundElementIndex) {
var vc = parentView.viewContainers[boundElementIndex]; var el = parentView.boundElements[boundElementIndex];
var vc = el.viewContainer;
if (isBlank(vc)) { if (isBlank(vc)) {
vc = new DomViewContainer(); vc = new DomViewContainer();
parentView.viewContainers[boundElementIndex] = vc; el.viewContainer = vc;
} }
return vc; return vc;
} }
_directParentLightDom(view: DomView, boundElementIndex: number) {
var directParentEl = view.getDirectParentElement(boundElementIndex);
return isPresent(directParentEl) ? directParentEl.lightDom : null;
}
_createGlobalEventListener(view, elementIndex, eventName, eventTarget, fullName): Function { _createGlobalEventListener(view, elementIndex, eventName, eventTarget, fullName): Function {
return this._eventManager.addGlobalEventListener( return this._eventManager.addGlobalEventListener(
eventTarget, eventName, (event) => { view.dispatchEvent(elementIndex, fullName, event); }); eventTarget, eventName, (event) => { view.dispatchEvent(elementIndex, fullName, event); });

View File

@ -3,18 +3,13 @@ import {List, ListWrapper} from 'angular2/src/facade/collection';
import {isBlank, isPresent} from 'angular2/src/facade/lang'; import {isBlank, isPresent} from 'angular2/src/facade/lang';
import * as viewModule from '../view/view'; import * as viewModule from '../view/view';
import * as elModule from '../view/element';
import {Content} from './content_tag'; import {Content} from './content_tag';
export class DestinationLightDom {} export class DestinationLightDom {}
class _Root { class _Root {
node; constructor(public node, public boundElement: elModule.DomElement) {}
boundElementIndex: number;
constructor(node, boundElementIndex) {
this.node = node;
this.boundElementIndex = boundElementIndex;
}
} }
// TODO: LightDom should implement DestinationLightDom // TODO: LightDom should implement DestinationLightDom
@ -59,16 +54,14 @@ export class LightDom {
if (view.proto.transitiveContentTagCount === 0) { if (view.proto.transitiveContentTagCount === 0) {
return acc; return acc;
} }
var contentTags = view.contentTags; var els = view.boundElements;
var vcs = view.viewContainers; for (var i = 0; i < els.length; i++) {
for (var i = 0; i < vcs.length; i++) { var el = els[i];
var vc = vcs[i]; if (isPresent(el.contentTag)) {
var contentTag = contentTags[i]; ListWrapper.push(acc, el.contentTag);
if (isPresent(contentTag)) {
ListWrapper.push(acc, contentTag);
} }
if (isPresent(vc)) { if (isPresent(el.viewContainer)) {
ListWrapper.forEach(vc.contentTagContainers(), ListWrapper.forEach(el.viewContainer.contentTagContainers(),
(view) => { this._collectAllContentTags(view, acc); }); (view) => { this._collectAllContentTags(view, acc); });
} }
} }
@ -85,9 +78,9 @@ export class LightDom {
var roots = this._findRoots(); var roots = this._findRoots();
for (var i = 0; i < roots.length; ++i) { for (var i = 0; i < roots.length; ++i) {
var root = roots[i]; var root = roots[i];
if (isPresent(root.boundElementIndex)) { if (isPresent(root.boundElement)) {
var vc = this.lightDomView.viewContainers[root.boundElementIndex]; var vc = root.boundElement.viewContainer;
var content = this.lightDomView.contentTags[root.boundElementIndex]; var content = root.boundElement.contentTag;
if (isPresent(vc)) { if (isPresent(vc)) {
res = ListWrapper.concat(res, vc.nodes()); res = ListWrapper.concat(res, vc.nodes());
} else if (isPresent(content)) { } else if (isPresent(content)) {
@ -103,22 +96,22 @@ export class LightDom {
} }
// Returns a list of Roots for all the nodes of the light DOM. // Returns a list of Roots for all the nodes of the light DOM.
// The Root object contains the DOM node and its corresponding boundElementIndex // The Root object contains the DOM node and its corresponding boundElement
private _findRoots() { private _findRoots() {
if (isPresent(this._roots)) return this._roots; if (isPresent(this._roots)) return this._roots;
var boundElements = this.lightDomView.boundElements; var boundElements = this.lightDomView.boundElements;
this._roots = ListWrapper.map(this.nodes, (n) => { this._roots = ListWrapper.map(this.nodes, (n) => {
var boundElementIndex = null; var boundElement = null;
for (var i = 0; i < boundElements.length; i++) { for (var i = 0; i < boundElements.length; i++) {
var boundEl = boundElements[i]; var boundEl = boundElements[i];
if (isPresent(boundEl) && boundEl === n) { if (isPresent(boundEl) && boundEl.element === n) {
boundElementIndex = i; boundElement = boundEl;
break; break;
} }
} }
return new _Root(n, boundElementIndex); return new _Root(n, boundElement);
}); });
return this._roots; return this._roots;

View File

@ -0,0 +1,11 @@
import {ElementBinder} from './element_binder';
import {DomViewContainer} from './view_container';
import {LightDom} from '../shadow_dom/light_dom';
import {Content} from '../shadow_dom/content_tag';
export class DomElement {
viewContainer: DomViewContainer;
lightDom: LightDom;
constructor(public proto: ElementBinder, public element: any /* element */,
public contentTag: Content) {}
}

View File

@ -3,10 +3,9 @@ import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src
import {Locals} from 'angular2/change_detection'; import {Locals} from 'angular2/change_detection';
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang'; import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import {DomViewContainer} from './view_container';
import {DomProtoView} from './proto_view'; import {DomProtoView} from './proto_view';
import {LightDom} from '../shadow_dom/light_dom'; import {LightDom} from '../shadow_dom/light_dom';
import {Content} from '../shadow_dom/content_tag'; import {DomElement} from './element';
import {RenderViewRef, EventDispatcher} from '../../api'; import {RenderViewRef, EventDispatcher} from '../../api';
@ -29,10 +28,6 @@ const NG_BINDING_CLASS = 'ng-binding';
* Const of making objects: http://jsperf.com/instantiate-size-of-object * Const of making objects: http://jsperf.com/instantiate-size-of-object
*/ */
export class DomView { export class DomView {
// TODO(tbosch): move componentChildViews, viewContainers, contentTags, lightDoms into
// a single array with records inside
viewContainers: List<DomViewContainer>;
lightDoms: List<LightDom>;
hostLightDom: LightDom; hostLightDom: LightDom;
shadowRoot; shadowRoot;
hydrated: boolean; hydrated: boolean;
@ -40,10 +35,7 @@ export class DomView {
eventHandlerRemovers: List<Function>; eventHandlerRemovers: List<Function>;
constructor(public proto: DomProtoView, public rootNodes: List</*node*/ any>, constructor(public proto: DomProtoView, public rootNodes: List</*node*/ any>,
public boundTextNodes: List</*node*/ any>, public boundTextNodes: List</*node*/ any>, public boundElements: List<DomElement>) {
public boundElements: List</*element*/ any>, public contentTags: List<Content>) {
this.viewContainers = ListWrapper.createFixedSize(boundElements.length);
this.lightDoms = ListWrapper.createFixedSize(boundElements.length);
this.hostLightDom = null; this.hostLightDom = null;
this.hydrated = false; this.hydrated = false;
this.eventHandlerRemovers = []; this.eventHandlerRemovers = [];
@ -51,25 +43,25 @@ export class DomView {
this.shadowRoot = null; this.shadowRoot = null;
} }
getDirectParentLightDom(boundElementIndex: number) { getDirectParentElement(boundElementIndex: number): DomElement {
var binder = this.proto.elementBinders[boundElementIndex]; var binder = this.proto.elementBinders[boundElementIndex];
var destLightDom = null; var parent = null;
if (binder.parentIndex !== -1 && binder.distanceToParent === 1) { if (binder.parentIndex !== -1 && binder.distanceToParent === 1) {
destLightDom = this.lightDoms[binder.parentIndex]; parent = this.boundElements[binder.parentIndex];
} }
return destLightDom; return parent;
} }
setElementProperty(elementIndex: number, propertyName: string, value: any) { setElementProperty(elementIndex: number, propertyName: string, value: any) {
var setter = var setter =
MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName); MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName);
setter(this.boundElements[elementIndex], value); setter(this.boundElements[elementIndex].element, value);
} }
callAction(elementIndex: number, actionExpression: string, actionArgs: any) { callAction(elementIndex: number, actionExpression: string, actionArgs: any) {
var binder = this.proto.elementBinders[elementIndex]; var binder = this.proto.elementBinders[elementIndex];
var hostAction = MapWrapper.get(binder.hostActions, actionExpression); var hostAction = MapWrapper.get(binder.hostActions, actionExpression);
hostAction.eval(this.boundElements[elementIndex], this._localsWithAction(actionArgs)); hostAction.eval(this.boundElements[elementIndex].element, this._localsWithAction(actionArgs));
} }
_localsWithAction(action: Object): Locals { _localsWithAction(action: Object): Locals {

View File

@ -123,7 +123,7 @@ export class DomTestbed {
} }
triggerEvent(viewRef: RenderViewRef, boundElementIndex: number, eventName: string) { triggerEvent(viewRef: RenderViewRef, boundElementIndex: number, eventName: string) {
var element = resolveInternalDomView(viewRef).boundElements[boundElementIndex]; var element = resolveInternalDomView(viewRef).boundElements[boundElementIndex].element;
dispatchEvent(element, eventName); dispatchEvent(element, eventName);
} }
} }

View File

@ -18,6 +18,7 @@ import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
import {DomView} from 'angular2/src/render/dom/view/view'; import {DomView} from 'angular2/src/render/dom/view/view';
import {DomProtoView} from 'angular2/src/render/dom/view/proto_view'; import {DomProtoView} from 'angular2/src/render/dom/view/proto_view';
import {DomViewContainer} from 'angular2/src/render/dom/view/view_container'; import {DomViewContainer} from 'angular2/src/render/dom/view/view_container';
import {DomElement} from 'angular2/src/render/dom/view/element';
@proxy @proxy
@IMPLEMENTS(DomProtoView) @IMPLEMENTS(DomProtoView)
@ -31,31 +32,27 @@ class FakeProtoView extends SpyObject {
@IMPLEMENTS(DomView) @IMPLEMENTS(DomView)
class FakeView extends SpyObject { class FakeView extends SpyObject {
boundElements; boundElements;
contentTags;
viewContainers;
proto; proto;
constructor(containers = null, transitiveContentTagCount: number = 1) { constructor(containers = null, transitiveContentTagCount: number = 1) {
super(DomView); super(DomView);
this.proto = new FakeProtoView(transitiveContentTagCount); this.proto = new FakeProtoView(transitiveContentTagCount);
this.boundElements = []; this.boundElements = [];
this.contentTags = [];
this.viewContainers = [];
if (isPresent(containers)) { if (isPresent(containers)) {
ListWrapper.forEach(containers, (c) => { ListWrapper.forEach(containers, (c) => {
var boundElement = null; var element = null;
var contentTag = null; var contentTag = null;
var vc = null; var vc = null;
if (c instanceof FakeContentTag) { if (c instanceof FakeContentTag) {
contentTag = c; contentTag = c;
boundElement = c.contentStartElement; element = c.contentStartElement;
} }
if (c instanceof FakeViewContainer) { if (c instanceof FakeViewContainer) {
vc = c; vc = c;
boundElement = c.templateElement; element = c.templateElement;
} }
ListWrapper.push(this.contentTags, contentTag); var boundElement = new DomElement(null, element, contentTag);
ListWrapper.push(this.viewContainers, vc); boundElement.viewContainer = vc;
ListWrapper.push(this.boundElements, boundElement); ListWrapper.push(this.boundElements, boundElement);
}); });
} }

View File

@ -15,13 +15,13 @@ import {
SpyObject, SpyObject,
proxy proxy
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang'; import {isBlank} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection'; import {ListWrapper} from 'angular2/src/facade/collection';
import {DomProtoView} from 'angular2/src/render/dom/view/proto_view'; import {DomProtoView} from 'angular2/src/render/dom/view/proto_view';
import {ElementBinder} from 'angular2/src/render/dom/view/element_binder'; import {ElementBinder} from 'angular2/src/render/dom/view/element_binder';
import {DomView} from 'angular2/src/render/dom/view/view'; import {DomView} from 'angular2/src/render/dom/view/view';
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom'; import {DomElement} from 'angular2/src/render/dom/view/element';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
export function main() { export function main() {
@ -42,20 +42,19 @@ export function main() {
var root = el('<div><div></div></div>'); var root = el('<div><div></div></div>');
var boundElements = []; var boundElements = [];
for (var i = 0; i < boundElementCount; i++) { for (var i = 0; i < boundElementCount; i++) {
ListWrapper.push(boundElements, el('<span></span')); ListWrapper.push(boundElements,
new DomElement(pv.elementBinders[i], el('<span></span'), null));
} }
return new DomView(pv, [DOM.childNodes(root)[0]], [], boundElements, []); return new DomView(pv, [DOM.childNodes(root)[0]], [], boundElements);
} }
describe('getDirectParentLightDom', () => { describe('getDirectParentElement', () => {
it('should return the LightDom of the direct parent', () => { it('should return the DomElement of the direct parent', () => {
var pv = createProtoView( var pv = createProtoView(
[new ElementBinder(), new ElementBinder({parentIndex: 0, distanceToParent: 1})]); [new ElementBinder(), new ElementBinder({parentIndex: 0, distanceToParent: 1})]);
var view = createView(pv, 2); var view = createView(pv, 2);
view.lightDoms[0] = <any>new SpyLightDom(); expect(view.getDirectParentElement(1)).toBe(view.boundElements[0]);
view.lightDoms[1] = <any>new SpyLightDom();
expect(view.getDirectParentLightDom(1)).toBe(view.lightDoms[0]);
}); });
it('should return null if the direct parent is not bound', () => { it('should return null if the direct parent is not bound', () => {
@ -65,20 +64,10 @@ export function main() {
new ElementBinder({parentIndex: 0, distanceToParent: 2}) new ElementBinder({parentIndex: 0, distanceToParent: 2})
]); ]);
var view = createView(pv, 3); var view = createView(pv, 3);
view.lightDoms[0] = <any>new SpyLightDom(); expect(view.getDirectParentElement(2)).toBe(null);
view.lightDoms[1] = <any>new SpyLightDom();
view.lightDoms[2] = <any>new SpyLightDom();
expect(view.getDirectParentLightDom(2)).toBe(null);
}); });
}); });
}); });
} }
@proxy
@IMPLEMENTS(LightDom)
class SpyLightDom extends SpyObject {
constructor() { super(LightDom); }
noSuchMethod(m) { return super.noSuchMethod(m) }
}