diff --git a/modules/angular2/src/core/application.ts b/modules/angular2/src/core/application.ts index f3bd56c49f..87536509fb 100644 --- a/modules/angular2/src/core/application.ts +++ b/modules/angular2/src/core/application.ts @@ -80,7 +80,7 @@ function _injectorBindings(appComponentType): List> { var domView = resolveInternalDomView(componentRef.hostView.render); // We need to do this here to ensure that we create Testability and // it's ready on the window for users. - registry.registerApplication(domView.boundElements[0], testability); + registry.registerApplication(domView.boundElements[0].element, testability); return componentRef; }); diff --git a/modules/angular2/src/core/compiler/element_ref.ts b/modules/angular2/src/core/compiler/element_ref.ts index 6a3a456d7f..593f88f160 100644 --- a/modules/angular2/src/core/compiler/element_ref.ts +++ b/modules/angular2/src/core/compiler/element_ref.ts @@ -23,7 +23,9 @@ export class ElementRef { // We need a more general way to read/write to the DOM element // via a proper abstraction in the render layer get domElement() { - return resolveInternalDomView(this.parentView.render).boundElements[this.boundElementIndex]; + return resolveInternalDomView(this.parentView.render) + .boundElements[this.boundElementIndex] + .element; } /** diff --git a/modules/angular2/src/debug/debug_element.ts b/modules/angular2/src/debug/debug_element.ts index 72f752ad34..127cd16d37 100644 --- a/modules/angular2/src/debug/debug_element.ts +++ b/modules/angular2/src/debug/debug_element.ts @@ -43,7 +43,9 @@ export class DebugElement { } get domElement(): any { - return resolveInternalDomView(this._parentView.render).boundElements[this._boundElementIndex]; + return resolveInternalDomView(this._parentView.render) + .boundElements[this._boundElementIndex] + .element; } getDirectiveInstance(directiveIndex: number): any { diff --git a/modules/angular2/src/debug/debug_element_view_listener.ts b/modules/angular2/src/debug/debug_element_view_listener.ts index 9b9c1bf19b..938ed22281 100644 --- a/modules/angular2/src/debug/debug_element_view_listener.ts +++ b/modules/angular2/src/debug/debug_element_view_listener.ts @@ -61,7 +61,7 @@ export class DebugElementViewListener implements AppViewListener { MapWrapper.set(_allIdsByView, view, viewId); var renderView = resolveInternalDomView(view.render); for (var i = 0; i < renderView.boundElements.length; i++) { - _setElementId(renderView.boundElements[i], [viewId, i]); + _setElementId(renderView.boundElements[i].element, [viewId, i]); } } diff --git a/modules/angular2/src/render/dom/dom_renderer.ts b/modules/angular2/src/render/dom/dom_renderer.ts index 9bea4069d0..178f725557 100644 --- a/modules/angular2/src/render/dom/dom_renderer.ts +++ b/modules/angular2/src/render/dom/dom_renderer.ts @@ -16,6 +16,7 @@ import {EventManager} from './events/event_manager'; import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './view/proto_view'; import {DomView, DomViewRef, resolveInternalDomView} from './view/view'; +import {DomElement} from './view/element'; import {DomViewContainer} from './view/view_container'; import {NG_BINDING_CLASS_SELECTOR, NG_BINDING_CLASS} from './util'; @@ -65,8 +66,8 @@ export class DomRenderer extends Renderer { componentViewRef: RenderViewRef) { var hostView = resolveInternalDomView(hostViewRef); var componentView = resolveInternalDomView(componentViewRef); - var element = hostView.boundElements[elementIndex]; - var lightDom = hostView.lightDoms[elementIndex]; + var element = hostView.boundElements[elementIndex].element; + var lightDom = hostView.boundElements[elementIndex].lightDom; if (isPresent(lightDom)) { lightDom.attachShadowDomView(componentView); } @@ -92,7 +93,7 @@ export class DomRenderer extends Renderer { var hostView = resolveInternalDomView(hostViewRef); var componentView = resolveInternalDomView(componentViewRef); this._removeViewNodes(componentView); - var lightDom = hostView.lightDoms[boundElementIndex]; + var lightDom = hostView.boundElements[boundElementIndex].lightDom; if (isPresent(lightDom)) { lightDom.detachShadowDomView(); } @@ -108,11 +109,11 @@ export class DomRenderer extends Renderer { ListWrapper.insert(viewContainer.views, atIndex, view); view.hostLightDom = parentView.hostLightDom; - var directParentLightDom = parentView.getDirectParentLightDom(boundElementIndex); + var directParentLightDom = this._directParentLightDom(parentView, boundElementIndex); if (isBlank(directParentLightDom)) { var siblingToInsertAfter; if (atIndex == 0) { - siblingToInsertAfter = parentView.boundElements[boundElementIndex]; + siblingToInsertAfter = parentView.boundElements[boundElementIndex].element; } else { siblingToInsertAfter = ListWrapper.last(viewContainer.views[atIndex - 1].rootNodes); } @@ -130,10 +131,10 @@ export class DomRenderer extends Renderer { viewRef: RenderViewRef) { var parentView = resolveInternalDomView(parentViewRef); var view = resolveInternalDomView(viewRef); - var viewContainer = parentView.viewContainers[boundElementIndex]; + var viewContainer = parentView.boundElements[boundElementIndex].viewContainer; var detachedView = viewContainer.views[atIndex]; ListWrapper.removeAt(viewContainer.views, atIndex); - var directParentLightDom = parentView.getDirectParentLightDom(boundElementIndex); + var directParentLightDom = this._directParentLightDom(parentView, boundElementIndex); if (isBlank(directParentLightDom)) { this._removeViewNodes(detachedView); } else { @@ -151,8 +152,8 @@ export class DomRenderer extends Renderer { if (view.hydrated) throw new BaseException('The view is already hydrated.'); view.hydrated = true; - for (var i = 0; i < view.lightDoms.length; ++i) { - var lightDom = view.lightDoms[i]; + for (var i = 0; i < view.boundElements.length; ++i) { + var lightDom = view.boundElements[i].lightDom; if (isPresent(lightDom)) { lightDom.redistribute(); } @@ -244,7 +245,6 @@ export class DomRenderer extends Renderer { var binders = protoView.elementBinders; var boundTextNodes = []; var boundElements = ListWrapper.createFixedSize(binders.length); - var contentTags = ListWrapper.createFixedSize(binders.length); for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) { var binder = binders[binderIdx]; @@ -261,7 +261,6 @@ export class DomRenderer extends Renderer { element = elementsWithBindings[binderIdx - protoView.rootBindingOffset]; childNodes = DOM.childNodes(element); } - boundElements[binderIdx] = element; // boundTextNodes var textNodeIndices = binder.textNodeIndices; @@ -274,10 +273,10 @@ export class DomRenderer extends Renderer { if (isPresent(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++) { var binder = binders[binderIdx]; @@ -286,21 +285,21 @@ export class DomRenderer extends Renderer { // lightDoms var lightDom = null; 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 - var contentTag = contentTags[binderIdx]; + var contentTag = element.contentTag; if (isPresent(contentTag)) { - var destLightDom = view.getDirectParentLightDom(binderIdx); - contentTag.init(destLightDom); + var directParentLightDom = this._directParentLightDom(view, binderIdx); + contentTag.init(directParentLightDom); } // events if (isPresent(binder.eventLocals) && isPresent(binder.localEvents)) { 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); } } @@ -337,14 +336,20 @@ export class DomRenderer extends Renderer { } _getOrCreateViewContainer(parentView: DomView, boundElementIndex) { - var vc = parentView.viewContainers[boundElementIndex]; + var el = parentView.boundElements[boundElementIndex]; + var vc = el.viewContainer; if (isBlank(vc)) { vc = new DomViewContainer(); - parentView.viewContainers[boundElementIndex] = vc; + el.viewContainer = 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 { return this._eventManager.addGlobalEventListener( eventTarget, eventName, (event) => { view.dispatchEvent(elementIndex, fullName, event); }); diff --git a/modules/angular2/src/render/dom/shadow_dom/light_dom.ts b/modules/angular2/src/render/dom/shadow_dom/light_dom.ts index 76296ff682..5ae4dcd857 100644 --- a/modules/angular2/src/render/dom/shadow_dom/light_dom.ts +++ b/modules/angular2/src/render/dom/shadow_dom/light_dom.ts @@ -3,18 +3,13 @@ import {List, ListWrapper} from 'angular2/src/facade/collection'; import {isBlank, isPresent} from 'angular2/src/facade/lang'; import * as viewModule from '../view/view'; +import * as elModule from '../view/element'; import {Content} from './content_tag'; export class DestinationLightDom {} class _Root { - node; - boundElementIndex: number; - - constructor(node, boundElementIndex) { - this.node = node; - this.boundElementIndex = boundElementIndex; - } + constructor(public node, public boundElement: elModule.DomElement) {} } // TODO: LightDom should implement DestinationLightDom @@ -59,16 +54,14 @@ export class LightDom { if (view.proto.transitiveContentTagCount === 0) { return acc; } - var contentTags = view.contentTags; - var vcs = view.viewContainers; - for (var i = 0; i < vcs.length; i++) { - var vc = vcs[i]; - var contentTag = contentTags[i]; - if (isPresent(contentTag)) { - ListWrapper.push(acc, contentTag); + var els = view.boundElements; + for (var i = 0; i < els.length; i++) { + var el = els[i]; + if (isPresent(el.contentTag)) { + ListWrapper.push(acc, el.contentTag); } - if (isPresent(vc)) { - ListWrapper.forEach(vc.contentTagContainers(), + if (isPresent(el.viewContainer)) { + ListWrapper.forEach(el.viewContainer.contentTagContainers(), (view) => { this._collectAllContentTags(view, acc); }); } } @@ -85,9 +78,9 @@ export class LightDom { var roots = this._findRoots(); for (var i = 0; i < roots.length; ++i) { var root = roots[i]; - if (isPresent(root.boundElementIndex)) { - var vc = this.lightDomView.viewContainers[root.boundElementIndex]; - var content = this.lightDomView.contentTags[root.boundElementIndex]; + if (isPresent(root.boundElement)) { + var vc = root.boundElement.viewContainer; + var content = root.boundElement.contentTag; if (isPresent(vc)) { res = ListWrapper.concat(res, vc.nodes()); } else if (isPresent(content)) { @@ -103,22 +96,22 @@ export class LightDom { } // 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() { if (isPresent(this._roots)) return this._roots; var boundElements = this.lightDomView.boundElements; this._roots = ListWrapper.map(this.nodes, (n) => { - var boundElementIndex = null; + var boundElement = null; for (var i = 0; i < boundElements.length; i++) { var boundEl = boundElements[i]; - if (isPresent(boundEl) && boundEl === n) { - boundElementIndex = i; + if (isPresent(boundEl) && boundEl.element === n) { + boundElement = boundEl; break; } } - return new _Root(n, boundElementIndex); + return new _Root(n, boundElement); }); return this._roots; diff --git a/modules/angular2/src/render/dom/view/element.ts b/modules/angular2/src/render/dom/view/element.ts new file mode 100644 index 0000000000..dd237a3c5e --- /dev/null +++ b/modules/angular2/src/render/dom/view/element.ts @@ -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) {} +} diff --git a/modules/angular2/src/render/dom/view/view.ts b/modules/angular2/src/render/dom/view/view.ts index a6a78bd651..b1fbe94725 100644 --- a/modules/angular2/src/render/dom/view/view.ts +++ b/modules/angular2/src/render/dom/view/view.ts @@ -3,10 +3,9 @@ import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src import {Locals} from 'angular2/change_detection'; import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang'; -import {DomViewContainer} from './view_container'; import {DomProtoView} from './proto_view'; import {LightDom} from '../shadow_dom/light_dom'; -import {Content} from '../shadow_dom/content_tag'; +import {DomElement} from './element'; 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 */ export class DomView { - // TODO(tbosch): move componentChildViews, viewContainers, contentTags, lightDoms into - // a single array with records inside - viewContainers: List; - lightDoms: List; hostLightDom: LightDom; shadowRoot; hydrated: boolean; @@ -40,10 +35,7 @@ export class DomView { eventHandlerRemovers: List; constructor(public proto: DomProtoView, public rootNodes: List, - public boundTextNodes: List, - public boundElements: List, public contentTags: List) { - this.viewContainers = ListWrapper.createFixedSize(boundElements.length); - this.lightDoms = ListWrapper.createFixedSize(boundElements.length); + public boundTextNodes: List, public boundElements: List) { this.hostLightDom = null; this.hydrated = false; this.eventHandlerRemovers = []; @@ -51,25 +43,25 @@ export class DomView { this.shadowRoot = null; } - getDirectParentLightDom(boundElementIndex: number) { + getDirectParentElement(boundElementIndex: number): DomElement { var binder = this.proto.elementBinders[boundElementIndex]; - var destLightDom = null; + var parent = null; 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) { var setter = 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) { var binder = this.proto.elementBinders[elementIndex]; 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 { diff --git a/modules/angular2/test/render/dom/dom_testbed.ts b/modules/angular2/test/render/dom/dom_testbed.ts index c03aeee8e3..272bcfdc32 100644 --- a/modules/angular2/test/render/dom/dom_testbed.ts +++ b/modules/angular2/test/render/dom/dom_testbed.ts @@ -123,7 +123,7 @@ export class DomTestbed { } triggerEvent(viewRef: RenderViewRef, boundElementIndex: number, eventName: string) { - var element = resolveInternalDomView(viewRef).boundElements[boundElementIndex]; + var element = resolveInternalDomView(viewRef).boundElements[boundElementIndex].element; dispatchEvent(element, eventName); } } diff --git a/modules/angular2/test/render/dom/shadow_dom/light_dom_spec.ts b/modules/angular2/test/render/dom/shadow_dom/light_dom_spec.ts index 3806e6a7ed..4fc3fb92cf 100644 --- a/modules/angular2/test/render/dom/shadow_dom/light_dom_spec.ts +++ b/modules/angular2/test/render/dom/shadow_dom/light_dom_spec.ts @@ -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 {DomProtoView} from 'angular2/src/render/dom/view/proto_view'; import {DomViewContainer} from 'angular2/src/render/dom/view/view_container'; +import {DomElement} from 'angular2/src/render/dom/view/element'; @proxy @IMPLEMENTS(DomProtoView) @@ -31,31 +32,27 @@ class FakeProtoView extends SpyObject { @IMPLEMENTS(DomView) class FakeView extends SpyObject { boundElements; - contentTags; - viewContainers; proto; constructor(containers = null, transitiveContentTagCount: number = 1) { super(DomView); this.proto = new FakeProtoView(transitiveContentTagCount); this.boundElements = []; - this.contentTags = []; - this.viewContainers = []; if (isPresent(containers)) { ListWrapper.forEach(containers, (c) => { - var boundElement = null; + var element = null; var contentTag = null; var vc = null; if (c instanceof FakeContentTag) { contentTag = c; - boundElement = c.contentStartElement; + element = c.contentStartElement; } if (c instanceof FakeViewContainer) { vc = c; - boundElement = c.templateElement; + element = c.templateElement; } - ListWrapper.push(this.contentTags, contentTag); - ListWrapper.push(this.viewContainers, vc); + var boundElement = new DomElement(null, element, contentTag); + boundElement.viewContainer = vc; ListWrapper.push(this.boundElements, boundElement); }); } diff --git a/modules/angular2/test/render/dom/view/view_spec.ts b/modules/angular2/test/render/dom/view/view_spec.ts index e96f97c6ba..3d3f6f82cc 100644 --- a/modules/angular2/test/render/dom/view/view_spec.ts +++ b/modules/angular2/test/render/dom/view/view_spec.ts @@ -15,13 +15,13 @@ import { SpyObject, proxy } 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 {DomProtoView} from 'angular2/src/render/dom/view/proto_view'; import {ElementBinder} from 'angular2/src/render/dom/view/element_binder'; 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'; export function main() { @@ -42,20 +42,19 @@ export function main() { var root = el('
'); var boundElements = []; for (var i = 0; i < boundElementCount; i++) { - ListWrapper.push(boundElements, el(' { + describe('getDirectParentElement', () => { - it('should return the LightDom of the direct parent', () => { + it('should return the DomElement of the direct parent', () => { var pv = createProtoView( [new ElementBinder(), new ElementBinder({parentIndex: 0, distanceToParent: 1})]); var view = createView(pv, 2); - view.lightDoms[0] = new SpyLightDom(); - view.lightDoms[1] = new SpyLightDom(); - expect(view.getDirectParentLightDom(1)).toBe(view.lightDoms[0]); + expect(view.getDirectParentElement(1)).toBe(view.boundElements[0]); }); it('should return null if the direct parent is not bound', () => { @@ -65,20 +64,10 @@ export function main() { new ElementBinder({parentIndex: 0, distanceToParent: 2}) ]); var view = createView(pv, 3); - view.lightDoms[0] = new SpyLightDom(); - view.lightDoms[1] = new SpyLightDom(); - view.lightDoms[2] = new SpyLightDom(); - expect(view.getDirectParentLightDom(2)).toBe(null); + expect(view.getDirectParentElement(2)).toBe(null); }); }); }); } - -@proxy -@IMPLEMENTS(LightDom) -class SpyLightDom extends SpyObject { - constructor() { super(LightDom); } - noSuchMethod(m) { return super.noSuchMethod(m) } -}