refactor(render): remove recursion from renderer
The goal is to make implementing a renderer straight forward. BREAKING_CHANGE: - Renderer interface was redone / simplified. - `DirectDomRenderer` was replaced by `DomRenderer`. - `DirectDomRenderer.setImperativeComponentRootNodes` is replaced by the following 2 steps: 1. `ViewManager.getComponentView(elementRef) -> ViewRef` 2. `DomRenderer.setComponentViewRootNodes(viewRef, rootNodes)` - all `@View` annotations need to have a template, but the template may be empty. Previously views that had a `renderer` property did not have to have a `template`. - `dynamicComponentLoader.loadIntoNewLocation` does no more allow to pass an element, but requires a css selector. Special syntax: `:document` can be used as prefix to search globally on the document instead of in the provided parent view. Part of #1675
This commit is contained in:
parent
d2507ac760
commit
c68fa27444
|
@ -5,4 +5,4 @@ export * from './directives';
|
||||||
export * from './forms';
|
export * from './forms';
|
||||||
export {Observable, EventEmitter} from 'angular2/src/facade/async';
|
export {Observable, EventEmitter} from 'angular2/src/facade/async';
|
||||||
export * from 'angular2/src/render/api';
|
export * from 'angular2/src/render/api';
|
||||||
export {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
export {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
|
||||||
|
|
|
@ -33,17 +33,14 @@ import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
||||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
import {Renderer, RenderCompiler} from 'angular2/src/render/api';
|
import {Renderer, RenderCompiler} from 'angular2/src/render/api';
|
||||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
|
||||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
|
||||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
|
||||||
import * as rvh from 'angular2/src/render/dom/view/view_hydrator';
|
|
||||||
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
appComponentRefToken,
|
appComponentRefToken,
|
||||||
appElementToken,
|
appComponentAnnotatedTypeToken
|
||||||
appComponentAnnotatedTypeToken,
|
|
||||||
appDocumentToken,
|
|
||||||
} from './application_tokens';
|
} from './application_tokens';
|
||||||
|
|
||||||
var _rootInjector: Injector;
|
var _rootInjector: Injector;
|
||||||
|
@ -56,28 +53,25 @@ var _rootBindings = [
|
||||||
|
|
||||||
function _injectorBindings(appComponentType): List<Binding> {
|
function _injectorBindings(appComponentType): List<Binding> {
|
||||||
return [
|
return [
|
||||||
bind(appDocumentToken).toValue(DOM.defaultDoc()),
|
bind(DOCUMENT_TOKEN).toValue(DOM.defaultDoc()),
|
||||||
bind(appComponentAnnotatedTypeToken).toFactory((reader) => {
|
bind(appComponentAnnotatedTypeToken).toFactory((reader) => {
|
||||||
// TODO(rado): investigate whether to support bindings on root component.
|
// TODO(rado): investigate whether to support bindings on root component.
|
||||||
return reader.read(appComponentType);
|
return reader.read(appComponentType);
|
||||||
}, [DirectiveMetadataReader]),
|
}, [DirectiveMetadataReader]),
|
||||||
|
|
||||||
bind(appElementToken).toFactory((appComponentAnnotatedType, appDocument) => {
|
bind(appComponentRefToken).toAsyncFactory((dynamicComponentLoader, injector,
|
||||||
var selector = appComponentAnnotatedType.annotation.selector;
|
|
||||||
var element = DOM.querySelector(appDocument, selector);
|
|
||||||
if (isBlank(element)) {
|
|
||||||
throw new BaseException(`The app selector "${selector}" did not match any elements`);
|
|
||||||
}
|
|
||||||
return element;
|
|
||||||
}, [appComponentAnnotatedTypeToken, appDocumentToken]),
|
|
||||||
bind(appComponentRefToken).toAsyncFactory((dynamicComponentLoader, injector, appElement,
|
|
||||||
appComponentAnnotatedType, testability, registry) => {
|
appComponentAnnotatedType, testability, registry) => {
|
||||||
|
|
||||||
|
var selector = appComponentAnnotatedType.annotation.selector;
|
||||||
|
return dynamicComponentLoader.loadIntoNewLocation(appComponentAnnotatedType.type, null, selector, injector).then( (componentRef) => {
|
||||||
|
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(appElement, testability);
|
registry.registerApplication(domView.boundElements[0], testability);
|
||||||
return dynamicComponentLoader.loadIntoNewLocation(appComponentAnnotatedType.type, null, appElement, injector);
|
|
||||||
}, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken,
|
return componentRef;
|
||||||
|
});
|
||||||
|
}, [DynamicComponentLoader, Injector, appComponentAnnotatedTypeToken,
|
||||||
Testability, TestabilityRegistry]),
|
Testability, TestabilityRegistry]),
|
||||||
|
|
||||||
bind(appComponentType).toFactory((ref) => ref.instance,
|
bind(appComponentType).toFactory((ref) => ref.instance,
|
||||||
|
@ -89,18 +83,16 @@ function _injectorBindings(appComponentType): List<Binding> {
|
||||||
}, [VmTurnZone]),
|
}, [VmTurnZone]),
|
||||||
bind(ShadowDomStrategy).toFactory(
|
bind(ShadowDomStrategy).toFactory(
|
||||||
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
||||||
[StyleUrlResolver, appDocumentToken]),
|
[StyleUrlResolver, DOCUMENT_TOKEN]),
|
||||||
DirectDomRenderer,
|
|
||||||
bind(Renderer).toClass(DirectDomRenderer),
|
|
||||||
bind(RenderCompiler).toClass(rc.DefaultDomCompiler),
|
|
||||||
// TODO(tbosch): We need an explicit factory here, as
|
// TODO(tbosch): We need an explicit factory here, as
|
||||||
// we are getting errors in dart2js with mirrors...
|
// we are getting errors in dart2js with mirrors...
|
||||||
bind(rvf.ViewFactory).toFactory(
|
bind(DomRenderer).toFactory(
|
||||||
(capacity, eventManager, shadowDomStrategy) => new rvf.ViewFactory(capacity, eventManager, shadowDomStrategy),
|
(eventManager, shadowDomStrategy, doc) => new DomRenderer(eventManager, shadowDomStrategy, doc),
|
||||||
[rvf.VIEW_POOL_CAPACITY, EventManager, ShadowDomStrategy]
|
[EventManager, ShadowDomStrategy, DOCUMENT_TOKEN]
|
||||||
),
|
),
|
||||||
bind(rvf.VIEW_POOL_CAPACITY).toValue(10000),
|
DefaultDomCompiler,
|
||||||
rvh.RenderViewHydrator,
|
bind(Renderer).toAlias(DomRenderer),
|
||||||
|
bind(RenderCompiler).toAlias(DefaultDomCompiler),
|
||||||
ProtoViewFactory,
|
ProtoViewFactory,
|
||||||
// TODO(tbosch): We need an explicit factory here, as
|
// TODO(tbosch): We need an explicit factory here, as
|
||||||
// we are getting errors in dart2js with mirrors...
|
// we are getting errors in dart2js with mirrors...
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import {OpaqueToken} from 'angular2/di';
|
import {OpaqueToken} from 'angular2/di';
|
||||||
|
|
||||||
export var appComponentRefToken:OpaqueToken = new OpaqueToken('ComponentRef');
|
export var appComponentRefToken:OpaqueToken = new OpaqueToken('ComponentRef');
|
||||||
export var appElementToken:OpaqueToken = new OpaqueToken('AppElement');
|
|
||||||
export var appComponentAnnotatedTypeToken:OpaqueToken = new OpaqueToken('AppComponentAnnotatedType');
|
export var appComponentAnnotatedTypeToken:OpaqueToken = new OpaqueToken('AppComponentAnnotatedType');
|
||||||
export var appDocumentToken:OpaqueToken = new OpaqueToken('AppDocument');
|
|
||||||
|
|
|
@ -133,12 +133,6 @@ export class Compiler {
|
||||||
if (isBlank(template)) {
|
if (isBlank(template)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (isPresent(template.renderer)) {
|
|
||||||
var directives = [];
|
|
||||||
pvPromise = this._render.createImperativeComponentProtoView(template.renderer).then( (renderPv) => {
|
|
||||||
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var directives = ListWrapper.map(
|
var directives = ListWrapper.map(
|
||||||
this._flattenDirectives(template),
|
this._flattenDirectives(template),
|
||||||
(directive) => this._bindDirective(directive)
|
(directive) => this._bindDirective(directive)
|
||||||
|
@ -147,7 +141,6 @@ export class Compiler {
|
||||||
pvPromise = this._render.compile(renderTemplate).then( (renderPv) => {
|
pvPromise = this._render.compile(renderTemplate).then( (renderPv) => {
|
||||||
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
|
return this._compileNestedProtoViews(null, componentBinding, renderPv, directives, true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
MapWrapper.set(this._compiling, component, pvPromise);
|
MapWrapper.set(this._compiling, component, pvPromise);
|
||||||
return pvPromise;
|
return pvPromise;
|
||||||
|
@ -187,14 +180,6 @@ export class Compiler {
|
||||||
});
|
});
|
||||||
|
|
||||||
var protoViewDone = (_) => {
|
var protoViewDone = (_) => {
|
||||||
var childComponentRenderPvRefs = [];
|
|
||||||
ListWrapper.forEach(protoView.elementBinders, (eb) => {
|
|
||||||
if (isPresent(eb.componentDirective)) {
|
|
||||||
var componentPv = eb.nestedProtoView;
|
|
||||||
ListWrapper.push(childComponentRenderPvRefs, isPresent(componentPv) ? componentPv.render : null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this._render.mergeChildComponentProtoViews(protoView.render, childComponentRenderPvRefs);
|
|
||||||
return protoView;
|
return protoView;
|
||||||
};
|
};
|
||||||
if (nestedPVPromises.length > 0) {
|
if (nestedPVPromises.length > 0) {
|
||||||
|
|
|
@ -62,14 +62,14 @@ export class DynamicComponentLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a component in the element specified by elementOrSelector. The loaded component receives
|
* Loads a component in the element specified by elementSelector. The loaded component receives
|
||||||
* injection normally as a hosted view.
|
* injection normally as a hosted view.
|
||||||
*/
|
*/
|
||||||
loadIntoNewLocation(typeOrBinding, parentComponentLocation:ElementRef, elementOrSelector:any,
|
loadIntoNewLocation(typeOrBinding, parentComponentLocation:ElementRef, elementSelector:string,
|
||||||
injector:Injector = null):Promise<ComponentRef> {
|
injector:Injector = null):Promise<ComponentRef> {
|
||||||
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
|
return this._compiler.compileInHost(this._getBinding(typeOrBinding)).then(hostProtoViewRef => {
|
||||||
var hostViewRef = this._viewManager.createInPlaceHostView(
|
var hostViewRef = this._viewManager.createInPlaceHostView(
|
||||||
parentComponentLocation, elementOrSelector, hostProtoViewRef, injector);
|
parentComponentLocation, elementSelector, hostProtoViewRef, injector);
|
||||||
var newLocation = new ElementRef(hostViewRef, 0);
|
var newLocation = new ElementRef(hostViewRef, 0);
|
||||||
var component = this._viewManager.getComponent(newLocation);
|
var component = this._viewManager.getComponent(newLocation);
|
||||||
|
|
||||||
|
|
|
@ -894,7 +894,7 @@ export class ElementInjector extends TreeNode {
|
||||||
|
|
||||||
_getPreBuiltObjectByKeyId(keyId:int) {
|
_getPreBuiltObjectByKeyId(keyId:int) {
|
||||||
var staticKeys = StaticKeys.instance();
|
var staticKeys = StaticKeys.instance();
|
||||||
if (keyId === staticKeys.viewManagerId) return this._preBuiltObjects.viewManagerId;
|
if (keyId === staticKeys.viewManagerId) return this._preBuiltObjects.viewManager;
|
||||||
|
|
||||||
//TODO add other objects as needed
|
//TODO add other objects as needed
|
||||||
return _undefined;
|
return _undefined;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
import {normalizeBlank} from 'angular2/src/facade/lang';
|
import {normalizeBlank} from 'angular2/src/facade/lang';
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
import {DirectDomViewRef} from 'angular2/src/render/dom/direct_dom_renderer';
|
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @exportedAs angular2/view
|
* @exportedAs angular2/view
|
||||||
|
@ -23,8 +23,7 @@ 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() {
|
||||||
var renderViewRef:DirectDomViewRef = this.parentView.render;
|
return resolveInternalDomView(this.parentView.render).boundElements[this.boundElementIndex];
|
||||||
return renderViewRef.delegate.boundElements[this.boundElementIndex];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,7 +32,7 @@ export class AppView {
|
||||||
componentChildViews: List<AppView>;
|
componentChildViews: List<AppView>;
|
||||||
/// Host views that were added by an imperative view.
|
/// Host views that were added by an imperative view.
|
||||||
/// This is a dynamically growing / shrinking array.
|
/// This is a dynamically growing / shrinking array.
|
||||||
imperativeHostViews: List<AppView>;
|
inPlaceHostViews: List<AppView>;
|
||||||
viewContainers: List<AppViewContainer>;
|
viewContainers: List<AppViewContainer>;
|
||||||
preBuiltObjects: List<PreBuiltObjects>;
|
preBuiltObjects: List<PreBuiltObjects>;
|
||||||
proto: AppProtoView;
|
proto: AppProtoView;
|
||||||
|
@ -64,7 +64,7 @@ export class AppView {
|
||||||
this.context = null;
|
this.context = null;
|
||||||
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); //TODO optimize this
|
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); //TODO optimize this
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.imperativeHostViews = [];
|
this.inPlaceHostViews = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List,
|
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import {Injector, Binding} from 'angular2/di';
|
import {Injector, Binding} from 'angular2/di';
|
||||||
import {Injectable} from 'angular2/src/di/annotations_impl';
|
import {Injectable} from 'angular2/src/di/annotations_impl';
|
||||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
|
||||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||||
import * as viewModule from './view';
|
import * as viewModule from './view';
|
||||||
import {ElementRef} from './element_ref';
|
import {ElementRef} from './element_ref';
|
||||||
import {ProtoViewRef, ViewRef, internalView, internalProtoView} from './view_ref';
|
import {ProtoViewRef, ViewRef, internalView, internalProtoView} from './view_ref';
|
||||||
import {ViewContainerRef} from './view_container_ref';
|
import {ViewContainerRef} from './view_container_ref';
|
||||||
import {Renderer, RenderViewRef, RenderViewContainerRef} from 'angular2/src/render/api';
|
import {Renderer, RenderViewRef} from 'angular2/src/render/api';
|
||||||
import {AppViewManagerUtils} from './view_manager_utils';
|
import {AppViewManagerUtils} from './view_manager_utils';
|
||||||
import {AppViewPool} from './view_pool';
|
import {AppViewPool} from './view_pool';
|
||||||
|
|
||||||
|
@ -27,6 +26,12 @@ export class AppViewManager {
|
||||||
this._utils = utils;
|
this._utils = utils;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getComponentView(hostLocation:ElementRef):ViewRef {
|
||||||
|
var hostView = internalView(hostLocation.parentView);
|
||||||
|
var boundElementIndex = hostLocation.boundElementIndex;
|
||||||
|
return new ViewRef(hostView.componentChildViews[boundElementIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
getViewContainer(location:ElementRef):ViewContainerRef {
|
getViewContainer(location:ElementRef):ViewContainerRef {
|
||||||
var hostView = internalView(location.parentView);
|
var hostView = internalView(location.parentView);
|
||||||
return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef();
|
return hostView.elementInjectors[location.boundElementIndex].getViewContainerRef();
|
||||||
|
@ -47,20 +52,18 @@ export class AppViewManager {
|
||||||
if (!binder.hasDynamicComponent()) {
|
if (!binder.hasDynamicComponent()) {
|
||||||
throw new BaseException(`There is no dynamic component directive at element ${boundElementIndex}`)
|
throw new BaseException(`There is no dynamic component directive at element ${boundElementIndex}`)
|
||||||
}
|
}
|
||||||
|
var componentView = this._createPooledView(componentProtoView);
|
||||||
var componentView = this._createViewRecurse(componentProtoView);
|
this._renderer.attachComponentView(hostView.render, boundElementIndex, componentView.render);
|
||||||
var renderViewRefs = this._renderer.createDynamicComponentView(hostView.render, boundElementIndex, componentProtoView.render);
|
|
||||||
componentView.render = renderViewRefs[0];
|
|
||||||
this._utils.attachComponentView(hostView, boundElementIndex, componentView);
|
this._utils.attachComponentView(hostView, boundElementIndex, componentView);
|
||||||
this._utils.hydrateDynamicComponentInElementInjector(hostView, boundElementIndex, componentBinding, injector);
|
this._utils.hydrateDynamicComponentInElementInjector(hostView, boundElementIndex, componentBinding, injector);
|
||||||
this._utils.hydrateComponentView(hostView, boundElementIndex);
|
this._utils.hydrateComponentView(hostView, boundElementIndex);
|
||||||
this._viewHydrateRecurse(componentView, renderViewRefs, 1);
|
this._viewHydrateRecurse(componentView);
|
||||||
|
|
||||||
return new ViewRef(componentView);
|
return new ViewRef(componentView);
|
||||||
}
|
}
|
||||||
|
|
||||||
createInPlaceHostView(parentComponentLocation:ElementRef,
|
createInPlaceHostView(parentComponentLocation:ElementRef,
|
||||||
hostElementSelector, hostProtoViewRef:ProtoViewRef, injector:Injector):ViewRef {
|
hostElementSelector:string, hostProtoViewRef:ProtoViewRef, injector:Injector):ViewRef {
|
||||||
var hostProtoView = internalProtoView(hostProtoViewRef);
|
var hostProtoView = internalProtoView(hostProtoViewRef);
|
||||||
var parentComponentHostView = null;
|
var parentComponentHostView = null;
|
||||||
var parentComponentBoundElementIndex = null;
|
var parentComponentBoundElementIndex = null;
|
||||||
|
@ -70,27 +73,22 @@ export class AppViewManager {
|
||||||
parentComponentBoundElementIndex = parentComponentLocation.boundElementIndex;
|
parentComponentBoundElementIndex = parentComponentLocation.boundElementIndex;
|
||||||
parentRenderViewRef = parentComponentHostView.componentChildViews[parentComponentBoundElementIndex].render;
|
parentRenderViewRef = parentComponentHostView.componentChildViews[parentComponentBoundElementIndex].render;
|
||||||
}
|
}
|
||||||
var hostView = this._createViewRecurse(hostProtoView);
|
var hostRenderView = this._renderer.createInPlaceHostView(parentRenderViewRef, hostElementSelector, hostProtoView.render);
|
||||||
var renderViewRefs = this._renderer.createInPlaceHostView(parentRenderViewRef, hostElementSelector, hostProtoView.render);
|
var hostView = this._utils.createView(hostProtoView, hostRenderView, this, this._renderer);
|
||||||
hostView.render = renderViewRefs[0];
|
this._renderer.setEventDispatcher(hostView.render, hostView);
|
||||||
|
this._createViewRecurse(hostView)
|
||||||
this._utils.attachAndHydrateInPlaceHostView(parentComponentHostView, parentComponentBoundElementIndex, hostView, injector);
|
this._utils.attachAndHydrateInPlaceHostView(parentComponentHostView, parentComponentBoundElementIndex, hostView, injector);
|
||||||
this._viewHydrateRecurse(hostView, renderViewRefs, 1);
|
this._viewHydrateRecurse(hostView);
|
||||||
return new ViewRef(hostView);
|
return new ViewRef(hostView);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyInPlaceHostView(parentComponentLocation:ElementRef, hostViewRef:ViewRef) {
|
destroyInPlaceHostView(parentComponentLocation:ElementRef, hostViewRef:ViewRef) {
|
||||||
var hostView = internalView(hostViewRef);
|
var hostView = internalView(hostViewRef);
|
||||||
var parentView = null;
|
var parentView = null;
|
||||||
var parentRenderViewRef = null;
|
|
||||||
if (isPresent(parentComponentLocation)) {
|
if (isPresent(parentComponentLocation)) {
|
||||||
parentView = internalView(parentComponentLocation.parentView).componentChildViews[parentComponentLocation.boundElementIndex];
|
parentView = internalView(parentComponentLocation.parentView).componentChildViews[parentComponentLocation.boundElementIndex];
|
||||||
parentRenderViewRef = parentView.render;
|
|
||||||
}
|
}
|
||||||
var hostViewRenderRef = hostView.render;
|
this._destroyInPlaceHostView(parentView, hostView);
|
||||||
this._viewDehydrateRecurse(hostView);
|
|
||||||
this._utils.detachInPlaceHostView(parentView, hostView);
|
|
||||||
this._renderer.destroyInPlaceHostView(parentRenderViewRef, hostViewRenderRef);
|
|
||||||
this._destroyView(hostView);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createViewInContainer(viewContainerLocation:ElementRef,
|
createViewInContainer(viewContainerLocation:ElementRef,
|
||||||
|
@ -99,25 +97,19 @@ export class AppViewManager {
|
||||||
var parentView = internalView(viewContainerLocation.parentView);
|
var parentView = internalView(viewContainerLocation.parentView);
|
||||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||||
|
|
||||||
var view = this._createViewRecurse(protoView);
|
var view = this._createPooledView(protoView);
|
||||||
var renderViewRefs = this._renderer.createViewInContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex, view.proto.render);
|
|
||||||
view.render = renderViewRefs[0];
|
|
||||||
|
|
||||||
|
this._renderer.attachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||||
this._utils.attachViewInContainer(parentView, boundElementIndex, atIndex, view);
|
this._utils.attachViewInContainer(parentView, boundElementIndex, atIndex, view);
|
||||||
this._utils.hydrateViewInContainer(parentView, boundElementIndex, atIndex, injector);
|
this._utils.hydrateViewInContainer(parentView, boundElementIndex, atIndex, injector);
|
||||||
this._viewHydrateRecurse(view, renderViewRefs, 1);
|
this._viewHydrateRecurse(view);
|
||||||
return new ViewRef(view);
|
return new ViewRef(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyViewInContainer(viewContainerLocation:ElementRef, atIndex:number) {
|
destroyViewInContainer(viewContainerLocation:ElementRef, atIndex:number) {
|
||||||
var parentView = internalView(viewContainerLocation.parentView);
|
var parentView = internalView(viewContainerLocation.parentView);
|
||||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
this._destroyViewInContainer(parentView, boundElementIndex, atIndex);
|
||||||
var view = viewContainer.views[atIndex];
|
|
||||||
this._viewDehydrateRecurse(view);
|
|
||||||
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
|
||||||
this._renderer.destroyViewInContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex);
|
|
||||||
this._destroyView(view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attachViewInContainer(viewContainerLocation:ElementRef, atIndex:number, viewRef:ViewRef):ViewRef {
|
attachViewInContainer(viewContainerLocation:ElementRef, atIndex:number, viewRef:ViewRef):ViewRef {
|
||||||
|
@ -125,7 +117,7 @@ export class AppViewManager {
|
||||||
var parentView = internalView(viewContainerLocation.parentView);
|
var parentView = internalView(viewContainerLocation.parentView);
|
||||||
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
var boundElementIndex = viewContainerLocation.boundElementIndex;
|
||||||
this._utils.attachViewInContainer(parentView, boundElementIndex, atIndex, view);
|
this._utils.attachViewInContainer(parentView, boundElementIndex, atIndex, view);
|
||||||
this._renderer.insertViewIntoContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex, view.render);
|
this._renderer.attachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||||
return viewRef;
|
return viewRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,86 +127,105 @@ export class AppViewManager {
|
||||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||||
var view = viewContainer.views[atIndex];
|
var view = viewContainer.views[atIndex];
|
||||||
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
||||||
this._renderer.detachViewFromContainer(this._getRenderViewContainerRef(parentView, boundElementIndex), atIndex);
|
this._renderer.detachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||||
return new ViewRef(view);
|
return new ViewRef(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
_getRenderViewContainerRef(parentView:viewModule.AppView, boundElementIndex:number) {
|
_createPooledView(protoView:viewModule.AppProtoView):viewModule.AppView {
|
||||||
return new RenderViewContainerRef(parentView.render, boundElementIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
_createViewRecurse(protoView:viewModule.AppProtoView) {
|
|
||||||
var view = this._viewPool.getView(protoView);
|
var view = this._viewPool.getView(protoView);
|
||||||
if (isBlank(view)) {
|
if (isBlank(view)) {
|
||||||
view = this._utils.createView(protoView, this, this._renderer);
|
view = this._utils.createView(protoView, this._renderer.createView(protoView.render), this, this._renderer);
|
||||||
var binders = protoView.elementBinders;
|
this._renderer.setEventDispatcher(view.render, view);
|
||||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
this._createViewRecurse(view);
|
||||||
var binder = binders[binderIdx];
|
|
||||||
if (binder.hasStaticComponent()) {
|
|
||||||
var childView = this._createViewRecurse(binder.nestedProtoView);
|
|
||||||
this._utils.attachComponentView(view, binderIdx, childView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
_destroyView(view:viewModule.AppView) {
|
_createViewRecurse(view:viewModule.AppView) {
|
||||||
|
var binders = view.proto.elementBinders;
|
||||||
|
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||||
|
var binder = binders[binderIdx];
|
||||||
|
if (binder.hasStaticComponent()) {
|
||||||
|
var childView = this._createPooledView(binder.nestedProtoView);
|
||||||
|
this._renderer.attachComponentView(view.render, binderIdx, childView.render);
|
||||||
|
this._utils.attachComponentView(view, binderIdx, childView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_destroyPooledView(view:viewModule.AppView) {
|
||||||
|
// TODO: if the pool is full, call renderer.destroyView as well!
|
||||||
this._viewPool.returnView(view);
|
this._viewPool.returnView(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_destroyViewInContainer(parentView, boundElementIndex, atIndex:number) {
|
||||||
|
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||||
|
var view = viewContainer.views[atIndex];
|
||||||
|
this._viewDehydrateRecurse(view, false);
|
||||||
|
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
|
||||||
|
this._renderer.detachViewInContainer(parentView.render, boundElementIndex, atIndex, view.render);
|
||||||
|
this._destroyPooledView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
_destroyComponentView(hostView, boundElementIndex, componentView) {
|
||||||
|
this._viewDehydrateRecurse(componentView, false);
|
||||||
|
this._renderer.detachComponentView(hostView.render, boundElementIndex, componentView.render);
|
||||||
|
this._utils.detachComponentView(hostView, boundElementIndex);
|
||||||
|
this._destroyPooledView(componentView);
|
||||||
|
}
|
||||||
|
|
||||||
|
_destroyInPlaceHostView(parentView, hostView) {
|
||||||
|
var parentRenderViewRef = null;
|
||||||
|
if (isPresent(parentView)) {
|
||||||
|
parentRenderViewRef = parentView.render;
|
||||||
|
}
|
||||||
|
this._viewDehydrateRecurse(hostView, true);
|
||||||
|
this._utils.detachInPlaceHostView(parentView, hostView);
|
||||||
|
this._renderer.destroyInPlaceHostView(parentRenderViewRef, hostView.render);
|
||||||
|
// Note: Don't put the inplace host view into the view pool
|
||||||
|
// as it is depending on the element for which it was created.
|
||||||
|
}
|
||||||
|
|
||||||
_viewHydrateRecurse(
|
_viewHydrateRecurse(
|
||||||
view:viewModule.AppView,
|
view:viewModule.AppView) {
|
||||||
renderComponentViewRefs:List<RenderViewRef>,
|
this._renderer.hydrateView(view.render);
|
||||||
renderComponentIndex:number):number {
|
|
||||||
this._renderer.setEventDispatcher(view.render, view);
|
|
||||||
|
|
||||||
var binders = view.proto.elementBinders;
|
var binders = view.proto.elementBinders;
|
||||||
for (var i = 0; i < binders.length; ++i) {
|
for (var i = 0; i < binders.length; ++i) {
|
||||||
if (binders[i].hasStaticComponent()) {
|
if (binders[i].hasStaticComponent()) {
|
||||||
var childView = view.componentChildViews[i];
|
|
||||||
childView.render = renderComponentViewRefs[renderComponentIndex++];
|
|
||||||
this._utils.hydrateComponentView(view, i);
|
this._utils.hydrateComponentView(view, i);
|
||||||
renderComponentIndex = this._viewHydrateRecurse(
|
this._viewHydrateRecurse(
|
||||||
view.componentChildViews[i],
|
view.componentChildViews[i]
|
||||||
renderComponentViewRefs,
|
|
||||||
renderComponentIndex
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return renderComponentIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_viewDehydrateRecurse(view:viewModule.AppView) {
|
_viewDehydrateRecurse(view:viewModule.AppView, forceDestroyComponents) {
|
||||||
this._utils.dehydrateView(view);
|
this._utils.dehydrateView(view);
|
||||||
|
this._renderer.dehydrateView(view.render);
|
||||||
var binders = view.proto.elementBinders;
|
var binders = view.proto.elementBinders;
|
||||||
for (var i = 0; i < binders.length; i++) {
|
for (var i = 0; i < binders.length; i++) {
|
||||||
var componentView = view.componentChildViews[i];
|
var componentView = view.componentChildViews[i];
|
||||||
if (isPresent(componentView)) {
|
if (isPresent(componentView)) {
|
||||||
this._viewDehydrateRecurse(componentView);
|
if (binders[i].hasDynamicComponent() || forceDestroyComponents) {
|
||||||
if (binders[i].hasDynamicComponent()) {
|
this._destroyComponentView(view, i, componentView);
|
||||||
this._utils.detachComponentView(view, i);
|
} else {
|
||||||
this._destroyView(componentView);
|
this._viewDehydrateRecurse(componentView, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var vc = view.viewContainers[i];
|
var vc = view.viewContainers[i];
|
||||||
if (isPresent(vc)) {
|
if (isPresent(vc)) {
|
||||||
for (var j = vc.views.length - 1; j >= 0; j--) {
|
for (var j = vc.views.length - 1; j >= 0; j--) {
|
||||||
var childView = vc.views[j];
|
this._destroyViewInContainer(view, i, j);
|
||||||
this._viewDehydrateRecurse(childView);
|
|
||||||
this._utils.detachViewInContainer(view, i, j);
|
|
||||||
this._destroyView(childView);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// imperativeHostViews
|
// inPlaceHostViews
|
||||||
for (var i = 0; i < view.imperativeHostViews.length; i++) {
|
for (var i = view.inPlaceHostViews.length-1; i>=0; i--) {
|
||||||
var hostView = view.imperativeHostViews[i];
|
var hostView = view.inPlaceHostViews[i];
|
||||||
this._viewDehydrateRecurse(hostView);
|
this._destroyInPlaceHostView(view, hostView);
|
||||||
this._utils.detachInPlaceHostView(view, hostView);
|
|
||||||
this._destroyView(hostView);
|
|
||||||
}
|
}
|
||||||
view.render = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as avmModule from './view_manager';
|
||||||
import {Renderer} from 'angular2/src/render/api';
|
import {Renderer} from 'angular2/src/render/api';
|
||||||
import {BindingPropagationConfig, Locals} from 'angular2/change_detection';
|
import {BindingPropagationConfig, Locals} from 'angular2/change_detection';
|
||||||
import {DirectiveMetadataReader} from './directive_metadata_reader';
|
import {DirectiveMetadataReader} from './directive_metadata_reader';
|
||||||
|
import {RenderViewRef} from 'angular2/src/render/api';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AppViewManagerUtils {
|
export class AppViewManagerUtils {
|
||||||
|
@ -27,8 +28,11 @@ export class AppViewManagerUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createView(protoView:viewModule.AppProtoView, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView {
|
createView(protoView:viewModule.AppProtoView, renderView:RenderViewRef, viewManager:avmModule.AppViewManager, renderer:Renderer): viewModule.AppView {
|
||||||
var view = new viewModule.AppView(renderer, protoView, protoView.protoLocals);
|
var view = new viewModule.AppView(renderer, protoView, protoView.protoLocals);
|
||||||
|
// TODO(tbosch): pass RenderViewRef as argument to AppView!
|
||||||
|
view.render = renderView;
|
||||||
|
|
||||||
var changeDetector = protoView.protoChangeDetector.instantiate(view);
|
var changeDetector = protoView.protoChangeDetector.instantiate(view);
|
||||||
|
|
||||||
var binders = protoView.elementBinders;
|
var binders = protoView.elementBinders;
|
||||||
|
@ -96,7 +100,7 @@ export class AppViewManagerUtils {
|
||||||
hostElementInjector = parentComponentHostView.elementInjectors[parentComponentBoundElementIndex];
|
hostElementInjector = parentComponentHostView.elementInjectors[parentComponentBoundElementIndex];
|
||||||
var parentView = parentComponentHostView.componentChildViews[parentComponentBoundElementIndex];
|
var parentView = parentComponentHostView.componentChildViews[parentComponentBoundElementIndex];
|
||||||
parentView.changeDetector.addChild(hostView.changeDetector);
|
parentView.changeDetector.addChild(hostView.changeDetector);
|
||||||
ListWrapper.push(parentView.imperativeHostViews, hostView);
|
ListWrapper.push(parentView.inPlaceHostViews, hostView);
|
||||||
}
|
}
|
||||||
this._hydrateView(hostView, injector, hostElementInjector, new Object(), null);
|
this._hydrateView(hostView, injector, hostElementInjector, new Object(), null);
|
||||||
}
|
}
|
||||||
|
@ -105,7 +109,7 @@ export class AppViewManagerUtils {
|
||||||
hostView:viewModule.AppView) {
|
hostView:viewModule.AppView) {
|
||||||
if (isPresent(parentView)) {
|
if (isPresent(parentView)) {
|
||||||
parentView.changeDetector.removeChild(hostView.changeDetector);
|
parentView.changeDetector.removeChild(hostView.changeDetector);
|
||||||
ListWrapper.remove(parentView.imperativeHostViews, hostView);
|
ListWrapper.remove(parentView.inPlaceHostViews, hostView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,18 +134,11 @@ export class DirectiveMetadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
// An opaque reference to a DomProtoView
|
// An opaque reference to a DomProtoView
|
||||||
export class RenderProtoViewRef {}
|
export class RenderProtoViewRef {
|
||||||
|
}
|
||||||
|
|
||||||
// An opaque reference to a DomView
|
// An opaque reference to a DomView
|
||||||
export class RenderViewRef {}
|
export class RenderViewRef {
|
||||||
|
|
||||||
export class RenderViewContainerRef {
|
|
||||||
view:RenderViewRef;
|
|
||||||
elementIndex:number;
|
|
||||||
constructor(view:RenderViewRef, elementIndex: number) {
|
|
||||||
this.view = view;
|
|
||||||
this.elementIndex = elementIndex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ViewDefinition {
|
export class ViewDefinition {
|
||||||
|
@ -168,113 +161,101 @@ export class RenderCompiler {
|
||||||
*/
|
*/
|
||||||
compileHost(componentId):Promise<ProtoViewDto> { return null; }
|
compileHost(componentId):Promise<ProtoViewDto> { return null; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Creats a ProtoViewDto for a component that will use an imperative View using the given
|
|
||||||
* renderer.
|
|
||||||
* Note: Rigth now, the renderer argument is ignored, but will be used in the future to define
|
|
||||||
* a custom handler.
|
|
||||||
*/
|
|
||||||
createImperativeComponentProtoView(rendererId):Promise<ProtoViewDto> { return null; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles a single DomProtoView. Non recursive so that
|
* Compiles a single DomProtoView. Non recursive so that
|
||||||
* we don't need to serialize all possible components over the wire,
|
* we don't need to serialize all possible components over the wire,
|
||||||
* but only the needed ones based on previous calls.
|
* but only the needed ones based on previous calls.
|
||||||
*/
|
*/
|
||||||
compile(template:ViewDefinition):Promise<ProtoViewDto> { return null; }
|
compile(template:ViewDefinition):Promise<ProtoViewDto> { return null; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the preset nested components,
|
|
||||||
* which will be instantiated when this protoView is instantiated.
|
|
||||||
* Note: We can't create new ProtoViewRefs here as we need to support cycles / recursive components.
|
|
||||||
* @param {List<RenderProtoViewRef>} protoViewRefs
|
|
||||||
* DomProtoView for every element with a component in this protoView or in a view container's protoView
|
|
||||||
*/
|
|
||||||
mergeChildComponentProtoViews(protoViewRef:RenderProtoViewRef, componentProtoViewRefs:List<RenderProtoViewRef>) { return null; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Renderer {
|
export class Renderer {
|
||||||
/**
|
|
||||||
* Creates a view and inserts it into a ViewContainer.
|
|
||||||
* @param {RenderViewContainerRef} viewContainerRef
|
|
||||||
* @param {RenderProtoViewRef} protoViewRef A RenderProtoViewRef of type ProtoViewDto.HOST_VIEW_TYPE or ProtoViewDto.EMBEDDED_VIEW_TYPE
|
|
||||||
* @param {number} atIndex
|
|
||||||
* @return {List<RenderViewRef>} the view and all of its nested child component views
|
|
||||||
*/
|
|
||||||
createViewInContainer(vcRef:RenderViewContainerRef, atIndex:number, protoViewRef:RenderProtoViewRef):List<RenderViewRef> { return null; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys the view in the given ViewContainer
|
|
||||||
*/
|
|
||||||
destroyViewInContainer(vcRef:RenderViewContainerRef, atIndex:number):void {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a detached view into a viewContainer.
|
|
||||||
*/
|
|
||||||
insertViewIntoContainer(vcRef:RenderViewContainerRef, atIndex:number, view:RenderViewRef):void {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detaches a view from a container so that it can be inserted later on
|
|
||||||
*/
|
|
||||||
detachViewFromContainer(vcRef:RenderViewContainerRef, atIndex:number):void {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a view and
|
|
||||||
* installs it as a shadow view for an element.
|
|
||||||
*
|
|
||||||
* Note: only allowed if there is a dynamic component directive at this place.
|
|
||||||
* @param {RenderViewRef} hostView
|
|
||||||
* @param {number} elementIndex
|
|
||||||
* @param {RenderProtoViewRef} componentProtoViewRef A RenderProtoViewRef of type ProtoViewDto.COMPONENT_VIEW_TYPE
|
|
||||||
* @return {List<RenderViewRef>} the view and all of its nested child component views
|
|
||||||
*/
|
|
||||||
createDynamicComponentView(hostViewRef:RenderViewRef, elementIndex:number, componentProtoViewRef:RenderProtoViewRef):List<RenderViewRef> { return null; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys the component view at the given index
|
|
||||||
*
|
|
||||||
* Note: only allowed if there is a dynamic component directive at this place.
|
|
||||||
*/
|
|
||||||
destroyDynamicComponentView(hostViewRef:RenderViewRef, elementIndex:number):void {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a host view that includes the given element.
|
* Creates a host view that includes the given element.
|
||||||
* @param {RenderViewRef} parentViewRef (might be null)
|
* @param {RenderViewRef} parentHostViewRef (might be null)
|
||||||
* @param {any} hostElementSelector element or css selector for the host element
|
* @param {any} hostElementSelector css selector for the host element
|
||||||
* @param {RenderProtoViewRef} hostProtoView a RenderProtoViewRef of type ProtoViewDto.HOST_VIEW_TYPE
|
* @param {RenderProtoViewRef} hostProtoViewRef a RenderProtoViewRef of type ProtoViewDto.HOST_VIEW_TYPE
|
||||||
* @return {List<RenderViewRef>} the view and all of its nested child component views
|
* @return {RenderViewRef} the created view
|
||||||
*/
|
*/
|
||||||
createInPlaceHostView(parentViewRef:RenderViewRef, hostElementSelector, hostProtoViewRef:RenderProtoViewRef):List<RenderViewRef> { return null; }
|
createInPlaceHostView(parentHostViewRef:RenderViewRef, hostElementSelector:string, hostProtoViewRef:RenderProtoViewRef):RenderViewRef {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the given host view in the given parent view.
|
* Destroys the given host view in the given parent view.
|
||||||
*/
|
*/
|
||||||
destroyInPlaceHostView(parentViewRef:RenderViewRef, hostViewRef:RenderViewRef):void {}
|
destroyInPlaceHostView(parentHostViewRef:RenderViewRef, hostViewRef:RenderViewRef) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a property on an element.
|
* Creates a regular view out of the given ProtoView
|
||||||
|
*/
|
||||||
|
createView(protoViewRef:RenderProtoViewRef):RenderViewRef {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the given view after it has been dehydrated and detached
|
||||||
|
*/
|
||||||
|
destroyView(viewRef:RenderViewRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches a componentView into the given hostView at the given element
|
||||||
|
*/
|
||||||
|
attachComponentView(hostViewRef:RenderViewRef, elementIndex:number, componentViewRef:RenderViewRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detaches a componentView into the given hostView at the given element
|
||||||
|
*/
|
||||||
|
detachComponentView(hostViewRef:RenderViewRef, boundElementIndex:number, componentViewRef:RenderViewRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches a view into a ViewContainer (in the given parentView at the given element) at the given index.
|
||||||
|
*/
|
||||||
|
attachViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detaches a view into a ViewContainer (in the given parentView at the given element) at the given index.
|
||||||
|
*/
|
||||||
|
// TODO(tbosch): this should return a promise as it can be animated!
|
||||||
|
detachViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hydrates a view after it has been attached. Hydration/dehydration is used for reusing views inside of the view pool.
|
||||||
|
*/
|
||||||
|
hydrateView(hviewRef:RenderViewRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dehydrates a view after it has been attached. Hydration/dehydration is used for reusing views inside of the view pool.
|
||||||
|
*/
|
||||||
|
dehydrateView(viewRef:RenderViewRef) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a porperty on an element.
|
||||||
* Note: This will fail if the property was not mentioned previously as a host property
|
* Note: This will fail if the property was not mentioned previously as a host property
|
||||||
* in the View.
|
* in the ProtoView
|
||||||
*/
|
*/
|
||||||
setElementProperty(view:RenderViewRef, elementIndex:number, propertyName:string, propertyValue:any):void {}
|
setElementProperty(viewRef:RenderViewRef, elementIndex:number, propertyName:string, propertyValue:any):void {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the value of a text node.
|
||||||
|
*/
|
||||||
|
setText(viewRef:RenderViewRef, textNodeIndex:number, text:string):void {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will set the value for a text node.
|
* Sets the dispatcher for all events of the given view
|
||||||
* Note: This needs to be separate from setElementProperty as we don't have ElementBinders
|
|
||||||
* for text nodes in the DomProtoView either.
|
|
||||||
*/
|
*/
|
||||||
setText(view:RenderViewRef, textNodeIndex:number, text:string):void {}
|
setEventDispatcher(viewRef:RenderViewRef, dispatcher:any/*api.EventDispatcher*/):void {
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Sets the dispatcher for all events that have been defined in the template or in directives
|
|
||||||
* in the given view.
|
|
||||||
*/
|
|
||||||
setEventDispatcher(viewRef:RenderViewRef, dispatcher:any/*EventDispatcher*/):void {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To be called at the end of the VmTurn so the API can buffer calls
|
|
||||||
*/
|
|
||||||
flush():void {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import {Injectable} from 'angular2/src/di/annotations_impl';
|
||||||
|
|
||||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
import {BaseException, isPresent} from 'angular2/src/facade/lang';
|
import {BaseException, isPresent} from 'angular2/src/facade/lang';
|
||||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
import {ViewDefinition, ProtoViewDto, DirectiveMetadata, RenderCompiler, RenderProtoViewRef} from '../../api';
|
import {ViewDefinition, ProtoViewDto, DirectiveMetadata, RenderCompiler, RenderProtoViewRef} from '../../api';
|
||||||
|
@ -11,13 +10,6 @@ import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||||
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
|
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
|
||||||
import {Parser} from 'angular2/change_detection';
|
import {Parser} from 'angular2/change_detection';
|
||||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
||||||
import {ProtoViewBuilder} from '../view/proto_view_builder';
|
|
||||||
|
|
||||||
import {DirectDomProtoViewRef} from '../direct_dom_renderer';
|
|
||||||
|
|
||||||
function _resolveProtoView(protoViewRef:DirectDomProtoViewRef) {
|
|
||||||
return isPresent(protoViewRef) ? protoViewRef.delegate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The compiler loads and translates the html templates of components into
|
* The compiler loads and translates the html templates of components into
|
||||||
|
@ -53,18 +45,6 @@ export class DomCompiler extends RenderCompiler {
|
||||||
return this._compileTemplate(hostViewDef, element);
|
return this._compileTemplate(hostViewDef, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
createImperativeComponentProtoView(rendererId):Promise<ProtoViewDto> {
|
|
||||||
var protoViewBuilder = new ProtoViewBuilder(null);
|
|
||||||
protoViewBuilder.setImperativeRendererId(rendererId);
|
|
||||||
return PromiseWrapper.resolve(protoViewBuilder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
mergeChildComponentProtoViews(protoViewRef:RenderProtoViewRef, protoViewRefs:List<RenderProtoViewRef>) {
|
|
||||||
_resolveProtoView(protoViewRef).mergeChildComponentProtoViews(
|
|
||||||
ListWrapper.map(protoViewRefs, _resolveProtoView)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_compileTemplate(viewDef: ViewDefinition, tplElement):Promise<ProtoViewDto> {
|
_compileTemplate(viewDef: ViewDefinition, tplElement):Promise<ProtoViewDto> {
|
||||||
var subTaskPromises = [];
|
var subTaskPromises = [];
|
||||||
var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef, subTaskPromises));
|
var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef, subTaskPromises));
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
import {Injectable} from 'angular2/src/di/annotations_impl';
|
|
||||||
|
|
||||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
|
||||||
import {isBlank, isPresent, BaseException} from 'angular2/src/facade/lang';
|
|
||||||
|
|
||||||
import * as api from '../api';
|
|
||||||
import {DomView} from './view/view';
|
|
||||||
import {DomProtoView} from './view/proto_view';
|
|
||||||
import {ViewFactory} from './view/view_factory';
|
|
||||||
import {RenderViewHydrator} from './view/view_hydrator';
|
|
||||||
import {ShadowDomStrategy} from './shadow_dom/shadow_dom_strategy';
|
|
||||||
import {ViewContainer} from './view/view_container';
|
|
||||||
|
|
||||||
function _resolveViewContainer(vc:api.RenderViewContainerRef) {
|
|
||||||
return _resolveView(vc.view).getOrCreateViewContainer(vc.elementIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _resolveView(viewRef:DirectDomViewRef) {
|
|
||||||
return isPresent(viewRef) ? viewRef.delegate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _resolveProtoView(protoViewRef:DirectDomProtoViewRef) {
|
|
||||||
return isPresent(protoViewRef) ? protoViewRef.delegate : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _wrapView(view:DomView) {
|
|
||||||
return new DirectDomViewRef(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _collectComponentChildViewRefs(view, target = null) {
|
|
||||||
if (isBlank(target)) {
|
|
||||||
target = [];
|
|
||||||
}
|
|
||||||
ListWrapper.push(target, _wrapView(view));
|
|
||||||
ListWrapper.forEach(view.componentChildViews, (view) => {
|
|
||||||
if (isPresent(view)) {
|
|
||||||
_collectComponentChildViewRefs(view, target);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// public so that the compiler can use it.
|
|
||||||
export class DirectDomProtoViewRef extends api.RenderProtoViewRef {
|
|
||||||
delegate:DomProtoView;
|
|
||||||
|
|
||||||
constructor(delegate:DomProtoView) {
|
|
||||||
super();
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DirectDomViewRef extends api.RenderViewRef {
|
|
||||||
delegate:DomView;
|
|
||||||
|
|
||||||
constructor(delegate:DomView) {
|
|
||||||
super();
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class DirectDomRenderer extends api.Renderer {
|
|
||||||
_viewFactory: ViewFactory;
|
|
||||||
_viewHydrator: RenderViewHydrator;
|
|
||||||
_shadowDomStrategy: ShadowDomStrategy;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
viewFactory: ViewFactory, viewHydrator: RenderViewHydrator, shadowDomStrategy: ShadowDomStrategy) {
|
|
||||||
super();
|
|
||||||
this._viewFactory = viewFactory;
|
|
||||||
this._viewHydrator = viewHydrator;
|
|
||||||
this._shadowDomStrategy = shadowDomStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
createViewInContainer(vcRef:api.RenderViewContainerRef, atIndex:number, protoViewRef:api.RenderProtoViewRef):List<api.RenderViewRef> {
|
|
||||||
var view = this._viewFactory.getView(_resolveProtoView(protoViewRef));
|
|
||||||
var vc = _resolveViewContainer(vcRef);
|
|
||||||
this._viewHydrator.hydrateViewInViewContainer(vc, view);
|
|
||||||
vc.insert(view, atIndex);
|
|
||||||
return _collectComponentChildViewRefs(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroyViewInContainer(vcRef:api.RenderViewContainerRef, atIndex:number):void {
|
|
||||||
var vc = _resolveViewContainer(vcRef);
|
|
||||||
var view = vc.detach(atIndex);
|
|
||||||
this._viewHydrator.dehydrateViewInViewContainer(vc, view);
|
|
||||||
this._viewFactory.returnView(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
insertViewIntoContainer(vcRef:api.RenderViewContainerRef, atIndex=-1, viewRef:api.RenderViewRef):void {
|
|
||||||
_resolveViewContainer(vcRef).insert(_resolveView(viewRef), atIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
detachViewFromContainer(vcRef:api.RenderViewContainerRef, atIndex:number):void {
|
|
||||||
_resolveViewContainer(vcRef).detach(atIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
createDynamicComponentView(hostViewRef:api.RenderViewRef, elementIndex:number, componentViewRef:api.RenderProtoViewRef):List<api.RenderViewRef> {
|
|
||||||
var hostView = _resolveView(hostViewRef);
|
|
||||||
var componentView = this._viewFactory.getView(_resolveProtoView(componentViewRef));
|
|
||||||
this._viewHydrator.hydrateDynamicComponentView(hostView, elementIndex, componentView);
|
|
||||||
return _collectComponentChildViewRefs(componentView);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroyDynamicComponentView(hostViewRef:api.RenderViewRef, elementIndex:number):void {
|
|
||||||
throw new BaseException('Not supported yet');
|
|
||||||
// Something along these lines:
|
|
||||||
// var hostView = _resolveView(hostViewRef);
|
|
||||||
// var componentView = hostView.childComponentViews[elementIndex];
|
|
||||||
// this._viewHydrator.dehydrateDynamicComponentView(hostView, componentView);
|
|
||||||
}
|
|
||||||
|
|
||||||
createInPlaceHostView(parentViewRef:api.RenderViewRef, hostElementSelector, hostProtoViewRef:api.RenderProtoViewRef):List<api.RenderViewRef> {
|
|
||||||
var parentView = _resolveView(parentViewRef);
|
|
||||||
var hostView = this._viewFactory.createInPlaceHostView(hostElementSelector, _resolveProtoView(hostProtoViewRef));
|
|
||||||
this._viewHydrator.hydrateInPlaceHostView(parentView, hostView);
|
|
||||||
return _collectComponentChildViewRefs(hostView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys the given host view in the given parent view.
|
|
||||||
*/
|
|
||||||
destroyInPlaceHostView(parentViewRef:api.RenderViewRef, hostViewRef:api.RenderViewRef):void {
|
|
||||||
var parentView = _resolveView(parentViewRef);
|
|
||||||
var hostView = _resolveView(hostViewRef);
|
|
||||||
this._viewHydrator.dehydrateInPlaceHostView(parentView, hostView);
|
|
||||||
}
|
|
||||||
|
|
||||||
setImperativeComponentRootNodes(parentViewRef:api.RenderViewRef, elementIndex:number, nodes:List):void {
|
|
||||||
var parentView = _resolveView(parentViewRef);
|
|
||||||
var hostElement = parentView.boundElements[elementIndex];
|
|
||||||
var componentView = parentView.componentChildViews[elementIndex];
|
|
||||||
if (isBlank(componentView)) {
|
|
||||||
throw new BaseException(`There is no componentChildView at index ${elementIndex}`);
|
|
||||||
}
|
|
||||||
if (isBlank(componentView.proto.imperativeRendererId)) {
|
|
||||||
throw new BaseException(`This component view has no imperative renderer`);
|
|
||||||
}
|
|
||||||
ViewContainer.removeViewNodes(componentView);
|
|
||||||
componentView.rootNodes = nodes;
|
|
||||||
this._shadowDomStrategy.attachTemplate(hostElement, componentView);
|
|
||||||
}
|
|
||||||
|
|
||||||
setElementProperty(viewRef:api.RenderViewRef, elementIndex:number, propertyName:string, propertyValue:any):void {
|
|
||||||
_resolveView(viewRef).setElementProperty(elementIndex, propertyName, propertyValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
setText(viewRef:api.RenderViewRef, textNodeIndex:number, text:string):void {
|
|
||||||
_resolveView(viewRef).setText(textNodeIndex, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
setEventDispatcher(viewRef:api.RenderViewRef, dispatcher:any/*api.EventDispatcher*/):void {
|
|
||||||
_resolveView(viewRef).setEventDispatcher(dispatcher);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,338 @@
|
||||||
|
import {Inject, Injectable} from 'angular2/src/di/annotations_impl';
|
||||||
|
import {int, isPresent, isBlank, BaseException, RegExpWrapper} from 'angular2/src/facade/lang';
|
||||||
|
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
|
import {Content} from './shadow_dom/content_tag';
|
||||||
|
import {ShadowDomStrategy} from './shadow_dom/shadow_dom_strategy';
|
||||||
|
import {EventManager} from './events/event_manager';
|
||||||
|
|
||||||
|
import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './view/proto_view';
|
||||||
|
import {DomView, DomViewRef, resolveInternalDomView} from './view/view';
|
||||||
|
import {DomViewContainer} from './view/view_container';
|
||||||
|
import {NG_BINDING_CLASS_SELECTOR, NG_BINDING_CLASS} from './util';
|
||||||
|
|
||||||
|
import {Renderer, RenderProtoViewRef, RenderViewRef} from '../api';
|
||||||
|
|
||||||
|
// TODO(tbosch): use an OpaqueToken here once our transpiler supports
|
||||||
|
// const expressions!
|
||||||
|
export const DOCUMENT_TOKEN = 'DocumentToken';
|
||||||
|
|
||||||
|
var _DOCUMENT_SELECTOR_REGEX = RegExpWrapper.create('\\:document(.+)');
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DomRenderer extends Renderer {
|
||||||
|
_eventManager:EventManager;
|
||||||
|
_shadowDomStrategy:ShadowDomStrategy;
|
||||||
|
_document;
|
||||||
|
|
||||||
|
constructor(eventManager:EventManager, shadowDomStrategy:ShadowDomStrategy, @Inject(DOCUMENT_TOKEN) document) {
|
||||||
|
super();
|
||||||
|
this._eventManager = eventManager;
|
||||||
|
this._shadowDomStrategy = shadowDomStrategy;
|
||||||
|
this._document = document;
|
||||||
|
}
|
||||||
|
|
||||||
|
createInPlaceHostView(parentHostViewRef:RenderViewRef, hostElementSelector:string, hostProtoViewRef:RenderProtoViewRef):RenderViewRef {
|
||||||
|
var containerNode;
|
||||||
|
var documentSelectorMatch = RegExpWrapper.firstMatch(_DOCUMENT_SELECTOR_REGEX, hostElementSelector);
|
||||||
|
if (isPresent(documentSelectorMatch)) {
|
||||||
|
containerNode = this._document;
|
||||||
|
hostElementSelector = documentSelectorMatch[1];
|
||||||
|
} else if (isPresent(parentHostViewRef)) {
|
||||||
|
var parentHostView = resolveInternalDomView(parentHostViewRef);
|
||||||
|
containerNode = parentHostView.shadowRoot;
|
||||||
|
} else {
|
||||||
|
containerNode = this._document;
|
||||||
|
}
|
||||||
|
var element = DOM.querySelector(containerNode, hostElementSelector);
|
||||||
|
if (isBlank(element)) {
|
||||||
|
throw new BaseException(`The selector "${hostElementSelector}" did not match any elements`);
|
||||||
|
}
|
||||||
|
var hostProtoView = resolveInternalDomProtoView(hostProtoViewRef);
|
||||||
|
return new DomViewRef(this._createView(hostProtoView, element));
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyInPlaceHostView(parentHostViewRef:RenderViewRef, hostViewRef:RenderViewRef) {
|
||||||
|
var hostView = resolveInternalDomView(hostViewRef);
|
||||||
|
this._removeViewNodes(hostView);
|
||||||
|
}
|
||||||
|
|
||||||
|
createView(protoViewRef:RenderProtoViewRef):RenderViewRef {
|
||||||
|
var protoView = resolveInternalDomProtoView(protoViewRef);
|
||||||
|
return new DomViewRef(this._createView(protoView, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyView(view:RenderViewRef) {
|
||||||
|
// noop for now
|
||||||
|
}
|
||||||
|
|
||||||
|
attachComponentView(hostViewRef:RenderViewRef, elementIndex:number, componentViewRef:RenderViewRef) {
|
||||||
|
var hostView = resolveInternalDomView(hostViewRef);
|
||||||
|
var componentView = resolveInternalDomView(componentViewRef);
|
||||||
|
var element = hostView.boundElements[elementIndex];
|
||||||
|
var lightDom = hostView.lightDoms[elementIndex];
|
||||||
|
if (isPresent(lightDom)) {
|
||||||
|
lightDom.attachShadowDomView(componentView);
|
||||||
|
}
|
||||||
|
var shadowRoot = this._shadowDomStrategy.prepareShadowRoot(element);
|
||||||
|
this._moveViewNodesIntoParent(shadowRoot, componentView);
|
||||||
|
componentView.hostLightDom = lightDom;
|
||||||
|
componentView.shadowRoot = shadowRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
setComponentViewRootNodes(componentViewRef:RenderViewRef, rootNodes:List) {
|
||||||
|
var componentView = resolveInternalDomView(componentViewRef);
|
||||||
|
this._removeViewNodes(componentView);
|
||||||
|
componentView.rootNodes = rootNodes;
|
||||||
|
this._moveViewNodesIntoParent(componentView.shadowRoot, componentView);
|
||||||
|
}
|
||||||
|
|
||||||
|
detachComponentView(hostViewRef:RenderViewRef, boundElementIndex:number, componentViewRef:RenderViewRef) {
|
||||||
|
var hostView = resolveInternalDomView(hostViewRef);
|
||||||
|
var componentView = resolveInternalDomView(componentViewRef);
|
||||||
|
this._removeViewNodes(componentView);
|
||||||
|
var lightDom = hostView.lightDoms[boundElementIndex];
|
||||||
|
if (isPresent(lightDom)) {
|
||||||
|
lightDom.detachShadowDomView();
|
||||||
|
}
|
||||||
|
componentView.hostLightDom = null;
|
||||||
|
componentView.shadowRoot = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) {
|
||||||
|
var parentView = resolveInternalDomView(parentViewRef);
|
||||||
|
var view = resolveInternalDomView(viewRef);
|
||||||
|
var viewContainer = this._getOrCreateViewContainer(parentView, boundElementIndex);
|
||||||
|
ListWrapper.insert(viewContainer.views, atIndex, view);
|
||||||
|
view.hostLightDom = parentView.hostLightDom;
|
||||||
|
|
||||||
|
var directParentLightDom = parentView.getDirectParentLightDom(boundElementIndex);
|
||||||
|
if (isBlank(directParentLightDom)) {
|
||||||
|
var siblingToInsertAfter;
|
||||||
|
if (atIndex == 0) {
|
||||||
|
siblingToInsertAfter = parentView.boundElements[boundElementIndex];
|
||||||
|
} else {
|
||||||
|
siblingToInsertAfter = ListWrapper.last(viewContainer.views[atIndex - 1].rootNodes);
|
||||||
|
}
|
||||||
|
this._moveViewNodesAfterSibling(siblingToInsertAfter, view);
|
||||||
|
} else {
|
||||||
|
directParentLightDom.redistribute();
|
||||||
|
}
|
||||||
|
// new content tags might have appeared, we need to redistribute.
|
||||||
|
if (isPresent(parentView.hostLightDom)) {
|
||||||
|
parentView.hostLightDom.redistribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detachViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) {
|
||||||
|
var parentView = resolveInternalDomView(parentViewRef);
|
||||||
|
var view = resolveInternalDomView(viewRef);
|
||||||
|
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||||
|
var detachedView = viewContainer.views[atIndex];
|
||||||
|
ListWrapper.removeAt(viewContainer.views, atIndex);
|
||||||
|
var directParentLightDom = parentView.getDirectParentLightDom(boundElementIndex);
|
||||||
|
if (isBlank(directParentLightDom)) {
|
||||||
|
this._removeViewNodes(detachedView);
|
||||||
|
} else {
|
||||||
|
directParentLightDom.redistribute();
|
||||||
|
}
|
||||||
|
view.hostLightDom = null;
|
||||||
|
// content tags might have disappeared we need to do redistribution.
|
||||||
|
if (isPresent(parentView.hostLightDom)) {
|
||||||
|
parentView.hostLightDom.redistribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hydrateView(viewRef:RenderViewRef) {
|
||||||
|
var view = resolveInternalDomView(viewRef);
|
||||||
|
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];
|
||||||
|
if (isPresent(lightDom)) {
|
||||||
|
lightDom.redistribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add global events
|
||||||
|
view.eventHandlerRemovers = ListWrapper.create();
|
||||||
|
var binders = view.proto.elementBinders;
|
||||||
|
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||||
|
var binder = binders[binderIdx];
|
||||||
|
if (isPresent(binder.globalEvents)) {
|
||||||
|
for (var i = 0; i < binder.globalEvents.length; i++) {
|
||||||
|
var globalEvent = binder.globalEvents[i];
|
||||||
|
var remover = this._createGlobalEventListener(view, binderIdx, globalEvent.name, globalEvent.target, globalEvent.fullName);
|
||||||
|
ListWrapper.push(view.eventHandlerRemovers, remover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isPresent(view.hostLightDom)) {
|
||||||
|
view.hostLightDom.redistribute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dehydrateView(viewRef:RenderViewRef) {
|
||||||
|
var view = resolveInternalDomView(viewRef);
|
||||||
|
|
||||||
|
//remove global events
|
||||||
|
for (var i = 0; i < view.eventHandlerRemovers.length; i++) {
|
||||||
|
view.eventHandlerRemovers[i]();
|
||||||
|
}
|
||||||
|
|
||||||
|
view.eventHandlerRemovers = null;
|
||||||
|
view.hydrated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setElementProperty(viewRef:RenderViewRef, elementIndex:number, propertyName:string, propertyValue:any):void {
|
||||||
|
var view = resolveInternalDomView(viewRef);
|
||||||
|
view.setElementProperty(elementIndex, propertyName, propertyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(viewRef:RenderViewRef, textNodeIndex:number, text:string):void {
|
||||||
|
var view = resolveInternalDomView(viewRef);
|
||||||
|
DOM.setText(view.boundTextNodes[textNodeIndex], text);
|
||||||
|
}
|
||||||
|
|
||||||
|
setEventDispatcher(viewRef:RenderViewRef, dispatcher:any/*api.EventDispatcher*/):void {
|
||||||
|
var view = resolveInternalDomView(viewRef);
|
||||||
|
view.eventDispatcher = dispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createView(protoView:DomProtoView, inplaceElement): DomView {
|
||||||
|
var rootElementClone = isPresent(inplaceElement) ? inplaceElement : DOM.importIntoDoc(protoView.element);
|
||||||
|
var elementsWithBindingsDynamic;
|
||||||
|
if (protoView.isTemplateElement) {
|
||||||
|
elementsWithBindingsDynamic = DOM.querySelectorAll(DOM.content(rootElementClone), NG_BINDING_CLASS_SELECTOR);
|
||||||
|
} else {
|
||||||
|
elementsWithBindingsDynamic = DOM.getElementsByClassName(rootElementClone, NG_BINDING_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
var elementsWithBindings = ListWrapper.createFixedSize(elementsWithBindingsDynamic.length);
|
||||||
|
for (var binderIdx = 0; binderIdx < elementsWithBindingsDynamic.length; ++binderIdx) {
|
||||||
|
elementsWithBindings[binderIdx] = elementsWithBindingsDynamic[binderIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewRootNodes;
|
||||||
|
if (protoView.isTemplateElement) {
|
||||||
|
var childNode = DOM.firstChild(DOM.content(rootElementClone));
|
||||||
|
viewRootNodes = []; // TODO(perf): Should be fixed size, since we could pre-compute in in DomProtoView
|
||||||
|
// Note: An explicit loop is the fastest way to convert a DOM array into a JS array!
|
||||||
|
while(childNode != null) {
|
||||||
|
ListWrapper.push(viewRootNodes, childNode);
|
||||||
|
childNode = DOM.nextSibling(childNode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viewRootNodes = [rootElementClone];
|
||||||
|
}
|
||||||
|
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];
|
||||||
|
var element;
|
||||||
|
if (binderIdx === 0 && protoView.rootBindingOffset === 1) {
|
||||||
|
element = rootElementClone;
|
||||||
|
} else {
|
||||||
|
element = elementsWithBindings[binderIdx - protoView.rootBindingOffset];
|
||||||
|
}
|
||||||
|
boundElements[binderIdx] = element;
|
||||||
|
|
||||||
|
// boundTextNodes
|
||||||
|
var childNodes = DOM.childNodes(DOM.templateAwareRoot(element));
|
||||||
|
var textNodeIndices = binder.textNodeIndices;
|
||||||
|
for (var i = 0; i<textNodeIndices.length; i++) {
|
||||||
|
ListWrapper.push(boundTextNodes, childNodes[textNodeIndices[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// contentTags
|
||||||
|
var contentTag = null;
|
||||||
|
if (isPresent(binder.contentTagSelector)) {
|
||||||
|
contentTag = new Content(element, binder.contentTagSelector);
|
||||||
|
}
|
||||||
|
contentTags[binderIdx] = contentTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = new DomView(
|
||||||
|
protoView, viewRootNodes,
|
||||||
|
boundTextNodes, boundElements, contentTags
|
||||||
|
);
|
||||||
|
|
||||||
|
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||||
|
var binder = binders[binderIdx];
|
||||||
|
var element = boundElements[binderIdx];
|
||||||
|
|
||||||
|
// lightDoms
|
||||||
|
var lightDom = null;
|
||||||
|
if (isPresent(binder.componentId)) {
|
||||||
|
lightDom = this._shadowDomStrategy.constructLightDom(view, boundElements[binderIdx]);
|
||||||
|
}
|
||||||
|
view.lightDoms[binderIdx] = lightDom;
|
||||||
|
|
||||||
|
// init contentTags
|
||||||
|
var contentTag = contentTags[binderIdx];
|
||||||
|
if (isPresent(contentTag)) {
|
||||||
|
var destLightDom = view.getDirectParentLightDom(binderIdx);
|
||||||
|
contentTag.init(destLightDom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, binder.eventLocals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createEventListener(view, element, elementIndex, eventName, eventLocals) {
|
||||||
|
this._eventManager.addEventListener(element, eventName, (event) => {
|
||||||
|
view.dispatchEvent(elementIndex, eventName, event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_moveViewNodesAfterSibling(sibling, view) {
|
||||||
|
for (var i = view.rootNodes.length - 1; i >= 0; --i) {
|
||||||
|
DOM.insertAfter(sibling, view.rootNodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_moveViewNodesIntoParent(parent, view) {
|
||||||
|
for (var i = 0; i < view.rootNodes.length; ++i) {
|
||||||
|
DOM.appendChild(parent, view.rootNodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_removeViewNodes(view) {
|
||||||
|
var len = view.rootNodes.length;
|
||||||
|
if (len == 0) return;
|
||||||
|
var parent = view.rootNodes[0].parentNode;
|
||||||
|
for (var i = len - 1; i >= 0; --i) {
|
||||||
|
DOM.removeChild(parent, view.rootNodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getOrCreateViewContainer(parentView:DomView, boundElementIndex) {
|
||||||
|
var vc = parentView.viewContainers[boundElementIndex];
|
||||||
|
if (isBlank(vc)) {
|
||||||
|
vc = new DomViewContainer();
|
||||||
|
parentView.viewContainers[boundElementIndex] = vc;
|
||||||
|
}
|
||||||
|
return vc;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createGlobalEventListener(view, elementIndex, eventName, eventTarget, fullName): Function {
|
||||||
|
return this._eventManager.addGlobalEventListener(eventTarget, eventName, (event) => {
|
||||||
|
view.dispatchEvent(elementIndex, fullName, event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -74,16 +74,12 @@ export class Content {
|
||||||
this._strategy = null;
|
this._strategy = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrate(destinationLightDom:ldModule.LightDom) {
|
init(destinationLightDom:ldModule.LightDom) {
|
||||||
this._strategy = isPresent(destinationLightDom) ?
|
this._strategy = isPresent(destinationLightDom) ?
|
||||||
new IntermediateContent(destinationLightDom) :
|
new IntermediateContent(destinationLightDom) :
|
||||||
new RenderedContent(this.contentStartElement);
|
new RenderedContent(this.contentStartElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
dehydrate() {
|
|
||||||
this._strategy = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes():List {
|
nodes():List {
|
||||||
return this._strategy.nodes;
|
return this._strategy.nodes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import * as viewModule from '../view/view';
|
||||||
import {LightDom} from './light_dom';
|
import {LightDom} from './light_dom';
|
||||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||||
import {StyleUrlResolver} from './style_url_resolver';
|
import {StyleUrlResolver} from './style_url_resolver';
|
||||||
import {moveViewNodesIntoParent} from './util';
|
|
||||||
import {insertSharedStyleText} from './util';
|
import {insertSharedStyleText} from './util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,12 +32,12 @@ export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
attachTemplate(el, view:viewModule.DomView) {
|
prepareShadowRoot(el) {
|
||||||
moveViewNodesIntoParent(el, view);
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructLightDom(lightDomView:viewModule.DomView, shadowDomView:viewModule.DomView, el): LightDom {
|
constructLightDom(lightDomView:viewModule.DomView, el): LightDom {
|
||||||
return new LightDom(lightDomView, shadowDomView, el);
|
return new LightDom(lightDomView, el);
|
||||||
}
|
}
|
||||||
|
|
||||||
processStyleElement(hostComponentId:string, templateUrl:string, styleEl):Promise {
|
processStyleElement(hostComponentId:string, templateUrl:string, styleEl):Promise {
|
||||||
|
|
|
@ -28,12 +28,20 @@ export class LightDom {
|
||||||
nodes:List;
|
nodes:List;
|
||||||
roots:List<_Root>;
|
roots:List<_Root>;
|
||||||
|
|
||||||
constructor(lightDomView:viewModule.DomView, shadowDomView:viewModule.DomView, element) {
|
constructor(lightDomView:viewModule.DomView, element) {
|
||||||
this.lightDomView = lightDomView;
|
this.lightDomView = lightDomView;
|
||||||
this.shadowDomView = shadowDomView;
|
|
||||||
this.nodes = DOM.childNodesAsList(element);
|
this.nodes = DOM.childNodesAsList(element);
|
||||||
|
|
||||||
this.roots = null;
|
this.roots = null;
|
||||||
|
this.shadowDomView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachShadowDomView(shadowDomView:viewModule.DomView) {
|
||||||
|
this.shadowDomView = shadowDomView;
|
||||||
|
}
|
||||||
|
|
||||||
|
detachShadowDomView() {
|
||||||
|
this.shadowDomView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
redistribute() {
|
redistribute() {
|
||||||
|
@ -41,7 +49,11 @@ export class LightDom {
|
||||||
}
|
}
|
||||||
|
|
||||||
contentTags(): List<Content> {
|
contentTags(): List<Content> {
|
||||||
|
if (isPresent(this.shadowDomView)) {
|
||||||
return this._collectAllContentTags(this.shadowDomView, []);
|
return this._collectAllContentTags(this.shadowDomView, []);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collects the Content directives from the view and all its child views
|
// Collects the Content directives from the view and all its child views
|
||||||
|
|
|
@ -2,11 +2,8 @@ import {Promise} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
import * as viewModule from '../view/view';
|
|
||||||
|
|
||||||
import {StyleUrlResolver} from './style_url_resolver';
|
import {StyleUrlResolver} from './style_url_resolver';
|
||||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||||
import {moveViewNodesIntoParent} from './util';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This strategies uses the native Shadow DOM support.
|
* This strategies uses the native Shadow DOM support.
|
||||||
|
@ -22,8 +19,8 @@ export class NativeShadowDomStrategy extends ShadowDomStrategy {
|
||||||
this.styleUrlResolver = styleUrlResolver;
|
this.styleUrlResolver = styleUrlResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
attachTemplate(el, view:viewModule.DomView){
|
prepareShadowRoot(el) {
|
||||||
moveViewNodesIntoParent(DOM.createShadowRoot(el), view);
|
return DOM.createShadowRoot(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
processStyleElement(hostComponentId:string, templateUrl:string, styleEl):Promise {
|
processStyleElement(hostComponentId:string, templateUrl:string, styleEl):Promise {
|
||||||
|
|
|
@ -9,9 +9,14 @@ export class ShadowDomStrategy {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
attachTemplate(el, view:viewModule.DomView) {}
|
/**
|
||||||
|
* Prepares and returns the shadow root for the given element.
|
||||||
|
*/
|
||||||
|
prepareShadowRoot(el):any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
constructLightDom(lightDomView:viewModule.DomView, shadowDomView:viewModule.DomView, el): LightDom {
|
constructLightDom(lightDomView:viewModule.DomView, el): LightDom {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,6 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
import {ShadowCss} from './shadow_css';
|
import {ShadowCss} from './shadow_css';
|
||||||
|
|
||||||
export function moveViewNodesIntoParent(parent, view) {
|
|
||||||
for (var i = 0; i < view.rootNodes.length; ++i) {
|
|
||||||
DOM.appendChild(parent, view.rootNodes[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _componentUIDs: Map<string, int> = MapWrapper.create();
|
var _componentUIDs: Map<string, int> = MapWrapper.create();
|
||||||
var _nextComponentUID: int = 0;
|
var _nextComponentUID: int = 0;
|
||||||
var _sharedStyleTexts: Map<string, boolean> = MapWrapper.create();
|
var _sharedStyleTexts: Map<string, boolean> = MapWrapper.create();
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
|
||||||
import {AST} from 'angular2/change_detection';
|
import {AST} from 'angular2/change_detection';
|
||||||
import {SetterFn} from 'angular2/src/reflection/types';
|
import {SetterFn} from 'angular2/src/reflection/types';
|
||||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||||
|
@ -39,14 +38,6 @@ export class ElementBinder {
|
||||||
this.distanceToParent = distanceToParent;
|
this.distanceToParent = distanceToParent;
|
||||||
this.propertySetters = propertySetters;
|
this.propertySetters = propertySetters;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasStaticComponent() {
|
|
||||||
return isPresent(this.componentId) && isPresent(this.nestedProtoView);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasDynamicComponent() {
|
|
||||||
return isPresent(this.componentId) && isBlank(this.nestedProtoView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Event {
|
export class Event {
|
||||||
|
|
|
@ -1,43 +1,39 @@
|
||||||
import {isPresent} from 'angular2/src/facade/lang';
|
import {isPresent} from 'angular2/src/facade/lang';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
import {List, Map, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
import {List} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
import {ElementBinder} from './element_binder';
|
import {ElementBinder} from './element_binder';
|
||||||
import {NG_BINDING_CLASS} from '../util';
|
import {NG_BINDING_CLASS} from '../util';
|
||||||
|
|
||||||
|
import {RenderProtoViewRef} from '../../api';
|
||||||
|
|
||||||
|
export function resolveInternalDomProtoView(protoViewRef:RenderProtoViewRef) {
|
||||||
|
var domProtoViewRef:DomProtoViewRef = protoViewRef;
|
||||||
|
return domProtoViewRef._protoView;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DomProtoViewRef extends RenderProtoViewRef {
|
||||||
|
_protoView:DomProtoView;
|
||||||
|
constructor(protoView:DomProtoView) {
|
||||||
|
super();
|
||||||
|
this._protoView = protoView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class DomProtoView {
|
export class DomProtoView {
|
||||||
element;
|
element;
|
||||||
elementBinders:List<ElementBinder>;
|
elementBinders:List<ElementBinder>;
|
||||||
isTemplateElement:boolean;
|
isTemplateElement:boolean;
|
||||||
rootBindingOffset:int;
|
rootBindingOffset:int;
|
||||||
imperativeRendererId:string;
|
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
elementBinders,
|
elementBinders,
|
||||||
element,
|
element
|
||||||
imperativeRendererId
|
|
||||||
}) {
|
}) {
|
||||||
this.element = element;
|
this.element = element;
|
||||||
this.elementBinders = elementBinders;
|
this.elementBinders = elementBinders;
|
||||||
this.imperativeRendererId = imperativeRendererId;
|
|
||||||
if (isPresent(imperativeRendererId)) {
|
|
||||||
this.rootBindingOffset = 0;
|
|
||||||
this.isTemplateElement = false;
|
|
||||||
} else {
|
|
||||||
this.isTemplateElement = DOM.isTemplateElement(this.element);
|
this.isTemplateElement = DOM.isTemplateElement(this.element);
|
||||||
this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS)) ? 1 : 0;
|
this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS)) ? 1 : 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mergeChildComponentProtoViews(componentProtoViews:List<DomProtoView>) {
|
|
||||||
var componentProtoViewIndex = 0;
|
|
||||||
for (var i=0; i<this.elementBinders.length; i++) {
|
|
||||||
var eb = this.elementBinders[i];
|
|
||||||
if (isPresent(eb.componentId)) {
|
|
||||||
eb.nestedProtoView = componentProtoViews[componentProtoViewIndex];
|
|
||||||
componentProtoViewIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,11 @@ import {
|
||||||
ASTWithSource, AST, AstTransformer, AccessMember, LiteralArray, ImplicitReceiver
|
ASTWithSource, AST, AstTransformer, AccessMember, LiteralArray, ImplicitReceiver
|
||||||
} from 'angular2/change_detection';
|
} from 'angular2/change_detection';
|
||||||
|
|
||||||
import {DomProtoView} from './proto_view';
|
import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './proto_view';
|
||||||
import {ElementBinder, Event} from './element_binder';
|
import {ElementBinder, Event} from './element_binder';
|
||||||
import {setterFactory} from './property_setter_factory';
|
import {setterFactory} from './property_setter_factory';
|
||||||
|
|
||||||
import * as api from '../../api';
|
import * as api from '../../api';
|
||||||
import * as directDomRenderer from '../direct_dom_renderer';
|
|
||||||
|
|
||||||
import {NG_BINDING_CLASS, EVENT_TARGET_SEPARATOR} from '../util';
|
import {NG_BINDING_CLASS, EVENT_TARGET_SEPARATOR} from '../util';
|
||||||
|
|
||||||
|
@ -19,18 +18,11 @@ export class ProtoViewBuilder {
|
||||||
rootElement;
|
rootElement;
|
||||||
variableBindings: Map<string, string>;
|
variableBindings: Map<string, string>;
|
||||||
elements:List<ElementBinderBuilder>;
|
elements:List<ElementBinderBuilder>;
|
||||||
imperativeRendererId:string;
|
|
||||||
|
|
||||||
constructor(rootElement) {
|
constructor(rootElement) {
|
||||||
this.rootElement = rootElement;
|
this.rootElement = rootElement;
|
||||||
this.elements = [];
|
this.elements = [];
|
||||||
this.variableBindings = MapWrapper.create();
|
this.variableBindings = MapWrapper.create();
|
||||||
this.imperativeRendererId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
setImperativeRendererId(id:string):ProtoViewBuilder {
|
|
||||||
this.imperativeRendererId = id;
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bindElement(element, description = null):ElementBinderBuilder {
|
bindElement(element, description = null):ElementBinderBuilder {
|
||||||
|
@ -93,7 +85,7 @@ export class ProtoViewBuilder {
|
||||||
contentTagSelector: ebb.contentTagSelector,
|
contentTagSelector: ebb.contentTagSelector,
|
||||||
parentIndex: parentIndex,
|
parentIndex: parentIndex,
|
||||||
distanceToParent: ebb.distanceToParent,
|
distanceToParent: ebb.distanceToParent,
|
||||||
nestedProtoView: isPresent(nestedProtoView) ? nestedProtoView.render.delegate : null,
|
nestedProtoView: isPresent(nestedProtoView) ? resolveInternalDomProtoView(nestedProtoView.render) : null,
|
||||||
componentId: ebb.componentId,
|
componentId: ebb.componentId,
|
||||||
eventLocals: new LiteralArray(ebb.eventBuilder.buildEventLocals()),
|
eventLocals: new LiteralArray(ebb.eventBuilder.buildEventLocals()),
|
||||||
localEvents: ebb.eventBuilder.buildLocalEvents(),
|
localEvents: ebb.eventBuilder.buildLocalEvents(),
|
||||||
|
@ -102,10 +94,9 @@ export class ProtoViewBuilder {
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
return new api.ProtoViewDto({
|
return new api.ProtoViewDto({
|
||||||
render: new directDomRenderer.DirectDomProtoViewRef(new DomProtoView({
|
render: new DomProtoViewRef(new DomProtoView({
|
||||||
element: this.rootElement,
|
element: this.rootElement,
|
||||||
elementBinders: renderElementBinders,
|
elementBinders: renderElementBinders
|
||||||
imperativeRendererId: this.imperativeRendererId
|
|
||||||
})),
|
})),
|
||||||
elementBinders: apiElementBinders,
|
elementBinders: apiElementBinders,
|
||||||
variableBindings: this.variableBindings
|
variableBindings: this.variableBindings
|
||||||
|
|
|
@ -2,13 +2,30 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||||
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {ViewContainer} from './view_container';
|
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 {Content} from '../shadow_dom/content_tag';
|
||||||
|
|
||||||
|
import {RenderViewRef} from '../../api';
|
||||||
|
|
||||||
|
// TODO(tbosch): enable this again!
|
||||||
// import {EventDispatcher} from '../../api';
|
// import {EventDispatcher} from '../../api';
|
||||||
|
|
||||||
|
export function resolveInternalDomView(viewRef:RenderViewRef) {
|
||||||
|
var domViewRef:DomViewRef = viewRef;
|
||||||
|
return domViewRef._view;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DomViewRef extends RenderViewRef {
|
||||||
|
_view:DomView;
|
||||||
|
constructor(view:DomView) {
|
||||||
|
super();
|
||||||
|
this._view = view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const NG_BINDING_CLASS = 'ng-binding';
|
const NG_BINDING_CLASS = 'ng-binding';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,18 +39,15 @@ export class DomView {
|
||||||
rootNodes:List;
|
rootNodes:List;
|
||||||
// TODO(tbosch): move componentChildViews, viewContainers, contentTags, lightDoms into
|
// TODO(tbosch): move componentChildViews, viewContainers, contentTags, lightDoms into
|
||||||
// a single array with records inside
|
// a single array with records inside
|
||||||
componentChildViews: List<DomView>;
|
viewContainers: List<DomViewContainer>;
|
||||||
viewContainers: List<ViewContainer>;
|
|
||||||
contentTags: List<Content>;
|
contentTags: List<Content>;
|
||||||
lightDoms: List<LightDom>;
|
lightDoms: List<LightDom>;
|
||||||
hostLightDom: LightDom;
|
hostLightDom: LightDom;
|
||||||
|
shadowRoot;
|
||||||
proto: DomProtoView;
|
proto: DomProtoView;
|
||||||
hydrated: boolean;
|
hydrated: boolean;
|
||||||
_eventDispatcher: any/*EventDispatcher*/;
|
eventDispatcher: any/*EventDispatcher*/;
|
||||||
eventHandlerRemovers: List<Function>;
|
eventHandlerRemovers: List<Function>;
|
||||||
/// Host views that were added by an imperative view.
|
|
||||||
/// This is a dynamically growing / shrinking array.
|
|
||||||
imperativeHostViews: List<DomView>;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
proto:DomProtoView, rootNodes:List,
|
proto:DomProtoView, rootNodes:List,
|
||||||
|
@ -45,12 +59,11 @@ export class DomView {
|
||||||
this.viewContainers = ListWrapper.createFixedSize(boundElements.length);
|
this.viewContainers = ListWrapper.createFixedSize(boundElements.length);
|
||||||
this.contentTags = contentTags;
|
this.contentTags = contentTags;
|
||||||
this.lightDoms = ListWrapper.createFixedSize(boundElements.length);
|
this.lightDoms = ListWrapper.createFixedSize(boundElements.length);
|
||||||
ListWrapper.fill(this.lightDoms, null);
|
|
||||||
this.componentChildViews = ListWrapper.createFixedSize(boundElements.length);
|
|
||||||
this.hostLightDom = null;
|
this.hostLightDom = null;
|
||||||
this.hydrated = false;
|
this.hydrated = false;
|
||||||
this.eventHandlerRemovers = [];
|
this.eventHandlerRemovers = [];
|
||||||
this.imperativeHostViews = [];
|
this.eventDispatcher = null;
|
||||||
|
this.shadowRoot = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDirectParentLightDom(boundElementIndex:number) {
|
getDirectParentLightDom(boundElementIndex:number) {
|
||||||
|
@ -62,15 +75,6 @@ export class DomView {
|
||||||
return destLightDom;
|
return destLightDom;
|
||||||
}
|
}
|
||||||
|
|
||||||
getOrCreateViewContainer(binderIndex) {
|
|
||||||
var vc = this.viewContainers[binderIndex];
|
|
||||||
if (isBlank(vc)) {
|
|
||||||
vc = new ViewContainer(this, binderIndex);
|
|
||||||
this.viewContainers[binderIndex] = vc;
|
|
||||||
}
|
|
||||||
return vc;
|
|
||||||
}
|
|
||||||
|
|
||||||
setElementProperty(elementIndex:number, propertyName:string, value:any) {
|
setElementProperty(elementIndex:number, propertyName:string, value:any) {
|
||||||
var setter = MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName);
|
var setter = MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName);
|
||||||
setter(this.boundElements[elementIndex], value);
|
setter(this.boundElements[elementIndex], value);
|
||||||
|
@ -80,24 +84,16 @@ export class DomView {
|
||||||
DOM.setText(this.boundTextNodes[textIndex], value);
|
DOM.setText(this.boundTextNodes[textIndex], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
getViewContainer(index:number):ViewContainer {
|
|
||||||
return this.viewContainers[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
setEventDispatcher(dispatcher:any/*EventDispatcher*/) {
|
|
||||||
this._eventDispatcher = dispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchEvent(elementIndex, eventName, event): boolean {
|
dispatchEvent(elementIndex, eventName, event): boolean {
|
||||||
var allowDefaultBehavior = true;
|
var allowDefaultBehavior = true;
|
||||||
if (isPresent(this._eventDispatcher)) {
|
if (isPresent(this.eventDispatcher)) {
|
||||||
var evalLocals = MapWrapper.create();
|
var evalLocals = MapWrapper.create();
|
||||||
MapWrapper.set(evalLocals, '$event', event);
|
MapWrapper.set(evalLocals, '$event', event);
|
||||||
// TODO(tbosch): reenable this when we are parsing element properties
|
// TODO(tbosch): reenable this when we are parsing element properties
|
||||||
// out of action expressions
|
// out of action expressions
|
||||||
// var localValues = this.proto.elementBinders[elementIndex].eventLocals.eval(null, new Locals(null, evalLocals));
|
// var localValues = this.proto.elementBinders[elementIndex].eventLocals.eval(null, new Locals(null, evalLocals));
|
||||||
// this._eventDispatcher.dispatchEvent(elementIndex, eventName, localValues);
|
// this.eventDispatcher.dispatchEvent(elementIndex, eventName, localValues);
|
||||||
allowDefaultBehavior = this._eventDispatcher.dispatchEvent(elementIndex, eventName, evalLocals);
|
allowDefaultBehavior = this.eventDispatcher.dispatchEvent(elementIndex, eventName, evalLocals);
|
||||||
if (!allowDefaultBehavior) {
|
if (!allowDefaultBehavior) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +1,15 @@
|
||||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
|
||||||
import {ListWrapper, MapWrapper, List} from 'angular2/src/facade/collection';
|
import {ListWrapper, MapWrapper, List} from 'angular2/src/facade/collection';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
||||||
|
|
||||||
import * as viewModule from './view';
|
import * as viewModule from './view';
|
||||||
|
|
||||||
export class ViewContainer {
|
export class DomViewContainer {
|
||||||
parentView: viewModule.DomView;
|
|
||||||
boundElementIndex: number;
|
|
||||||
views: List<viewModule.DomView>;
|
views: List<viewModule.DomView>;
|
||||||
|
|
||||||
constructor(parentView: viewModule.DomView, boundElementIndex: number) {
|
constructor() {
|
||||||
this.parentView = parentView;
|
|
||||||
this.boundElementIndex = boundElementIndex;
|
|
||||||
// The order in this list matches the DOM order.
|
// The order in this list matches the DOM order.
|
||||||
this.views = [];
|
this.views = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
get(index: number): viewModule.DomView {
|
|
||||||
return this.views[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
size() {
|
|
||||||
return this.views.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
_siblingToInsertAfter(index: number) {
|
|
||||||
if (index == 0) return this.parentView.boundElements[this.boundElementIndex];
|
|
||||||
return ListWrapper.last(this.views[index - 1].rootNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
_checkHydrated() {
|
|
||||||
if (!this.parentView.hydrated) throw new BaseException(
|
|
||||||
'Cannot change dehydrated ViewContainer');
|
|
||||||
}
|
|
||||||
|
|
||||||
_getDirectParentLightDom() {
|
|
||||||
return this.parentView.getDirectParentLightDom(this.boundElementIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this._checkHydrated();
|
|
||||||
for (var i=this.views.length-1; i>=0; i--) {
|
|
||||||
this.detach(i);
|
|
||||||
}
|
|
||||||
if (isPresent(this._getDirectParentLightDom())) {
|
|
||||||
this._getDirectParentLightDom().redistribute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insert(view, atIndex=-1): viewModule.DomView {
|
|
||||||
this._checkHydrated();
|
|
||||||
if (atIndex == -1) atIndex = this.views.length;
|
|
||||||
ListWrapper.insert(this.views, atIndex, view);
|
|
||||||
|
|
||||||
if (isBlank(this._getDirectParentLightDom())) {
|
|
||||||
ViewContainer.moveViewNodesAfterSibling(this._siblingToInsertAfter(atIndex), view);
|
|
||||||
} else {
|
|
||||||
this._getDirectParentLightDom().redistribute();
|
|
||||||
}
|
|
||||||
// new content tags might have appeared, we need to redistribute.
|
|
||||||
if (isPresent(this.parentView.hostLightDom)) {
|
|
||||||
this.parentView.hostLightDom.redistribute();
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The method can be used together with insert to implement a view move, i.e.
|
|
||||||
* moving the dom nodes while the directives in the view stay intact.
|
|
||||||
*/
|
|
||||||
detach(atIndex:number) {
|
|
||||||
this._checkHydrated();
|
|
||||||
var detachedView = this.get(atIndex);
|
|
||||||
ListWrapper.removeAt(this.views, atIndex);
|
|
||||||
if (isBlank(this._getDirectParentLightDom())) {
|
|
||||||
ViewContainer.removeViewNodes(detachedView);
|
|
||||||
} else {
|
|
||||||
this._getDirectParentLightDom().redistribute();
|
|
||||||
}
|
|
||||||
// content tags might have disappeared we need to do redistribution.
|
|
||||||
if (isPresent(this.parentView.hostLightDom)) {
|
|
||||||
this.parentView.hostLightDom.redistribute();
|
|
||||||
}
|
|
||||||
return detachedView;
|
|
||||||
}
|
|
||||||
|
|
||||||
contentTagContainers() {
|
contentTagContainers() {
|
||||||
return this.views;
|
return this.views;
|
||||||
}
|
}
|
||||||
|
@ -97,18 +22,4 @@ export class ViewContainer {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static moveViewNodesAfterSibling(sibling, view) {
|
|
||||||
for (var i = view.rootNodes.length - 1; i >= 0; --i) {
|
|
||||||
DOM.insertAfter(sibling, view.rootNodes[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static removeViewNodes(view) {
|
|
||||||
var len = view.rootNodes.length;
|
|
||||||
if (len == 0) return;
|
|
||||||
var parent = view.rootNodes[0].parentNode;
|
|
||||||
for (var i = len - 1; i >= 0; --i) {
|
|
||||||
DOM.removeChild(parent, view.rootNodes[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,164 +0,0 @@
|
||||||
import {Inject, Injectable} from 'angular2/src/di/annotations_impl';
|
|
||||||
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
|
||||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
|
||||||
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
||||||
|
|
||||||
import {Content} from '../shadow_dom/content_tag';
|
|
||||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
|
||||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
|
||||||
|
|
||||||
import * as pvModule from './proto_view';
|
|
||||||
import * as viewModule from './view';
|
|
||||||
import {NG_BINDING_CLASS_SELECTOR, NG_BINDING_CLASS} from '../util';
|
|
||||||
|
|
||||||
// TODO(tbosch): Make this an OpaqueToken as soon as our transpiler supports this!
|
|
||||||
export const VIEW_POOL_CAPACITY = 'render.ViewFactory.viewPoolCapacity';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ViewFactory {
|
|
||||||
_poolCapacityPerProtoView:number;
|
|
||||||
_pooledViewsPerProtoView:Map<pvModule.DomProtoView, List<viewModule.DomView>>;
|
|
||||||
_eventManager:EventManager;
|
|
||||||
_shadowDomStrategy:ShadowDomStrategy;
|
|
||||||
|
|
||||||
constructor(@Inject(VIEW_POOL_CAPACITY) poolCapacityPerProtoView,
|
|
||||||
eventManager:EventManager, shadowDomStrategy:ShadowDomStrategy) {
|
|
||||||
this._poolCapacityPerProtoView = poolCapacityPerProtoView;
|
|
||||||
this._pooledViewsPerProtoView = MapWrapper.create();
|
|
||||||
this._eventManager = eventManager;
|
|
||||||
this._shadowDomStrategy = shadowDomStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
createInPlaceHostView(hostElementSelector, hostProtoView:pvModule.DomProtoView):viewModule.DomView {
|
|
||||||
return this._createView(hostProtoView, hostElementSelector);
|
|
||||||
}
|
|
||||||
|
|
||||||
getView(protoView:pvModule.DomProtoView):viewModule.DomView {
|
|
||||||
var pooledViews = MapWrapper.get(this._pooledViewsPerProtoView, protoView);
|
|
||||||
if (isPresent(pooledViews) && pooledViews.length > 0) {
|
|
||||||
return ListWrapper.removeLast(pooledViews);
|
|
||||||
}
|
|
||||||
return this._createView(protoView, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
returnView(view:viewModule.DomView) {
|
|
||||||
if (view.hydrated) {
|
|
||||||
throw new BaseException('View is still hydrated');
|
|
||||||
}
|
|
||||||
var protoView = view.proto;
|
|
||||||
var pooledViews = MapWrapper.get(this._pooledViewsPerProtoView, protoView);
|
|
||||||
if (isBlank(pooledViews)) {
|
|
||||||
pooledViews = [];
|
|
||||||
MapWrapper.set(this._pooledViewsPerProtoView, protoView, pooledViews);
|
|
||||||
}
|
|
||||||
if (pooledViews.length < this._poolCapacityPerProtoView) {
|
|
||||||
ListWrapper.push(pooledViews, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_createView(protoView:pvModule.DomProtoView, inplaceElement): viewModule.DomView {
|
|
||||||
if (isPresent(protoView.imperativeRendererId)) {
|
|
||||||
return new viewModule.DomView(
|
|
||||||
protoView, [], [], [], []
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rootElementClone = isPresent(inplaceElement) ? inplaceElement : DOM.importIntoDoc(protoView.element);
|
|
||||||
var elementsWithBindingsDynamic;
|
|
||||||
if (protoView.isTemplateElement) {
|
|
||||||
elementsWithBindingsDynamic = DOM.querySelectorAll(DOM.content(rootElementClone), NG_BINDING_CLASS_SELECTOR);
|
|
||||||
} else {
|
|
||||||
elementsWithBindingsDynamic = DOM.getElementsByClassName(rootElementClone, NG_BINDING_CLASS);
|
|
||||||
}
|
|
||||||
|
|
||||||
var elementsWithBindings = ListWrapper.createFixedSize(elementsWithBindingsDynamic.length);
|
|
||||||
for (var binderIdx = 0; binderIdx < elementsWithBindingsDynamic.length; ++binderIdx) {
|
|
||||||
elementsWithBindings[binderIdx] = elementsWithBindingsDynamic[binderIdx];
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewRootNodes;
|
|
||||||
if (protoView.isTemplateElement) {
|
|
||||||
var childNode = DOM.firstChild(DOM.content(rootElementClone));
|
|
||||||
viewRootNodes = []; // TODO(perf): Should be fixed size, since we could pre-compute in in pvModule.DomProtoView
|
|
||||||
// Note: An explicit loop is the fastest way to convert a DOM array into a JS array!
|
|
||||||
while(childNode != null) {
|
|
||||||
ListWrapper.push(viewRootNodes, childNode);
|
|
||||||
childNode = DOM.nextSibling(childNode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
viewRootNodes = [rootElementClone];
|
|
||||||
}
|
|
||||||
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];
|
|
||||||
var element;
|
|
||||||
if (binderIdx === 0 && protoView.rootBindingOffset === 1) {
|
|
||||||
element = rootElementClone;
|
|
||||||
} else {
|
|
||||||
element = elementsWithBindings[binderIdx - protoView.rootBindingOffset];
|
|
||||||
}
|
|
||||||
boundElements[binderIdx] = element;
|
|
||||||
|
|
||||||
// boundTextNodes
|
|
||||||
var childNodes = DOM.childNodes(DOM.templateAwareRoot(element));
|
|
||||||
var textNodeIndices = binder.textNodeIndices;
|
|
||||||
for (var i = 0; i<textNodeIndices.length; i++) {
|
|
||||||
ListWrapper.push(boundTextNodes, childNodes[textNodeIndices[i]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// contentTags
|
|
||||||
var contentTag = null;
|
|
||||||
if (isPresent(binder.contentTagSelector)) {
|
|
||||||
contentTag = new Content(element, binder.contentTagSelector);
|
|
||||||
}
|
|
||||||
contentTags[binderIdx] = contentTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
var view = new viewModule.DomView(
|
|
||||||
protoView, viewRootNodes,
|
|
||||||
boundTextNodes, boundElements, contentTags
|
|
||||||
);
|
|
||||||
|
|
||||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
|
||||||
var binder = binders[binderIdx];
|
|
||||||
var element = boundElements[binderIdx];
|
|
||||||
|
|
||||||
// static child components
|
|
||||||
if (binder.hasStaticComponent()) {
|
|
||||||
var childView = this._createView(binder.nestedProtoView, null);
|
|
||||||
ViewFactory.setComponentView(this._shadowDomStrategy, view, binderIdx, childView);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, binder.eventLocals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
_createEventListener(view, element, elementIndex, eventName, eventLocals) {
|
|
||||||
this._eventManager.addEventListener(element, eventName, (event) => {
|
|
||||||
view.dispatchEvent(elementIndex, eventName, event);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method is used by the ViewFactory and the ViewHydrator
|
|
||||||
// TODO(tbosch): change shadow dom emulation so that LightDom
|
|
||||||
// instances don't need to be recreated by instead hydrated/dehydrated
|
|
||||||
static setComponentView(shadowDomStrategy:ShadowDomStrategy, hostView:viewModule.DomView, elementIndex:number, componentView:viewModule.DomView) {
|
|
||||||
var element = hostView.boundElements[elementIndex];
|
|
||||||
var lightDom = shadowDomStrategy.constructLightDom(hostView, componentView, element);
|
|
||||||
shadowDomStrategy.attachTemplate(element, componentView);
|
|
||||||
hostView.lightDoms[elementIndex] = lightDom;
|
|
||||||
hostView.componentChildViews[elementIndex] = componentView;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,190 +0,0 @@
|
||||||
import {Injectable} from 'angular2/src/di/annotations_impl';
|
|
||||||
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
|
||||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
|
||||||
|
|
||||||
import * as ldModule from '../shadow_dom/light_dom';
|
|
||||||
import {EventManager} from '../events/event_manager';
|
|
||||||
import {ViewFactory} from './view_factory';
|
|
||||||
import * as vcModule from './view_container';
|
|
||||||
import * as viewModule from './view';
|
|
||||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dehydrated view is a state of the view that allows it to be moved around
|
|
||||||
* the view tree.
|
|
||||||
*
|
|
||||||
* A dehydrated view has the following properties:
|
|
||||||
*
|
|
||||||
* - all viewcontainers are empty.
|
|
||||||
*
|
|
||||||
* A call to hydrate/dehydrate is called whenever a view is attached/detached,
|
|
||||||
* but it does not do the attach/detach itself.
|
|
||||||
*/
|
|
||||||
@Injectable()
|
|
||||||
export class RenderViewHydrator {
|
|
||||||
_eventManager:EventManager;
|
|
||||||
_viewFactory:ViewFactory;
|
|
||||||
_shadowDomStrategy:ShadowDomStrategy;
|
|
||||||
|
|
||||||
constructor(eventManager:EventManager, viewFactory:ViewFactory, shadowDomStrategy:ShadowDomStrategy) {
|
|
||||||
this._eventManager = eventManager;
|
|
||||||
this._viewFactory = viewFactory;
|
|
||||||
this._shadowDomStrategy = shadowDomStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
hydrateDynamicComponentView(hostView:viewModule.DomView, boundElementIndex:number, componentView:viewModule.DomView) {
|
|
||||||
ViewFactory.setComponentView(this._shadowDomStrategy, hostView, boundElementIndex, componentView);
|
|
||||||
var lightDom = hostView.lightDoms[boundElementIndex];
|
|
||||||
this._viewHydrateRecurse(componentView, lightDom);
|
|
||||||
if (isPresent(lightDom)) {
|
|
||||||
lightDom.redistribute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dehydrateDynamicComponentView(parentView:viewModule.DomView, boundElementIndex:number) {
|
|
||||||
throw new BaseException('Not supported yet');
|
|
||||||
// Something along these lines:
|
|
||||||
// var componentView = parentView.componentChildViews[boundElementIndex];
|
|
||||||
// vcModule.ViewContainer.removeViewNodes(componentView);
|
|
||||||
// parentView.componentChildViews[boundElementIndex] = null;
|
|
||||||
// parentView.lightDoms[boundElementIndex] = null;
|
|
||||||
// this._viewDehydrateRecurse(componentView);
|
|
||||||
}
|
|
||||||
|
|
||||||
hydrateInPlaceHostView(parentView:viewModule.DomView, hostView:viewModule.DomView) {
|
|
||||||
if (isPresent(parentView)) {
|
|
||||||
ListWrapper.push(parentView.imperativeHostViews, hostView);
|
|
||||||
}
|
|
||||||
this._viewHydrateRecurse(hostView, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
dehydrateInPlaceHostView(parentView:viewModule.DomView, hostView:viewModule.DomView) {
|
|
||||||
if (isPresent(parentView)) {
|
|
||||||
ListWrapper.remove(parentView.imperativeHostViews, hostView);
|
|
||||||
}
|
|
||||||
vcModule.ViewContainer.removeViewNodes(hostView);
|
|
||||||
hostView.rootNodes = [];
|
|
||||||
this._viewDehydrateRecurse(hostView);
|
|
||||||
}
|
|
||||||
|
|
||||||
hydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, view:viewModule.DomView) {
|
|
||||||
this._viewHydrateRecurse(view, viewContainer.parentView.hostLightDom);
|
|
||||||
}
|
|
||||||
|
|
||||||
dehydrateViewInViewContainer(viewContainer:vcModule.ViewContainer, view:viewModule.DomView) {
|
|
||||||
this._viewDehydrateRecurse(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
_viewHydrateRecurse(view, hostLightDom: ldModule.LightDom) {
|
|
||||||
if (view.hydrated) throw new BaseException('The view is already hydrated.');
|
|
||||||
view.hydrated = true;
|
|
||||||
view.hostLightDom = hostLightDom;
|
|
||||||
|
|
||||||
// content tags
|
|
||||||
for (var i = 0; i < view.contentTags.length; i++) {
|
|
||||||
var destLightDom = view.getDirectParentLightDom(i);
|
|
||||||
var ct = view.contentTags[i];
|
|
||||||
if (isPresent(ct)) {
|
|
||||||
ct.hydrate(destLightDom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// componentChildViews
|
|
||||||
for (var i = 0; i < view.componentChildViews.length; i++) {
|
|
||||||
var cv = view.componentChildViews[i];
|
|
||||||
if (isPresent(cv)) {
|
|
||||||
this._viewHydrateRecurse(cv, view.lightDoms[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < view.lightDoms.length; ++i) {
|
|
||||||
var lightDom = view.lightDoms[i];
|
|
||||||
if (isPresent(lightDom)) {
|
|
||||||
lightDom.redistribute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//add global events
|
|
||||||
view.eventHandlerRemovers = ListWrapper.create();
|
|
||||||
var binders = view.proto.elementBinders;
|
|
||||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
|
||||||
var binder = binders[binderIdx];
|
|
||||||
if (isPresent(binder.globalEvents)) {
|
|
||||||
for (var i = 0; i < binder.globalEvents.length; i++) {
|
|
||||||
var globalEvent = binder.globalEvents[i];
|
|
||||||
var remover = this._createGlobalEventListener(view, binderIdx, globalEvent.name, globalEvent.target, globalEvent.fullName);
|
|
||||||
ListWrapper.push(view.eventHandlerRemovers, remover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_createGlobalEventListener(view, elementIndex, eventName, eventTarget, fullName): Function {
|
|
||||||
return this._eventManager.addGlobalEventListener(eventTarget, eventName, (event) => {
|
|
||||||
view.dispatchEvent(elementIndex, fullName, event);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_viewDehydrateRecurse(view) {
|
|
||||||
// Note: preserve the opposite order of the hydration process.
|
|
||||||
|
|
||||||
// componentChildViews
|
|
||||||
for (var i = 0; i < view.componentChildViews.length; i++) {
|
|
||||||
var cv = view.componentChildViews[i];
|
|
||||||
if (isPresent(cv)) {
|
|
||||||
this._viewDehydrateRecurse(cv);
|
|
||||||
if (view.proto.elementBinders[i].hasDynamicComponent()) {
|
|
||||||
vcModule.ViewContainer.removeViewNodes(cv);
|
|
||||||
this._viewFactory.returnView(cv);
|
|
||||||
view.lightDoms[i] = null;
|
|
||||||
view.componentChildViews[i] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// imperativeHostViews
|
|
||||||
for (var i = 0; i < view.imperativeHostViews.length; i++) {
|
|
||||||
var hostView = view.imperativeHostViews[i];
|
|
||||||
this._viewDehydrateRecurse(hostView);
|
|
||||||
vcModule.ViewContainer.removeViewNodes(hostView);
|
|
||||||
hostView.rootNodes = [];
|
|
||||||
this._viewFactory.returnView(hostView);
|
|
||||||
}
|
|
||||||
view.imperativeHostViews = [];
|
|
||||||
|
|
||||||
|
|
||||||
// viewContainers and content tags
|
|
||||||
if (isPresent(view.viewContainers)) {
|
|
||||||
for (var i = 0; i < view.viewContainers.length; i++) {
|
|
||||||
var vc = view.viewContainers[i];
|
|
||||||
if (isPresent(vc)) {
|
|
||||||
this._viewContainerDehydrateRecurse(vc);
|
|
||||||
}
|
|
||||||
var ct = view.contentTags[i];
|
|
||||||
if (isPresent(ct)) {
|
|
||||||
ct.dehydrate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove global events
|
|
||||||
for (var i = 0; i < view.eventHandlerRemovers.length; i++) {
|
|
||||||
view.eventHandlerRemovers[i]();
|
|
||||||
}
|
|
||||||
|
|
||||||
view.hostLightDom = null;
|
|
||||||
view.eventHandlerRemovers = null;
|
|
||||||
view.setEventDispatcher(null);
|
|
||||||
view.hydrated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_viewContainerDehydrateRecurse(viewContainer) {
|
|
||||||
for (var i=0; i<viewContainer.views.length; i++) {
|
|
||||||
var view = viewContainer.views[i];
|
|
||||||
this._viewDehydrateRecurse(view);
|
|
||||||
this._viewFactory.returnView(view);
|
|
||||||
}
|
|
||||||
viewContainer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -15,6 +15,9 @@ import {DynamicComponentLoader, ComponentRef} from 'angular2/src/core/compiler/d
|
||||||
import {queryView, viewRootNodes, el} from './utils';
|
import {queryView, viewRootNodes, el} from './utils';
|
||||||
import {instantiateType, getTypeOf} from './lang_utils';
|
import {instantiateType, getTypeOf} from './lang_utils';
|
||||||
|
|
||||||
|
import {DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @exportedAs angular2/test
|
* @exportedAs angular2/test
|
||||||
*/
|
*/
|
||||||
|
@ -87,9 +90,12 @@ export class TestBed {
|
||||||
this.setInlineTemplate(component, html);
|
this.setInlineTemplate(component, html);
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootEl = el('<div></div>');
|
var doc = this._injector.get(DOCUMENT_TOKEN);
|
||||||
|
var rootEl = el('<div id="root"></div>');
|
||||||
|
DOM.appendChild(doc.body, rootEl);
|
||||||
|
|
||||||
var componentBinding = bind(component).toValue(context);
|
var componentBinding = bind(component).toValue(context);
|
||||||
return this._injector.get(DynamicComponentLoader).loadIntoNewLocation(componentBinding, null, rootEl, this._injector).then((hostComponentRef) => {
|
return this._injector.get(DynamicComponentLoader).loadIntoNewLocation(componentBinding, null, '#root', this._injector).then((hostComponentRef) => {
|
||||||
return new ViewProxy(hostComponentRef);
|
return new ViewProxy(hostComponentRef);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,6 @@ import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
|
||||||
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
import {appDocumentToken} from 'angular2/src/core/application_tokens';
|
|
||||||
|
|
||||||
import {EventManager, DomEventsPlugin} from 'angular2/src/render/dom/events/event_manager';
|
import {EventManager, DomEventsPlugin} from 'angular2/src/render/dom/events/event_manager';
|
||||||
|
|
||||||
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
|
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
|
||||||
|
@ -40,10 +38,8 @@ import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils';
|
||||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||||
import {RenderCompiler, Renderer} from 'angular2/src/render/api';
|
import {RenderCompiler, Renderer} from 'angular2/src/render/api';
|
||||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
|
||||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
|
||||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
|
||||||
import * as rvh from 'angular2/src/render/dom/view/view_hydrator';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the root injector bindings.
|
* Returns the root injector bindings.
|
||||||
|
@ -76,16 +72,14 @@ function _getAppBindings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
bind(appDocumentToken).toValue(appDoc),
|
bind(DOCUMENT_TOKEN).toValue(appDoc),
|
||||||
bind(ShadowDomStrategy).toFactory(
|
bind(ShadowDomStrategy).toFactory(
|
||||||
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
||||||
[StyleUrlResolver, appDocumentToken]),
|
[StyleUrlResolver, DOCUMENT_TOKEN]),
|
||||||
bind(DirectDomRenderer).toClass(DirectDomRenderer),
|
DomRenderer,
|
||||||
bind(Renderer).toClass(DirectDomRenderer),
|
DefaultDomCompiler,
|
||||||
bind(RenderCompiler).toClass(rc.DefaultDomCompiler),
|
bind(Renderer).toAlias(DomRenderer),
|
||||||
rvf.ViewFactory,
|
bind(RenderCompiler).toAlias(DefaultDomCompiler),
|
||||||
rvh.RenderViewHydrator,
|
|
||||||
bind(rvf.VIEW_POOL_CAPACITY).toValue(500),
|
|
||||||
ProtoViewFactory,
|
ProtoViewFactory,
|
||||||
AppViewPool,
|
AppViewPool,
|
||||||
AppViewManager,
|
AppViewManager,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
import {isPresent} from 'angular2/src/facade/lang';
|
import {isPresent} from 'angular2/src/facade/lang';
|
||||||
|
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
|
||||||
|
|
||||||
export class Log {
|
export class Log {
|
||||||
_result:List;
|
_result:List;
|
||||||
|
@ -25,7 +26,7 @@ export class Log {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function viewRootNodes(view):List {
|
export function viewRootNodes(view):List {
|
||||||
return view.render.delegate.rootNodes;
|
return resolveInternalDomView(view.render).rootNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function queryView(view, selector:string) {
|
export function queryView(view, selector:string) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
xit,
|
xit,
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {bootstrap} from 'angular2/src/core/application';
|
import {bootstrap} from 'angular2/src/core/application';
|
||||||
import {appDocumentToken, appElementToken} from 'angular2/src/core/application_tokens';
|
import {appComponentAnnotatedTypeToken} from 'angular2/src/core/application_tokens';
|
||||||
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
|
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
|
@ -21,6 +21,7 @@ import {Inject} from 'angular2/src/di/annotations_impl';
|
||||||
import {View} from 'angular2/src/core/annotations_impl/view';
|
import {View} from 'angular2/src/core/annotations_impl/view';
|
||||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||||
import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability';
|
import {Testability, TestabilityRegistry} from 'angular2/src/core/testability/testability';
|
||||||
|
import {DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
|
||||||
|
|
||||||
@Component({selector: 'hello-app'})
|
@Component({selector: 'hello-app'})
|
||||||
@View({template: '{{greeting}} world!'})
|
@View({template: '{{greeting}} world!'})
|
||||||
|
@ -84,7 +85,7 @@ export function main() {
|
||||||
DOM.appendChild(fakeDoc.body, el2);
|
DOM.appendChild(fakeDoc.body, el2);
|
||||||
DOM.appendChild(el, lightDom);
|
DOM.appendChild(el, lightDom);
|
||||||
DOM.setText(lightDom, 'loading');
|
DOM.setText(lightDom, 'loading');
|
||||||
testBindings = [bind(appDocumentToken).toValue(fakeDoc)];
|
testBindings = [bind(DOCUMENT_TOKEN).toValue(fakeDoc)];
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('bootstrap factory method', () => {
|
describe('bootstrap factory method', () => {
|
||||||
|
@ -100,7 +101,7 @@ export function main() {
|
||||||
var refPromise = bootstrap(HelloRootCmp, [], (e,t) => {throw e;});
|
var refPromise = bootstrap(HelloRootCmp, [], (e,t) => {throw e;});
|
||||||
PromiseWrapper.then(refPromise, null, (reason) => {
|
PromiseWrapper.then(refPromise, null, (reason) => {
|
||||||
expect(reason.message).toContain(
|
expect(reason.message).toContain(
|
||||||
'The app selector "hello-app" did not match any elements');
|
'The selector "hello-app" did not match any elements');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -113,7 +114,7 @@ export function main() {
|
||||||
it('should resolve an injector promise and contain bindings', inject([AsyncTestCompleter], (async) => {
|
it('should resolve an injector promise and contain bindings', inject([AsyncTestCompleter], (async) => {
|
||||||
var refPromise = bootstrap(HelloRootCmp, testBindings);
|
var refPromise = bootstrap(HelloRootCmp, testBindings);
|
||||||
refPromise.then((ref) => {
|
refPromise.then((ref) => {
|
||||||
expect(ref.injector.get(appElementToken)).toBe(el);
|
expect(ref.injector.get(appComponentAnnotatedTypeToken).type).toBe(HelloRootCmp);
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -129,7 +130,7 @@ export function main() {
|
||||||
it('should display hello world', inject([AsyncTestCompleter], (async) => {
|
it('should display hello world', inject([AsyncTestCompleter], (async) => {
|
||||||
var refPromise = bootstrap(HelloRootCmp, testBindings);
|
var refPromise = bootstrap(HelloRootCmp, testBindings);
|
||||||
refPromise.then((ref) => {
|
refPromise.then((ref) => {
|
||||||
expect(ref.injector.get(appElementToken)).toHaveText('hello world!');
|
expect(el).toHaveText('hello world!');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -138,8 +139,8 @@ export function main() {
|
||||||
var refPromise1 = bootstrap(HelloRootCmp, testBindings);
|
var refPromise1 = bootstrap(HelloRootCmp, testBindings);
|
||||||
var refPromise2 = bootstrap(HelloRootCmp2, testBindings);
|
var refPromise2 = bootstrap(HelloRootCmp2, testBindings);
|
||||||
PromiseWrapper.all([refPromise1, refPromise2]).then((refs) => {
|
PromiseWrapper.all([refPromise1, refPromise2]).then((refs) => {
|
||||||
expect(refs[0].injector.get(appElementToken)).toHaveText('hello world!');
|
expect(el).toHaveText('hello world!');
|
||||||
expect(refs[1].injector.get(appElementToken)).toHaveText('hello world, again!');
|
expect(el2).toHaveText('hello world, again!');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -168,7 +169,7 @@ export function main() {
|
||||||
it("should support shadow dom content tag", inject([AsyncTestCompleter], (async) => {
|
it("should support shadow dom content tag", inject([AsyncTestCompleter], (async) => {
|
||||||
var refPromise = bootstrap(HelloRootCmpContent, testBindings);
|
var refPromise = bootstrap(HelloRootCmpContent, testBindings);
|
||||||
refPromise.then((ref) => {
|
refPromise.then((ref) => {
|
||||||
expect(ref.injector.get(appElementToken)).toHaveText('before: loading after: done');
|
expect(el).toHaveText('before: loading after: done');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -391,25 +391,6 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create imperative proto views', inject([AsyncTestCompleter], (async) => {
|
|
||||||
renderCompiler.spy('createImperativeComponentProtoView').andCallFake( (rendererId) => {
|
|
||||||
return PromiseWrapper.resolve(
|
|
||||||
createRenderProtoView([])
|
|
||||||
);
|
|
||||||
});
|
|
||||||
tplResolver.setView(MainComponent, new View({renderer: 'some-renderer'}));
|
|
||||||
var mainProtoView = createProtoView();
|
|
||||||
var compiler = createCompiler(
|
|
||||||
[],
|
|
||||||
[mainProtoView]
|
|
||||||
);
|
|
||||||
compiler.compile(MainComponent).then( (protoViewRef) => {
|
|
||||||
expect(internalProtoView(protoViewRef)).toBe(mainProtoView);
|
|
||||||
expect(renderCompiler.spy('createImperativeComponentProtoView')).toHaveBeenCalledWith('some-renderer');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should throw for non component types', () => {
|
it('should throw for non component types', () => {
|
||||||
var compiler = createCompiler([], []);
|
var compiler = createCompiler([], []);
|
||||||
expect(
|
expect(
|
||||||
|
|
|
@ -21,9 +21,9 @@ import {View} from 'angular2/src/core/annotations_impl/view';
|
||||||
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
|
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
|
||||||
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||||
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 {DomRenderer} from 'angular2/src/render/dom/dom_renderer';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('DynamicComponentLoader', function () {
|
describe('DynamicComponentLoader', function () {
|
||||||
|
@ -200,15 +200,17 @@ export function main() {
|
||||||
selector: 'imp-ng-cmp'
|
selector: 'imp-ng-cmp'
|
||||||
})
|
})
|
||||||
@View({
|
@View({
|
||||||
renderer: 'imp-ng-cmp-renderer'
|
renderer: 'imp-ng-cmp-renderer',
|
||||||
|
template: ''
|
||||||
})
|
})
|
||||||
class ImperativeViewComponentUsingNgComponent {
|
class ImperativeViewComponentUsingNgComponent {
|
||||||
done;
|
done;
|
||||||
|
|
||||||
constructor(self:ElementRef, dynamicComponentLoader:DynamicComponentLoader, renderer:DirectDomRenderer) {
|
constructor(self:ElementRef, dynamicComponentLoader:DynamicComponentLoader, viewManager:AppViewManager, renderer:DomRenderer) {
|
||||||
var div = el('<div></div>');
|
var div = el('<div id="impHost"></div>');
|
||||||
renderer.setImperativeComponentRootNodes(self.parentView.render, self.boundElementIndex, [div]);
|
var shadowViewRef = viewManager.getComponentView(self);
|
||||||
this.done = dynamicComponentLoader.loadIntoNewLocation(ChildComp, self, div, null);
|
renderer.setComponentViewRootNodes(shadowViewRef.render, [div]);
|
||||||
|
this.done = dynamicComponentLoader.loadIntoNewLocation(ChildComp, self, '#impHost', null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
|
||||||
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||||
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||||
|
|
||||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
import {DomRenderer} from 'angular2/src/render/dom/dom_renderer';
|
||||||
|
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('integration tests', function() {
|
describe('integration tests', function() {
|
||||||
|
@ -863,13 +864,15 @@ export function main() {
|
||||||
selector: 'simple-imp-cmp'
|
selector: 'simple-imp-cmp'
|
||||||
})
|
})
|
||||||
@View({
|
@View({
|
||||||
renderer: 'simple-imp-cmp-renderer'
|
renderer: 'simple-imp-cmp-renderer',
|
||||||
|
template: ''
|
||||||
})
|
})
|
||||||
class SimpleImperativeViewComponent {
|
class SimpleImperativeViewComponent {
|
||||||
done;
|
done;
|
||||||
|
|
||||||
constructor(self:ElementRef, renderer:DirectDomRenderer) {
|
constructor(self:ElementRef, viewManager:AppViewManager, renderer:DomRenderer) {
|
||||||
renderer.setImperativeComponentRootNodes(self.parentView.render, self.boundElementIndex, [el('hello imp view')]);
|
var shadowViewRef = viewManager.getComponentView(self);
|
||||||
|
renderer.setComponentViewRootNodes(shadowViewRef.render, [el('hello imp view')]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,11 +94,15 @@ export function main() {
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createView(pv=null) {
|
function createView(pv=null, renderViewRef=null) {
|
||||||
if (isBlank(pv)) {
|
if (isBlank(pv)) {
|
||||||
pv = createProtoView();
|
pv = createProtoView();
|
||||||
}
|
}
|
||||||
|
if (isBlank(renderViewRef)) {
|
||||||
|
renderViewRef = new RenderViewRef();
|
||||||
|
}
|
||||||
var view = new AppView(renderer, pv, MapWrapper.create());
|
var view = new AppView(renderer, pv, MapWrapper.create());
|
||||||
|
view.render = renderViewRef;
|
||||||
var elementInjectors = ListWrapper.createFixedSize(pv.elementBinders.length);
|
var elementInjectors = ListWrapper.createFixedSize(pv.elementBinders.length);
|
||||||
for (var i=0; i<pv.elementBinders.length; i++) {
|
for (var i=0; i<pv.elementBinders.length; i++) {
|
||||||
elementInjectors[i] = createElementInjector();
|
elementInjectors[i] = createElementInjector();
|
||||||
|
@ -121,8 +125,8 @@ export function main() {
|
||||||
createdViews = [];
|
createdViews = [];
|
||||||
createdRenderViews = [];
|
createdRenderViews = [];
|
||||||
|
|
||||||
utils.spy('createView').andCallFake( (proto, _a, _b) => {
|
utils.spy('createView').andCallFake( (proto, renderViewRef, _a, _b) => {
|
||||||
var view = createView(proto);
|
var view = createView(proto, renderViewRef);
|
||||||
ListWrapper.push(createdViews, view);
|
ListWrapper.push(createdViews, view);
|
||||||
return view;
|
return view;
|
||||||
});
|
});
|
||||||
|
@ -137,23 +141,15 @@ export function main() {
|
||||||
}
|
}
|
||||||
ListWrapper.insert(viewContainer.views, atIndex, childView);
|
ListWrapper.insert(viewContainer.views, atIndex, childView);
|
||||||
});
|
});
|
||||||
var createRenderViewRefs = function(renderPvRef) {
|
renderer.spy('createInPlaceHostView').andCallFake( (_a, _b, _c) => {
|
||||||
var res = [];
|
var rv = new RenderViewRef();
|
||||||
for (var i=0; i<renderPvRef.nestedComponentCount+1; i++) {
|
ListWrapper.push(createdRenderViews, rv);
|
||||||
var renderViewRef = new RenderViewRef();
|
return rv;
|
||||||
ListWrapper.push(res, renderViewRef);
|
|
||||||
ListWrapper.push(createdRenderViews, renderViewRef);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
renderer.spy('createDynamicComponentView').andCallFake( (_a, _b, childPvRef) => {
|
|
||||||
return createRenderViewRefs(childPvRef);
|
|
||||||
});
|
});
|
||||||
renderer.spy('createInPlaceHostView').andCallFake( (_a, _b, childPvRef) => {
|
renderer.spy('createView').andCallFake( (_a) => {
|
||||||
return createRenderViewRefs(childPvRef);
|
var rv = new RenderViewRef();
|
||||||
});
|
ListWrapper.push(createdRenderViews, rv);
|
||||||
renderer.spy('createViewInContainer').andCallFake( (_a, _b, childPvRef) => {
|
return rv;
|
||||||
return createRenderViewRefs(childPvRef);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -165,7 +161,6 @@ export function main() {
|
||||||
hostView = createView(createProtoView(
|
hostView = createView(createProtoView(
|
||||||
[createComponentElBinder(null)]
|
[createComponentElBinder(null)]
|
||||||
));
|
));
|
||||||
hostView.render = new RenderViewRef();
|
|
||||||
componentProtoView = createProtoView();
|
componentProtoView = createProtoView();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -186,11 +181,13 @@ export function main() {
|
||||||
internalView(manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null))
|
internalView(manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null))
|
||||||
).toBe(createdView);
|
).toBe(createdView);
|
||||||
expect(utils.spy('createView')).not.toHaveBeenCalled();
|
expect(utils.spy('createView')).not.toHaveBeenCalled();
|
||||||
|
expect(renderer.spy('createView')).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should attach the view', () => {
|
it('should attach the view', () => {
|
||||||
manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null)
|
manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null)
|
||||||
expect(utils.spy('attachComponentView')).toHaveBeenCalledWith(hostView, 0, createdViews[0]);
|
expect(utils.spy('attachComponentView')).toHaveBeenCalledWith(hostView, 0, createdViews[0]);
|
||||||
|
expect(renderer.spy('attachComponentView')).toHaveBeenCalledWith(hostView.render, 0, createdViews[0].render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should hydrate the dynamic component', () => {
|
it('should hydrate the dynamic component', () => {
|
||||||
|
@ -203,11 +200,12 @@ export function main() {
|
||||||
it('should hydrate the view', () => {
|
it('should hydrate the view', () => {
|
||||||
manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null);
|
manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null);
|
||||||
expect(utils.spy('hydrateComponentView')).toHaveBeenCalledWith(hostView, 0);
|
expect(utils.spy('hydrateComponentView')).toHaveBeenCalledWith(hostView, 0);
|
||||||
|
expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(createdViews[0].render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create and set the render view', () => {
|
it('should create and set the render view', () => {
|
||||||
manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null);
|
manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null);
|
||||||
expect(renderer.spy('createDynamicComponentView')).toHaveBeenCalledWith(hostView.render, 0, componentProtoView.render);
|
expect(renderer.spy('createView')).toHaveBeenCalledWith(componentProtoView.render);
|
||||||
expect(createdViews[0].render).toBe(createdRenderViews[0]);
|
expect(createdViews[0].render).toBe(createdRenderViews[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -256,7 +254,6 @@ export function main() {
|
||||||
hostView = createView(createProtoView(
|
hostView = createView(createProtoView(
|
||||||
[createComponentElBinder(null)]
|
[createComponentElBinder(null)]
|
||||||
));
|
));
|
||||||
hostView.render = new RenderViewRef();
|
|
||||||
nestedProtoView = createProtoView();
|
nestedProtoView = createProtoView();
|
||||||
componentProtoView = createProtoView([
|
componentProtoView = createProtoView([
|
||||||
createComponentElBinder(nestedProtoView)
|
createComponentElBinder(nestedProtoView)
|
||||||
|
@ -272,6 +269,7 @@ export function main() {
|
||||||
it('should hydrate the view', () => {
|
it('should hydrate the view', () => {
|
||||||
manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null);
|
manager.createDynamicComponentView(elementRef(wrapView(hostView), 0), wrapPv(componentProtoView), null, null);
|
||||||
expect(utils.spy('hydrateComponentView')).toHaveBeenCalledWith(createdViews[0], 0);
|
expect(utils.spy('hydrateComponentView')).toHaveBeenCalledWith(createdViews[0], 0);
|
||||||
|
expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(createdViews[0].render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the render view', () => {
|
it('should set the render view', () => {
|
||||||
|
@ -309,7 +307,6 @@ export function main() {
|
||||||
));
|
));
|
||||||
parentView = createView();
|
parentView = createView();
|
||||||
utils.attachComponentView(parentHostView, 0, parentView);
|
utils.attachComponentView(parentHostView, 0, parentView);
|
||||||
parentView.render = new RenderViewRef();
|
|
||||||
hostProtoView = createProtoView(
|
hostProtoView = createProtoView(
|
||||||
[createComponentElBinder(null)]
|
[createComponentElBinder(null)]
|
||||||
);
|
);
|
||||||
|
@ -326,6 +323,7 @@ export function main() {
|
||||||
var injector = new Injector([], null, false);
|
var injector = new Injector([], null, false);
|
||||||
manager.createInPlaceHostView(elementRef(wrapView(parentHostView), 0), null, wrapPv(hostProtoView), injector);
|
manager.createInPlaceHostView(elementRef(wrapView(parentHostView), 0), null, wrapPv(hostProtoView), injector);
|
||||||
expect(utils.spy('attachAndHydrateInPlaceHostView')).toHaveBeenCalledWith(parentHostView, 0, createdViews[0], injector);
|
expect(utils.spy('attachAndHydrateInPlaceHostView')).toHaveBeenCalledWith(parentHostView, 0, createdViews[0], injector);
|
||||||
|
expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(createdViews[0].render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create and set the render view', () => {
|
it('should create and set the render view', () => {
|
||||||
|
@ -354,7 +352,6 @@ export function main() {
|
||||||
));
|
));
|
||||||
parentView = createView();
|
parentView = createView();
|
||||||
utils.attachComponentView(parentHostView, 0, parentView);
|
utils.attachComponentView(parentHostView, 0, parentView);
|
||||||
parentView.render = new RenderViewRef();
|
|
||||||
hostProtoView = createProtoView(
|
hostProtoView = createProtoView(
|
||||||
[createComponentElBinder(null)]
|
[createComponentElBinder(null)]
|
||||||
);
|
);
|
||||||
|
@ -362,25 +359,25 @@ export function main() {
|
||||||
hostRenderViewRef = hostView.render;
|
hostRenderViewRef = hostView.render;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should dehydrate', () => {
|
it('should detach', () => {
|
||||||
manager.destroyInPlaceHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
manager.destroyInPlaceHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
||||||
expect(utils.spy('detachInPlaceHostView')).toHaveBeenCalledWith(parentView, hostView);
|
expect(utils.spy('detachInPlaceHostView')).toHaveBeenCalledWith(parentView, hostView);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should detach', () => {
|
it('should dehydrate', () => {
|
||||||
manager.destroyInPlaceHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
manager.destroyInPlaceHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
||||||
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(hostView);
|
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(hostView);
|
||||||
|
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(hostView.render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should destroy and clear the render view', () => {
|
it('should destroy and clear the render view', () => {
|
||||||
manager.destroyInPlaceHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
manager.destroyInPlaceHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
||||||
expect(renderer.spy('destroyInPlaceHostView')).toHaveBeenCalledWith(parentView.render, hostRenderViewRef);
|
expect(renderer.spy('destroyInPlaceHostView')).toHaveBeenCalledWith(parentView.render, hostRenderViewRef);
|
||||||
expect(hostView.render).toBe(null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the view to the pool', () => {
|
it('should not return the view to the pool', () => {
|
||||||
manager.destroyInPlaceHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
manager.destroyInPlaceHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
||||||
expect(viewPool.spy('returnView')).toHaveBeenCalledWith(hostView);
|
expect(viewPool.spy('returnView')).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -398,7 +395,6 @@ export function main() {
|
||||||
parentView = createView(createProtoView(
|
parentView = createView(createProtoView(
|
||||||
[createEmptyElBinder()]
|
[createEmptyElBinder()]
|
||||||
));
|
));
|
||||||
parentView.render = new RenderViewRef();
|
|
||||||
childProtoView = createProtoView();
|
childProtoView = createProtoView();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -417,18 +413,19 @@ export function main() {
|
||||||
it('should attach the view', () => {
|
it('should attach the view', () => {
|
||||||
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null)
|
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null)
|
||||||
expect(utils.spy('attachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0, createdViews[0]);
|
expect(utils.spy('attachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0, createdViews[0]);
|
||||||
|
expect(renderer.spy('attachViewInContainer')).toHaveBeenCalledWith(parentView.render, 0, 0, createdViews[0].render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should hydrate the view', () => {
|
it('should hydrate the view', () => {
|
||||||
var injector = new Injector([], null, false);
|
var injector = new Injector([], null, false);
|
||||||
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), injector);
|
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), injector);
|
||||||
expect(utils.spy('hydrateViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0, injector);
|
expect(utils.spy('hydrateViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0, injector);
|
||||||
|
expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(createdViews[0].render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create and set the render view', () => {
|
it('should create and set the render view', () => {
|
||||||
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null);
|
manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null);
|
||||||
expect(renderer.spy('createViewInContainer')).toHaveBeenCalledWith(
|
expect(renderer.spy('createView')).toHaveBeenCalledWith(childProtoView.render);
|
||||||
new RenderViewContainerRef(parentView.render, 0), 0, childProtoView.render);
|
|
||||||
expect(createdViews[0].render).toBe(createdRenderViews[0]);
|
expect(createdViews[0].render).toBe(createdRenderViews[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -449,7 +446,6 @@ export function main() {
|
||||||
parentView = createView(createProtoView(
|
parentView = createView(createProtoView(
|
||||||
[createEmptyElBinder()]
|
[createEmptyElBinder()]
|
||||||
));
|
));
|
||||||
parentView.render = new RenderViewRef();
|
|
||||||
childProtoView = createProtoView();
|
childProtoView = createProtoView();
|
||||||
childView = internalView(manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null));
|
childView = internalView(manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null));
|
||||||
});
|
});
|
||||||
|
@ -457,17 +453,13 @@ export function main() {
|
||||||
it('should dehydrate', () => {
|
it('should dehydrate', () => {
|
||||||
manager.destroyViewInContainer(elementRef(wrapView(parentView), 0), 0);
|
manager.destroyViewInContainer(elementRef(wrapView(parentView), 0), 0);
|
||||||
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(parentView.viewContainers[0].views[0]);
|
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(parentView.viewContainers[0].views[0]);
|
||||||
|
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(childView.render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should detach', () => {
|
it('should detach', () => {
|
||||||
manager.destroyViewInContainer(elementRef(wrapView(parentView), 0), 0);
|
manager.destroyViewInContainer(elementRef(wrapView(parentView), 0), 0);
|
||||||
expect(utils.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0);
|
expect(utils.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0);
|
||||||
});
|
expect(renderer.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView.render, 0, 0, childView.render);
|
||||||
|
|
||||||
it('should destroy and clear the render view', () => {
|
|
||||||
manager.destroyViewInContainer(elementRef(wrapView(parentView), 0), 0);
|
|
||||||
expect(renderer.spy('destroyViewInContainer')).toHaveBeenCalledWith(new RenderViewContainerRef(parentView.render, 0), 0);
|
|
||||||
expect(childView.render).toBe(null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the view to the pool', () => {
|
it('should return the view to the pool', () => {
|
||||||
|
@ -482,7 +474,6 @@ export function main() {
|
||||||
parentView = createView(createProtoView(
|
parentView = createView(createProtoView(
|
||||||
[createEmptyElBinder()]
|
[createEmptyElBinder()]
|
||||||
));
|
));
|
||||||
parentView.render = new RenderViewRef();
|
|
||||||
childProtoView = createProtoView();
|
childProtoView = createProtoView();
|
||||||
childView = internalView(manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null));
|
childView = internalView(manager.createViewInContainer(elementRef(wrapView(parentView), 0), 0, wrapPv(childProtoView), null));
|
||||||
});
|
});
|
||||||
|
@ -490,17 +481,13 @@ export function main() {
|
||||||
it('should dehydrate', () => {
|
it('should dehydrate', () => {
|
||||||
manager.destroyInPlaceHostView(null, wrapView(parentView));
|
manager.destroyInPlaceHostView(null, wrapView(parentView));
|
||||||
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(parentView.viewContainers[0].views[0]);
|
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(parentView.viewContainers[0].views[0]);
|
||||||
|
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(childView.render);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should detach', () => {
|
it('should detach', () => {
|
||||||
manager.destroyInPlaceHostView(null, wrapView(parentView));
|
manager.destroyInPlaceHostView(null, wrapView(parentView));
|
||||||
expect(utils.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0);
|
expect(utils.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView, 0, 0);
|
||||||
});
|
expect(renderer.spy('detachViewInContainer')).toHaveBeenCalledWith(parentView.render, 0, 0, childView.render);
|
||||||
|
|
||||||
it('should not destroy but clear the render view', () => {
|
|
||||||
manager.destroyInPlaceHostView(null, wrapView(parentView));
|
|
||||||
expect(renderer.spy('destroyViewInContainer')).not.toHaveBeenCalled();
|
|
||||||
expect(childView.render).toBe(null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the view to the pool', () => {
|
it('should return the view to the pool', () => {
|
||||||
|
|
|
@ -26,6 +26,8 @@ import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||||
|
|
||||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||||
|
|
||||||
|
import {resolveInternalDomProtoView} from 'angular2/src/render/dom/view/proto_view';
|
||||||
|
|
||||||
export function runCompilerCommonTests() {
|
export function runCompilerCommonTests() {
|
||||||
describe('DomCompiler', function() {
|
describe('DomCompiler', function() {
|
||||||
var mockStepFactory;
|
var mockStepFactory;
|
||||||
|
@ -61,7 +63,7 @@ export function runCompilerCommonTests() {
|
||||||
|
|
||||||
var dirMetadata = new DirectiveMetadata({id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE});
|
var dirMetadata = new DirectiveMetadata({id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE});
|
||||||
compiler.compileHost(dirMetadata).then( (protoView) => {
|
compiler.compileHost(dirMetadata).then( (protoView) => {
|
||||||
expect(DOM.tagName(protoView.render.delegate.element)).toEqual('CUSTOM')
|
expect(DOM.tagName(resolveInternalDomProtoView(protoView.render).element)).toEqual('CUSTOM')
|
||||||
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
|
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
|
||||||
expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
|
expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
|
||||||
'a': 'b'
|
'a': 'b'
|
||||||
|
@ -76,7 +78,7 @@ export function runCompilerCommonTests() {
|
||||||
componentId: 'someId',
|
componentId: 'someId',
|
||||||
template: 'inline component'
|
template: 'inline component'
|
||||||
})).then( (protoView) => {
|
})).then( (protoView) => {
|
||||||
expect(DOM.getInnerHTML(protoView.render.delegate.element)).toEqual('inline component');
|
expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).element)).toEqual('inline component');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -90,7 +92,7 @@ export function runCompilerCommonTests() {
|
||||||
componentId: 'someId',
|
componentId: 'someId',
|
||||||
absUrl: 'someUrl'
|
absUrl: 'someUrl'
|
||||||
})).then( (protoView) => {
|
})).then( (protoView) => {
|
||||||
expect(DOM.getInnerHTML(protoView.render.delegate.element)).toEqual('url component');
|
expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).element)).toEqual('url component');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,213 +0,0 @@
|
||||||
import {
|
|
||||||
AsyncTestCompleter,
|
|
||||||
beforeEach,
|
|
||||||
ddescribe,
|
|
||||||
describe,
|
|
||||||
el,
|
|
||||||
elementText,
|
|
||||||
expect,
|
|
||||||
iit,
|
|
||||||
inject,
|
|
||||||
it,
|
|
||||||
xit,
|
|
||||||
SpyObject,
|
|
||||||
} from 'angular2/test_lib';
|
|
||||||
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
||||||
|
|
||||||
import {ProtoViewDto, ViewDefinition, RenderViewContainerRef, EventDispatcher, DirectiveMetadata} from 'angular2/src/render/api';
|
|
||||||
|
|
||||||
import {IntegrationTestbed, LoggingEventDispatcher, FakeEvent} from './integration_testbed';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
describe('DirectDomRenderer integration', () => {
|
|
||||||
var testbed, renderer, renderCompiler, eventPlugin, compileRoot, rootEl;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
rootEl = el('<div></div>');
|
|
||||||
});
|
|
||||||
|
|
||||||
function createRenderer({urlData, viewCacheCapacity, shadowDomStrategy, templates}={}) {
|
|
||||||
testbed = new IntegrationTestbed({
|
|
||||||
urlData: urlData,
|
|
||||||
viewCacheCapacity: viewCacheCapacity,
|
|
||||||
shadowDomStrategy: shadowDomStrategy,
|
|
||||||
templates: templates
|
|
||||||
});
|
|
||||||
renderer = testbed.renderer;
|
|
||||||
renderCompiler = testbed.renderCompiler;
|
|
||||||
eventPlugin = testbed.eventPlugin;
|
|
||||||
compileRoot = (componentId) => testbed.compileRoot(componentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should create host views while using the given elements in place', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer();
|
|
||||||
renderCompiler.compileHost(someComponent).then( (rootProtoView) => {
|
|
||||||
expect(rootProtoView.elementBinders[0].directives[0].directiveIndex).toBe(0);
|
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
|
||||||
expect(viewRefs.length).toBe(1);
|
|
||||||
expect(viewRefs[0].delegate.rootNodes[0]).toEqual(rootEl);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should create imperative proto views', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer();
|
|
||||||
renderCompiler.createImperativeComponentProtoView('someRenderId').then( (rootProtoView) => {
|
|
||||||
expect(rootProtoView.elementBinders).toEqual([]);
|
|
||||||
|
|
||||||
expect(rootProtoView.render.delegate.imperativeRendererId).toBe('someRenderId');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should add a static component', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer();
|
|
||||||
renderCompiler.compileHost(someComponent).then( (rootProtoView) => {
|
|
||||||
var template = new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: 'hello',
|
|
||||||
directives: []
|
|
||||||
});
|
|
||||||
renderCompiler.compile(template).then( (pv) => {
|
|
||||||
renderCompiler.mergeChildComponentProtoViews(rootProtoView.render, [pv.render]);
|
|
||||||
renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
|
||||||
expect(rootEl).toHaveText('hello');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should add a a dynamic component', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer();
|
|
||||||
renderCompiler.compileHost(someComponent).then( (rootProtoView) => {
|
|
||||||
var template = new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: 'hello',
|
|
||||||
directives: []
|
|
||||||
});
|
|
||||||
renderCompiler.compile(template).then( (pv) => {
|
|
||||||
var rootViewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[0];
|
|
||||||
renderer.createDynamicComponentView(rootViewRef, 0, pv.render)[0];
|
|
||||||
expect(rootEl).toHaveText('hello');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should update text nodes', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer({
|
|
||||||
templates: [new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '{{a}}',
|
|
||||||
directives: []
|
|
||||||
})]
|
|
||||||
});
|
|
||||||
compileRoot(someComponent).then( (rootProtoView) => {
|
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
|
||||||
renderer.setText(viewRefs[1], 0, 'hello');
|
|
||||||
expect(rootEl).toHaveText('hello');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should update element properties', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer({
|
|
||||||
templates: [new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<input [value]="someProp">',
|
|
||||||
directives: []
|
|
||||||
})]
|
|
||||||
});
|
|
||||||
compileRoot(someComponent).then( (rootProtoView) => {
|
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render);
|
|
||||||
renderer.setElementProperty(viewRefs[1], 0, 'value', 'hello');
|
|
||||||
expect(DOM.childNodes(rootEl)[0].value).toEqual('hello');
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should add and remove views to and from containers', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer({
|
|
||||||
templates: [new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<template>hello</template>',
|
|
||||||
directives: []
|
|
||||||
})]
|
|
||||||
});
|
|
||||||
compileRoot(someComponent).then( (rootProtoView) => {
|
|
||||||
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
|
||||||
var vcProtoViewRef = rootProtoView.elementBinders[0]
|
|
||||||
.nestedProtoView.elementBinders[0].nestedProtoView.render;
|
|
||||||
var vcRef = new RenderViewContainerRef(viewRef, 0);
|
|
||||||
expect(rootEl).toHaveText('');
|
|
||||||
var childViewRef = renderer.createViewInContainer(vcRef, 0, vcProtoViewRef)[0];
|
|
||||||
expect(rootEl).toHaveText('hello');
|
|
||||||
renderer.detachViewFromContainer(vcRef, 0);
|
|
||||||
expect(rootEl).toHaveText('');
|
|
||||||
renderer.insertViewIntoContainer(vcRef, 0, childViewRef);
|
|
||||||
expect(rootEl).toHaveText('hello');
|
|
||||||
renderer.destroyViewInContainer(vcRef, 0);
|
|
||||||
expect(rootEl).toHaveText('');
|
|
||||||
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should cache views', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer({
|
|
||||||
templates: [new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<template>hello</template>',
|
|
||||||
directives: []
|
|
||||||
})],
|
|
||||||
viewCacheCapacity: 2
|
|
||||||
});
|
|
||||||
compileRoot(someComponent).then( (rootProtoView) => {
|
|
||||||
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
|
||||||
var vcProtoViewRef = rootProtoView.elementBinders[0]
|
|
||||||
.nestedProtoView.elementBinders[0].nestedProtoView.render;
|
|
||||||
var vcRef = new RenderViewContainerRef(viewRef, 0);
|
|
||||||
|
|
||||||
var viewRef1 = renderer.createViewInContainer(vcRef, 0, vcProtoViewRef)[0];
|
|
||||||
renderer.destroyViewInContainer(vcRef, 0);
|
|
||||||
var viewRef2 = renderer.createViewInContainer(vcRef, 0, vcProtoViewRef)[0];
|
|
||||||
var viewRef3 = renderer.createViewInContainer(vcRef, 0, vcProtoViewRef)[0];
|
|
||||||
expect(viewRef2.delegate).toBe(viewRef1.delegate);
|
|
||||||
expect(viewRef3.delegate).not.toBe(viewRef1.delegate);
|
|
||||||
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
// TODO(tbosch): This is not working yet as we commented out
|
|
||||||
// the event expression processing...
|
|
||||||
xit('should handle events', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer({
|
|
||||||
templates: [new ViewDefinition({
|
|
||||||
componentId: 'someComponent',
|
|
||||||
template: '<input (change)="$event.target.value">',
|
|
||||||
directives: []
|
|
||||||
})]
|
|
||||||
});
|
|
||||||
compileRoot(someComponent).then( (rootProtoView) => {
|
|
||||||
var viewRef = renderer.createInPlaceHostView(null, rootEl, rootProtoView.render)[1];
|
|
||||||
var dispatcher = new LoggingEventDispatcher();
|
|
||||||
renderer.setEventDispatcher(viewRef, dispatcher);
|
|
||||||
var inputEl = DOM.childNodes(rootEl)[0];
|
|
||||||
inputEl.value = 'hello';
|
|
||||||
eventPlugin.dispatchEvent('change', new FakeEvent(inputEl));
|
|
||||||
expect(dispatcher.log).toEqual([[0, 'change', ['hello']]]);
|
|
||||||
async.done();
|
|
||||||
});
|
|
||||||
|
|
||||||
}));
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var someComponent = new DirectiveMetadata({
|
|
||||||
id: 'someComponent',
|
|
||||||
type: DirectiveMetadata.COMPONENT_TYPE,
|
|
||||||
selector: 'some-comp'
|
|
||||||
});
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
import {
|
||||||
|
AsyncTestCompleter,
|
||||||
|
beforeEach,
|
||||||
|
ddescribe,
|
||||||
|
describe,
|
||||||
|
el,
|
||||||
|
elementText,
|
||||||
|
expect,
|
||||||
|
iit,
|
||||||
|
inject,
|
||||||
|
it,
|
||||||
|
xit,
|
||||||
|
beforeEachBindings,
|
||||||
|
SpyObject,
|
||||||
|
} from 'angular2/test_lib';
|
||||||
|
|
||||||
|
import {MapWrapper} from 'angular2/src/facade/collection';
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
|
import {DomTestbed} from './dom_testbed';
|
||||||
|
|
||||||
|
import {ViewDefinition, DirectiveMetadata, RenderViewRef} from 'angular2/src/render/api';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe('DomRenderer integration', () => {
|
||||||
|
beforeEachBindings(() => [
|
||||||
|
DomTestbed
|
||||||
|
]);
|
||||||
|
|
||||||
|
it('should create and destroy host views while using the given elements in place',
|
||||||
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
|
tb.compileAll([someComponent]).then( (protoViewDtos) => {
|
||||||
|
var view = tb.createRootView(protoViewDtos[0]);
|
||||||
|
expect(tb.rootEl.parentNode).toBeTruthy();
|
||||||
|
expect(view.rawView.rootNodes[0]).toEqual(tb.rootEl);
|
||||||
|
|
||||||
|
tb.renderer.destroyInPlaceHostView(null, view.viewRef);
|
||||||
|
expect(tb.rootEl.parentNode).toBeFalsy();
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should attach and detach component views',
|
||||||
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
|
tb.compileAll([
|
||||||
|
someComponent,
|
||||||
|
new ViewDefinition({
|
||||||
|
componentId: 'someComponent',
|
||||||
|
template: 'hello',
|
||||||
|
directives: []
|
||||||
|
})
|
||||||
|
]).then( (protoViewDtos) => {
|
||||||
|
var rootView = tb.createRootView(protoViewDtos[0]);
|
||||||
|
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
|
||||||
|
expect(tb.rootEl).toHaveText('hello');
|
||||||
|
tb.destroyComponentView(rootView.viewRef, 0, cmpView.viewRef);
|
||||||
|
expect(tb.rootEl).toHaveText('');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should update text nodes',
|
||||||
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
|
tb.compileAll([someComponent,
|
||||||
|
new ViewDefinition({
|
||||||
|
componentId: 'someComponent',
|
||||||
|
template: '{{a}}',
|
||||||
|
directives: []
|
||||||
|
})
|
||||||
|
]).then( (protoViewDtos) => {
|
||||||
|
var rootView = tb.createRootView(protoViewDtos[0]);
|
||||||
|
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
|
||||||
|
|
||||||
|
tb.renderer.setText(cmpView.viewRef, 0, 'hello');
|
||||||
|
expect(tb.rootEl).toHaveText('hello');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should update element properties',
|
||||||
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
|
tb.compileAll([someComponent,
|
||||||
|
new ViewDefinition({
|
||||||
|
componentId: 'someComponent',
|
||||||
|
template: '<input [value]="someProp">asdf',
|
||||||
|
directives: []
|
||||||
|
})
|
||||||
|
]).then( (protoViewDtos) => {
|
||||||
|
var rootView = tb.createRootView(protoViewDtos[0]);
|
||||||
|
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
|
||||||
|
|
||||||
|
tb.renderer.setElementProperty(cmpView.viewRef, 0, 'value', 'hello');
|
||||||
|
expect(DOM.childNodes(tb.rootEl)[0].value).toEqual('hello');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should add and remove views to and from containers',
|
||||||
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
|
tb.compileAll([someComponent,
|
||||||
|
new ViewDefinition({
|
||||||
|
componentId: 'someComponent',
|
||||||
|
template: '<template>hello</template>',
|
||||||
|
directives: []
|
||||||
|
})
|
||||||
|
]).then( (protoViewDtos) => {
|
||||||
|
var rootView = tb.createRootView(protoViewDtos[0]);
|
||||||
|
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
|
||||||
|
|
||||||
|
var childProto = protoViewDtos[1].elementBinders[0].nestedProtoView;
|
||||||
|
expect(tb.rootEl).toHaveText('');
|
||||||
|
var childView = tb.createViewInContainer(cmpView.viewRef, 0, 0, childProto);
|
||||||
|
expect(tb.rootEl).toHaveText('hello');
|
||||||
|
tb.destroyViewInContainer(cmpView.viewRef, 0, 0, childView.viewRef);
|
||||||
|
expect(tb.rootEl).toHaveText('');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should handle events',
|
||||||
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
|
tb.compileAll([someComponent,
|
||||||
|
new ViewDefinition({
|
||||||
|
componentId: 'someComponent',
|
||||||
|
template: '<input (change)="doSomething()">',
|
||||||
|
directives: []
|
||||||
|
})
|
||||||
|
]).then( (protoViewDtos) => {
|
||||||
|
var rootView = tb.createRootView(protoViewDtos[0]);
|
||||||
|
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
|
||||||
|
|
||||||
|
tb.triggerEvent(cmpView.viewRef, 0, 'change');
|
||||||
|
var eventEntry = cmpView.events[0];
|
||||||
|
// bound element index
|
||||||
|
expect(eventEntry[0]).toEqual(0);
|
||||||
|
// event type
|
||||||
|
expect(eventEntry[1]).toEqual('change');
|
||||||
|
// actual event
|
||||||
|
expect(MapWrapper.get(eventEntry[2], '$event').type).toEqual('change');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var someComponent = new DirectiveMetadata({
|
||||||
|
id: 'someComponent',
|
||||||
|
type: DirectiveMetadata.COMPONENT_TYPE,
|
||||||
|
selector: 'some-comp'
|
||||||
|
});
|
|
@ -0,0 +1,126 @@
|
||||||
|
import {Inject, Injectable} from 'angular2/src/di/annotations_impl';
|
||||||
|
import {MapWrapper, ListWrapper, List, Map} from 'angular2/src/facade/collection';
|
||||||
|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
|
import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
|
||||||
|
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
|
||||||
|
import {DomView} from 'angular2/src/render/dom/view/view';
|
||||||
|
import {RenderViewRef, ProtoViewDto, ViewDefinition, EventDispatcher, DirectiveMetadata} from 'angular2/src/render/api';
|
||||||
|
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
|
||||||
|
import {el, dispatchEvent} from 'angular2/test_lib';
|
||||||
|
|
||||||
|
export class TestView extends EventDispatcher {
|
||||||
|
rawView:DomView;
|
||||||
|
viewRef:RenderViewRef;
|
||||||
|
events:List;
|
||||||
|
|
||||||
|
constructor(viewRef:RenderViewRef) {
|
||||||
|
super();
|
||||||
|
this.viewRef = viewRef;
|
||||||
|
this.rawView = resolveInternalDomView(viewRef);
|
||||||
|
this.events = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class LoggingEventDispatcher extends EventDispatcher {
|
||||||
|
log:List;
|
||||||
|
|
||||||
|
constructor(log:List) {
|
||||||
|
super();
|
||||||
|
this.log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvent(
|
||||||
|
elementIndex:number, eventName:string, locals:Map<string, any>
|
||||||
|
) {
|
||||||
|
ListWrapper.push(this.log, [elementIndex, eventName, locals]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DomTestbed {
|
||||||
|
renderer:DomRenderer;
|
||||||
|
compiler:DefaultDomCompiler;
|
||||||
|
rootEl;
|
||||||
|
|
||||||
|
constructor(renderer:DomRenderer, compiler:DefaultDomCompiler, @Inject(DOCUMENT_TOKEN) document) {
|
||||||
|
this.renderer = renderer;
|
||||||
|
this.compiler = compiler;
|
||||||
|
this.rootEl = el('<div id="root"></div>');
|
||||||
|
var oldRoots = DOM.querySelectorAll(document, '#root');
|
||||||
|
for (var i=0; i<oldRoots.length; i++) {
|
||||||
|
DOM.remove(oldRoots[i]);
|
||||||
|
}
|
||||||
|
DOM.appendChild(DOM.querySelector(document, 'body'), this.rootEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileAll(directivesOrViewDefinitions:List):Promise<List<ProtoViewDto>> {
|
||||||
|
return PromiseWrapper.all(
|
||||||
|
ListWrapper.map(directivesOrViewDefinitions, (entry) => {
|
||||||
|
if (entry instanceof DirectiveMetadata) {
|
||||||
|
return this.compiler.compileHost(entry);
|
||||||
|
} else {
|
||||||
|
return this.compiler.compile(entry);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createTestView(viewRef:RenderViewRef) {
|
||||||
|
var testView = new TestView(viewRef);
|
||||||
|
this.renderer.setEventDispatcher(viewRef, new LoggingEventDispatcher(testView.events));
|
||||||
|
return testView;
|
||||||
|
}
|
||||||
|
|
||||||
|
createRootView(rootProtoView:ProtoViewDto):TestView {
|
||||||
|
var viewRef = this.renderer.createInPlaceHostView(null, '#root', rootProtoView.render);
|
||||||
|
this.renderer.hydrateView(viewRef);
|
||||||
|
return this._createTestView(viewRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
createComponentView(parentViewRef:RenderViewRef, boundElementIndex:number, componentProtoView:ProtoViewDto):TestView {
|
||||||
|
var componentViewRef = this.renderer.createView(componentProtoView.render);
|
||||||
|
this.renderer.attachComponentView(parentViewRef, boundElementIndex, componentViewRef);
|
||||||
|
this.renderer.hydrateView(componentViewRef);
|
||||||
|
return this._createTestView(componentViewRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
createRootViews(protoViews:List<ProtoViewDto>):List<TestView> {
|
||||||
|
var views = [];
|
||||||
|
var lastView = this.createRootView(protoViews[0]);
|
||||||
|
ListWrapper.push(views, lastView);
|
||||||
|
for (var i=1; i<protoViews.length; i++) {
|
||||||
|
lastView = this.createComponentView(lastView.viewRef, 0, protoViews[i]);
|
||||||
|
ListWrapper.push(views, lastView);
|
||||||
|
}
|
||||||
|
return views;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyComponentView(parentViewRef:RenderViewRef, boundElementIndex:number, componentView:RenderViewRef) {
|
||||||
|
this.renderer.dehydrateView(componentView);
|
||||||
|
this.renderer.detachComponentView(parentViewRef, boundElementIndex, componentView);
|
||||||
|
}
|
||||||
|
|
||||||
|
createViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, protoView:ProtoViewDto):TestView {
|
||||||
|
var viewRef = this.renderer.createView(protoView.render);
|
||||||
|
this.renderer.attachViewInContainer(parentViewRef, boundElementIndex, atIndex, viewRef);
|
||||||
|
this.renderer.hydrateView(viewRef);
|
||||||
|
return this._createTestView(viewRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) {
|
||||||
|
this.renderer.dehydrateView(viewRef);
|
||||||
|
this.renderer.detachViewInContainer(parentViewRef, boundElementIndex, atIndex, viewRef);
|
||||||
|
this.renderer.destroyView(viewRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerEvent(viewRef:RenderViewRef, boundElementIndex:number, eventName:string) {
|
||||||
|
var element = resolveInternalDomView(viewRef).boundElements[boundElementIndex];
|
||||||
|
dispatchEvent(element, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,195 +0,0 @@
|
||||||
import {isBlank, isPresent, BaseException} from 'angular2/src/facade/lang';
|
|
||||||
import {MapWrapper, ListWrapper, List, Map} from 'angular2/src/facade/collection';
|
|
||||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
||||||
|
|
||||||
import {Parser, Lexer} from 'angular2/change_detection';
|
|
||||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
|
||||||
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
|
|
||||||
import {RenderProtoViewRef, ProtoViewDto, ViewDefinition, RenderViewContainerRef, EventDispatcher, DirectiveMetadata} from 'angular2/src/render/api';
|
|
||||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
|
||||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
|
||||||
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
|
||||||
import {EventManager, EventManagerPlugin} from 'angular2/src/render/dom/events/event_manager';
|
|
||||||
import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
|
|
||||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
|
||||||
import {ViewFactory} from 'angular2/src/render/dom/view/view_factory';
|
|
||||||
import {RenderViewHydrator} from 'angular2/src/render/dom/view/view_hydrator';
|
|
||||||
|
|
||||||
export class IntegrationTestbed {
|
|
||||||
renderer;
|
|
||||||
renderCompiler;
|
|
||||||
parser;
|
|
||||||
eventPlugin;
|
|
||||||
_templates:Map<string, ViewDefinition>;
|
|
||||||
|
|
||||||
constructor({urlData, viewCacheCapacity, shadowDomStrategy, templates}) {
|
|
||||||
this._templates = MapWrapper.create();
|
|
||||||
if (isPresent(templates)) {
|
|
||||||
ListWrapper.forEach(templates, (template) => {
|
|
||||||
MapWrapper.set(this._templates, template.componentId, template);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var parser = new Parser(new Lexer());
|
|
||||||
var urlResolver = new UrlResolver();
|
|
||||||
if (isBlank(shadowDomStrategy)) {
|
|
||||||
shadowDomStrategy = new EmulatedUnscopedShadowDomStrategy(new StyleUrlResolver(urlResolver), null);
|
|
||||||
}
|
|
||||||
this.renderCompiler = new DefaultDomCompiler(parser, shadowDomStrategy, new FakeTemplateLoader(urlResolver, urlData));
|
|
||||||
|
|
||||||
if (isBlank(viewCacheCapacity)) {
|
|
||||||
viewCacheCapacity = 0;
|
|
||||||
}
|
|
||||||
if (isBlank(urlData)) {
|
|
||||||
urlData = MapWrapper.create();
|
|
||||||
}
|
|
||||||
this.eventPlugin = new FakeEventManagerPlugin();
|
|
||||||
var eventManager = new EventManager([this.eventPlugin], new FakeVmTurnZone());
|
|
||||||
var viewFactory = new ViewFactory(viewCacheCapacity, eventManager, shadowDomStrategy);
|
|
||||||
var viewHydrator = new RenderViewHydrator(eventManager, viewFactory, shadowDomStrategy);
|
|
||||||
this.renderer = new DirectDomRenderer(viewFactory, viewHydrator, shadowDomStrategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
compileRoot(componentMetadata):Promise<ProtoViewDto> {
|
|
||||||
return this.renderCompiler.compileHost(componentMetadata).then( (rootProtoView) => {
|
|
||||||
return this._compileNestedProtoViews(rootProtoView, [componentMetadata]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
compile(componentId):Promise<ProtoViewDto> {
|
|
||||||
var childTemplate = MapWrapper.get(this._templates, componentId);
|
|
||||||
if (isBlank(childTemplate)) {
|
|
||||||
throw new BaseException(`No template for component ${componentId}`);
|
|
||||||
}
|
|
||||||
return this.renderCompiler.compile(childTemplate).then( (protoView) => {
|
|
||||||
return this._compileNestedProtoViews(protoView, childTemplate.directives);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_compileNestedProtoViews(protoView, directives):Promise<ProtoViewDto> {
|
|
||||||
var childComponentRenderPvRefs = [];
|
|
||||||
var nestedPVPromises = [];
|
|
||||||
ListWrapper.forEach(protoView.elementBinders, (elementBinder) => {
|
|
||||||
var nestedComponentId = null;
|
|
||||||
ListWrapper.forEach(elementBinder.directives, (db) => {
|
|
||||||
var directiveMeta = directives[db.directiveIndex];
|
|
||||||
if (directiveMeta.type === DirectiveMetadata.COMPONENT_TYPE) {
|
|
||||||
nestedComponentId = directiveMeta.id;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var nestedCall;
|
|
||||||
if (isPresent(nestedComponentId)) {
|
|
||||||
var childTemplate = MapWrapper.get(this._templates, nestedComponentId);
|
|
||||||
if (isBlank(childTemplate)) {
|
|
||||||
// dynamic component
|
|
||||||
ListWrapper.push(childComponentRenderPvRefs, null);
|
|
||||||
} else {
|
|
||||||
nestedCall = this.compile(nestedComponentId);
|
|
||||||
}
|
|
||||||
} else if (isPresent(elementBinder.nestedProtoView)) {
|
|
||||||
nestedCall = this._compileNestedProtoViews(elementBinder.nestedProtoView, directives);
|
|
||||||
}
|
|
||||||
if (isPresent(nestedCall)) {
|
|
||||||
ListWrapper.push(
|
|
||||||
nestedPVPromises,
|
|
||||||
nestedCall.then( (nestedPv) => {
|
|
||||||
elementBinder.nestedProtoView = nestedPv;
|
|
||||||
if (isPresent(nestedComponentId)) {
|
|
||||||
ListWrapper.push(childComponentRenderPvRefs, nestedPv.render);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (nestedPVPromises.length > 0) {
|
|
||||||
return PromiseWrapper.all(nestedPVPromises).then((_) => {
|
|
||||||
this.renderCompiler.mergeChildComponentProtoViews(protoView.render, childComponentRenderPvRefs);
|
|
||||||
return protoView;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return PromiseWrapper.resolve(protoView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class FakeTemplateLoader extends TemplateLoader {
|
|
||||||
_urlData: Map<string, string>;
|
|
||||||
|
|
||||||
constructor(urlResolver, urlData) {
|
|
||||||
super(null, urlResolver);
|
|
||||||
this._urlData = urlData;
|
|
||||||
}
|
|
||||||
|
|
||||||
load(template: ViewDefinition) {
|
|
||||||
if (isPresent(template.template)) {
|
|
||||||
return PromiseWrapper.resolve(DOM.createTemplate(template.template));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPresent(template.absUrl)) {
|
|
||||||
var content = this._urlData[template.absUrl];
|
|
||||||
if (isPresent(content)) {
|
|
||||||
return PromiseWrapper.resolve(DOM.createTemplate(content));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PromiseWrapper.reject('Load failed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FakeVmTurnZone extends VmTurnZone {
|
|
||||||
constructor() {
|
|
||||||
super({enableLongStackTrace: false});
|
|
||||||
}
|
|
||||||
|
|
||||||
run(fn) {
|
|
||||||
fn();
|
|
||||||
}
|
|
||||||
|
|
||||||
runOutsideAngular(fn) {
|
|
||||||
fn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FakeEventManagerPlugin extends EventManagerPlugin {
|
|
||||||
_eventHandlers: Map;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this._eventHandlers = MapWrapper.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchEvent(eventName, event) {
|
|
||||||
MapWrapper.get(this._eventHandlers, eventName)(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
supports(eventName: string): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
|
|
||||||
MapWrapper.set(this._eventHandlers, eventName, handler);
|
|
||||||
return () => {MapWrapper.delete(this._eventHandlers, eventName);}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LoggingEventDispatcher extends EventDispatcher {
|
|
||||||
log:List;
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.log = [];
|
|
||||||
}
|
|
||||||
dispatchEvent(
|
|
||||||
elementIndex:number, eventName:string, locals:Map<string, any>
|
|
||||||
) {
|
|
||||||
ListWrapper.push(this.log, [elementIndex, eventName, locals]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FakeEvent {
|
|
||||||
target;
|
|
||||||
constructor(target) {
|
|
||||||
this.target = target;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,7 +23,7 @@ export function main() {
|
||||||
|
|
||||||
it("should insert the nodes", () => {
|
it("should insert the nodes", () => {
|
||||||
var c = new Content(content, '');
|
var c = new Content(content, '');
|
||||||
c.hydrate(null);
|
c.init(null);
|
||||||
c.insert([el("<a></a>"), el("<b></b>")])
|
c.insert([el("<a></a>"), el("<b></b>")])
|
||||||
|
|
||||||
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}<a></a><b></b>${_scriptEnd}`);
|
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}<a></a><b></b>${_scriptEnd}`);
|
||||||
|
@ -31,7 +31,7 @@ export function main() {
|
||||||
|
|
||||||
it("should remove the nodes from the previous insertion", () => {
|
it("should remove the nodes from the previous insertion", () => {
|
||||||
var c = new Content(content, '');
|
var c = new Content(content, '');
|
||||||
c.hydrate(null);
|
c.init(null);
|
||||||
c.insert([el("<a></a>")]);
|
c.insert([el("<a></a>")]);
|
||||||
c.insert([el("<b></b>")]);
|
c.insert([el("<b></b>")]);
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ export function main() {
|
||||||
|
|
||||||
it("should insert empty list", () => {
|
it("should insert empty list", () => {
|
||||||
var c = new Content(content, '');
|
var c = new Content(content, '');
|
||||||
c.hydrate(null);
|
c.init(null);
|
||||||
c.insert([el("<a></a>")]);
|
c.insert([el("<a></a>")]);
|
||||||
c.insert([]);
|
c.insert([]);
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ import {
|
||||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||||
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
||||||
import {DomView} from 'angular2/src/render/dom/view/view';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('EmulatedScopedShadowDomStrategy', () => {
|
describe('EmulatedScopedShadowDomStrategy', () => {
|
||||||
|
@ -44,15 +43,9 @@ export function main() {
|
||||||
resetShadowDomCache();
|
resetShadowDomCache();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should attach the view nodes as child of the host element', () => {
|
it('should use the host element as shadow root', () => {
|
||||||
var host = el('<div><span>original content</span></div>');
|
var host = el('<div><span>original content</span></div>');
|
||||||
var originalChild = DOM.childNodes(host)[0];
|
expect(strategy.prepareShadowRoot(host)).toBe(host);
|
||||||
var nodes = el('<div>view</div>');
|
|
||||||
var view = new DomView(null, [nodes], [], [], []);
|
|
||||||
|
|
||||||
strategy.attachTemplate(host, view);
|
|
||||||
expect(DOM.childNodes(host)[0]).toBe(originalChild);
|
|
||||||
expect(DOM.childNodes(host)[1]).toBe(nodes);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rewrite style urls', () => {
|
it('should rewrite style urls', () => {
|
||||||
|
|
|
@ -23,7 +23,6 @@ import {
|
||||||
} from 'angular2/src/render/dom/shadow_dom/util';
|
} from 'angular2/src/render/dom/shadow_dom/util';
|
||||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||||
import {DomView} from 'angular2/src/render/dom/view/view';
|
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
var strategy;
|
var strategy;
|
||||||
|
@ -39,15 +38,9 @@ export function main() {
|
||||||
resetShadowDomCache();
|
resetShadowDomCache();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should attach the view nodes as child of the host element', () => {
|
it('should use the host element as shadow root', () => {
|
||||||
var host = el('<div><span>original content</span></div>');
|
var host = el('<div><span>original content</span></div>');
|
||||||
var originalChild = DOM.childNodes(host)[0];
|
expect(strategy.prepareShadowRoot(host)).toBe(host);
|
||||||
var nodes = el('<div>view</div>');
|
|
||||||
var view = new DomView(null, [nodes], [], [], []);
|
|
||||||
|
|
||||||
strategy.attachTemplate(host, view);
|
|
||||||
expect(DOM.childNodes(host)[0]).toBe(originalChild);
|
|
||||||
expect(DOM.childNodes(host)[1]).toBe(nodes);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rewrite style urls', () => {
|
it('should rewrite style urls', () => {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
import {Content} from 'angular2/src/render/dom/shadow_dom/content_tag';
|
import {Content} from 'angular2/src/render/dom/shadow_dom/content_tag';
|
||||||
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
|
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 {ViewContainer} from 'angular2/src/render/dom/view/view_container';
|
import {DomViewContainer} from 'angular2/src/render/dom/view/view_container';
|
||||||
|
|
||||||
@proxy
|
@proxy
|
||||||
@IMPLEMENTS(DomView)
|
@IMPLEMENTS(DomView)
|
||||||
|
@ -44,7 +44,7 @@ class FakeView {
|
||||||
}
|
}
|
||||||
|
|
||||||
@proxy
|
@proxy
|
||||||
@IMPLEMENTS(ViewContainer)
|
@IMPLEMENTS(DomViewContainer)
|
||||||
class FakeViewContainer {
|
class FakeViewContainer {
|
||||||
_nodes;
|
_nodes;
|
||||||
_contentTagContainers;
|
_contentTagContainers;
|
||||||
|
@ -96,6 +96,11 @@ class FakeContentTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createLightDom(hostView, shadowView, el) {
|
||||||
|
var lightDom = new LightDom(hostView, el);
|
||||||
|
lightDom.attachShadowDomView(shadowView);
|
||||||
|
return lightDom;
|
||||||
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('LightDom', function() {
|
describe('LightDom', function() {
|
||||||
|
@ -110,7 +115,7 @@ export function main() {
|
||||||
var tag = new FakeContentTag(el('<script></script>'));
|
var tag = new FakeContentTag(el('<script></script>'));
|
||||||
var shadowDomView = new FakeView([tag]);
|
var shadowDomView = new FakeView([tag]);
|
||||||
|
|
||||||
var lightDom = new LightDom(lightDomView, shadowDomView,
|
var lightDom = createLightDom(lightDomView, shadowDomView,
|
||||||
el("<div></div>"));
|
el("<div></div>"));
|
||||||
|
|
||||||
expect(lightDom.contentTags()).toEqual([tag]);
|
expect(lightDom.contentTags()).toEqual([tag]);
|
||||||
|
@ -122,7 +127,7 @@ export function main() {
|
||||||
new FakeView([tag])
|
new FakeView([tag])
|
||||||
]);
|
]);
|
||||||
var shadowDomView = new FakeView([vc]);
|
var shadowDomView = new FakeView([vc]);
|
||||||
var lightDom = new LightDom(lightDomView, shadowDomView,
|
var lightDom = createLightDom(lightDomView, shadowDomView,
|
||||||
el("<div></div>"));
|
el("<div></div>"));
|
||||||
|
|
||||||
expect(lightDom.contentTags()).toEqual([tag]);
|
expect(lightDom.contentTags()).toEqual([tag]);
|
||||||
|
@ -132,13 +137,13 @@ export function main() {
|
||||||
describe("expandedDomNodes", () => {
|
describe("expandedDomNodes", () => {
|
||||||
it("should contain root nodes", () => {
|
it("should contain root nodes", () => {
|
||||||
var lightDomEl = el("<div><a></a></div>")
|
var lightDomEl = el("<div><a></a></div>")
|
||||||
var lightDom = new LightDom(lightDomView, new FakeView(), lightDomEl);
|
var lightDom = createLightDom(lightDomView, new FakeView(), lightDomEl);
|
||||||
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
|
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should include view container nodes", () => {
|
it("should include view container nodes", () => {
|
||||||
var lightDomEl = el("<div><template></template></div>");
|
var lightDomEl = el("<div><template></template></div>");
|
||||||
var lightDom = new LightDom(
|
var lightDom = createLightDom(
|
||||||
new FakeView([
|
new FakeView([
|
||||||
new FakeViewContainer(
|
new FakeViewContainer(
|
||||||
DOM.firstChild(lightDomEl), // template element
|
DOM.firstChild(lightDomEl), // template element
|
||||||
|
@ -153,7 +158,7 @@ export function main() {
|
||||||
|
|
||||||
it("should include content nodes", () => {
|
it("should include content nodes", () => {
|
||||||
var lightDomEl = el("<div><content></content></div>");
|
var lightDomEl = el("<div><content></content></div>");
|
||||||
var lightDom = new LightDom(
|
var lightDom = createLightDom(
|
||||||
new FakeView([
|
new FakeView([
|
||||||
new FakeContentTag(
|
new FakeContentTag(
|
||||||
DOM.firstChild(lightDomEl), // content element
|
DOM.firstChild(lightDomEl), // content element
|
||||||
|
@ -172,7 +177,7 @@ export function main() {
|
||||||
|
|
||||||
var lightDomView = new FakeView();
|
var lightDomView = new FakeView();
|
||||||
|
|
||||||
var lightDom = new LightDom(
|
var lightDom = createLightDom(
|
||||||
lightDomView,
|
lightDomView,
|
||||||
new FakeView(),
|
new FakeView(),
|
||||||
lightDomEl);
|
lightDomEl);
|
||||||
|
@ -188,7 +193,7 @@ export function main() {
|
||||||
|
|
||||||
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
|
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
|
||||||
|
|
||||||
var lightDom = new LightDom(lightDomView, new FakeView([
|
var lightDom = createLightDom(lightDomView, new FakeView([
|
||||||
contentA,
|
contentA,
|
||||||
contentB
|
contentB
|
||||||
]), lightDomEl);
|
]), lightDomEl);
|
||||||
|
@ -205,7 +210,7 @@ export function main() {
|
||||||
|
|
||||||
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
|
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
|
||||||
|
|
||||||
var lightDom = new LightDom(lightDomView, new FakeView([
|
var lightDom = createLightDom(lightDomView, new FakeView([
|
||||||
wildcard,
|
wildcard,
|
||||||
contentB
|
contentB
|
||||||
]), lightDomEl);
|
]), lightDomEl);
|
||||||
|
@ -219,7 +224,7 @@ export function main() {
|
||||||
it("should remove all nodes if there are no content tags", () => {
|
it("should remove all nodes if there are no content tags", () => {
|
||||||
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
|
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
|
||||||
|
|
||||||
var lightDom = new LightDom(lightDomView, new FakeView([]), lightDomEl);
|
var lightDom = createLightDom(lightDomView, new FakeView([]), lightDomEl);
|
||||||
|
|
||||||
lightDom.redistribute();
|
lightDom.redistribute();
|
||||||
|
|
||||||
|
@ -230,7 +235,7 @@ export function main() {
|
||||||
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>");
|
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>");
|
||||||
var bNode = DOM.childNodes(lightDomEl)[1];
|
var bNode = DOM.childNodes(lightDomEl)[1];
|
||||||
|
|
||||||
var lightDom = new LightDom(lightDomView, new FakeView([
|
var lightDom = createLightDom(lightDomView, new FakeView([
|
||||||
new FakeContentTag(null, "a")
|
new FakeContentTag(null, "a")
|
||||||
]), lightDomEl);
|
]), lightDomEl);
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,7 @@ import {
|
||||||
} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||||
import {DomView} from 'angular2/src/render/dom/view/view';
|
|
||||||
|
|
||||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
|
@ -32,15 +30,9 @@ export function main() {
|
||||||
strategy = new NativeShadowDomStrategy(styleUrlResolver);
|
strategy = new NativeShadowDomStrategy(styleUrlResolver);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should attach the view nodes to the shadow root', () => {
|
it('should use the native shadow root', () => {
|
||||||
var host = el('<div><span>original content</span></div>');
|
var host = el('<div><span>original content</span></div>');
|
||||||
var nodes = el('<div>view</div>');
|
expect(strategy.prepareShadowRoot(host)).toBe(DOM.getShadowRoot(host));
|
||||||
var view = new DomView(null, [nodes], [], [], []);
|
|
||||||
|
|
||||||
strategy.attachTemplate(host, view);
|
|
||||||
var shadowRoot = DOM.getShadowRoot(host);
|
|
||||||
expect(isPresent(shadowRoot)).toBeTruthy();
|
|
||||||
expect(shadowRoot).toHaveText('view');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should rewrite style urls', () => {
|
it('should rewrite style urls', () => {
|
||||||
|
|
|
@ -10,128 +10,118 @@ import {
|
||||||
inject,
|
inject,
|
||||||
it,
|
it,
|
||||||
xit,
|
xit,
|
||||||
|
beforeEachBindings,
|
||||||
SpyObject,
|
SpyObject,
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
|
|
||||||
|
import {bind} from 'angular2/di';
|
||||||
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ProtoViewDto, ViewDefinition, RenderViewContainerRef, DirectiveMetadata
|
ViewDefinition, DirectiveMetadata
|
||||||
} from 'angular2/src/render/api';
|
} from 'angular2/src/render/api';
|
||||||
|
|
||||||
|
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||||
import {EmulatedScopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy';
|
import {EmulatedScopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy';
|
||||||
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||||
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
|
||||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||||
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
||||||
|
|
||||||
import {IntegrationTestbed} from './integration_testbed';
|
import {DomTestbed} from './dom_testbed';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('ShadowDom integration tests', function() {
|
describe('ShadowDom integration tests', function() {
|
||||||
var urlResolver, styleUrlResolver, styleInliner;
|
|
||||||
var strategies = {
|
var strategies = {
|
||||||
"scoped" : () => new EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, null),
|
"scoped" : bind(ShadowDomStrategy).toFactory(
|
||||||
"unscoped" : () => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null)
|
(styleInliner, styleUrlResolver) => new EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, null),
|
||||||
|
[StyleInliner, StyleUrlResolver]),
|
||||||
|
"unscoped" : bind(ShadowDomStrategy).toFactory(
|
||||||
|
(styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null),
|
||||||
|
[StyleUrlResolver])
|
||||||
}
|
}
|
||||||
if (DOM.supportsNativeShadowDOM()) {
|
if (DOM.supportsNativeShadowDOM()) {
|
||||||
StringMapWrapper.set(strategies, "native", () => new NativeShadowDomStrategy(styleUrlResolver));
|
StringMapWrapper.set(strategies, "native", bind(ShadowDomStrategy).toFactory(
|
||||||
|
(styleUrlResolver) => new NativeShadowDomStrategy(styleUrlResolver),
|
||||||
|
[StyleUrlResolver])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach( () => {
|
|
||||||
urlResolver = new UrlResolver();
|
|
||||||
styleUrlResolver = new StyleUrlResolver(urlResolver);
|
|
||||||
styleInliner = new StyleInliner(null, styleUrlResolver, urlResolver);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
StringMapWrapper.forEach(strategies,
|
StringMapWrapper.forEach(strategies,
|
||||||
(strategyFactory, name) => {
|
(strategyBinding, name) => {
|
||||||
|
|
||||||
|
beforeEachBindings( () => {
|
||||||
|
return [strategyBinding, DomTestbed];
|
||||||
|
});
|
||||||
|
|
||||||
describe(`${name} shadow dom strategy`, () => {
|
describe(`${name} shadow dom strategy`, () => {
|
||||||
|
|
||||||
var testbed, renderer, rootEl, compile, compileRoot;
|
it('should support simple components', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
|
tb.compileAll([
|
||||||
function createRenderer({templates, viewCacheCapacity}) {
|
mainDir,
|
||||||
testbed = new IntegrationTestbed({
|
new ViewDefinition({
|
||||||
shadowDomStrategy: strategyFactory(),
|
|
||||||
templates: ListWrapper.concat(templates, componentTemplates),
|
|
||||||
viewCacheCapacity: viewCacheCapacity
|
|
||||||
});
|
|
||||||
renderer = testbed.renderer;
|
|
||||||
compileRoot = (rootEl) => testbed.compileRoot(rootEl);
|
|
||||||
compile = (componentId) => testbed.compile(componentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach( () => {
|
|
||||||
rootEl = el('<div></div>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support simple components', inject([AsyncTestCompleter], (async) => {
|
|
||||||
createRenderer({
|
|
||||||
templates: [new ViewDefinition({
|
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<simple>' +
|
template: '<simple>' +
|
||||||
'<div>A</div>' +
|
'<div>A</div>' +
|
||||||
'</simple>',
|
'</simple>',
|
||||||
directives: [simple]
|
directives: [simple]
|
||||||
})]
|
}),
|
||||||
});
|
simpleTemplate
|
||||||
compileRoot(mainDir).then( (pv) => {
|
]).then( (protoViews) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
tb.createRootViews(protoViews);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('SIMPLE(A)');
|
expect(tb.rootEl).toHaveText('SIMPLE(A)');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not show the light dom event if there is not content tag', inject([AsyncTestCompleter], (async) => {
|
it('should not show the light dom even if there is not content tag', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
createRenderer({
|
tb.compileAll([
|
||||||
templates: [new ViewDefinition({
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<empty>' +
|
template: '<empty>' +
|
||||||
'<div>A</div>' +
|
'<div>A</div>' +
|
||||||
'</empty>',
|
'</empty>',
|
||||||
directives: [empty]
|
directives: [empty]
|
||||||
})]
|
}),
|
||||||
});
|
emptyTemplate
|
||||||
compileRoot(mainDir).then( (pv) => {
|
]).then( (protoViews) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
tb.createRootViews(protoViews);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('');
|
expect(tb.rootEl).toHaveText('');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should support dynamic components', inject([AsyncTestCompleter], (async) => {
|
it('should support dynamic components', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
createRenderer({
|
tb.compileAll([
|
||||||
templates: [new ViewDefinition({
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<dynamic>' +
|
template: '<dynamic>' +
|
||||||
'<div>A</div>' +
|
'<div>A</div>' +
|
||||||
'</dynamic>',
|
'</dynamic>',
|
||||||
directives: [dynamicComponent]
|
directives: [dynamicComponent]
|
||||||
})]
|
}),
|
||||||
});
|
simpleTemplate
|
||||||
compileRoot(mainDir).then( (rootPv) => {
|
]).then( (protoViews) => {
|
||||||
compile('simple').then( (simplePv) => {
|
var views = tb.createRootViews(ListWrapper.slice(protoViews, 0, 2));
|
||||||
var views = renderer.createInPlaceHostView(null, rootEl, rootPv.render);
|
tb.createComponentView(views[1].viewRef, 0, protoViews[2]);
|
||||||
renderer.createDynamicComponentView(views[1], 0, simplePv.render);
|
|
||||||
|
|
||||||
expect(rootEl).toHaveText('SIMPLE(A)');
|
expect(tb.rootEl).toHaveText('SIMPLE(A)');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should support multiple content tags', inject([AsyncTestCompleter], (async) => {
|
it('should support multiple content tags', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
createRenderer({
|
tb.compileAll([
|
||||||
templates: [new ViewDefinition({
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<multiple-content-tags>' +
|
template: '<multiple-content-tags>' +
|
||||||
'<div>B</div>' +
|
'<div>B</div>' +
|
||||||
|
@ -139,120 +129,126 @@ export function main() {
|
||||||
'<div class="left">A</div>' +
|
'<div class="left">A</div>' +
|
||||||
'</multiple-content-tags>',
|
'</multiple-content-tags>',
|
||||||
directives: [multipleContentTagsComponent]
|
directives: [multipleContentTagsComponent]
|
||||||
})]
|
}),
|
||||||
});
|
multipleContentTagsTemplate
|
||||||
compileRoot(mainDir).then( (pv) => {
|
]).then( (protoViews) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
tb.createRootViews(protoViews);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(A, BC)');
|
expect(tb.rootEl).toHaveText('(A, BC)');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should redistribute only direct children', inject([AsyncTestCompleter], (async) => {
|
it('should redistribute only direct children', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
createRenderer({
|
tb.compileAll([
|
||||||
templates: [new ViewDefinition({
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<multiple-content-tags>' +
|
template: '<multiple-content-tags>' +
|
||||||
'<div>B<div class="left">A</div></div>' +
|
'<div>B<div class="left">A</div></div>' +
|
||||||
'<div>C</div>' +
|
'<div>C</div>' +
|
||||||
'</multiple-content-tags>',
|
'</multiple-content-tags>',
|
||||||
directives: [multipleContentTagsComponent]
|
directives: [multipleContentTagsComponent]
|
||||||
})]
|
}),
|
||||||
});
|
multipleContentTagsTemplate
|
||||||
compileRoot(mainDir).then( (pv) => {
|
]).then( (protoViews) => {
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
tb.createRootViews(protoViews);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(, BAC)');
|
expect(tb.rootEl).toHaveText('(, BAC)');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should redistribute direct child viewcontainers when the light dom changes", inject([AsyncTestCompleter], (async) => {
|
it("should redistribute direct child viewcontainers when the light dom changes",
|
||||||
createRenderer({
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
templates: [new ViewDefinition({
|
tb.compileAll([
|
||||||
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<multiple-content-tags>' +
|
template: '<multiple-content-tags>' +
|
||||||
'<div><div template="manual" class="left">A</div></div>' +
|
'<div><div template="manual" class="left">A</div></div>' +
|
||||||
'<div>B</div>' +
|
'<div>B</div>' +
|
||||||
'</multiple-content-tags>',
|
'</multiple-content-tags>',
|
||||||
directives: [multipleContentTagsComponent, manualViewportDirective]
|
directives: [multipleContentTagsComponent, manualViewportDirective]
|
||||||
})]
|
}),
|
||||||
});
|
multipleContentTagsTemplate
|
||||||
compileRoot(mainDir).then( (pv) => {
|
]).then( (protoViews) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var views = tb.createRootViews(protoViews);
|
||||||
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
|
||||||
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
expect(tb.rootEl).toHaveText('(, B)');
|
||||||
.elementBinders[1].nestedProtoView.render;
|
|
||||||
expect(rootEl).toHaveText('(, B)');
|
|
||||||
|
|
||||||
renderer.createViewInContainer(vcRef, 0, vcProtoViewRef)[0];
|
var childView = tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(, AB)');
|
expect(tb.rootEl).toHaveText('(, AB)');
|
||||||
|
|
||||||
renderer.destroyViewInContainer(vcRef, 0);
|
tb.destroyViewInContainer(views[1].viewRef, 1, 0, childView.viewRef);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(, B)');
|
expect(tb.rootEl).toHaveText('(, B)');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should redistribute when the light dom changes", inject([AsyncTestCompleter], (async) => {
|
it("should redistribute when the light dom changes",
|
||||||
createRenderer({
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
templates: [new ViewDefinition({
|
tb.compileAll([
|
||||||
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<multiple-content-tags>' +
|
template: '<multiple-content-tags>' +
|
||||||
'<div template="manual" class="left">A</div>' +
|
'<div template="manual" class="left">A</div>' +
|
||||||
'<div>B</div>' +
|
'<div>B</div>' +
|
||||||
'</multiple-content-tags>',
|
'</multiple-content-tags>',
|
||||||
directives: [multipleContentTagsComponent, manualViewportDirective]
|
directives: [multipleContentTagsComponent, manualViewportDirective]
|
||||||
})]
|
}),
|
||||||
});
|
multipleContentTagsTemplate
|
||||||
compileRoot(mainDir).then( (pv) => {
|
]).then( (protoViews) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var views = tb.createRootViews(protoViews);
|
||||||
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
|
||||||
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
|
||||||
.elementBinders[1].nestedProtoView.render;
|
|
||||||
expect(rootEl).toHaveText('(, B)');
|
|
||||||
|
|
||||||
renderer.createViewInContainer(vcRef, 0, vcProtoViewRef)[0];
|
expect(tb.rootEl).toHaveText('(, B)');
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(A, B)');
|
var childView = tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
|
||||||
|
|
||||||
renderer.destroyViewInContainer(vcRef, 0);
|
expect(tb.rootEl).toHaveText('(A, B)');
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(, B)');
|
tb.destroyViewInContainer(views[1].viewRef, 1, 0, childView.viewRef);
|
||||||
|
|
||||||
|
expect(tb.rootEl).toHaveText('(, B)');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should support nested components", inject([AsyncTestCompleter], (async) => {
|
it("should support nested components", inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
createRenderer({
|
tb.compileAll([
|
||||||
templates: [new ViewDefinition({
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<outer-with-indirect-nested>' +
|
template: '<outer-with-indirect-nested>' +
|
||||||
'<div>A</div>' +
|
'<div>A</div>' +
|
||||||
'<div>B</div>' +
|
'<div>B</div>' +
|
||||||
'</outer-with-indirect-nested>',
|
'</outer-with-indirect-nested>',
|
||||||
directives: [outerWithIndirectNestedComponent]
|
directives: [outerWithIndirectNestedComponent]
|
||||||
})]
|
}),
|
||||||
});
|
outerWithIndirectNestedTemplate,
|
||||||
compileRoot(mainDir).then( (pv) => {
|
simpleTemplate
|
||||||
renderer.createInPlaceHostView(null, rootEl, pv.render);
|
]).then( (protoViews) => {
|
||||||
|
tb.createRootViews(protoViews);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('OUTER(SIMPLE(AB))');
|
expect(tb.rootEl).toHaveText('OUTER(SIMPLE(AB))');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should support nesting with content being direct child of a nested component", inject([AsyncTestCompleter], (async) => {
|
it("should support nesting with content being direct child of a nested component",
|
||||||
createRenderer({
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
templates: [new ViewDefinition({
|
tb.compileAll([
|
||||||
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<outer>' +
|
template: '<outer>' +
|
||||||
'<div template="manual" class="left">A</div>' +
|
'<div template="manual" class="left">A</div>' +
|
||||||
|
@ -260,25 +256,27 @@ export function main() {
|
||||||
'<div>C</div>' +
|
'<div>C</div>' +
|
||||||
'</outer>',
|
'</outer>',
|
||||||
directives: [outerComponent, manualViewportDirective]
|
directives: [outerComponent, manualViewportDirective]
|
||||||
})]
|
}),
|
||||||
});
|
outerTemplate,
|
||||||
compileRoot(mainDir).then( (pv) => {
|
innerTemplate,
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
innerInnerTemplate
|
||||||
var vcRef = new RenderViewContainerRef(viewRefs[1], 1);
|
]).then( (protoViews) => {
|
||||||
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
var views = tb.createRootViews(protoViews);
|
||||||
.elementBinders[1].nestedProtoView.render;
|
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
|
||||||
expect(rootEl).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
|
|
||||||
|
|
||||||
renderer.createViewInContainer(vcRef, 0, vcProtoViewRef)[0];
|
expect(tb.rootEl).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
|
||||||
|
|
||||||
expect(rootEl).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');
|
tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
|
||||||
|
|
||||||
|
expect(tb.rootEl).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should redistribute when the shadow dom changes', inject([AsyncTestCompleter], (async) => {
|
it('should redistribute when the shadow dom changes', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
createRenderer({
|
tb.compileAll([
|
||||||
templates: [new ViewDefinition({
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template: '<conditional-content>' +
|
template: '<conditional-content>' +
|
||||||
'<div class="left">A</div>' +
|
'<div class="left">A</div>' +
|
||||||
|
@ -286,64 +284,68 @@ export function main() {
|
||||||
'<div>C</div>' +
|
'<div>C</div>' +
|
||||||
'</conditional-content>',
|
'</conditional-content>',
|
||||||
directives: [conditionalContentComponent]
|
directives: [conditionalContentComponent]
|
||||||
})]
|
}),
|
||||||
});
|
conditionalContentTemplate
|
||||||
compileRoot(mainDir).then( (pv) => {
|
]).then( (protoViews) => {
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var views = tb.createRootViews(protoViews);
|
||||||
var vcRef = new RenderViewContainerRef(viewRefs[2], 0);
|
var childProtoView = protoViews[2].elementBinders[0].nestedProtoView;
|
||||||
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
|
|
||||||
.elementBinders[0].nestedProtoView
|
|
||||||
.elementBinders[0].nestedProtoView.render;
|
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(, ABC)');
|
expect(tb.rootEl).toHaveText('(, ABC)');
|
||||||
|
|
||||||
renderer.createViewInContainer(vcRef, 0, vcProtoViewRef)[0];
|
var childView = tb.createViewInContainer(views[2].viewRef, 0, 0, childProtoView);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(A, BC)');
|
expect(tb.rootEl).toHaveText('(A, BC)');
|
||||||
|
|
||||||
renderer.destroyViewInContainer(vcRef, 0);
|
tb.destroyViewInContainer(views[2].viewRef, 0, 0, childView.viewRef);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(, ABC)');
|
expect(tb.rootEl).toHaveText('(, ABC)');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should support tabs with view caching", inject([AsyncTestCompleter], (async) => {
|
it("should support tabs with view caching", inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
createRenderer({
|
tb.compileAll([
|
||||||
templates: [new ViewDefinition({
|
mainDir,
|
||||||
|
new ViewDefinition({
|
||||||
componentId: 'main',
|
componentId: 'main',
|
||||||
template:
|
template:
|
||||||
'(<tab><span>0</span></tab>'+
|
'(<tab><span>0</span></tab>'+
|
||||||
'<tab><span>1</span></tab>'+
|
'<tab><span>1</span></tab>'+
|
||||||
'<tab><span>2</span></tab>)',
|
'<tab><span>2</span></tab>)',
|
||||||
directives: [tabComponent]
|
directives: [tabComponent]
|
||||||
})],
|
}),
|
||||||
viewCacheCapacity: 5
|
tabTemplate
|
||||||
});
|
]).then( (protoViews) => {
|
||||||
compileRoot(mainDir).then( (pv) => {
|
var views = tb.createRootViews(ListWrapper.slice(protoViews, 0, 2));
|
||||||
var viewRefs = renderer.createInPlaceHostView(null, rootEl, pv.render);
|
var tabProtoView = protoViews[2];
|
||||||
var vcRef0 = new RenderViewContainerRef(viewRefs[2], 0);
|
var tabChildProtoView = tabProtoView.elementBinders[0].nestedProtoView;
|
||||||
var vcRef1 = new RenderViewContainerRef(viewRefs[3], 0);
|
|
||||||
var vcRef2 = new RenderViewContainerRef(viewRefs[4], 0);
|
|
||||||
var mainPv = pv.elementBinders[0].nestedProtoView;
|
|
||||||
var pvRef = mainPv.elementBinders[0].nestedProtoView.elementBinders[0].nestedProtoView.render;
|
|
||||||
|
|
||||||
expect(rootEl).toHaveText('()');
|
var tab1View = tb.createComponentView(views[1].viewRef, 0, tabProtoView);
|
||||||
|
var tab2View = tb.createComponentView(views[1].viewRef, 1, tabProtoView);
|
||||||
|
var tab3View = tb.createComponentView(views[1].viewRef, 2, tabProtoView);
|
||||||
|
|
||||||
renderer.createViewInContainer(vcRef0, 0, pvRef);
|
expect(tb.rootEl).toHaveText('()');
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(TAB(0))');
|
var tabChildView = tb.createViewInContainer(tab1View.viewRef, 0, 0, tabChildProtoView);
|
||||||
|
|
||||||
renderer.destroyViewInContainer(vcRef0, 0);
|
expect(tb.rootEl).toHaveText('(TAB(0))');
|
||||||
renderer.createViewInContainer(vcRef1, 0, pvRef);
|
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(TAB(1))');
|
tb.renderer.dehydrateView(tabChildView.viewRef);
|
||||||
|
tb.renderer.detachViewInContainer(tab1View.viewRef, 0, 0, tabChildView.viewRef);
|
||||||
|
|
||||||
renderer.destroyViewInContainer(vcRef1, 0);
|
tb.renderer.attachViewInContainer(tab2View.viewRef, 0, 0, tabChildView.viewRef);
|
||||||
renderer.createViewInContainer(vcRef2, 0, pvRef);
|
tb.renderer.hydrateView(tabChildView.viewRef);
|
||||||
|
|
||||||
expect(rootEl).toHaveText('(TAB(2))');
|
expect(tb.rootEl).toHaveText('(TAB(1))');
|
||||||
|
|
||||||
|
tb.renderer.dehydrateView(tabChildView.viewRef);
|
||||||
|
tb.renderer.detachViewInContainer(tab2View.viewRef, 0, 0, tabChildView.viewRef);
|
||||||
|
|
||||||
|
tb.renderer.attachViewInContainer(tab3View.viewRef, 0, 0, tabChildView.viewRef);
|
||||||
|
tb.renderer.hydrateView(tabChildView.viewRef);
|
||||||
|
|
||||||
|
expect(tb.rootEl).toHaveText('(TAB(2))');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -444,67 +446,62 @@ var autoViewportDirective = new DirectiveMetadata({
|
||||||
type: DirectiveMetadata.DIRECTIVE_TYPE
|
type: DirectiveMetadata.DIRECTIVE_TYPE
|
||||||
});
|
});
|
||||||
|
|
||||||
var tabGroupComponent = new DirectiveMetadata({
|
|
||||||
selector: 'tab-group',
|
|
||||||
id: 'tab-group',
|
|
||||||
type: DirectiveMetadata.COMPONENT_TYPE
|
|
||||||
});
|
|
||||||
|
|
||||||
var tabComponent = new DirectiveMetadata({
|
var tabComponent = new DirectiveMetadata({
|
||||||
selector: 'tab',
|
selector: 'tab',
|
||||||
id: 'tab',
|
id: 'tab',
|
||||||
type: DirectiveMetadata.COMPONENT_TYPE
|
type: DirectiveMetadata.COMPONENT_TYPE
|
||||||
});
|
});
|
||||||
|
|
||||||
var componentTemplates = [
|
var simpleTemplate = new ViewDefinition({
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'simple',
|
componentId: 'simple',
|
||||||
template: 'SIMPLE(<content></content>)',
|
template: 'SIMPLE(<content></content>)',
|
||||||
directives: []
|
directives: []
|
||||||
}),
|
});
|
||||||
new ViewDefinition({
|
|
||||||
|
var emptyTemplate = new ViewDefinition({
|
||||||
componentId: 'empty',
|
componentId: 'empty',
|
||||||
template: '',
|
template: '',
|
||||||
directives: []
|
directives: []
|
||||||
}),
|
});
|
||||||
new ViewDefinition({
|
|
||||||
|
var multipleContentTagsTemplate = new ViewDefinition({
|
||||||
componentId: 'multiple-content-tags',
|
componentId: 'multiple-content-tags',
|
||||||
template: '(<content select=".left"></content>, <content></content>)',
|
template: '(<content select=".left"></content>, <content></content>)',
|
||||||
directives: []
|
directives: []
|
||||||
}),
|
});
|
||||||
new ViewDefinition({
|
|
||||||
|
var outerWithIndirectNestedTemplate = new ViewDefinition({
|
||||||
componentId: 'outer-with-indirect-nested',
|
componentId: 'outer-with-indirect-nested',
|
||||||
template: 'OUTER(<simple><div><content></content></div></simple>)',
|
template: 'OUTER(<simple><div><content></content></div></simple>)',
|
||||||
directives: [simple]
|
directives: [simple]
|
||||||
}),
|
});
|
||||||
new ViewDefinition({
|
|
||||||
|
var outerTemplate = new ViewDefinition({
|
||||||
componentId: 'outer',
|
componentId: 'outer',
|
||||||
template: 'OUTER(<inner><content></content></inner>)',
|
template: 'OUTER(<inner><content></content></inner>)',
|
||||||
directives: [innerComponent]
|
directives: [innerComponent]
|
||||||
}),
|
});
|
||||||
new ViewDefinition({
|
|
||||||
|
var innerTemplate = new ViewDefinition({
|
||||||
componentId: 'inner',
|
componentId: 'inner',
|
||||||
template: 'INNER(<innerinner><content></content></innerinner>)',
|
template: 'INNER(<innerinner><content></content></innerinner>)',
|
||||||
directives: [innerInnerComponent]
|
directives: [innerInnerComponent]
|
||||||
}),
|
});
|
||||||
new ViewDefinition({
|
|
||||||
|
var innerInnerTemplate = new ViewDefinition({
|
||||||
componentId: 'innerinner',
|
componentId: 'innerinner',
|
||||||
template: 'INNERINNER(<content select=".left"></content>,<content></content>)',
|
template: 'INNERINNER(<content select=".left"></content>,<content></content>)',
|
||||||
directives: []
|
directives: []
|
||||||
}),
|
});
|
||||||
new ViewDefinition({
|
|
||||||
|
var conditionalContentTemplate = new ViewDefinition({
|
||||||
componentId: 'conditional-content',
|
componentId: 'conditional-content',
|
||||||
template: '<div>(<div *auto="cond"><content select=".left"></content></div>, <content></content>)</div>',
|
template: '<div>(<div *auto="cond"><content select=".left"></content></div>, <content></content>)</div>',
|
||||||
directives: [autoViewportDirective]
|
directives: [autoViewportDirective]
|
||||||
}),
|
});
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'tab-group',
|
var tabTemplate = new ViewDefinition({
|
||||||
template: 'GROUP(<content></content>)',
|
|
||||||
directives: []
|
|
||||||
}),
|
|
||||||
new ViewDefinition({
|
|
||||||
componentId: 'tab',
|
componentId: 'tab',
|
||||||
template: '<div><div *auto="cond">TAB(<content></content>)</div></div>',
|
template: '<div><div *auto="cond">TAB(<content></content>)</div></div>',
|
||||||
directives: [autoViewportDirective]
|
directives: [autoViewportDirective]
|
||||||
})
|
});
|
||||||
];
|
|
||||||
|
|
|
@ -1,183 +0,0 @@
|
||||||
import {
|
|
||||||
AsyncTestCompleter,
|
|
||||||
beforeEach,
|
|
||||||
ddescribe,
|
|
||||||
xdescribe,
|
|
||||||
describe,
|
|
||||||
el,
|
|
||||||
dispatchEvent,
|
|
||||||
expect,
|
|
||||||
iit,
|
|
||||||
inject,
|
|
||||||
beforeEachBindings,
|
|
||||||
it,
|
|
||||||
xit,
|
|
||||||
SpyObject, proxy
|
|
||||||
} from 'angular2/test_lib';
|
|
||||||
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
|
|
||||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
|
||||||
import {ViewFactory} from 'angular2/src/render/dom/view/view_factory';
|
|
||||||
import {DomProtoView} from 'angular2/src/render/dom/view/proto_view';
|
|
||||||
import {DomView} from 'angular2/src/render/dom/view/view';
|
|
||||||
import {ElementBinder} from 'angular2/src/render/dom/view/element_binder';
|
|
||||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
|
||||||
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom'
|
|
||||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
describe('RenderViewFactory', () => {
|
|
||||||
var eventManager;
|
|
||||||
var shadowDomStrategy;
|
|
||||||
|
|
||||||
function createViewFactory({capacity}):ViewFactory {
|
|
||||||
return new ViewFactory(capacity, eventManager, shadowDomStrategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createProtoView(rootEl=null, binders=null) {
|
|
||||||
if (isBlank(rootEl)) {
|
|
||||||
rootEl = el('<div></div>');
|
|
||||||
}
|
|
||||||
if (isBlank(binders)) {
|
|
||||||
binders = [];
|
|
||||||
}
|
|
||||||
return new DomProtoView({
|
|
||||||
element: rootEl,
|
|
||||||
elementBinders: binders
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createComponentElBinder(componentId, nestedProtoView = null) {
|
|
||||||
var binder = new ElementBinder({
|
|
||||||
componentId: componentId,
|
|
||||||
textNodeIndices: []
|
|
||||||
});
|
|
||||||
binder.nestedProtoView = nestedProtoView;
|
|
||||||
return binder;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
beforeEach( () => {
|
|
||||||
eventManager = new SpyEventManager();
|
|
||||||
shadowDomStrategy = new SpyShadowDomStrategy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create views without cache', () => {
|
|
||||||
var pv = createProtoView();
|
|
||||||
var vf = createViewFactory({
|
|
||||||
capacity: 0
|
|
||||||
});
|
|
||||||
expect(vf.getView(pv) instanceof DomView).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('caching', () => {
|
|
||||||
|
|
||||||
it('should support multiple RenderProtoViews', () => {
|
|
||||||
var pv1 = createProtoView();
|
|
||||||
var pv2 = createProtoView();
|
|
||||||
var vf = createViewFactory({ capacity: 2 });
|
|
||||||
var view1 = vf.getView(pv1);
|
|
||||||
var view2 = vf.getView(pv2);
|
|
||||||
vf.returnView(view1);
|
|
||||||
vf.returnView(view2);
|
|
||||||
|
|
||||||
expect(vf.getView(pv1)).toBe(view1);
|
|
||||||
expect(vf.getView(pv2)).toBe(view2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reuse the newest view that has been returned', () => {
|
|
||||||
var pv = createProtoView();
|
|
||||||
var vf = createViewFactory({ capacity: 2 });
|
|
||||||
var view1 = vf.getView(pv);
|
|
||||||
var view2 = vf.getView(pv);
|
|
||||||
vf.returnView(view1);
|
|
||||||
vf.returnView(view2);
|
|
||||||
|
|
||||||
expect(vf.getView(pv)).toBe(view2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not add views when the capacity has been reached', () => {
|
|
||||||
var pv = createProtoView();
|
|
||||||
var vf = createViewFactory({ capacity: 2 });
|
|
||||||
var view1 = vf.getView(pv);
|
|
||||||
var view2 = vf.getView(pv);
|
|
||||||
var view3 = vf.getView(pv);
|
|
||||||
vf.returnView(view1);
|
|
||||||
vf.returnView(view2);
|
|
||||||
vf.returnView(view3);
|
|
||||||
|
|
||||||
expect(vf.getView(pv)).toBe(view2);
|
|
||||||
expect(vf.getView(pv)).toBe(view1);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('child components', () => {
|
|
||||||
|
|
||||||
var vf, log;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
vf = createViewFactory({capacity: 1});
|
|
||||||
log = [];
|
|
||||||
shadowDomStrategy.spy('attachTemplate').andCallFake( (el, view) => {
|
|
||||||
ListWrapper.push(log, ['attachTemplate', el, view]);
|
|
||||||
});
|
|
||||||
shadowDomStrategy.spy('constructLightDom').andCallFake( (lightDomView, shadowDomView, el) => {
|
|
||||||
ListWrapper.push(log, ['constructLightDom', lightDomView, shadowDomView, el]);
|
|
||||||
return new SpyLightDom();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create static child component views', () => {
|
|
||||||
var hostPv = createProtoView(el('<div><div class="ng-binding"></div></div>'), [
|
|
||||||
createComponentElBinder(
|
|
||||||
'someComponent',
|
|
||||||
createProtoView()
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
var hostView = vf.getView(hostPv);
|
|
||||||
var shadowView = hostView.componentChildViews[0];
|
|
||||||
expect(shadowView).toBeTruthy();
|
|
||||||
expect(hostView.lightDoms[0]).toBeTruthy();
|
|
||||||
expect(log[0]).toEqual(['constructLightDom', hostView, shadowView, hostView.boundElements[0]]);
|
|
||||||
expect(log[1]).toEqual(['attachTemplate', hostView.boundElements[0], shadowView]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not create dynamic child component views', () => {
|
|
||||||
var hostPv = createProtoView(el('<div><div class="ng-binding"></div></div>'), [
|
|
||||||
createComponentElBinder(
|
|
||||||
'someComponent',
|
|
||||||
null
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
var hostView = vf.getView(hostPv);
|
|
||||||
var shadowView = hostView.componentChildViews[0];
|
|
||||||
expect(shadowView).toBeFalsy();
|
|
||||||
expect(hostView.lightDoms[0]).toBeFalsy();
|
|
||||||
expect(log).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(EventManager)
|
|
||||||
class SpyEventManager extends SpyObject {
|
|
||||||
constructor(){super(EventManager);}
|
|
||||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(ShadowDomStrategy)
|
|
||||||
class SpyShadowDomStrategy extends SpyObject {
|
|
||||||
constructor(){super(ShadowDomStrategy);}
|
|
||||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(LightDom)
|
|
||||||
class SpyLightDom extends SpyObject {
|
|
||||||
constructor(){super(LightDom);}
|
|
||||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
|
||||||
}
|
|
|
@ -1,285 +0,0 @@
|
||||||
import {
|
|
||||||
AsyncTestCompleter,
|
|
||||||
beforeEach,
|
|
||||||
ddescribe,
|
|
||||||
xdescribe,
|
|
||||||
describe,
|
|
||||||
el,
|
|
||||||
dispatchEvent,
|
|
||||||
expect,
|
|
||||||
iit,
|
|
||||||
inject,
|
|
||||||
beforeEachBindings,
|
|
||||||
it,
|
|
||||||
xit,
|
|
||||||
SpyObject, proxy
|
|
||||||
} from 'angular2/test_lib';
|
|
||||||
import {IMPLEMENTS, isBlank, isPresent} from 'angular2/src/facade/lang';
|
|
||||||
|
|
||||||
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 {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
|
||||||
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
|
|
||||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
||||||
import {ViewFactory} from 'angular2/src/render/dom/view/view_factory';
|
|
||||||
import {RenderViewHydrator} from 'angular2/src/render/dom/view/view_hydrator';
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
|
|
||||||
describe('RenderViewHydrator', () => {
|
|
||||||
var shadowDomStrategy;
|
|
||||||
var eventManager;
|
|
||||||
var viewFactory;
|
|
||||||
var viewHydrator;
|
|
||||||
|
|
||||||
function createProtoView({rootEl, binders}={}) {
|
|
||||||
if (isBlank(rootEl)) {
|
|
||||||
rootEl = el('<div></div>');
|
|
||||||
}
|
|
||||||
if (isBlank(binders)) {
|
|
||||||
binders = [];
|
|
||||||
}
|
|
||||||
return new DomProtoView({
|
|
||||||
element: rootEl,
|
|
||||||
elementBinders: binders
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createComponentElBinder(componentId, nestedProtoView = null) {
|
|
||||||
var binder = new ElementBinder({
|
|
||||||
componentId: componentId,
|
|
||||||
textNodeIndices: []
|
|
||||||
});
|
|
||||||
binder.nestedProtoView = nestedProtoView;
|
|
||||||
return binder;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createHostProtoView(nestedProtoView) {
|
|
||||||
return createProtoView({
|
|
||||||
binders: [
|
|
||||||
createComponentElBinder(
|
|
||||||
'someComponent',
|
|
||||||
nestedProtoView
|
|
||||||
)
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createEmptyView() {
|
|
||||||
var root = el('<div><div></div></div>');
|
|
||||||
return new DomView(createProtoView(), [DOM.childNodes(root)[0]],
|
|
||||||
[], [], []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createHostView(pv, shadowDomView) {
|
|
||||||
var view = new DomView(pv, [el('<div></div>')],
|
|
||||||
[], [el('<div></div>')], [null]);
|
|
||||||
ViewFactory.setComponentView(shadowDomStrategy, view, 0, shadowDomView);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hydrate(view) {
|
|
||||||
viewHydrator.hydrateInPlaceHostView(null, view);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dehydrate(view) {
|
|
||||||
viewHydrator.dehydrateInPlaceHostView(null, view);
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach( () => {
|
|
||||||
eventManager = new SpyEventManager();
|
|
||||||
shadowDomStrategy = new SpyShadowDomStrategy();
|
|
||||||
shadowDomStrategy.spy('constructLightDom').andCallFake( (lightDomView, shadowDomView, el) => {
|
|
||||||
return new SpyLightDom();
|
|
||||||
});
|
|
||||||
viewFactory = new SpyViewFactory();
|
|
||||||
viewHydrator = new RenderViewHydrator(eventManager, viewFactory, shadowDomStrategy);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('hydrateDynamicComponentView', () => {
|
|
||||||
|
|
||||||
it('should redistribute', () => {
|
|
||||||
var shadowView = createEmptyView();
|
|
||||||
var hostPv = createHostProtoView(createProtoView());
|
|
||||||
var hostView = createHostView(hostPv, shadowView);
|
|
||||||
viewHydrator.hydrateDynamicComponentView(hostView, 0, shadowView);
|
|
||||||
var lightDomSpy:SpyLightDom = hostView.lightDoms[0];
|
|
||||||
expect(lightDomSpy.spy('redistribute')).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('hydrateInPlaceHostView', () => {
|
|
||||||
|
|
||||||
function createInPlaceHostView() {
|
|
||||||
var hostPv = createHostProtoView(createProtoView());
|
|
||||||
var shadowView = createEmptyView();
|
|
||||||
return createHostView(hostPv, shadowView);
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should hydrate the view', () => {
|
|
||||||
var hostView = createInPlaceHostView();
|
|
||||||
viewHydrator.hydrateInPlaceHostView(null, hostView);
|
|
||||||
|
|
||||||
expect(hostView.hydrated).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should store the view in the parent view', () => {
|
|
||||||
var parentView = createEmptyView();
|
|
||||||
var hostView = createInPlaceHostView();
|
|
||||||
|
|
||||||
viewHydrator.hydrateInPlaceHostView(parentView, hostView);
|
|
||||||
|
|
||||||
expect(parentView.imperativeHostViews).toEqual([hostView]);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('dehydrateInPlaceHostView', () => {
|
|
||||||
|
|
||||||
function createAndHydrateInPlaceHostView(parentView) {
|
|
||||||
var hostPv = createHostProtoView(createProtoView());
|
|
||||||
var shadowView = createEmptyView();
|
|
||||||
var hostView = createHostView(hostPv, shadowView);
|
|
||||||
viewHydrator.hydrateInPlaceHostView(parentView, hostView);
|
|
||||||
return hostView;
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should clear the host view', () => {
|
|
||||||
var parentView = createEmptyView();
|
|
||||||
var hostView = createAndHydrateInPlaceHostView(parentView);
|
|
||||||
|
|
||||||
var rootNodes = hostView.rootNodes;
|
|
||||||
expect(rootNodes[0].parentNode).toBeTruthy();
|
|
||||||
|
|
||||||
viewHydrator.dehydrateInPlaceHostView(parentView, hostView);
|
|
||||||
|
|
||||||
expect(parentView.imperativeHostViews).toEqual([]);
|
|
||||||
expect(rootNodes[0].parentNode).toBeFalsy();
|
|
||||||
expect(hostView.rootNodes).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('hydrate... shared functionality', () => {
|
|
||||||
|
|
||||||
it('should hydrate existing child components', () => {
|
|
||||||
var hostPv = createHostProtoView(createProtoView());
|
|
||||||
var shadowView = createEmptyView();
|
|
||||||
createHostView(hostPv, shadowView);
|
|
||||||
|
|
||||||
hydrate(shadowView);
|
|
||||||
|
|
||||||
expect(shadowView.hydrated).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('dehydrate... shared functionality', () => {
|
|
||||||
var hostView;
|
|
||||||
|
|
||||||
function createAndHydrate(nestedProtoView, shadowView, imperativeHostView = null) {
|
|
||||||
var hostPv = createHostProtoView(nestedProtoView);
|
|
||||||
hostView = createHostView(hostPv, shadowView);
|
|
||||||
if (isPresent(imperativeHostView)) {
|
|
||||||
viewHydrator.hydrateInPlaceHostView(hostView, imperativeHostView);
|
|
||||||
}
|
|
||||||
|
|
||||||
hydrate(hostView);
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should dehydrate child components', () => {
|
|
||||||
var shadowView = createEmptyView();
|
|
||||||
createAndHydrate(createProtoView(), shadowView);
|
|
||||||
|
|
||||||
expect(shadowView.hydrated).toBe(true);
|
|
||||||
dehydrate(hostView);
|
|
||||||
|
|
||||||
expect(shadowView.hydrated).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not clear static child components', () => {
|
|
||||||
var shadowView = createEmptyView();
|
|
||||||
createAndHydrate(createProtoView(), shadowView);
|
|
||||||
dehydrate(hostView);
|
|
||||||
|
|
||||||
expect(hostView.componentChildViews[0]).toBe(shadowView);
|
|
||||||
expect(shadowView.rootNodes[0].parentNode).toBeTruthy();
|
|
||||||
expect(viewFactory.spy('returnView')).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should clear dynamic child components', () => {
|
|
||||||
var shadowView = createEmptyView();
|
|
||||||
createAndHydrate(null, shadowView);
|
|
||||||
expect(shadowView.rootNodes[0].parentNode).toBeTruthy();
|
|
||||||
|
|
||||||
dehydrate(hostView);
|
|
||||||
|
|
||||||
expect(hostView.componentChildViews[0]).toBe(null);
|
|
||||||
expect(shadowView.rootNodes[0].parentNode).toBe(null);
|
|
||||||
expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(shadowView);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should clear views in ViewContainers', () => {
|
|
||||||
createAndHydrate(null, null);
|
|
||||||
var vc = hostView.getOrCreateViewContainer(0);
|
|
||||||
var childView = createEmptyView();
|
|
||||||
vc.insert(childView);
|
|
||||||
|
|
||||||
dehydrate(hostView);
|
|
||||||
|
|
||||||
expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(childView);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should clear imperatively added child components', () => {
|
|
||||||
var shadowView = createEmptyView();
|
|
||||||
createAndHydrate(createProtoView(), shadowView);
|
|
||||||
var impHostView = createHostView(createHostProtoView(createProtoView()), createEmptyView());
|
|
||||||
shadowView.imperativeHostViews = [impHostView];
|
|
||||||
|
|
||||||
var rootNodes = impHostView.rootNodes;
|
|
||||||
expect(rootNodes[0].parentNode).toBeTruthy();
|
|
||||||
|
|
||||||
dehydrate(hostView);
|
|
||||||
|
|
||||||
expect(shadowView.imperativeHostViews).toEqual([]);
|
|
||||||
expect(impHostView.rootNodes).toEqual([]);
|
|
||||||
expect(rootNodes[0].parentNode).toBeFalsy();
|
|
||||||
expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(impHostView);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(EventManager)
|
|
||||||
class SpyEventManager extends SpyObject {
|
|
||||||
constructor(){super(EventManager);}
|
|
||||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(ShadowDomStrategy)
|
|
||||||
class SpyShadowDomStrategy extends SpyObject {
|
|
||||||
constructor(){super(ShadowDomStrategy);}
|
|
||||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(LightDom)
|
|
||||||
class SpyLightDom extends SpyObject {
|
|
||||||
constructor(){super(LightDom);}
|
|
||||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
|
||||||
}
|
|
||||||
|
|
||||||
@proxy
|
|
||||||
@IMPLEMENTS(ViewFactory)
|
|
||||||
class SpyViewFactory extends SpyObject {
|
|
||||||
constructor(){super(ViewFactory);}
|
|
||||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
|
||||||
}
|
|
|
@ -20,7 +20,6 @@ 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 {ViewContainer} from 'angular2/src/render/dom/view/view_container';
|
|
||||||
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
|
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
|
||||||
|
@ -82,21 +81,6 @@ export function main() {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getOrCreateViewContainer', () => {
|
|
||||||
it('should create a new container', () => {
|
|
||||||
var pv = createProtoView([new ElementBinder()]);
|
|
||||||
var view = createView(pv, 1);
|
|
||||||
expect(view.getOrCreateViewContainer(0) instanceof ViewContainer).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an existing container', () => {
|
|
||||||
var pv = createProtoView([new ElementBinder()]);
|
|
||||||
var view = createView(pv, 1);
|
|
||||||
var vc = view.getOrCreateViewContainer(0);
|
|
||||||
expect(view.getOrCreateViewContainer(0)).toBe(vc);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {View} from 'angular2/src/core/annotations_impl/view';
|
||||||
// TODO(jelbourn): Pre-built `alert` and `confirm` dialogs.
|
// TODO(jelbourn): Pre-built `alert` and `confirm` dialogs.
|
||||||
// TODO(jelbourn): Animate dialog out of / into opening element.
|
// TODO(jelbourn): Animate dialog out of / into opening element.
|
||||||
|
|
||||||
|
var _nextDialogId = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for opening modal dialogs.
|
* Service for opening modal dialogs.
|
||||||
|
@ -49,7 +50,7 @@ export class MdDialog {
|
||||||
// TODO(jelbourn): Don't use direct DOM access. Need abstraction to create an element
|
// TODO(jelbourn): Don't use direct DOM access. Need abstraction to create an element
|
||||||
// directly on the document body (also needed for web workers stuff).
|
// directly on the document body (also needed for web workers stuff).
|
||||||
// Create a DOM node to serve as a physical host element for the dialog.
|
// Create a DOM node to serve as a physical host element for the dialog.
|
||||||
var dialogElement = DOM.createElement('div');
|
var dialogElement = this._createHostElement();
|
||||||
DOM.appendChild(DOM.query('body'), dialogElement);
|
DOM.appendChild(DOM.query('body'), dialogElement);
|
||||||
|
|
||||||
// TODO(jelbourn): Use hostProperties binding to set these once #1539 is fixed.
|
// TODO(jelbourn): Use hostProperties binding to set these once #1539 is fixed.
|
||||||
|
@ -75,7 +76,7 @@ export class MdDialog {
|
||||||
|
|
||||||
// First, load the MdDialogContainer, into which the given component will be loaded.
|
// First, load the MdDialogContainer, into which the given component will be loaded.
|
||||||
return this.componentLoader.loadIntoNewLocation(
|
return this.componentLoader.loadIntoNewLocation(
|
||||||
MdDialogContainer, elementRef, dialogElement).then(containerRef => {
|
MdDialogContainer, elementRef, `:document#${dialogElement.id}`).then(containerRef => {
|
||||||
dialogRef.containerRef = containerRef;
|
dialogRef.containerRef = containerRef;
|
||||||
|
|
||||||
// Now load the given component into the MdDialogContainer.
|
// Now load the given component into the MdDialogContainer.
|
||||||
|
@ -101,12 +102,18 @@ export class MdDialog {
|
||||||
|
|
||||||
/** Loads the dialog backdrop (transparent overlay over the rest of the page). */
|
/** Loads the dialog backdrop (transparent overlay over the rest of the page). */
|
||||||
_openBackdrop(elementRef:ElementRef, injector: Injector): Promise<ComponentRef> {
|
_openBackdrop(elementRef:ElementRef, injector: Injector): Promise<ComponentRef> {
|
||||||
var backdropElement = DOM.createElement('div');
|
var backdropElement = this._createHostElement();
|
||||||
DOM.addClass(backdropElement, 'md-backdrop');
|
DOM.addClass(backdropElement, 'md-backdrop');
|
||||||
DOM.appendChild(DOM.query('body'), backdropElement);
|
DOM.appendChild(DOM.query('body'), backdropElement);
|
||||||
|
|
||||||
return this.componentLoader.loadIntoNewLocation(
|
return this.componentLoader.loadIntoNewLocation(
|
||||||
MdBackdrop, elementRef, backdropElement, injector);
|
MdBackdrop, elementRef, `:document#${backdropElement.id}`, injector);
|
||||||
|
}
|
||||||
|
|
||||||
|
_createHostElement() {
|
||||||
|
var hostElement = DOM.createElement('div');
|
||||||
|
hostElement.id = `mdDialog${_nextDialogId++}`;
|
||||||
|
return hostElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
alert(message: string, okMessage: string): Promise {
|
alert(message: string, okMessage: string): Promise {
|
||||||
|
|
|
@ -16,13 +16,11 @@ import {getIntParameter, getStringParameter, bindAction} from 'angular2/src/test
|
||||||
import {If} from 'angular2/directives';
|
import {If} from 'angular2/directives';
|
||||||
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
||||||
import {APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
|
import {APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
|
||||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
|
||||||
import {bind} from 'angular2/di';
|
import {bind} from 'angular2/di';
|
||||||
|
|
||||||
function createBindings():List {
|
function createBindings():List {
|
||||||
var viewCacheCapacity = getStringParameter('viewcache') == 'true' ? 10000 : 1;
|
var viewCacheCapacity = getStringParameter('viewcache') == 'true' ? 10000 : 1;
|
||||||
return [
|
return [
|
||||||
bind(rvf.VIEW_POOL_CAPACITY).toValue(viewCacheCapacity),
|
|
||||||
bind(APP_VIEW_POOL_CAPACITY).toValue(viewCacheCapacity)
|
bind(APP_VIEW_POOL_CAPACITY).toValue(viewCacheCapacity)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue