refactor(render): use render layer fully
Introduces angular2/src/core/compiler/ViewFactory which extracts ProtoView.instantiate and replaces ViewPool. Note: This is a work in progress commit to unblock other commits. There will be follow ups to add unit tests, remove TODOs, …
This commit is contained in:
parent
de581ea8b3
commit
50098767fc
|
@ -8,6 +8,8 @@ module.exports = function(config) {
|
|||
frameworks: ['dart-unittest'],
|
||||
|
||||
files: [
|
||||
// Init and configure guiness.
|
||||
{pattern: 'test-init.dart', included: true},
|
||||
// Unit test files needs to be included.
|
||||
// Karma-dart generates `__adapter_unittest.dart` that imports these files.
|
||||
{pattern: 'modules/*/test/**/*_spec.js', included: true},
|
||||
|
|
|
@ -14,5 +14,5 @@ export * from './src/core/compiler/private_component_location';
|
|||
export * from './src/core/compiler/view';
|
||||
export * from './src/core/compiler/view_container';
|
||||
|
||||
export * from './src/core/dom/element';
|
||||
export * from './src/core/compiler/ng_element';
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@ import {ExceptionHandler} from './exception_handler';
|
|||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {TemplateResolver} from './compiler/template_resolver';
|
||||
import {DirectiveMetadataReader} from './compiler/directive_metadata_reader';
|
||||
import {DirectiveBinding} from './compiler/element_injector';
|
||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
|
||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||
import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import {XHR} from 'angular2/src/services/xhr';
|
||||
import {XHRImpl} from 'angular2/src/services/xhr_impl';
|
||||
import {EventManager, DomEventsPlugin} from 'angular2/src/render/dom/events/event_manager';
|
||||
|
@ -27,6 +27,13 @@ import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
|||
import {Component} from 'angular2/src/core/annotations/annotations';
|
||||
import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader';
|
||||
import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/testability';
|
||||
import {ViewFactory, VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_factory';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
||||
|
||||
import {
|
||||
appViewToken,
|
||||
appChangeDetectorToken,
|
||||
|
@ -60,7 +67,7 @@ function _injectorBindings(appComponentType): List<Binding> {
|
|||
return element;
|
||||
}, [appComponentAnnotatedTypeToken, appDocumentToken]),
|
||||
bind(appViewToken).toAsyncFactory((changeDetection, compiler, injector, appElement,
|
||||
appComponentAnnotatedType, strategy, eventManager, testability, registry) => {
|
||||
appComponentAnnotatedType, testability, registry, viewFactory) => {
|
||||
|
||||
// We need to do this here to ensure that we create Testability and
|
||||
// it's ready on the window for users.
|
||||
|
@ -73,18 +80,18 @@ function _injectorBindings(appComponentType): List<Binding> {
|
|||
}
|
||||
return compiler.compileRoot(
|
||||
appElement,
|
||||
DirectiveBinding.createFromType(appComponentAnnotatedType.type, appComponentAnnotatedType.annotation)
|
||||
appComponentAnnotatedType.type
|
||||
).then(
|
||||
(appProtoView) => {
|
||||
// The light Dom of the app element is not considered part of
|
||||
// the angular application. Thus the context and lightDomInjector are
|
||||
// empty.
|
||||
var view = appProtoView.instantiate(null, eventManager);
|
||||
view.hydrate(injector, null, null, new Object(), null);
|
||||
var view = viewFactory.getView(appProtoView);
|
||||
view.hydrate(injector, null, new Object(), null);
|
||||
return view;
|
||||
});
|
||||
}, [ChangeDetection, Compiler, Injector, appElementToken, appComponentAnnotatedTypeToken,
|
||||
ShadowDomStrategy, EventManager, Testability, TestabilityRegistry]),
|
||||
Testability, TestabilityRegistry, ViewFactory]),
|
||||
|
||||
bind(appChangeDetectorToken).toFactory((rootView) => rootView.changeDetector,
|
||||
[appViewToken]),
|
||||
|
@ -98,6 +105,23 @@ function _injectorBindings(appComponentType): List<Binding> {
|
|||
bind(ShadowDomStrategy).toFactory(
|
||||
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
||||
[StyleUrlResolver, appDocumentToken]),
|
||||
bind(Renderer).toClass(DirectDomRenderer),
|
||||
bind(rc.Compiler).toClass(rc.DefaultCompiler),
|
||||
// TODO(tbosch): We need an explicit factory here, as
|
||||
// we are getting errors in dart2js with mirrors...
|
||||
bind(rvf.ViewFactory).toFactory(
|
||||
(capacity, eventManager, shadowDomStrategy) => new rvf.ViewFactory(capacity, eventManager, shadowDomStrategy),
|
||||
[rvf.VIEW_POOL_CAPACITY, EventManager, ShadowDomStrategy]
|
||||
),
|
||||
bind(rvf.VIEW_POOL_CAPACITY).toValue(100000),
|
||||
ProtoViewFactory,
|
||||
// TODO(tbosch): We need an explicit factory here, as
|
||||
// we are getting errors in dart2js with mirrors...
|
||||
bind(ViewFactory).toFactory(
|
||||
(capacity) => new ViewFactory(capacity),
|
||||
[VIEW_POOL_CAPACITY]
|
||||
),
|
||||
bind(VIEW_POOL_CAPACITY).toValue(100000),
|
||||
Compiler,
|
||||
CompilerCache,
|
||||
TemplateResolver,
|
||||
|
|
|
@ -3,24 +3,16 @@ import {Type, isBlank, isPresent, BaseException, normalizeBlank, stringify} from
|
|||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
import {ChangeDetection, Parser} from 'angular2/change_detection';
|
||||
|
||||
import {DirectiveMetadataReader} from './directive_metadata_reader';
|
||||
import {Component, Viewport, DynamicComponent, Decorator} from '../annotations/annotations';
|
||||
import {ProtoView} from './view';
|
||||
import {DirectiveBinding} from './element_injector';
|
||||
import {TemplateResolver} from './template_resolver';
|
||||
import {Template} from '../annotations/template';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {ComponentUrlMapper} from './component_url_mapper';
|
||||
import {ProtoViewFactory} from './proto_view_factory';
|
||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {DefaultStepFactory} from 'angular2/src/render/dom/compiler/compile_step_factory';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
import * as renderApi from 'angular2/src/render/api';
|
||||
|
||||
/**
|
||||
|
@ -49,9 +41,7 @@ export class CompilerCache {
|
|||
}
|
||||
|
||||
|
||||
// TODO(tbosch): rename this class to Compiler
|
||||
// and remove the current Compiler when core uses the render views.
|
||||
export class NewCompiler {
|
||||
export class Compiler {
|
||||
_reader: DirectiveMetadataReader;
|
||||
_compilerCache:CompilerCache;
|
||||
_compiling:Map<Type, Promise>;
|
||||
|
@ -80,19 +70,19 @@ export class NewCompiler {
|
|||
this._protoViewFactory = protoViewFactory;
|
||||
}
|
||||
|
||||
_bindDirective(directive) {
|
||||
var meta = this._reader.read(directive);
|
||||
_bindDirective(directiveTypeOrBinding) {
|
||||
if (directiveTypeOrBinding instanceof DirectiveBinding) {
|
||||
return directiveTypeOrBinding;
|
||||
}
|
||||
var meta = this._reader.read(directiveTypeOrBinding);
|
||||
return DirectiveBinding.createFromType(meta.type, meta.annotation);
|
||||
}
|
||||
|
||||
// Create a rootView as if the compiler encountered <rootcmp></rootcmp>.
|
||||
// Used for bootstrapping.
|
||||
compileRoot(elementOrSelector, componentBinding:DirectiveBinding):Promise<ProtoView> {
|
||||
compileRoot(elementOrSelector, componentTypeOrBinding:any):Promise<ProtoView> {
|
||||
return this._renderer.createRootProtoView(elementOrSelector, 'root').then( (rootRenderPv) => {
|
||||
return this._compileNestedProtoViews(null, rootRenderPv, [componentBinding], true)
|
||||
}).then( (rootProtoView) => {
|
||||
rootProtoView.instantiateInPlace = true;
|
||||
return rootProtoView;
|
||||
return this._compileNestedProtoViews(null, rootRenderPv, [this._bindDirective(componentTypeOrBinding)], true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -266,40 +256,3 @@ export class NewCompiler {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO(tbosch): delete this class once we use the render views
|
||||
/**
|
||||
* The compiler loads and translates the html templates of components into
|
||||
* nested ProtoViews. To decompose its functionality it uses
|
||||
* the render compiler.
|
||||
*
|
||||
* @publicModule angular2/template
|
||||
*/
|
||||
@Injectable()
|
||||
export class Compiler extends NewCompiler {
|
||||
constructor(changeDetection:ChangeDetection,
|
||||
templateLoader:TemplateLoader,
|
||||
reader: DirectiveMetadataReader,
|
||||
parser:Parser,
|
||||
cache:CompilerCache,
|
||||
shadowDomStrategy: ShadowDomStrategy,
|
||||
templateResolver: TemplateResolver,
|
||||
componentUrlMapper: ComponentUrlMapper,
|
||||
urlResolver: UrlResolver) {
|
||||
super(
|
||||
reader,
|
||||
cache,
|
||||
templateResolver,
|
||||
componentUrlMapper,
|
||||
urlResolver,
|
||||
new DirectDomRenderer(
|
||||
new rc.Compiler(
|
||||
new DefaultStepFactory(parser, shadowDomStrategy.render),
|
||||
templateLoader
|
||||
),
|
||||
null, shadowDomStrategy.render
|
||||
),
|
||||
new ProtoViewFactory(changeDetection, shadowDomStrategy)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,8 @@ export class ElementBinder {
|
|||
protoElementInjector:eiModule.ProtoElementInjector;
|
||||
componentDirective:DirectiveBinding;
|
||||
viewportDirective:DirectiveBinding;
|
||||
textNodeIndices:List<int>;
|
||||
hasElementPropertyBindings:boolean;
|
||||
nestedProtoView: viewModule.ProtoView;
|
||||
events:StringMap;
|
||||
contentTagSelector:string;
|
||||
parent:ElementBinder;
|
||||
index:int;
|
||||
distanceToParent:int;
|
||||
|
@ -32,13 +29,7 @@ export class ElementBinder {
|
|||
this.distanceToParent = distanceToParent;
|
||||
// updated later when events are bound
|
||||
this.events = null;
|
||||
// updated later when text nodes are bound
|
||||
this.textNodeIndices = null;
|
||||
// updated later when element properties are bound
|
||||
this.hasElementPropertyBindings = false;
|
||||
// updated later, so we are able to resolve cycles
|
||||
this.nestedProtoView = null;
|
||||
// updated later in the compilation pipeline
|
||||
this.contentTagSelector = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,10 @@ import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
|
|||
import {EventEmitter, PropertySetter, Attribute} from 'angular2/src/core/annotations/di';
|
||||
import * as viewModule from 'angular2/src/core/compiler/view';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {NgElement} from 'angular2/src/core/compiler/ng_element';
|
||||
import {Directive, onChange, onDestroy, onAllChangesDone} from 'angular2/src/core/annotations/annotations';
|
||||
import {BindingPropagationConfig} from 'angular2/change_detection';
|
||||
import * as pclModule from 'angular2/src/core/compiler/private_component_location';
|
||||
import {setterFactory} from 'angular2/src/render/dom/view/property_setter_factory';
|
||||
|
||||
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
||||
|
||||
|
@ -268,8 +267,8 @@ export class ProtoElementInjector {
|
|||
}
|
||||
}
|
||||
|
||||
instantiate(parent:ElementInjector, host:ElementInjector):ElementInjector {
|
||||
return new ElementInjector(this, parent, host);
|
||||
instantiate(parent:ElementInjector):ElementInjector {
|
||||
return new ElementInjector(this, parent);
|
||||
}
|
||||
|
||||
directParent(): ProtoElementInjector {
|
||||
|
@ -339,21 +338,12 @@ export class ElementInjector extends TreeNode {
|
|||
_privateComponent;
|
||||
_privateComponentBinding:DirectiveBinding;
|
||||
|
||||
constructor(proto:ProtoElementInjector, parent:ElementInjector, host:ElementInjector) {
|
||||
constructor(proto:ProtoElementInjector, parent:ElementInjector) {
|
||||
super(parent);
|
||||
if (isPresent(parent) && isPresent(host)) {
|
||||
throw new BaseException('Only either parent or host is allowed');
|
||||
}
|
||||
this._host = null; // needed to satisfy Dart
|
||||
if (isPresent(parent)) {
|
||||
this._host = parent._host;
|
||||
} else {
|
||||
this._host = host;
|
||||
}
|
||||
|
||||
this._proto = proto;
|
||||
|
||||
//we cannot call clearDirectives because fields won't be detected
|
||||
this._host = null;
|
||||
this._preBuiltObjects = null;
|
||||
this._lightDomAppInjector = null;
|
||||
this._shadowDomAppInjector = null;
|
||||
|
@ -371,6 +361,7 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
|
||||
clearDirectives() {
|
||||
this._host = null;
|
||||
this._preBuiltObjects = null;
|
||||
this._lightDomAppInjector = null;
|
||||
this._shadowDomAppInjector = null;
|
||||
|
@ -406,7 +397,8 @@ export class ElementInjector extends TreeNode {
|
|||
this._constructionCounter = 0;
|
||||
}
|
||||
|
||||
instantiateDirectives(lightDomAppInjector:Injector, shadowDomAppInjector:Injector, preBuiltObjects:PreBuiltObjects) {
|
||||
instantiateDirectives(lightDomAppInjector:Injector, host:ElementInjector, shadowDomAppInjector:Injector, preBuiltObjects:PreBuiltObjects) {
|
||||
this._host = host;
|
||||
this._checkShadowDomAppInjector(shadowDomAppInjector);
|
||||
|
||||
this._preBuiltObjects = preBuiltObjects;
|
||||
|
@ -456,10 +448,6 @@ export class ElementInjector extends TreeNode {
|
|||
return pb !== _undefined && isPresent(pb);
|
||||
}
|
||||
|
||||
forElement(el):boolean {
|
||||
return this._preBuiltObjects.element.domElement === el;
|
||||
}
|
||||
|
||||
/** Gets the NgElement associated with this ElementInjector */
|
||||
getNgElement() {
|
||||
return this._preBuiltObjects.element;
|
||||
|
@ -538,6 +526,10 @@ export class ElementInjector extends TreeNode {
|
|||
return obj;
|
||||
}
|
||||
|
||||
getBoundElementIndex() {
|
||||
return this._proto.index;
|
||||
}
|
||||
|
||||
_getByDependency(dep:DirectiveDependency, requestor:Key) {
|
||||
if (isPresent(dep.eventEmitterName)) return this._buildEventEmitter(dep);
|
||||
if (isPresent(dep.propSetterName)) return this._buildPropSetter(dep);
|
||||
|
@ -553,10 +545,12 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
|
||||
_buildPropSetter(dep) {
|
||||
var ngElement = this._getPreBuiltObjectByKeyId(StaticKeys.instance().ngElementId);
|
||||
var domElement = ngElement.domElement;
|
||||
var setter = setterFactory(dep.propSetterName);
|
||||
return function(v) { setter(domElement, v) };
|
||||
var view = this._getPreBuiltObjectByKeyId(StaticKeys.instance().viewId);
|
||||
var renderer = view.proto.renderer;
|
||||
var index = this._proto.index;
|
||||
return function(v) {
|
||||
renderer.setElementProperty(view.render, index, dep.propSetterName, v);
|
||||
};
|
||||
}
|
||||
|
||||
_buildAttribute(dep): string {
|
||||
|
@ -582,7 +576,6 @@ export class ElementInjector extends TreeNode {
|
|||
*/
|
||||
_getByKey(key:Key, depth:number, optional:boolean, requestor:Key) {
|
||||
var ei = this;
|
||||
|
||||
if (! this._shouldIncludeSelf(depth)) {
|
||||
depth -= ei._proto.distanceToParent;
|
||||
ei = ei._parent;
|
||||
|
@ -631,7 +624,7 @@ export class ElementInjector extends TreeNode {
|
|||
if (keyId === staticKeys.bindingPropagationConfigId) return this._preBuiltObjects.bindingPropagationConfig;
|
||||
|
||||
if (keyId === staticKeys.privateComponentLocationId) {
|
||||
return new pclModule.PrivateComponentLocation(this, this._preBuiltObjects.element, this._preBuiltObjects.view);
|
||||
return new pclModule.PrivateComponentLocation(this, this._preBuiltObjects.view);
|
||||
}
|
||||
|
||||
//TODO add other objects as needed
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {normalizeBlank} from 'angular2/src/facade/lang';
|
||||
import * as viewModule from '../compiler/view';
|
||||
import {DirectDomViewRef} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
|
||||
/**
|
||||
* Allows direct access to the underlying DOM element.
|
||||
*
|
||||
* Attention: NgElement will be replaced by a different concept
|
||||
* for accessing an element in a way that is compatible with the render layer.
|
||||
*
|
||||
* @publicModule angular2/angular2
|
||||
*/
|
||||
export class NgElement {
|
||||
_view:viewModule.View;
|
||||
_boundElementIndex:number;
|
||||
|
||||
constructor(view, boundElementIndex) {
|
||||
this._view = view;
|
||||
this._boundElementIndex = boundElementIndex;
|
||||
}
|
||||
|
||||
// TODO(tbosch): Here we expose the real DOM element.
|
||||
// We need a more general way to read/write to the DOM element
|
||||
// via a proper abstraction in the render layer
|
||||
get domElement() {
|
||||
var domViewRef:DirectDomViewRef = this._view.render;
|
||||
return domViewRef.delegate.boundElements[this._boundElementIndex];
|
||||
}
|
||||
|
||||
getAttribute(name:string) {
|
||||
return normalizeBlank(DOM.getAttribute(this.domElement, name));
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import {Compiler} from './compiler';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {ViewFactory} from './view_factory';
|
||||
import {Injectable} from 'angular2/di';
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {Component} from 'angular2/src/core/annotations/annotations';
|
||||
import {PrivateComponentLocation} from './private_component_location';
|
||||
|
@ -11,17 +10,14 @@ import {Type, stringify, BaseException} from 'angular2/src/facade/lang';
|
|||
@Injectable()
|
||||
export class PrivateComponentLoader {
|
||||
compiler:Compiler;
|
||||
shadowDomStrategy:ShadowDomStrategy;
|
||||
eventManager:EventManager;
|
||||
directiveMetadataReader:DirectiveMetadataReader;
|
||||
viewFactory:ViewFactory;
|
||||
|
||||
constructor(compiler:Compiler, shadowDomStrategy:ShadowDomStrategy,
|
||||
eventManager:EventManager, directiveMetadataReader:DirectiveMetadataReader) {
|
||||
constructor(compiler:Compiler, directiveMetadataReader:DirectiveMetadataReader, viewFactory:ViewFactory) {
|
||||
|
||||
this.compiler = compiler;
|
||||
this.shadowDomStrategy = shadowDomStrategy;
|
||||
this.eventManager = eventManager;
|
||||
this.directiveMetadataReader = directiveMetadataReader;
|
||||
this.viewFactory = viewFactory;
|
||||
}
|
||||
|
||||
load(type:Type, location:PrivateComponentLocation) {
|
||||
|
@ -33,10 +29,10 @@ export class PrivateComponentLoader {
|
|||
|
||||
return this.compiler.compile(type).then((componentProtoView) => {
|
||||
location.createComponent(
|
||||
this.viewFactory,
|
||||
type, annotation,
|
||||
componentProtoView,
|
||||
this.eventManager,
|
||||
this.shadowDomStrategy);
|
||||
componentProtoView
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,28 @@
|
|||
import {Directive} from 'angular2/src/core/annotations/annotations'
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import * as viewModule from './view';
|
||||
import * as eiModule from './element_injector';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
|
||||
import * as vfModule from './view_factory';
|
||||
|
||||
export class PrivateComponentLocation {
|
||||
_elementInjector:eiModule.ElementInjector;
|
||||
_elt:NgElement;
|
||||
_view:viewModule.View;
|
||||
|
||||
constructor(elementInjector:eiModule.ElementInjector, elt:NgElement, view:viewModule.View){
|
||||
constructor(elementInjector:eiModule.ElementInjector, view:viewModule.View){
|
||||
this._elementInjector = elementInjector;
|
||||
this._elt = elt;
|
||||
this._view = view;
|
||||
}
|
||||
|
||||
createComponent(type:Type, annotation:Directive, componentProtoView:viewModule.ProtoView,
|
||||
eventManager:EventManager, shadowDomStrategy:ShadowDomStrategy) {
|
||||
createComponent(viewFactory: vfModule.ViewFactory, type:Type, annotation:Directive, componentProtoView:viewModule.ProtoView) {
|
||||
var context = this._elementInjector.createPrivateComponent(type, annotation);
|
||||
|
||||
var view = componentProtoView.instantiate(this._elementInjector, eventManager);
|
||||
view.hydrate(this._elementInjector.getShadowDomAppInjector(), this._elementInjector, null, context, null);
|
||||
|
||||
shadowDomStrategy.attachTemplate(this._elt.domElement, view);
|
||||
var view = viewFactory.getView(componentProtoView);
|
||||
view.hydrate(this._elementInjector.getShadowDomAppInjector(), this._elementInjector, context, null);
|
||||
|
||||
this._view.proto.renderer.setDynamicComponentView(
|
||||
this._view.render, this._elementInjector.getBoundElementIndex(), view.render
|
||||
);
|
||||
ListWrapper.push(this._view.componentChildViews, view);
|
||||
this._view.changeDetector.addChild(view.changeDetector);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import {Injectable} from 'angular2/di';
|
||||
import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
|
||||
import {ChangeDetection} from 'angular2/change_detection';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {Component, Viewport, DynamicComponent} from '../annotations/annotations';
|
||||
|
||||
import * as renderApi from 'angular2/src/render/api';
|
||||
import {DirectDomProtoViewRef} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import {ProtoView} from './view';
|
||||
import {ProtoElementInjector, DirectiveBinding} from './element_injector';
|
||||
|
||||
@Injectable()
|
||||
export class ProtoViewFactory {
|
||||
_changeDetection:ChangeDetection;
|
||||
_shadowDomStrategy:ShadowDomStrategy;
|
||||
_renderer:renderApi.Renderer;
|
||||
|
||||
constructor(changeDetection, shadowDomStrategy) {
|
||||
constructor(changeDetection:ChangeDetection, renderer:renderApi.Renderer) {
|
||||
this._changeDetection = changeDetection;
|
||||
this._shadowDomStrategy = shadowDomStrategy;
|
||||
this._renderer = renderer;
|
||||
}
|
||||
|
||||
createProtoView(componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoView, directives:List<DirectiveBinding>):ProtoView {
|
||||
|
@ -30,13 +30,10 @@ export class ProtoViewFactory {
|
|||
'dummy', componentAnnotation.changeDetection
|
||||
);
|
||||
}
|
||||
var domProtoView = this._getDomProtoView(renderProtoView.render);
|
||||
var protoView = new ProtoView(renderProtoView.render, domProtoView.element, protoChangeDetector,
|
||||
this._shadowDomStrategy, null);
|
||||
var protoView = new ProtoView(this._renderer, renderProtoView.render, protoChangeDetector);
|
||||
|
||||
for (var i=0; i<renderProtoView.elementBinders.length; i++) {
|
||||
var renderElementBinder = renderProtoView.elementBinders[i];
|
||||
var domElementBinder = domProtoView.elementBinders[i];
|
||||
var sortedDirectives = new SortedDirectives(renderElementBinder.directives, directives);
|
||||
var parentPeiWithDistance = this._findParentProtoElementInjectorWithDistance(
|
||||
i, protoView.elementBinders, renderProtoView.elementBinders
|
||||
|
@ -46,7 +43,7 @@ export class ProtoViewFactory {
|
|||
sortedDirectives, renderElementBinder
|
||||
);
|
||||
this._createElementBinder(
|
||||
protoView, renderElementBinder, domElementBinder, protoElementInjector, sortedDirectives
|
||||
protoView, renderElementBinder, protoElementInjector, sortedDirectives
|
||||
);
|
||||
this._createDirectiveBinders(protoView, sortedDirectives);
|
||||
}
|
||||
|
@ -56,11 +53,6 @@ export class ProtoViewFactory {
|
|||
return protoView;
|
||||
}
|
||||
|
||||
// This method is needed to make DartAnalyzer happy
|
||||
_getDomProtoView(protoViewRef: DirectDomProtoViewRef) {
|
||||
return protoViewRef.delegate;
|
||||
}
|
||||
|
||||
_findParentProtoElementInjectorWithDistance(binderIndex, elementBinders, renderElementBinders) {
|
||||
var distance = 0;
|
||||
do {
|
||||
|
@ -105,7 +97,7 @@ export class ProtoViewFactory {
|
|||
return protoElementInjector;
|
||||
}
|
||||
|
||||
_createElementBinder(protoView, renderElementBinder, domElementBinder, protoElementInjector, sortedDirectives) {
|
||||
_createElementBinder(protoView, renderElementBinder, protoElementInjector, sortedDirectives) {
|
||||
var parent = null;
|
||||
if (renderElementBinder.parentIndex !== -1) {
|
||||
parent = protoView.elementBinders[renderElementBinder.parentIndex];
|
||||
|
@ -117,14 +109,13 @@ export class ProtoViewFactory {
|
|||
sortedDirectives.componentDirective,
|
||||
sortedDirectives.viewportDirective
|
||||
);
|
||||
elBinder.contentTagSelector = domElementBinder.contentTagSelector;
|
||||
// text nodes
|
||||
for (var i=0; i<renderElementBinder.textBindings.length; i++) {
|
||||
protoView.bindTextNode(domElementBinder.textNodeIndices[i], renderElementBinder.textBindings[i].ast);
|
||||
protoView.bindTextNode(renderElementBinder.textBindings[i].ast);
|
||||
}
|
||||
// element properties
|
||||
MapWrapper.forEach(renderElementBinder.propertyBindings, (astWithSource, propertyName) => {
|
||||
protoView.bindElementProperty(astWithSource.ast, propertyName, MapWrapper.get(domElementBinder.propertySetters, propertyName));
|
||||
protoView.bindElementProperty(astWithSource.ast, propertyName);
|
||||
});
|
||||
// events
|
||||
MapWrapper.forEach(renderElementBinder.eventBindings, (astWithSource, eventName) => {
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
import * as ldModule from './light_dom';
|
||||
import {Inject, Injectable} from 'angular2/di';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
class ContentStrategy {
|
||||
nodes:List;
|
||||
insert(nodes:List){}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of the content tag that is used by transcluding components.
|
||||
* It is used when the content tag is not a direct child of another component,
|
||||
* and thus does not affect redistribution.
|
||||
*/
|
||||
@Injectable()
|
||||
class RenderedContent extends ContentStrategy {
|
||||
beginScript;
|
||||
endScript;
|
||||
|
||||
constructor(contentEl) {
|
||||
super();
|
||||
this.beginScript = contentEl;
|
||||
this.endScript = DOM.nextSibling(this.beginScript);
|
||||
this.nodes = [];
|
||||
}
|
||||
|
||||
// Inserts the nodes in between the start and end scripts.
|
||||
// Previous content is removed.
|
||||
insert(nodes:List) {
|
||||
this.nodes = nodes;
|
||||
DOM.insertAllBefore(this.endScript, nodes);
|
||||
this._removeNodesUntil(ListWrapper.isEmpty(nodes) ? this.endScript : nodes[0]);
|
||||
}
|
||||
|
||||
_removeNodesUntil(node) {
|
||||
var p = DOM.parentElement(this.beginScript);
|
||||
for (var next = DOM.nextSibling(this.beginScript);
|
||||
next !== node;
|
||||
next = DOM.nextSibling(this.beginScript)) {
|
||||
DOM.removeChild(p, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of the content tag that is used by transcluding components.
|
||||
* It is used when the content tag is a direct child of another component,
|
||||
* and thus does not get rendered but only affect the distribution of its parent component.
|
||||
*/
|
||||
class IntermediateContent extends ContentStrategy {
|
||||
destinationLightDom:ldModule.LightDom;
|
||||
|
||||
constructor(destinationLightDom:ldModule.LightDom) {
|
||||
super();
|
||||
this.destinationLightDom = destinationLightDom;
|
||||
this.nodes = [];
|
||||
}
|
||||
|
||||
insert(nodes:List) {
|
||||
this.nodes = nodes;
|
||||
this.destinationLightDom.redistribute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class Content {
|
||||
select:string;
|
||||
_strategy:ContentStrategy;
|
||||
contentStartElement;
|
||||
|
||||
constructor(destinationLightDom:ldModule.LightDom, contentStartEl, selector:string) {
|
||||
this.select = selector;
|
||||
this.contentStartElement = contentStartEl;
|
||||
this._strategy = isPresent(destinationLightDom) ?
|
||||
new IntermediateContent(destinationLightDom) :
|
||||
new RenderedContent(contentStartEl);
|
||||
}
|
||||
|
||||
nodes():List {
|
||||
return this._strategy.nodes;
|
||||
}
|
||||
|
||||
insert(nodes:List) {
|
||||
this._strategy.insert(nodes);
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
|
||||
import * as viewModule from '../view';
|
||||
import {Content} from './content_tag';
|
||||
|
||||
export class DestinationLightDom {}
|
||||
|
||||
|
||||
class _Root {
|
||||
node;
|
||||
viewContainer;
|
||||
content;
|
||||
|
||||
constructor(node, viewContainer, content) {
|
||||
this.node = node;
|
||||
this.viewContainer = viewContainer;
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: LightDom should implement DestinationLightDom
|
||||
// once interfaces are supported
|
||||
export class LightDom {
|
||||
// The light DOM of the element is enclosed inside the lightDomView
|
||||
lightDomView:viewModule.View;
|
||||
// The shadow DOM
|
||||
shadowDomView:viewModule.View;
|
||||
// The nodes of the light DOM
|
||||
nodes:List;
|
||||
roots:List<_Root>;
|
||||
|
||||
constructor(lightDomView:viewModule.View, shadowDomView:viewModule.View, element) {
|
||||
this.lightDomView = lightDomView;
|
||||
this.shadowDomView = shadowDomView;
|
||||
this.nodes = DOM.childNodesAsList(element);
|
||||
|
||||
this.roots = null;
|
||||
}
|
||||
|
||||
redistribute() {
|
||||
var tags = this.contentTags();
|
||||
if (tags.length > 0) {
|
||||
redistributeNodes(tags, this.expandedDomNodes());
|
||||
}
|
||||
}
|
||||
|
||||
contentTags(): List<Content> {
|
||||
return this._collectAllContentTags(this.shadowDomView, []);
|
||||
}
|
||||
|
||||
// Collects the Content directives from the view and all its child views
|
||||
_collectAllContentTags(view: viewModule.View, acc:List<Content>):List<Content> {
|
||||
var contentTags = view.contentTags;
|
||||
var vcs = view.viewContainers;
|
||||
for (var i=0; i<vcs.length; i++) {
|
||||
var vc = vcs[i];
|
||||
var contentTag = contentTags[i];
|
||||
if (isPresent(contentTag)) {
|
||||
ListWrapper.push(acc, contentTag);
|
||||
}
|
||||
if (isPresent(vc)) {
|
||||
ListWrapper.forEach(vc.contentTagContainers(), (view) => {
|
||||
this._collectAllContentTags(view, acc);
|
||||
});
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
// Collects the nodes of the light DOM by merging:
|
||||
// - nodes from enclosed ViewContainers,
|
||||
// - nodes from enclosed content tags,
|
||||
// - plain DOM nodes
|
||||
expandedDomNodes():List {
|
||||
var res = [];
|
||||
|
||||
var roots = this._roots();
|
||||
for (var i = 0; i < roots.length; ++i) {
|
||||
|
||||
var root = roots[i];
|
||||
|
||||
if (isPresent(root.viewContainer)) {
|
||||
res = ListWrapper.concat(res, root.viewContainer.nodes());
|
||||
} else if (isPresent(root.content)) {
|
||||
res = ListWrapper.concat(res, root.content.nodes());
|
||||
} else {
|
||||
ListWrapper.push(res, root.node);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Returns a list of Roots for all the nodes of the light DOM.
|
||||
// The Root object contains the DOM node and its corresponding injector (could be null).
|
||||
_roots() {
|
||||
if (isPresent(this.roots)) return this.roots;
|
||||
|
||||
var viewContainers = this.lightDomView.viewContainers;
|
||||
var contentTags = this.lightDomView.contentTags;
|
||||
|
||||
this.roots = ListWrapper.map(this.nodes, (n) => {
|
||||
var foundVc = null;
|
||||
var foundContentTag = null;
|
||||
for (var i=0; i<viewContainers.length; i++) {
|
||||
var vc = viewContainers[i];
|
||||
var contentTag = contentTags[i];
|
||||
if (isPresent(vc) && vc.templateElement === n) {
|
||||
foundVc = vc;
|
||||
}
|
||||
if (isPresent(contentTag) && contentTag.contentStartElement === n) {
|
||||
foundContentTag = contentTag;
|
||||
}
|
||||
}
|
||||
return new _Root(n, foundVc, foundContentTag);
|
||||
});
|
||||
|
||||
return this.roots;
|
||||
}
|
||||
}
|
||||
|
||||
// Projects the light DOM into the shadow DOM
|
||||
function redistributeNodes(contents:List<Content>, nodes:List) {
|
||||
for (var i = 0; i < contents.length; ++i) {
|
||||
var content = contents[i];
|
||||
var select = content.select;
|
||||
var matchSelector = (n) => DOM.elementMatches(n, select);
|
||||
|
||||
// Empty selector is identical to <content/>
|
||||
if (select.length === 0) {
|
||||
content.insert(nodes);
|
||||
ListWrapper.clear(nodes);
|
||||
} else {
|
||||
var matchingNodes = ListWrapper.filter(nodes, matchSelector);
|
||||
content.insert(matchingNodes);
|
||||
ListWrapper.removeAll(nodes, matchingNodes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
import {Injectable} from 'angular2/di';
|
||||
|
||||
import {stringify} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import * as viewModule from './view';
|
||||
import {LightDom} from './shadow_dom_emulation/light_dom';
|
||||
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
|
||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||
|
||||
// temporal import while we migrated the views over
|
||||
import * as sds from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import * as nsds from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||
import * as eusds from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import * as essds from 'angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy';
|
||||
|
||||
/**
|
||||
* @publicModule angular2/template
|
||||
*/
|
||||
export class ShadowDomStrategy {
|
||||
render: sds.ShadowDomStrategy;
|
||||
|
||||
attachTemplate(el, view:viewModule.View) {}
|
||||
constructLightDom(lightDomView:viewModule.View, shadowDomView:viewModule.View, el): LightDom { return null; }
|
||||
|
||||
shimAppElement(componentType, insertionElement) {
|
||||
this.render.processElement(null, stringify(componentType), insertionElement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This strategy emulates the Shadow DOM for the templates, styles **excluded**:
|
||||
* - components templates are added as children of their component element,
|
||||
* - styles are moved from the templates to the styleHost (i.e. the document head).
|
||||
*
|
||||
* Notes:
|
||||
* - styles are **not** scoped to their component and will apply to the whole document,
|
||||
* - you can **not** use shadow DOM specific selectors in the styles
|
||||
*
|
||||
* @publicModule angular2/template
|
||||
*/
|
||||
@Injectable()
|
||||
export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy {
|
||||
|
||||
constructor(styleUrlResolver: StyleUrlResolver, styleHost) {
|
||||
super();
|
||||
this.render = new eusds.EmulatedUnscopedShadowDomStrategy(styleUrlResolver, styleHost);
|
||||
}
|
||||
|
||||
attachTemplate(el, view:viewModule.View) {
|
||||
DOM.clearNodes(el);
|
||||
_moveViewNodesIntoParent(el, view);
|
||||
}
|
||||
|
||||
constructLightDom(lightDomView:viewModule.View, shadowDomView:viewModule.View, el): LightDom {
|
||||
return new LightDom(lightDomView, shadowDomView, el);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This strategy emulates the Shadow DOM for the templates, styles **included**:
|
||||
* - components templates are added as children of their component element,
|
||||
* - both the template and the styles are modified so that styles are scoped to the component
|
||||
* they belong to,
|
||||
* - styles are moved from the templates to the styleHost (i.e. the document head).
|
||||
*
|
||||
* Notes:
|
||||
* - styles are scoped to their component and will apply only to it,
|
||||
* - a common subset of shadow DOM selectors are supported,
|
||||
* - see `ShadowCss` for more information and limitations.
|
||||
*
|
||||
* @publicModule angular2/template
|
||||
*/
|
||||
@Injectable()
|
||||
export class EmulatedScopedShadowDomStrategy extends ShadowDomStrategy {
|
||||
|
||||
constructor(styleInliner: StyleInliner, styleUrlResolver: StyleUrlResolver, styleHost) {
|
||||
super();
|
||||
this.render = new essds.EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, styleHost);
|
||||
}
|
||||
|
||||
attachTemplate(el, view:viewModule.View) {
|
||||
DOM.clearNodes(el);
|
||||
_moveViewNodesIntoParent(el, view);
|
||||
}
|
||||
|
||||
constructLightDom(lightDomView:viewModule.View, shadowDomView:viewModule.View, el): LightDom {
|
||||
return new LightDom(lightDomView, shadowDomView, el);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This strategies uses the native Shadow DOM support.
|
||||
*
|
||||
* The templates for the component are inserted in a Shadow Root created on the component element.
|
||||
* Hence they are strictly isolated.
|
||||
*/
|
||||
@Injectable()
|
||||
export class NativeShadowDomStrategy extends ShadowDomStrategy {
|
||||
|
||||
constructor(styleUrlResolver: StyleUrlResolver) {
|
||||
super();
|
||||
this.render = new nsds.NativeShadowDomStrategy(styleUrlResolver);
|
||||
}
|
||||
|
||||
attachTemplate(el, view:viewModule.View){
|
||||
_moveViewNodesIntoParent(DOM.createShadowRoot(el), view);
|
||||
}
|
||||
}
|
||||
|
||||
function _moveViewNodesIntoParent(parent, view) {
|
||||
for (var i = 0; i < view.nodes.length; ++i) {
|
||||
DOM.appendChild(parent, view.nodes[i]);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {AST, Locals, ChangeDispatcher, ProtoChangeDetector, ChangeDetector,
|
||||
ChangeRecord, BindingRecord, BindingPropagationConfig, uninitialized} from 'angular2/change_detection';
|
||||
|
@ -9,76 +7,51 @@ import {ElementBinder} from './element_binder';
|
|||
import {SetterFn} from 'angular2/src/reflection/types';
|
||||
import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {Injector} from 'angular2/di';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {ViewContainer} from './view_container';
|
||||
import {LightDom} from './shadow_dom_emulation/light_dom';
|
||||
import {Content} from './shadow_dom_emulation/content_tag';
|
||||
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
||||
import {ViewPool} from './view_pool';
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
import * as renderApi from 'angular2/src/render/api';
|
||||
|
||||
const NG_BINDING_CLASS = 'ng-binding';
|
||||
const NG_BINDING_CLASS_SELECTOR = '.ng-binding';
|
||||
|
||||
// TODO(rado): make this configurable/smarter.
|
||||
var VIEW_POOL_CAPACITY = 10000;
|
||||
var VIEW_POOL_PREFILL = 0;
|
||||
|
||||
/**
|
||||
* Const of making objects: http://jsperf.com/instantiate-size-of-object
|
||||
*
|
||||
* @publicModule angular2/template
|
||||
*/
|
||||
@IMPLEMENTS(ChangeDispatcher)
|
||||
// TODO(tbosch): this is not supported in dart2js (no '.' is allowed)
|
||||
// @IMPLEMENTS(renderApi.EventDispatcher)
|
||||
export class View {
|
||||
render:renderApi.ViewRef;
|
||||
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector
|
||||
rootElementInjectors:List<ElementInjector>;
|
||||
elementInjectors:List<ElementInjector>;
|
||||
bindElements:List;
|
||||
textNodes:List;
|
||||
changeDetector:ChangeDetector;
|
||||
/// When the view is part of render tree, the DocumentFragment is empty, which is why we need
|
||||
/// to keep track of the nodes.
|
||||
nodes:List;
|
||||
componentChildViews: List<View>;
|
||||
viewContainers: List<ViewContainer>;
|
||||
contentTags: List<Content>;
|
||||
preBuiltObjects: List<PreBuiltObjects>;
|
||||
lightDoms: List<LightDom>;
|
||||
proto: ProtoView;
|
||||
context: any;
|
||||
locals:Locals;
|
||||
|
||||
constructor(proto:ProtoView, nodes:List, protoLocals:Map) {
|
||||
constructor(proto:ProtoView, protoLocals:Map) {
|
||||
this.render = null;
|
||||
this.proto = proto;
|
||||
this.nodes = nodes;
|
||||
this.changeDetector = null;
|
||||
this.elementInjectors = null;
|
||||
this.rootElementInjectors = null;
|
||||
this.textNodes = null;
|
||||
this.bindElements = null;
|
||||
this.componentChildViews = null;
|
||||
this.viewContainers = null;
|
||||
this.contentTags = null;
|
||||
this.preBuiltObjects = null;
|
||||
this.lightDoms = null;
|
||||
this.context = null;
|
||||
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); //TODO optimize this
|
||||
}
|
||||
|
||||
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List,
|
||||
viewContainers:List, contentTags:List, preBuiltObjects:List, componentChildViews:List, lightDoms:List<LightDom>) {
|
||||
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List,
|
||||
viewContainers:List, preBuiltObjects:List, componentChildViews:List) {
|
||||
this.changeDetector = changeDetector;
|
||||
this.elementInjectors = elementInjectors;
|
||||
this.rootElementInjectors = rootElementInjectors;
|
||||
this.textNodes = textNodes;
|
||||
this.bindElements = bindElements;
|
||||
this.viewContainers = viewContainers;
|
||||
this.contentTags = contentTags;
|
||||
this.preBuiltObjects = preBuiltObjects;
|
||||
this.componentChildViews = componentChildViews;
|
||||
this.lightDoms = lightDoms;
|
||||
}
|
||||
|
||||
setLocal(contextName: string, value) {
|
||||
|
@ -124,16 +97,33 @@ export class View {
|
|||
* A call to hydrate/dehydrate does not attach/detach the view from the view
|
||||
* tree.
|
||||
*/
|
||||
hydrate(appInjector: Injector, hostElementInjector: ElementInjector, hostLightDom: LightDom,
|
||||
hydrate(appInjector: Injector, hostElementInjector: ElementInjector,
|
||||
context: Object, locals:Locals) {
|
||||
var renderComponentViewRefs = this.proto.renderer.createView(this.proto.render);
|
||||
this.internalHydrateRecurse(renderComponentViewRefs, 0, appInjector, hostElementInjector, context, locals);
|
||||
}
|
||||
|
||||
dehydrate() {
|
||||
var render = this.render;
|
||||
this.internalDehydrateRecurse();
|
||||
this.proto.renderer.destroyView(render);
|
||||
}
|
||||
|
||||
internalHydrateRecurse(
|
||||
renderComponentViewRefs:List<renderApi.ViewRef>,
|
||||
renderComponentIndex:number,
|
||||
appInjector: Injector, hostElementInjector: ElementInjector,
|
||||
context: Object, locals:Locals):number {
|
||||
if (this.hydrated()) throw new BaseException('The view is already hydrated.');
|
||||
|
||||
this.render = renderComponentViewRefs[renderComponentIndex++];
|
||||
this._hydrateContext(context, locals);
|
||||
|
||||
// viewContainers
|
||||
for (var i = 0; i < this.viewContainers.length; i++) {
|
||||
var vc = this.viewContainers[i];
|
||||
if (isPresent(vc)) {
|
||||
vc.hydrate(appInjector, hostElementInjector, hostLightDom);
|
||||
vc.internalHydrateRecurse(new renderApi.ViewContainerRef(this.render, i), appInjector, hostElementInjector);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,7 +148,7 @@ export class View {
|
|||
// elementInjectors
|
||||
var elementInjector = this.elementInjectors[i];
|
||||
if (isPresent(elementInjector)) {
|
||||
elementInjector.instantiateDirectives(appInjector, shadowDomAppInjector, this.preBuiltObjects[i]);
|
||||
elementInjector.instantiateDirectives(appInjector, hostElementInjector, shadowDomAppInjector, this.preBuiltObjects[i]);
|
||||
|
||||
// The exporting of $implicit is a special case. Since multiple elements will all export
|
||||
// the different values as $implicit, directly assign $implicit bindings to the variable
|
||||
|
@ -167,30 +157,32 @@ export class View {
|
|||
if (elementInjector.isExportingComponent()) {
|
||||
this.locals.set(exportImplicitName, elementInjector.getComponent());
|
||||
} else if (elementInjector.isExportingElement()) {
|
||||
this.locals.set(exportImplicitName, elementInjector.getNgElement().domElement);
|
||||
this.locals.set(exportImplicitName, elementInjector.getNgElement());
|
||||
}
|
||||
}
|
||||
|
||||
if (isPresent(binders[i].nestedProtoView) && isPresent(componentDirective)) {
|
||||
this.componentChildViews[componentChildViewIndex++].hydrate(shadowDomAppInjector,
|
||||
elementInjector, this.lightDoms[i], elementInjector.getComponent(), null);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.lightDoms.length; ++i) {
|
||||
var lightDom = this.lightDoms[i];
|
||||
if (isPresent(lightDom)) {
|
||||
lightDom.redistribute();
|
||||
renderComponentIndex = this.componentChildViews[componentChildViewIndex].internalHydrateRecurse(
|
||||
renderComponentViewRefs,
|
||||
renderComponentIndex,
|
||||
shadowDomAppInjector,
|
||||
elementInjector,
|
||||
elementInjector.getComponent(),
|
||||
null
|
||||
);
|
||||
componentChildViewIndex++;
|
||||
}
|
||||
}
|
||||
this.proto.renderer.setEventDispatcher(this.render, this);
|
||||
return renderComponentIndex;
|
||||
}
|
||||
|
||||
dehydrate() {
|
||||
internalDehydrateRecurse() {
|
||||
// Note: preserve the opposite order of the hydration process.
|
||||
|
||||
// componentChildViews
|
||||
for (var i = 0; i < this.componentChildViews.length; i++) {
|
||||
this.componentChildViews[i].dehydrate();
|
||||
this.componentChildViews[i].internalDehydrateRecurse();
|
||||
}
|
||||
|
||||
// elementInjectors
|
||||
|
@ -205,11 +197,13 @@ export class View {
|
|||
for (var i = 0; i < this.viewContainers.length; i++) {
|
||||
var vc = this.viewContainers[i];
|
||||
if (isPresent(vc)) {
|
||||
vc.dehydrate();
|
||||
vc.internalDehydrateRecurse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.render = null;
|
||||
|
||||
this._dehydrateContext();
|
||||
}
|
||||
|
||||
|
@ -223,11 +217,9 @@ export class View {
|
|||
* @param {int} binderIndex
|
||||
*/
|
||||
triggerEventHandlers(eventName: string, eventObj, binderIndex: int) {
|
||||
var handlers = this.proto.eventHandlers[binderIndex];
|
||||
if (isBlank(handlers)) return;
|
||||
var handler = StringMapWrapper.get(handlers, eventName);
|
||||
if (isBlank(handler)) return;
|
||||
handler(eventObj, this);
|
||||
var locals = MapWrapper.create();
|
||||
MapWrapper.set(locals, '$event', eventObj);
|
||||
this.dispatchEvent(binderIndex, eventName, locals);
|
||||
}
|
||||
|
||||
onAllChangesDone(directiveMemento:DirectiveMemento) {
|
||||
|
@ -245,15 +237,39 @@ export class View {
|
|||
if (memento instanceof DirectiveBindingMemento) {
|
||||
var directiveMemento:DirectiveBindingMemento = memento;
|
||||
directiveMemento.invoke(currentValue, this.elementInjectors);
|
||||
|
||||
} else if (memento instanceof ElementBindingMemento) {
|
||||
var elementMemento:ElementBindingMemento = memento;
|
||||
elementMemento.invoke(currentValue, this.bindElements);
|
||||
|
||||
this.proto.renderer.setElementProperty(
|
||||
this.render, elementMemento.elementIndex, elementMemento.propertyName, currentValue
|
||||
);
|
||||
} else {
|
||||
// we know it refers to _textNodes.
|
||||
var textNodeIndex:number = memento;
|
||||
DOM.setText(this.textNodes[textNodeIndex], currentValue);
|
||||
this.proto.renderer.setText(this.render, textNodeIndex, currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
// implementation of EventDispatcher#dispatchEvent
|
||||
dispatchEvent(
|
||||
elementIndex:number, eventName:string, locals:Map<string, any>
|
||||
):void {
|
||||
// Most of the time the event will be fired only when the view is in the live document.
|
||||
// However, in a rare circumstance the view might get dehydrated, in between the event
|
||||
// queuing up and firing.
|
||||
if (this.hydrated()) {
|
||||
var elBinder = this.proto.elementBinders[elementIndex];
|
||||
if (isBlank(elBinder.events)) return;
|
||||
var eventMap = elBinder.events[eventName];
|
||||
if (isBlank(eventName)) return;
|
||||
MapWrapper.forEach(eventMap, (expr, directiveIndex) => {
|
||||
var context;
|
||||
if (directiveIndex === -1) {
|
||||
context = this.context;
|
||||
} else {
|
||||
context = this.elementInjectors[elementIndex].getDirectiveAtIndex(directiveIndex);
|
||||
}
|
||||
expr.eval(context, new Locals(this.locals, locals));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,21 +279,11 @@ export class View {
|
|||
* @publicModule angular2/template
|
||||
*/
|
||||
export class ProtoView {
|
||||
element;
|
||||
elementBinders:List<ElementBinder>;
|
||||
protoChangeDetector:ProtoChangeDetector;
|
||||
variableBindings: Map;
|
||||
protoLocals:Map;
|
||||
textNodesWithBindingCount:int;
|
||||
elementsWithBindingCount:int;
|
||||
instantiateInPlace:boolean;
|
||||
rootBindingOffset:int;
|
||||
isTemplateElement:boolean;
|
||||
shadowDomStrategy: ShadowDomStrategy;
|
||||
_viewPool: ViewPool;
|
||||
stylePromises: List<Promise>;
|
||||
// List<Map<eventName, handler>>, indexed by binder index
|
||||
eventHandlers:List;
|
||||
bindingRecords:List;
|
||||
parentProtoView:ProtoView;
|
||||
_variableBindings:List;
|
||||
|
@ -285,58 +291,36 @@ export class ProtoView {
|
|||
_directiveMementosMap:Map;
|
||||
_directiveMementos:List;
|
||||
render:renderApi.ProtoViewRef;
|
||||
renderer:renderApi.Renderer;
|
||||
|
||||
constructor(
|
||||
renderer:renderApi.Renderer,
|
||||
render:renderApi.ProtoViewRef,
|
||||
template,
|
||||
protoChangeDetector:ProtoChangeDetector,
|
||||
shadowDomStrategy:ShadowDomStrategy, parentProtoView:ProtoView = null) {
|
||||
protoChangeDetector:ProtoChangeDetector) {
|
||||
this.renderer = renderer;
|
||||
this.render = render;
|
||||
this.element = template;
|
||||
this.elementBinders = [];
|
||||
this.variableBindings = MapWrapper.create();
|
||||
this.protoLocals = MapWrapper.create();
|
||||
this.protoChangeDetector = protoChangeDetector;
|
||||
this.parentProtoView = parentProtoView;
|
||||
this.parentProtoView = null;
|
||||
this.textNodesWithBindingCount = 0;
|
||||
this.elementsWithBindingCount = 0;
|
||||
this.instantiateInPlace = false;
|
||||
this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS))
|
||||
? 1 : 0;
|
||||
this.isTemplateElement = DOM.isTemplateElement(this.element);
|
||||
this.shadowDomStrategy = shadowDomStrategy;
|
||||
this._viewPool = new ViewPool(VIEW_POOL_CAPACITY);
|
||||
this.stylePromises = [];
|
||||
this.eventHandlers = [];
|
||||
this.bindingRecords = [];
|
||||
this._directiveMementosMap = MapWrapper.create();
|
||||
this._variableBindings = null;
|
||||
this._directiveMementos = null;
|
||||
}
|
||||
|
||||
// TODO(rado): hostElementInjector should be moved to hydrate phase.
|
||||
instantiate(hostElementInjector: ElementInjector, eventManager: EventManager):View {
|
||||
if (this._viewPool.length() == 0) this._preFillPool(hostElementInjector, eventManager);
|
||||
var view = this._viewPool.pop();
|
||||
return isPresent(view) ? view : this._instantiate(hostElementInjector, eventManager);
|
||||
}
|
||||
|
||||
_preFillPool(hostElementInjector: ElementInjector, eventManager: EventManager) {
|
||||
for (var i = 0; i < VIEW_POOL_PREFILL; i++) {
|
||||
this._viewPool.push(this._instantiate(hostElementInjector, eventManager));
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Tobias or Victor. Moving it into the constructor.
|
||||
// this work should be done the constructor of ProtoView once we separate
|
||||
// ProtoView and ProtoViewBuilder
|
||||
_getVariableBindings() {
|
||||
getVariableBindings() {
|
||||
if (isPresent(this._variableBindings)) {
|
||||
return this._variableBindings;
|
||||
}
|
||||
|
||||
this._variableBindings = isPresent(this.parentProtoView) ?
|
||||
ListWrapper.clone(this.parentProtoView._getVariableBindings()) : [];
|
||||
ListWrapper.clone(this.parentProtoView.getVariableBindings()) : [];
|
||||
|
||||
MapWrapper.forEach(this.protoLocals, (v, local) => {
|
||||
ListWrapper.push(this._variableBindings, local);
|
||||
|
@ -348,7 +332,7 @@ export class ProtoView {
|
|||
//TODO: Tobias or Victor. Moving it into the constructor.
|
||||
// this work should be done the constructor of ProtoView once we separate
|
||||
// ProtoView and ProtoViewBuilder
|
||||
_getDirectiveMementos() {
|
||||
getDirectiveMementos() {
|
||||
if (isPresent(this._directiveMementos)) {
|
||||
return this._directiveMementos;
|
||||
}
|
||||
|
@ -367,185 +351,6 @@ export class ProtoView {
|
|||
return this._directiveMementos;
|
||||
}
|
||||
|
||||
_instantiate(hostElementInjector: ElementInjector, eventManager: EventManager): View {
|
||||
var rootElementClone = this.instantiateInPlace ? this.element : DOM.importIntoDoc(this.element);
|
||||
var elementsWithBindingsDynamic;
|
||||
if (this.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 viewNodes;
|
||||
if (this.isTemplateElement) {
|
||||
var childNode = DOM.firstChild(DOM.content(rootElementClone));
|
||||
viewNodes = []; // TODO(perf): Should be fixed size, since we could pre-compute in in ProtoView
|
||||
// Note: An explicit loop is the fastest way to convert a DOM array into a JS array!
|
||||
while(childNode != null) {
|
||||
ListWrapper.push(viewNodes, childNode);
|
||||
childNode = DOM.nextSibling(childNode);
|
||||
}
|
||||
} else {
|
||||
viewNodes = [rootElementClone];
|
||||
}
|
||||
|
||||
var view = new View(this, viewNodes, this.protoLocals);
|
||||
var changeDetector = this.protoChangeDetector.instantiate(view, this.bindingRecords,
|
||||
this._getVariableBindings(), this._getDirectiveMementos());
|
||||
|
||||
var binders = this.elementBinders;
|
||||
var elementInjectors = ListWrapper.createFixedSize(binders.length);
|
||||
var eventHandlers = ListWrapper.createFixedSize(binders.length);
|
||||
var rootElementInjectors = [];
|
||||
var textNodes = [];
|
||||
var elementsWithPropertyBindings = [];
|
||||
var preBuiltObjects = ListWrapper.createFixedSize(binders.length);
|
||||
var viewContainers = ListWrapper.createFixedSize(binders.length);
|
||||
var contentTags = ListWrapper.createFixedSize(binders.length);
|
||||
var componentChildViews = [];
|
||||
var lightDoms = ListWrapper.createFixedSize(binders.length);
|
||||
|
||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||
var binder = binders[binderIdx];
|
||||
var element;
|
||||
if (binderIdx === 0 && this.rootBindingOffset === 1) {
|
||||
element = rootElementClone;
|
||||
} else {
|
||||
element = elementsWithBindings[binderIdx - this.rootBindingOffset];
|
||||
}
|
||||
var elementInjector = null;
|
||||
|
||||
// elementInjectors and rootElementInjectors
|
||||
var protoElementInjector = binder.protoElementInjector;
|
||||
if (isPresent(protoElementInjector)) {
|
||||
if (isPresent(protoElementInjector.parent)) {
|
||||
var parentElementInjector = elementInjectors[protoElementInjector.parent.index];
|
||||
elementInjector = protoElementInjector.instantiate(parentElementInjector, null);
|
||||
} else {
|
||||
elementInjector = protoElementInjector.instantiate(null, hostElementInjector);
|
||||
ListWrapper.push(rootElementInjectors, elementInjector);
|
||||
}
|
||||
}
|
||||
elementInjectors[binderIdx] = elementInjector;
|
||||
|
||||
if (binder.hasElementPropertyBindings) {
|
||||
ListWrapper.push(elementsWithPropertyBindings, element);
|
||||
}
|
||||
|
||||
// textNodes
|
||||
var textNodeIndices = binder.textNodeIndices;
|
||||
if (isPresent(textNodeIndices)) {
|
||||
var childNode = DOM.firstChild(DOM.templateAwareRoot(element));
|
||||
for (var j = 0, k = 0; j < textNodeIndices.length; j++) {
|
||||
for(var index = textNodeIndices[j]; k < index; k++) {
|
||||
childNode = DOM.nextSibling(childNode);
|
||||
}
|
||||
ListWrapper.push(textNodes, childNode);
|
||||
}
|
||||
}
|
||||
|
||||
// componentChildViews
|
||||
var lightDom = null;
|
||||
var bindingPropagationConfig = null;
|
||||
if (isPresent(binder.nestedProtoView) && isPresent(binder.componentDirective)) {
|
||||
var strategy = this.shadowDomStrategy;
|
||||
var childView = binder.nestedProtoView.instantiate(elementInjector, eventManager);
|
||||
changeDetector.addChild(childView.changeDetector);
|
||||
|
||||
lightDom = strategy.constructLightDom(view, childView, element);
|
||||
strategy.attachTemplate(element, childView);
|
||||
|
||||
bindingPropagationConfig = new BindingPropagationConfig(childView.changeDetector);
|
||||
|
||||
ListWrapper.push(componentChildViews, childView);
|
||||
}
|
||||
lightDoms[binderIdx] = lightDom;
|
||||
|
||||
var destLightDom = null;
|
||||
if (isPresent(binder.parent) && binder.distanceToParent === 1) {
|
||||
destLightDom = lightDoms[binder.parent.index];
|
||||
}
|
||||
|
||||
// viewContainers
|
||||
var viewContainer = null;
|
||||
if (isPresent(binder.viewportDirective)) {
|
||||
viewContainer = new ViewContainer(view, element, binder.nestedProtoView, elementInjector,
|
||||
eventManager, destLightDom);
|
||||
}
|
||||
viewContainers[binderIdx] = viewContainer;
|
||||
|
||||
// contentTags
|
||||
var contentTag = null;
|
||||
if (isPresent(binder.contentTagSelector)) {
|
||||
contentTag = new Content(destLightDom, element, binder.contentTagSelector);
|
||||
}
|
||||
contentTags[binderIdx] = contentTag;
|
||||
|
||||
// preBuiltObjects
|
||||
if (isPresent(elementInjector)) {
|
||||
preBuiltObjects[binderIdx] = new PreBuiltObjects(view, new NgElement(element), viewContainer,
|
||||
bindingPropagationConfig);
|
||||
}
|
||||
|
||||
// events
|
||||
if (isPresent(binder.events)) {
|
||||
eventHandlers[binderIdx] = StringMapWrapper.create();
|
||||
StringMapWrapper.forEach(binder.events, (eventMap, eventName) => {
|
||||
var handler = ProtoView.buildEventHandler(eventMap, binderIdx);
|
||||
StringMapWrapper.set(eventHandlers[binderIdx], eventName, handler);
|
||||
if (isBlank(elementInjector) || !elementInjector.hasEventEmitter(eventName)) {
|
||||
eventManager.addEventListener(element, eventName,
|
||||
(event) => { handler(event, view); });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.eventHandlers = eventHandlers;
|
||||
|
||||
view.init(changeDetector, elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
|
||||
viewContainers, contentTags, preBuiltObjects, componentChildViews, lightDoms);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
returnToPool(view: View) {
|
||||
this._viewPool.push(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event handler.
|
||||
*
|
||||
* @param {Map} eventMap Map directiveIndexes to expressions
|
||||
* @param {int} injectorIdx
|
||||
* @returns {Function}
|
||||
*/
|
||||
static buildEventHandler(eventMap: Map, injectorIdx: int) {
|
||||
var locals = MapWrapper.create();
|
||||
return (event, view) => {
|
||||
// Most of the time the event will be fired only when the view is in the live document.
|
||||
// However, in a rare circumstance the view might get dehydrated, in between the event
|
||||
// queuing up and firing.
|
||||
if (view.hydrated()) {
|
||||
MapWrapper.set(locals, '$event', event);
|
||||
MapWrapper.forEach(eventMap, (expr, directiveIndex) => {
|
||||
var context;
|
||||
if (directiveIndex === -1) {
|
||||
context = view.context;
|
||||
} else {
|
||||
context = view.elementInjectors[injectorIdx].getDirectiveAtIndex(directiveIndex);
|
||||
}
|
||||
expr.eval(context, new Locals(view.locals, locals));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bindVariable(contextName:string, templateName:string) {
|
||||
MapWrapper.set(this.variableBindings, contextName, templateName);
|
||||
MapWrapper.set(this.protoLocals, templateName, null);
|
||||
|
@ -562,12 +367,7 @@ export class ProtoView {
|
|||
/**
|
||||
* Adds a text node binding for the last created ElementBinder via bindElement
|
||||
*/
|
||||
bindTextNode(indexInParent:int, expression:AST) {
|
||||
var elBinder = this.elementBinders[this.elementBinders.length-1];
|
||||
if (isBlank(elBinder.textNodeIndices)) {
|
||||
elBinder.textNodeIndices = ListWrapper.create();
|
||||
}
|
||||
ListWrapper.push(elBinder.textNodeIndices, indexInParent);
|
||||
bindTextNode(expression:AST) {
|
||||
var memento = this.textNodesWithBindingCount++;
|
||||
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, memento, null));
|
||||
}
|
||||
|
@ -575,13 +375,8 @@ export class ProtoView {
|
|||
/**
|
||||
* Adds an element property binding for the last created ElementBinder via bindElement
|
||||
*/
|
||||
bindElementProperty(expression:AST, setterName:string, setter:SetterFn) {
|
||||
var elBinder = this.elementBinders[this.elementBinders.length-1];
|
||||
if (!elBinder.hasElementPropertyBindings) {
|
||||
elBinder.hasElementPropertyBindings = true;
|
||||
this.elementsWithBindingCount++;
|
||||
}
|
||||
var memento = new ElementBindingMemento(this.elementsWithBindingCount-1, setter);
|
||||
bindElementProperty(expression:AST, setterName:string) {
|
||||
var memento = new ElementBindingMemento(this.elementBinders.length-1, setterName);
|
||||
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, memento, null));
|
||||
}
|
||||
|
||||
|
@ -651,16 +446,12 @@ export class ProtoView {
|
|||
/**
|
||||
*/
|
||||
export class ElementBindingMemento {
|
||||
_elementIndex:int;
|
||||
_setter:SetterFn;
|
||||
constructor(elementIndex:int, setter:SetterFn) {
|
||||
this._elementIndex = elementIndex;
|
||||
this._setter = setter;
|
||||
}
|
||||
elementIndex:int;
|
||||
propertyName:string;
|
||||
|
||||
invoke(currentValue:any, bindElements:List) {
|
||||
var element = bindElements[this._elementIndex];
|
||||
this._setter(element, currentValue);
|
||||
constructor(elementIndex:int, propertyName:string) {
|
||||
this.elementIndex = elementIndex;
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,59 +1,64 @@
|
|||
import * as viewModule from './view';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ListWrapper, MapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {BaseException} from 'angular2/src/facade/lang';
|
||||
import {Injector} from 'angular2/di';
|
||||
import * as eiModule from 'angular2/src/core/compiler/element_injector';
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
import {LightDom} from './shadow_dom_emulation/light_dom';
|
||||
|
||||
import * as renderApi from 'angular2/src/render/api';
|
||||
import * as viewModule from './view';
|
||||
import * as vfModule from './view_factory';
|
||||
|
||||
/**
|
||||
* @publicModule angular2/template
|
||||
*/
|
||||
export class ViewContainer {
|
||||
render:renderApi.ViewContainerRef;
|
||||
viewFactory: vfModule.ViewFactory;
|
||||
parentView: viewModule.View;
|
||||
templateElement;
|
||||
defaultProtoView: viewModule.ProtoView;
|
||||
_views: List<viewModule.View>;
|
||||
_lightDom: LightDom;
|
||||
_eventManager: EventManager;
|
||||
elementInjector: eiModule.ElementInjector;
|
||||
appInjector: Injector;
|
||||
hostElementInjector: eiModule.ElementInjector;
|
||||
hostLightDom: LightDom;
|
||||
|
||||
constructor(parentView: viewModule.View,
|
||||
templateElement,
|
||||
constructor(viewFactory:vfModule.ViewFactory,
|
||||
parentView: viewModule.View,
|
||||
defaultProtoView: viewModule.ProtoView,
|
||||
elementInjector: eiModule.ElementInjector,
|
||||
eventManager: EventManager,
|
||||
lightDom = null) {
|
||||
elementInjector: eiModule.ElementInjector) {
|
||||
this.viewFactory = viewFactory;
|
||||
this.render = null;
|
||||
this.parentView = parentView;
|
||||
this.templateElement = templateElement;
|
||||
this.defaultProtoView = defaultProtoView;
|
||||
this.elementInjector = elementInjector;
|
||||
this._lightDom = lightDom;
|
||||
|
||||
// The order in this list matches the DOM order.
|
||||
this._views = [];
|
||||
this.appInjector = null;
|
||||
this.hostElementInjector = null;
|
||||
this.hostLightDom = null;
|
||||
this._eventManager = eventManager;
|
||||
}
|
||||
|
||||
hydrate(appInjector: Injector, hostElementInjector: eiModule.ElementInjector, hostLightDom: LightDom) {
|
||||
internalHydrateRecurse(render:renderApi.ViewContainerRef, appInjector: Injector, hostElementInjector: eiModule.ElementInjector) {
|
||||
this.render = render;
|
||||
this.appInjector = appInjector;
|
||||
this.hostElementInjector = hostElementInjector;
|
||||
this.hostLightDom = hostLightDom;
|
||||
}
|
||||
|
||||
dehydrate() {
|
||||
internalDehydrateRecurse() {
|
||||
this.appInjector = null;
|
||||
this.hostElementInjector = null;
|
||||
this.hostLightDom = null;
|
||||
this.clear();
|
||||
this.render = null;
|
||||
// Note: We don't call clear here,
|
||||
// as we don't want to change the render side
|
||||
// (i.e. don't deattach views on the render side),
|
||||
// as the render side does its own recursion.
|
||||
for (var i = this._views.length - 1; i >= 0; i--) {
|
||||
var view = this._views[i];
|
||||
view.changeDetector.remove();
|
||||
this._unlinkElementInjectors(view);
|
||||
view.internalDehydrateRecurse();
|
||||
this.viewFactory.returnView(view);
|
||||
}
|
||||
this._views = [];
|
||||
}
|
||||
|
||||
clear() {
|
||||
|
@ -70,11 +75,6 @@ export class ViewContainer {
|
|||
return this._views.length;
|
||||
}
|
||||
|
||||
_siblingToInsertAfter(index: number) {
|
||||
if (index == 0) return this.templateElement;
|
||||
return ListWrapper.last(this._views[index - 1].nodes);
|
||||
}
|
||||
|
||||
hydrated() {
|
||||
return isPresent(this.appInjector);
|
||||
}
|
||||
|
@ -84,28 +84,27 @@ export class ViewContainer {
|
|||
create(atIndex=-1): viewModule.View {
|
||||
if (!this.hydrated()) throw new BaseException(
|
||||
'Cannot create views on a dehydrated ViewContainer');
|
||||
// TODO(rado): replace with viewFactory.
|
||||
var newView = this.defaultProtoView.instantiate(this.hostElementInjector, this._eventManager);
|
||||
var newView = this.viewFactory.getView(this.defaultProtoView);
|
||||
// insertion must come before hydration so that element injector trees are attached.
|
||||
this.insert(newView, atIndex);
|
||||
newView.hydrate(this.appInjector, this.hostElementInjector, this.hostLightDom,
|
||||
this._insertWithoutRender(newView, atIndex);
|
||||
// hydration must come before changing the render side,
|
||||
// as it acquires the render views.
|
||||
newView.hydrate(this.appInjector, this.hostElementInjector,
|
||||
this.parentView.context, this.parentView.locals);
|
||||
this.defaultProtoView.renderer.insertViewIntoContainer(this.render, newView.render, atIndex);
|
||||
|
||||
// new content tags might have appeared, we need to redistrubute.
|
||||
if (isPresent(this.hostLightDom)) {
|
||||
this.hostLightDom.redistribute();
|
||||
}
|
||||
return newView;
|
||||
}
|
||||
|
||||
insert(view, atIndex=-1): viewModule.View {
|
||||
this._insertWithoutRender(view, atIndex);
|
||||
this.defaultProtoView.renderer.insertViewIntoContainer(this.render, view.render, atIndex);
|
||||
return view;
|
||||
}
|
||||
|
||||
_insertWithoutRender(view, atIndex=-1): viewModule.View {
|
||||
if (atIndex == -1) atIndex = this._views.length;
|
||||
ListWrapper.insert(this._views, atIndex, view);
|
||||
if (isBlank(this._lightDom)) {
|
||||
ViewContainer.moveViewNodesAfterSibling(this._siblingToInsertAfter(atIndex), view);
|
||||
} else {
|
||||
this._lightDom.redistribute();
|
||||
}
|
||||
this.parentView.changeDetector.addChild(view.changeDetector);
|
||||
this._linkElementInjectors(view);
|
||||
|
||||
|
@ -116,8 +115,7 @@ export class ViewContainer {
|
|||
if (atIndex == -1) atIndex = this._views.length - 1;
|
||||
var view = this.detach(atIndex);
|
||||
view.dehydrate();
|
||||
// TODO(rado): this needs to be delayed until after any pending animations.
|
||||
this.defaultProtoView.returnToPool(view);
|
||||
this.viewFactory.returnView(view);
|
||||
// view is intentionally not returned to the client.
|
||||
}
|
||||
|
||||
|
@ -129,32 +127,12 @@ export class ViewContainer {
|
|||
if (atIndex == -1) atIndex = this._views.length - 1;
|
||||
var detachedView = this.get(atIndex);
|
||||
ListWrapper.removeAt(this._views, atIndex);
|
||||
if (isBlank(this._lightDom)) {
|
||||
ViewContainer.removeViewNodes(detachedView);
|
||||
} else {
|
||||
this._lightDom.redistribute();
|
||||
}
|
||||
// content tags might have disappeared we need to do redistribution.
|
||||
if (isPresent(this.hostLightDom)) {
|
||||
this.hostLightDom.redistribute();
|
||||
}
|
||||
this.defaultProtoView.renderer.detachViewFromContainer(this.render, atIndex);
|
||||
detachedView.changeDetector.remove();
|
||||
this._unlinkElementInjectors(detachedView);
|
||||
return detachedView;
|
||||
}
|
||||
|
||||
contentTagContainers() {
|
||||
return this._views;
|
||||
}
|
||||
|
||||
nodes():List {
|
||||
var r = [];
|
||||
for (var i = 0; i < this._views.length; ++i) {
|
||||
r = ListWrapper.concat(r, this._views[i].nodes);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
_linkElementInjectors(view) {
|
||||
for (var i = 0; i < view.rootElementInjectors.length; ++i) {
|
||||
view.rootElementInjectors[i].parent = this.elementInjector;
|
||||
|
@ -166,19 +144,4 @@ export class ViewContainer {
|
|||
view.rootElementInjectors[i].parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
static moveViewNodesAfterSibling(sibling, view) {
|
||||
for (var i = view.nodes.length - 1; i >= 0; --i) {
|
||||
DOM.insertAfter(sibling, view.nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static removeViewNodes(view) {
|
||||
var len = view.nodes.length;
|
||||
if (len == 0) return;
|
||||
var parent = view.nodes[0].parentNode;
|
||||
for (var i = len - 1; i >= 0; --i) {
|
||||
DOM.removeChild(parent, view.nodes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
import {Injectable, Inject, OpaqueToken} from 'angular2/di';
|
||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import * as eli from './element_injector';
|
||||
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {NgElement} from 'angular2/src/core/compiler/ng_element';
|
||||
import * as vcModule from './view_container';
|
||||
import * as viewModule from './view';
|
||||
import {BindingPropagationConfig} from 'angular2/change_detection';
|
||||
|
||||
// TODO(tbosch): Make this an OpaqueToken as soon as our transpiler supports this!
|
||||
export const VIEW_POOL_CAPACITY = 'ViewFactory.viewPoolCapacity';
|
||||
|
||||
@Injectable()
|
||||
export class ViewFactory {
|
||||
_poolCapacity:number;
|
||||
_pooledViews:List<viewModule.View>;
|
||||
|
||||
constructor(@Inject(VIEW_POOL_CAPACITY) capacity) {
|
||||
this._poolCapacity = capacity;
|
||||
this._pooledViews = ListWrapper.create();
|
||||
}
|
||||
|
||||
getView(protoView:viewModule.ProtoView):viewModule.View {
|
||||
// TODO(tbosch): benchmark this scanning of views and maybe
|
||||
// replace it with a fancy LRU Map/List combination...
|
||||
var view;
|
||||
for (var i=this._pooledViews.length-1; i>=0; i--) {
|
||||
var pooledView = this._pooledViews[i];
|
||||
if (pooledView.proto === protoView) {
|
||||
view = ListWrapper.removeAt(this._pooledViews, i);
|
||||
}
|
||||
}
|
||||
if (isBlank(view)) {
|
||||
view = this._createView(protoView);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
returnView(view:viewModule.View) {
|
||||
if (view.hydrated()) {
|
||||
throw new BaseException('Only dehydrated Views can be put back into the pool!');
|
||||
}
|
||||
ListWrapper.push(this._pooledViews, view);
|
||||
while (this._pooledViews.length > this._poolCapacity) {
|
||||
ListWrapper.removeAt(this._pooledViews, 0);
|
||||
}
|
||||
}
|
||||
|
||||
_createView(protoView:viewModule.ProtoView): viewModule.View {
|
||||
var view = new viewModule.View(protoView, protoView.protoLocals);
|
||||
var changeDetector = protoView.protoChangeDetector.instantiate(view, protoView.bindingRecords,
|
||||
protoView.getVariableBindings(), protoView.getDirectiveMementos());
|
||||
|
||||
var binders = protoView.elementBinders;
|
||||
var elementInjectors = ListWrapper.createFixedSize(binders.length);
|
||||
var rootElementInjectors = [];
|
||||
var preBuiltObjects = ListWrapper.createFixedSize(binders.length);
|
||||
var viewContainers = ListWrapper.createFixedSize(binders.length);
|
||||
var componentChildViews = [];
|
||||
|
||||
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
||||
var binder = binders[binderIdx];
|
||||
var elementInjector = null;
|
||||
|
||||
// elementInjectors and rootElementInjectors
|
||||
var protoElementInjector = binder.protoElementInjector;
|
||||
if (isPresent(protoElementInjector)) {
|
||||
if (isPresent(protoElementInjector.parent)) {
|
||||
var parentElementInjector = elementInjectors[protoElementInjector.parent.index];
|
||||
elementInjector = protoElementInjector.instantiate(parentElementInjector);
|
||||
} else {
|
||||
elementInjector = protoElementInjector.instantiate(null);
|
||||
ListWrapper.push(rootElementInjectors, elementInjector);
|
||||
}
|
||||
}
|
||||
elementInjectors[binderIdx] = elementInjector;
|
||||
|
||||
// componentChildViews
|
||||
var bindingPropagationConfig = null;
|
||||
if (isPresent(binder.nestedProtoView) && isPresent(binder.componentDirective)) {
|
||||
var childView = this._createView(binder.nestedProtoView);
|
||||
changeDetector.addChild(childView.changeDetector);
|
||||
|
||||
bindingPropagationConfig = new BindingPropagationConfig(childView.changeDetector);
|
||||
|
||||
ListWrapper.push(componentChildViews, childView);
|
||||
}
|
||||
|
||||
// viewContainers
|
||||
var viewContainer = null;
|
||||
if (isPresent(binder.viewportDirective)) {
|
||||
viewContainer = new vcModule.ViewContainer(this, view, binder.nestedProtoView, elementInjector);
|
||||
}
|
||||
viewContainers[binderIdx] = viewContainer;
|
||||
|
||||
// preBuiltObjects
|
||||
if (isPresent(elementInjector)) {
|
||||
preBuiltObjects[binderIdx] = new eli.PreBuiltObjects(view, new NgElement(view, binderIdx), viewContainer,
|
||||
bindingPropagationConfig);
|
||||
}
|
||||
}
|
||||
|
||||
view.init(changeDetector, elementInjectors, rootElementInjectors,
|
||||
viewContainers, preBuiltObjects, componentChildViews);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import {ListWrapper, MapWrapper, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import * as viewModule from './view';
|
||||
|
||||
export class ViewPool {
|
||||
_views: List<viewModule.View>;
|
||||
_capacity: number;
|
||||
constructor(capacity: number) {
|
||||
this._views = [];
|
||||
this._capacity = capacity;
|
||||
}
|
||||
|
||||
pop(): viewModule.View {
|
||||
return ListWrapper.isEmpty(this._views) ? null : ListWrapper.removeLast(this._views);
|
||||
}
|
||||
|
||||
push(view: viewModule.View) {
|
||||
if (this._views.length < this._capacity) {
|
||||
ListWrapper.push(this._views, view);
|
||||
}
|
||||
}
|
||||
|
||||
length() {
|
||||
return this._views.length;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {normalizeBlank} from 'angular2/src/facade/lang';
|
||||
|
||||
/**
|
||||
* @publicModule angular2/angular2
|
||||
*/
|
||||
export class NgElement {
|
||||
domElement;
|
||||
constructor(domElement) {
|
||||
this.domElement = domElement;
|
||||
}
|
||||
|
||||
getAttribute(name:string) {
|
||||
return normalizeBlank(DOM.getAttribute(this.domElement, name));
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import {Decorator} from 'angular2/src/core/annotations/annotations';
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {NgElement} from 'angular2/src/core/compiler/ng_element';
|
||||
|
||||
@Decorator({
|
||||
selector: '[class]',
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {Decorator, Viewport} from 'angular2/src/core/annotations/annotations';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, List, MapWrapper, Map} from 'angular2/src/facade/collection';
|
||||
import {Parent} from 'angular2/src/core/annotations/visibility';
|
||||
|
@ -156,7 +155,7 @@ export class SwitchWhen {
|
|||
_switch: Switch;
|
||||
_viewContainer: ViewContainer;
|
||||
|
||||
constructor(el: NgElement, viewContainer: ViewContainer, @Parent() sswitch: Switch) {
|
||||
constructor(viewContainer: ViewContainer, @Parent() sswitch: Switch) {
|
||||
// `_whenDefault` is used as a marker for a not yet initialized value
|
||||
this._value = _whenDefault;
|
||||
this._switch = sswitch;
|
||||
|
|
|
@ -203,7 +203,7 @@ export class Renderer {
|
|||
* Sets the dispatcher for all events that have been defined in the template or in directives
|
||||
* in the given view.
|
||||
*/
|
||||
setEventDispatcher(viewRef:ViewRef, dispatcher:EventDispatcher):void {}
|
||||
setEventDispatcher(viewRef:ViewRef, dispatcher:any/*EventDispatcher*/):void {}
|
||||
|
||||
/**
|
||||
* To be called at the end of the VmTurn so the API can buffer calls
|
||||
|
@ -218,10 +218,10 @@ export class Renderer {
|
|||
export class EventDispatcher {
|
||||
/**
|
||||
* Called when an event was triggered for a on-* attribute on an element.
|
||||
* @param {List<any>} locals Locals to be used to evaluate the
|
||||
* @param {Map<string, any>} locals Locals to be used to evaluate the
|
||||
* event expressions
|
||||
*/
|
||||
dispatchEvent(
|
||||
elementIndex:number, eventName:string, locals:List<any>
|
||||
elementIndex:number, eventName:string, locals:Map<string, any>
|
||||
):void {}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import {Injectable} from 'angular2/di';
|
||||
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
import {BaseException} from 'angular2/src/facade/lang';
|
||||
|
||||
import {Template, ProtoView} from '../../api';
|
||||
import {CompilePipeline} from './compile_pipeline';
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {CompileStepFactory} from './compile_step_factory';
|
||||
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
|
||||
import {Parser} from 'angular2/change_detection';
|
||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
||||
|
||||
/**
|
||||
* The compiler loads and translates the html templates of components into
|
||||
|
@ -43,4 +47,11 @@ export class Compiler {
|
|||
return PromiseWrapper.resolve(protoView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DefaultCompiler extends Compiler {
|
||||
constructor(parser:Parser, shadowDomStrategy:ShadowDomStrategy, templateLoader: TemplateLoader) {
|
||||
super(new DefaultStepFactory(parser, shadowDomStrategy), templateLoader);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import {Injectable} from 'angular2/di';
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
|
@ -14,7 +15,7 @@ function _resolveViewContainer(vc:api.ViewContainerRef) {
|
|||
return _resolveView(vc.view).viewContainers[vc.elementIndex];
|
||||
}
|
||||
|
||||
function _resolveView(viewRef:_DirectDomViewRef) {
|
||||
function _resolveView(viewRef:DirectDomViewRef) {
|
||||
return isPresent(viewRef) ? viewRef.delegate : null;
|
||||
}
|
||||
|
||||
|
@ -23,7 +24,7 @@ function _resolveProtoView(protoViewRef:DirectDomProtoViewRef) {
|
|||
}
|
||||
|
||||
function _wrapView(view:View) {
|
||||
return new _DirectDomViewRef(view);
|
||||
return new DirectDomViewRef(view);
|
||||
}
|
||||
|
||||
function _collectComponentChildViewRefs(view, target = null) {
|
||||
|
@ -51,7 +52,7 @@ export class DirectDomProtoViewRef extends api.ProtoViewRef {
|
|||
}
|
||||
}
|
||||
|
||||
class _DirectDomViewRef extends api.ViewRef {
|
||||
export class DirectDomViewRef extends api.ViewRef {
|
||||
delegate:View;
|
||||
|
||||
constructor(delegate:View) {
|
||||
|
@ -60,6 +61,7 @@ class _DirectDomViewRef extends api.ViewRef {
|
|||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DirectDomRenderer extends api.Renderer {
|
||||
_compiler: Compiler;
|
||||
_viewFactory: ViewFactory;
|
||||
|
@ -131,7 +133,7 @@ export class DirectDomRenderer extends api.Renderer {
|
|||
_resolveView(viewRef).setText(textNodeIndex, text);
|
||||
}
|
||||
|
||||
setEventDispatcher(viewRef:api.ViewRef, dispatcher:api.EventDispatcher) {
|
||||
setEventDispatcher(viewRef:api.ViewRef, dispatcher:any/*api.EventDispatcher*/):void {
|
||||
_resolveView(viewRef).setEventDispatcher(dispatcher);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,19 +242,19 @@ export class EventLocalsAstSplitter extends AstTransformer {
|
|||
}
|
||||
|
||||
splitEventAstIntoLocals(eventBindings:Map<string, ASTWithSource>):Map<string, ASTWithSource> {
|
||||
// TODO(tbosch): reenable this when we are using
|
||||
// the render views
|
||||
return eventBindings;
|
||||
// if (isPresent(eventBindings)) {
|
||||
// var result = MapWrapper.create();
|
||||
// MapWrapper.forEach(eventBindings, (astWithSource, eventName) => {
|
||||
// var adjustedAst = astWithSource.ast.visit(this);
|
||||
// MapWrapper.set(result, eventName, new ASTWithSource(adjustedAst, astWithSource.source, ''));
|
||||
// ListWrapper.push(this.eventNames, eventName);
|
||||
// });
|
||||
// return result;
|
||||
// }
|
||||
// return null;
|
||||
if (isPresent(eventBindings)) {
|
||||
var result = MapWrapper.create();
|
||||
MapWrapper.forEach(eventBindings, (astWithSource, eventName) => {
|
||||
// TODO(tbosch): reenable this when we are parsing element properties
|
||||
// out of action expressions
|
||||
// var adjustedAst = astWithSource.ast.visit(this);
|
||||
var adjustedAst = astWithSource.ast;
|
||||
MapWrapper.set(result, eventName, new ASTWithSource(adjustedAst, astWithSource.source, ''));
|
||||
ListWrapper.push(this.eventNames, eventName);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
visitAccessMember(ast:AccessMember) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {Locals} from 'angular2/change_detection';
|
||||
|
||||
import {ViewContainer} from './view_container';
|
||||
import {ProtoView} from './proto_view';
|
||||
|
@ -10,7 +9,7 @@ import {Content} from '../shadow_dom/content_tag';
|
|||
|
||||
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
|
||||
|
||||
import {EventDispatcher} from '../../api';
|
||||
// import {EventDispatcher} from '../../api';
|
||||
|
||||
const NG_BINDING_CLASS = 'ng-binding';
|
||||
|
||||
|
@ -31,7 +30,7 @@ export class View {
|
|||
lightDoms: List<LightDom>;
|
||||
proto: ProtoView;
|
||||
_hydrated: boolean;
|
||||
_eventDispatcher: EventDispatcher;
|
||||
_eventDispatcher: any/*EventDispatcher*/;
|
||||
|
||||
constructor(
|
||||
proto:ProtoView, rootNodes:List,
|
||||
|
@ -43,6 +42,7 @@ export class View {
|
|||
this.viewContainers = viewContainers;
|
||||
this.contentTags = contentTags;
|
||||
this.lightDoms = ListWrapper.createFixedSize(boundElements.length);
|
||||
ListWrapper.fill(this.lightDoms, null);
|
||||
this.componentChildViews = ListWrapper.createFixedSize(boundElements.length);
|
||||
this._hydrated = false;
|
||||
}
|
||||
|
@ -134,7 +134,10 @@ export class View {
|
|||
|
||||
// componentChildViews
|
||||
for (var i = 0; i < this.componentChildViews.length; i++) {
|
||||
this.componentChildViews[i].dehydrate();
|
||||
var cv = this.componentChildViews[i];
|
||||
if (isPresent(cv)) {
|
||||
cv.dehydrate();
|
||||
}
|
||||
}
|
||||
|
||||
// viewContainers and content tags
|
||||
|
@ -150,10 +153,11 @@ export class View {
|
|||
}
|
||||
}
|
||||
}
|
||||
this._eventDispatcher = null;
|
||||
this._hydrated = false;
|
||||
}
|
||||
|
||||
setEventDispatcher(dispatcher:EventDispatcher) {
|
||||
setEventDispatcher(dispatcher:any/*EventDispatcher*/) {
|
||||
this._eventDispatcher = dispatcher;
|
||||
}
|
||||
|
||||
|
@ -161,8 +165,11 @@ export class View {
|
|||
if (isPresent(this._eventDispatcher)) {
|
||||
var evalLocals = MapWrapper.create();
|
||||
MapWrapper.set(evalLocals, '$event', event);
|
||||
var localValues = this.proto.elementBinders[elementIndex].eventLocals.eval(null, new Locals(null, evalLocals));
|
||||
this._eventDispatcher.dispatchEvent(elementIndex, eventName, localValues);
|
||||
// TODO(tbosch): reenable this when we are parsing element properties
|
||||
// out of action expressions
|
||||
// var localValues = this.proto.elementBinders[elementIndex].eventLocals.eval(null, new Locals(null, evalLocals));
|
||||
// this._eventDispatcher.dispatchEvent(elementIndex, eventName, localValues);
|
||||
this._eventDispatcher.dispatchEvent(elementIndex, eventName, evalLocals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ export class ViewContainer {
|
|||
if (isBlank(this._lightDom)) {
|
||||
for (var i = this._views.length - 1; i >= 0; i--) {
|
||||
var view = this._views[i];
|
||||
ViewContainer.removeViewNodesFromParent(this.templateElement.parentNode, view);
|
||||
ViewContainer.removeViewNodes(view);
|
||||
this._viewFactory.returnView(view);
|
||||
}
|
||||
this._views = [];
|
||||
|
@ -72,12 +72,11 @@ export class ViewContainer {
|
|||
}
|
||||
|
||||
insert(view, atIndex=-1): viewModule.View {
|
||||
this._checkHydrated();
|
||||
if (atIndex == -1) atIndex = this._views.length;
|
||||
ListWrapper.insert(this._views, atIndex, view);
|
||||
if (!view.hydrated()) {
|
||||
view.hydrate(this._hostLightDom);
|
||||
}
|
||||
if (atIndex == -1) atIndex = this._views.length;
|
||||
ListWrapper.insert(this._views, atIndex, view);
|
||||
|
||||
if (isBlank(this._lightDom)) {
|
||||
ViewContainer.moveViewNodesAfterSibling(this._siblingToInsertAfter(atIndex), view);
|
||||
|
@ -100,7 +99,7 @@ export class ViewContainer {
|
|||
var detachedView = this.get(atIndex);
|
||||
ListWrapper.removeAt(this._views, atIndex);
|
||||
if (isBlank(this._lightDom)) {
|
||||
ViewContainer.removeViewNodesFromParent(this.templateElement.parentNode, detachedView);
|
||||
ViewContainer.removeViewNodes(detachedView);
|
||||
} else {
|
||||
this._lightDom.redistribute();
|
||||
}
|
||||
|
@ -129,8 +128,11 @@ export class ViewContainer {
|
|||
}
|
||||
}
|
||||
|
||||
static removeViewNodesFromParent(parent, view) {
|
||||
for (var i = view.rootNodes.length - 1; i >= 0; --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,4 +1,4 @@
|
|||
import {OpaqueToken} from 'angular2/di';
|
||||
import {OpaqueToken, Inject, Injectable} from 'angular2/di';
|
||||
import {int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
|
||||
|
@ -8,32 +8,33 @@ 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 {ViewContainer} from './view_container';
|
||||
import {ProtoView} from './proto_view';
|
||||
import {View} from './view';
|
||||
import * as vcModule from './view_container';
|
||||
import * as pvModule from './proto_view';
|
||||
import * as viewModule from './view';
|
||||
import {NG_BINDING_CLASS_SELECTOR, NG_BINDING_CLASS} from '../util';
|
||||
|
||||
export var VIEW_POOL_CAPACITY = new OpaqueToken('ViewFactory.viewPoolCapacity');
|
||||
|
||||
// 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 {
|
||||
_poolCapacity:number;
|
||||
_pooledViews:List<View>;
|
||||
_pooledViews:List<viewModule.View>;
|
||||
_eventManager:EventManager;
|
||||
_shadowDomStrategy:ShadowDomStrategy;
|
||||
|
||||
constructor(capacity, eventManager, shadowDomStrategy) {
|
||||
constructor(@Inject(VIEW_POOL_CAPACITY) capacity, eventManager:EventManager, shadowDomStrategy:ShadowDomStrategy) {
|
||||
this._poolCapacity = capacity;
|
||||
this._pooledViews = ListWrapper.create();
|
||||
this._eventManager = eventManager;
|
||||
this._shadowDomStrategy = shadowDomStrategy;
|
||||
}
|
||||
|
||||
getView(protoView:ProtoView):View {
|
||||
getView(protoView:pvModule.ProtoView):viewModule.View {
|
||||
// TODO(tbosch): benchmark this scanning of views and maybe
|
||||
// replace it with a fancy LRU Map/List combination...
|
||||
var view;
|
||||
for (var i=0; i<this._pooledViews.length; i++) {
|
||||
for (var i=this._pooledViews.length-1; i>=0; i--) {
|
||||
var pooledView = this._pooledViews[i];
|
||||
if (pooledView.proto === protoView) {
|
||||
view = ListWrapper.removeAt(this._pooledViews, i);
|
||||
|
@ -45,7 +46,7 @@ export class ViewFactory {
|
|||
return view;
|
||||
}
|
||||
|
||||
returnView(view:View) {
|
||||
returnView(view:viewModule.View) {
|
||||
if (view.hydrated()) {
|
||||
view.dehydrate();
|
||||
}
|
||||
|
@ -55,7 +56,7 @@ export class ViewFactory {
|
|||
}
|
||||
}
|
||||
|
||||
_createView(protoView:ProtoView): View {
|
||||
_createView(protoView:pvModule.ProtoView): viewModule.View {
|
||||
var rootElementClone = protoView.isRootView ? protoView.element : DOM.importIntoDoc(protoView.element);
|
||||
var elementsWithBindingsDynamic;
|
||||
if (protoView.isTemplateElement) {
|
||||
|
@ -72,7 +73,7 @@ export class ViewFactory {
|
|||
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 ProtoView
|
||||
viewRootNodes = []; // TODO(perf): Should be fixed size, since we could pre-compute in in pvModule.ProtoView
|
||||
// Note: An explicit loop is the fastest way to convert a DOM array into a JS array!
|
||||
while(childNode != null) {
|
||||
ListWrapper.push(viewRootNodes, childNode);
|
||||
|
@ -108,7 +109,7 @@ export class ViewFactory {
|
|||
// viewContainers
|
||||
var viewContainer = null;
|
||||
if (isBlank(binder.componentId) && isPresent(binder.nestedProtoView)) {
|
||||
viewContainer = new ViewContainer(this, element);
|
||||
viewContainer = new vcModule.ViewContainer(this, element);
|
||||
}
|
||||
viewContainers[binderIdx] = viewContainer;
|
||||
|
||||
|
@ -120,7 +121,7 @@ export class ViewFactory {
|
|||
contentTags[binderIdx] = contentTag;
|
||||
}
|
||||
|
||||
var view = new View(
|
||||
var view = new viewModule.View(
|
||||
protoView, viewRootNodes,
|
||||
boundTextNodes, boundElements, viewContainers, contentTags
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {DomAdapter} from 'angular2/src/dom/dom_adapter';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {NgElement} from 'angular2/src/core/compiler/ng_element';
|
||||
|
||||
export class Rectangle {
|
||||
left;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {Injector} from 'angular2/di';
|
||||
import {Injector, bind} from 'angular2/di';
|
||||
|
||||
import {Type, isPresent, BaseException} from 'angular2/src/facade/lang';
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
|
@ -10,12 +10,15 @@ import {Template} from 'angular2/src/core/annotations/template';
|
|||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||
import {View} from 'angular2/src/core/compiler/view';
|
||||
import {ViewFactory} from 'angular2/src/core/compiler/view_factory';
|
||||
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
|
||||
import {queryView} from './utils';
|
||||
import {queryView, viewRootNodes, el} from './utils';
|
||||
import {instantiateType, getTypeOf} from './lang_utils';
|
||||
|
||||
|
||||
export class TestBed {
|
||||
_injector: Injector;
|
||||
|
||||
|
@ -85,11 +88,17 @@ export class TestBed {
|
|||
this.setInlineTemplate(component, html);
|
||||
}
|
||||
|
||||
return this._injector.get(Compiler).compile(component).then((pv) => {
|
||||
var eventManager = this._injector.get(EventManager);
|
||||
var view = pv.instantiate(null, eventManager);
|
||||
view.hydrate(this._injector, null, null, context, null);
|
||||
return new ViewProxy(view);
|
||||
var rootEl = el('<div></div>');
|
||||
var metadataReader = this._injector.get(DirectiveMetadataReader);
|
||||
var componentBinding = DirectiveBinding.createFromBinding(
|
||||
bind(component).toValue(context),
|
||||
metadataReader.read(component).annotation
|
||||
);
|
||||
return this._injector.get(Compiler).compileRoot(rootEl, componentBinding).then((pv) => {
|
||||
var viewFactory = this._injector.get(ViewFactory);
|
||||
var view = viewFactory.getView(pv);
|
||||
view.hydrate(this._injector, null, context, null);
|
||||
return new ViewProxy(view.componentChildViews[0]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -108,8 +117,8 @@ export class ViewProxy {
|
|||
return this._view.context;
|
||||
}
|
||||
|
||||
get nodes(): List {
|
||||
return this._view.nodes;
|
||||
get rootNodes(): List {
|
||||
return viewRootNodes(this._view);
|
||||
}
|
||||
|
||||
detectChanges(): void {
|
||||
|
|
|
@ -7,13 +7,15 @@ import {ExceptionHandler} from 'angular2/src/core/exception_handler';
|
|||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {ShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import {XHR} from 'angular2/src/services/xhr';
|
||||
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
|
||||
import {UrlResolver} from 'angular2/src/services/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 {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
|
||||
import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
|
@ -32,6 +34,13 @@ import {Injector} from 'angular2/di';
|
|||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {FunctionWrapper} from 'angular2/src/facade/lang';
|
||||
|
||||
import {ViewFactory, VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_factory';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
||||
|
||||
/**
|
||||
* Returns the root injector bindings.
|
||||
*
|
||||
|
@ -67,11 +76,19 @@ function _getAppBindings() {
|
|||
bind(ShadowDomStrategy).toFactory(
|
||||
(styleUrlResolver, doc) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, doc.head),
|
||||
[StyleUrlResolver, appDocumentToken]),
|
||||
bind(Renderer).toClass(DirectDomRenderer),
|
||||
bind(rc.Compiler).toClass(rc.DefaultCompiler),
|
||||
rvf.ViewFactory,
|
||||
bind(rvf.VIEW_POOL_CAPACITY).toValue(500),
|
||||
ProtoViewFactory,
|
||||
ViewFactory,
|
||||
bind(VIEW_POOL_CAPACITY).toValue(500),
|
||||
Compiler,
|
||||
CompilerCache,
|
||||
bind(TemplateResolver).toClass(MockTemplateResolver),
|
||||
bind(ChangeDetection).toValue(dynamicChangeDetection),
|
||||
TemplateLoader,
|
||||
PrivateComponentLoader,
|
||||
DirectiveMetadataReader,
|
||||
Parser,
|
||||
Lexer,
|
||||
|
|
|
@ -24,9 +24,14 @@ export class Log {
|
|||
}
|
||||
}
|
||||
|
||||
export function viewRootNodes(view) {
|
||||
return view.render.delegate.rootNodes;
|
||||
}
|
||||
|
||||
export function queryView(view, selector) {
|
||||
for (var i = 0; i < view.nodes.length; ++i) {
|
||||
var res = DOM.querySelector(view.nodes[i], selector);
|
||||
var rootNodes = viewRootNodes(view);
|
||||
for (var i = 0; i < rootNodes.length; ++i) {
|
||||
var res = DOM.querySelector(rootNodes[i], selector);
|
||||
if (isPresent(res)) {
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src
|
|||
import {Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
|
||||
import {NewCompiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {ProtoView} from 'angular2/src/core/compiler/view';
|
||||
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
|
@ -45,7 +45,7 @@ export function main() {
|
|||
var urlResolver = new FakeUrlResolver();
|
||||
renderer = new FakeRenderer(renderCompileResults);
|
||||
protoViewFactory = new FakeProtoViewFactory(protoViewFactoryResults)
|
||||
return new NewCompiler(
|
||||
return new Compiler(
|
||||
reader,
|
||||
new CompilerCache(),
|
||||
tplResolver,
|
||||
|
@ -373,7 +373,7 @@ export function main() {
|
|||
],
|
||||
[rootProtoView, mainProtoView]
|
||||
);
|
||||
compiler.compileRoot(null, createDirectiveBinding(reader, MainComponent)).then( (protoView) => {
|
||||
compiler.compileRoot(null, MainComponent).then( (protoView) => {
|
||||
expect(protoView).toBe(rootProtoView);
|
||||
expect(rootProtoView.elementBinders[0].nestedProtoView).toBe(mainProtoView);
|
||||
async.done();
|
||||
|
@ -388,7 +388,7 @@ function createDirectiveBinding(reader, type) {
|
|||
}
|
||||
|
||||
function createProtoView(elementBinders = null) {
|
||||
var pv = new ProtoView(null, null, null, null, null);
|
||||
var pv = new ProtoView(null, null, null);
|
||||
if (isBlank(elementBinders)) {
|
||||
elementBinders = [];
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, SpyObject, proxy, el} from 'angular2/test_lib';
|
||||
import {isBlank, isPresent, IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, MapWrapper, List, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ProtoElementInjector, PreBuiltObjects, DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
|
||||
import {EventEmitter, PropertySetter, Attribute} from 'angular2/src/core/annotations/di';
|
||||
|
@ -9,10 +8,11 @@ import {onDestroy} from 'angular2/src/core/annotations/annotations';
|
|||
import {Optional, Injector, Inject, bind} from 'angular2/di';
|
||||
import {ProtoView, View} from 'angular2/src/core/compiler/view';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {LightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
import {NgElement} from 'angular2/src/core/compiler/ng_element';
|
||||
import {Directive} from 'angular2/src/core/annotations/annotations';
|
||||
import {BindingPropagationConfig} from 'angular2/change_detection';
|
||||
import {BindingPropagationConfig, Parser, Lexer} from 'angular2/change_detection';
|
||||
|
||||
import {ViewRef, Renderer} from 'angular2/src/render/api';
|
||||
|
||||
class DummyDirective extends Directive {
|
||||
constructor({lifecycle} = {}) { super({lifecycle: lifecycle}); }
|
||||
|
@ -22,10 +22,6 @@ class DummyDirective extends Directive {
|
|||
@IMPLEMENTS(View)
|
||||
class DummyView extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(LightDom)
|
||||
class DummyLightDom extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
|
||||
|
||||
|
||||
class SimpleDirective {
|
||||
}
|
||||
|
@ -198,10 +194,10 @@ export function main() {
|
|||
|
||||
var proto = new ProtoElementInjector(null, 0, bindings, isPresent(shadowDomAppInjector));
|
||||
proto.attributes = attributes;
|
||||
var inj = proto.instantiate(null, null);
|
||||
var inj = proto.instantiate(null);
|
||||
var preBuilt = isPresent(preBuiltObjects) ? preBuiltObjects : defaultPreBuiltObjects;
|
||||
|
||||
inj.instantiateDirectives(lightDomAppInjector, shadowDomAppInjector, preBuilt);
|
||||
inj.instantiateDirectives(lightDomAppInjector, null, shadowDomAppInjector, preBuilt);
|
||||
return inj;
|
||||
}
|
||||
|
||||
|
@ -211,13 +207,13 @@ export function main() {
|
|||
var inj = new Injector([]);
|
||||
|
||||
var protoParent = new ProtoElementInjector(null, 0, parentBindings);
|
||||
var parent = protoParent.instantiate(null, null);
|
||||
var parent = protoParent.instantiate(null);
|
||||
|
||||
parent.instantiateDirectives(inj, null, parentPreBuildObjects);
|
||||
parent.instantiateDirectives(inj, null, null, parentPreBuildObjects);
|
||||
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, childBindings, false, 1);
|
||||
var child = protoChild.instantiate(parent, null);
|
||||
child.instantiateDirectives(inj, null, defaultPreBuiltObjects);
|
||||
var child = protoChild.instantiate(parent);
|
||||
child.instantiateDirectives(inj, null, null, defaultPreBuiltObjects);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
@ -229,12 +225,12 @@ export function main() {
|
|||
var shadowInj = inj.createChild([]);
|
||||
|
||||
var protoParent = new ProtoElementInjector(null, 0, hostBindings, true);
|
||||
var host = protoParent.instantiate(null, null);
|
||||
host.instantiateDirectives(inj, shadowInj, hostPreBuildObjects);
|
||||
var host = protoParent.instantiate(null);
|
||||
host.instantiateDirectives(inj, null, shadowInj, hostPreBuildObjects);
|
||||
|
||||
var protoChild = new ProtoElementInjector(protoParent, 0, shadowBindings, false, 1);
|
||||
var shadow = protoChild.instantiate(null, host);
|
||||
shadow.instantiateDirectives(shadowInj, null, null);
|
||||
var shadow = protoChild.instantiate(null);
|
||||
shadow.instantiateDirectives(shadowInj, host, null, null);
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
@ -278,9 +274,9 @@ export function main() {
|
|||
var protoChild1 = new ProtoElementInjector(protoParent, 1, []);
|
||||
var protoChild2 = new ProtoElementInjector(protoParent, 2, []);
|
||||
|
||||
var p = protoParent.instantiate(null, null);
|
||||
var c1 = protoChild1.instantiate(p, null);
|
||||
var c2 = protoChild2.instantiate(p, null);
|
||||
var p = protoParent.instantiate(null);
|
||||
var c1 = protoChild1.instantiate(p);
|
||||
var c2 = protoChild2.instantiate(p);
|
||||
|
||||
expect(humanize(p, [
|
||||
[p, 'parent'],
|
||||
|
@ -295,8 +291,8 @@ export function main() {
|
|||
var protoParent = new ProtoElementInjector(null, 0, []);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [], false, distance);
|
||||
|
||||
var p = protoParent.instantiate(null, null);
|
||||
var c = protoChild.instantiate(p, null);
|
||||
var p = protoParent.instantiate(null);
|
||||
var c = protoChild.instantiate(p);
|
||||
|
||||
expect(c.directParent()).toEqual(p);
|
||||
});
|
||||
|
@ -306,8 +302,8 @@ export function main() {
|
|||
var protoParent = new ProtoElementInjector(null, 0, []);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [], false, distance);
|
||||
|
||||
var p = protoParent.instantiate(null, null);
|
||||
var c = protoChild.instantiate(p, null);
|
||||
var p = protoParent.instantiate(null);
|
||||
var c = protoChild.instantiate(p);
|
||||
|
||||
expect(c.directParent()).toEqual(null);
|
||||
});
|
||||
|
@ -496,14 +492,14 @@ export function main() {
|
|||
});
|
||||
|
||||
it("should return element", function () {
|
||||
var element = new NgElement(null);
|
||||
var element = new NgElement(null, null);
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, element, null, null));
|
||||
|
||||
expect(inj.get(NgElement)).toEqual(element);
|
||||
});
|
||||
|
||||
it('should return viewContainer', function () {
|
||||
var viewContainer = new ViewContainer(null, null, null, null, null);
|
||||
var viewContainer = new ViewContainer(null, null, null, null);
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, viewContainer, null));
|
||||
|
||||
expect(inj.get(ViewContainer)).toEqual(viewContainer);
|
||||
|
@ -536,9 +532,9 @@ export function main() {
|
|||
injWithPrivateComponent.createPrivateComponent(SomeOtherDirective, null);
|
||||
|
||||
var shadowDomProtoInjector = new ProtoElementInjector(null, 0, [NeedDirectiveFromAncestor], false);
|
||||
var shadowDomInj = shadowDomProtoInjector.instantiate(null, injWithPrivateComponent);
|
||||
var shadowDomInj = shadowDomProtoInjector.instantiate(null);
|
||||
|
||||
expect(() => shadowDomInj.instantiateDirectives(appInjector, null, defaultPreBuiltObjects)).
|
||||
expect(() => shadowDomInj.instantiateDirectives(appInjector, injWithPrivateComponent, null, defaultPreBuiltObjects)).
|
||||
toThrowError(new RegExp("No provider for SimpleDirective"));
|
||||
});
|
||||
|
||||
|
@ -547,8 +543,8 @@ export function main() {
|
|||
injWithPrivateComponent.createPrivateComponent(SimpleDirective, null);
|
||||
|
||||
var shadowDomProtoInjector = new ProtoElementInjector(null, 0, [NeedDirectiveFromAncestor], false);
|
||||
var shadowDomInjector = shadowDomProtoInjector.instantiate(null, injWithPrivateComponent);
|
||||
shadowDomInjector.instantiateDirectives(appInjector, null, defaultPreBuiltObjects);
|
||||
var shadowDomInjector = shadowDomProtoInjector.instantiate(null);
|
||||
shadowDomInjector.instantiateDirectives(appInjector, injWithPrivateComponent, null, defaultPreBuiltObjects);
|
||||
|
||||
expect(shadowDomInjector.get(NeedDirectiveFromAncestor)).toBeAnInstanceOf(NeedDirectiveFromAncestor);
|
||||
expect(shadowDomInjector.get(NeedDirectiveFromAncestor).dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
|
@ -566,7 +562,7 @@ export function main() {
|
|||
expect(inj.getPrivateComponent()).toBe(null);
|
||||
expect(dir.onDestroyCounter).toBe(1);
|
||||
|
||||
inj.instantiateDirectives(null, null, null);
|
||||
inj.instantiateDirectives(null, null, null, null);
|
||||
|
||||
expect(inj.getPrivateComponent()).not.toBe(null);
|
||||
});
|
||||
|
@ -577,15 +573,18 @@ export function main() {
|
|||
function createpreBuildObject(eventName, eventHandler) {
|
||||
var handlers = StringMapWrapper.create();
|
||||
StringMapWrapper.set(handlers, eventName, eventHandler);
|
||||
var pv = new ProtoView(null, null, null, null);
|
||||
pv.eventHandlers = [handlers];
|
||||
var view = new View(pv, null, MapWrapper.create());
|
||||
var pv = new ProtoView(null, null, null);
|
||||
pv.bindElement(null, 0, null, null, null);
|
||||
pv.bindEvent(eventName, new Parser(new Lexer()).parseAction('handler()', ''));
|
||||
|
||||
var view = new View(pv, MapWrapper.create());
|
||||
view.context = new ContextWithHandler(eventHandler);
|
||||
return new PreBuiltObjects(view, null, null, null);
|
||||
}
|
||||
|
||||
it('should be injectable and callable', () => {
|
||||
var called = false;
|
||||
var preBuildObject = createpreBuildObject('click', (e, view) => { called = true;});
|
||||
var preBuildObject = createpreBuildObject('click', () => { called = true;});
|
||||
var inj = injector([NeedsEventEmitter], null, null, preBuildObject);
|
||||
inj.get(NeedsEventEmitter).click();
|
||||
expect(called).toEqual(true);
|
||||
|
@ -593,7 +592,7 @@ export function main() {
|
|||
|
||||
it('should be injectable and callable without specifying param type annotation', () => {
|
||||
var called = false;
|
||||
var preBuildObject = createpreBuildObject('click', (e, view) => { called = true;});
|
||||
var preBuildObject = createpreBuildObject('click', () => { called = true;});
|
||||
var inj = injector([NeedsEventEmitterNoType], null, null, preBuildObject);
|
||||
inj.get(NeedsEventEmitterNoType).click();
|
||||
expect(called).toEqual(true);
|
||||
|
@ -613,11 +612,17 @@ export function main() {
|
|||
});
|
||||
|
||||
describe('property setter', () => {
|
||||
it('should be injectable and callable', () => {
|
||||
var div = el('<div></div>');
|
||||
var ngElement = new NgElement(div);
|
||||
var renderer, view;
|
||||
|
||||
var preBuildObject = new PreBuiltObjects(null, ngElement, null, null);
|
||||
beforeEach( () => {
|
||||
renderer = new FakeRenderer();
|
||||
var protoView = new ProtoView(renderer, null, null);
|
||||
view = new View(protoView, MapWrapper.create());
|
||||
view.render = new ViewRef();
|
||||
});
|
||||
|
||||
it('should be injectable and callable', () => {
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null, null);
|
||||
var inj = injector([NeedsPropertySetter], null, null, preBuildObject);
|
||||
var component = inj.get(NeedsPropertySetter);
|
||||
component.setProp('foobar');
|
||||
|
@ -627,22 +632,21 @@ export function main() {
|
|||
component.setStyle('40px');
|
||||
component.setStyleWithUnit(50);
|
||||
|
||||
expect(div.title).toEqual('foobar');
|
||||
expect(DOM.getAttribute(div, 'role')).toEqual('button');
|
||||
expect(DOM.hasClass(div, 'active')).toEqual(true);
|
||||
expect(DOM.hasClass(div, 'foo-bar')).toEqual(true);
|
||||
expect(DOM.getStyle(div, 'width')).toEqual('40px');
|
||||
expect(DOM.getStyle(div, 'height')).toEqual('50px');
|
||||
expect(renderer.log[0]).toEqual([view.render, 0, 'title', 'foobar']);
|
||||
expect(renderer.log[1]).toEqual([view.render, 0, 'attr.role', 'button']);
|
||||
expect(renderer.log[2]).toEqual([view.render, 0, 'class.active', true]);
|
||||
expect(renderer.log[3]).toEqual([view.render, 0, 'class.foo-bar', true]);
|
||||
expect(renderer.log[4]).toEqual([view.render, 0, 'style.width', '40px']);
|
||||
expect(renderer.log[5]).toEqual([view.render, 0, 'style.height.px', 50]);
|
||||
});
|
||||
|
||||
it('should be injectable and callable without specifying param type annotation', () => {
|
||||
var div = el('<div></div>');
|
||||
var preBuildObject = new PreBuiltObjects(null, new NgElement(div), null, null);
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null, null);
|
||||
var inj = injector([NeedsPropertySetterNoType], null, null, preBuildObject);
|
||||
var component = inj.get(NeedsPropertySetterNoType);
|
||||
component.setProp('foobar');
|
||||
|
||||
expect(div.title).toEqual('foobar');
|
||||
expect(renderer.log[0]).toEqual([view.render, 0, 'title', 'foobar']);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -673,3 +677,22 @@ export function main() {
|
|||
|
||||
});
|
||||
}
|
||||
|
||||
class ContextWithHandler {
|
||||
handler;
|
||||
constructor(handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeRenderer extends Renderer {
|
||||
log:List;
|
||||
constructor() {
|
||||
super();
|
||||
this.log = [];
|
||||
}
|
||||
setElementProperty(viewRef, elementIndex, propertyName, value) {
|
||||
ListWrapper.push(this.log, [viewRef, elementIndex, propertyName, value]);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,32 +5,27 @@ import {
|
|||
xdescribe,
|
||||
describe,
|
||||
el,
|
||||
dispatchEvent,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
beforeEachBindings,
|
||||
it,
|
||||
xit,
|
||||
xit
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {TestBed} from 'angular2/src/test_lib/test_bed';
|
||||
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {Type, isPresent, BaseException, assertionsEnabled, isJsObject} from 'angular2/src/facade/lang';
|
||||
import {PromiseWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
import {Injector, bind} from 'angular2/di';
|
||||
import {Lexer, Parser, dynamicChangeDetection,
|
||||
DynamicChangeDetection, Pipe, PipeRegistry, BindingPropagationConfig, ON_PUSH} from 'angular2/change_detection';
|
||||
import {dynamicChangeDetection,
|
||||
ChangeDetection, DynamicChangeDetection, Pipe, PipeRegistry, BindingPropagationConfig, ON_PUSH} from 'angular2/change_detection';
|
||||
|
||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {ShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {PrivateComponentLocation} from 'angular2/src/core/compiler/private_component_location';
|
||||
import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader';
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
|
||||
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
|
||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
|
||||
import {Decorator, Component, Viewport, DynamicComponent} from 'angular2/src/core/annotations/annotations';
|
||||
import {Template} from 'angular2/src/core/annotations/template';
|
||||
|
@ -43,161 +38,117 @@ import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
|||
|
||||
export function main() {
|
||||
describe('integration tests', function() {
|
||||
var directiveMetadataReader, shadowDomStrategy, compiler, tplResolver;
|
||||
|
||||
function createCompiler(tplResolver, changedDetection) {
|
||||
var urlResolver = new UrlResolver();
|
||||
return new Compiler(changedDetection,
|
||||
new TemplateLoader(null, null),
|
||||
directiveMetadataReader,
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
shadowDomStrategy,
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver
|
||||
);
|
||||
}
|
||||
var ctx;
|
||||
|
||||
beforeEach( () => {
|
||||
tplResolver = new MockTemplateResolver();
|
||||
|
||||
directiveMetadataReader = new DirectiveMetadataReader();
|
||||
|
||||
var urlResolver = new UrlResolver();
|
||||
shadowDomStrategy = new EmulatedUnscopedShadowDomStrategy(new StyleUrlResolver(urlResolver), null);
|
||||
|
||||
compiler = createCompiler(tplResolver, dynamicChangeDetection);
|
||||
ctx = new MyComp();
|
||||
});
|
||||
|
||||
describe('react to record changes', function() {
|
||||
var view, ctx, cd;
|
||||
function createView(pv) {
|
||||
ctx = new MyComp();
|
||||
view = pv.instantiate(null, null);
|
||||
|
||||
view.hydrate(new Injector([
|
||||
bind(Compiler).toValue(compiler),
|
||||
bind(DirectiveMetadataReader).toValue(directiveMetadataReader),
|
||||
bind(ShadowDomStrategy).toValue(shadowDomStrategy),
|
||||
bind(EventManager).toValue(null),
|
||||
PrivateComponentLoader
|
||||
]), null, null, ctx, null);
|
||||
|
||||
cd = view.changeDetector;
|
||||
}
|
||||
|
||||
it('should consume text node changes', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: '<div>{{ctxProp}}</div>'}));
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
it('should consume text node changes', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({inline: '<div>{{ctxProp}}</div>'}));
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
ctx.ctxProp = 'Hello World!';
|
||||
|
||||
cd.detectChanges();
|
||||
expect(DOM.getInnerHTML(view.nodes[0])).toEqual('Hello World!');
|
||||
view.detectChanges();
|
||||
expect(DOM.getInnerHTML(view.rootNodes[0])).toEqual('Hello World!');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should consume element binding changes', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: '<div [id]="ctxProp"></div>'}));
|
||||
it('should consume element binding changes', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({inline: '<div [id]="ctxProp"></div>'}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
ctx.ctxProp = 'Hello World!';
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
|
||||
expect(view.nodes[0].id).toEqual('Hello World!');
|
||||
expect(view.rootNodes[0].id).toEqual('Hello World!');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should consume binding to aria-* attributes', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: '<div [attr.aria-label]="ctxProp"></div>'}));
|
||||
it('should consume binding to aria-* attributes', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({inline: '<div [attr.aria-label]="ctxProp"></div>'}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
ctx.ctxProp = 'Initial aria label';
|
||||
cd.detectChanges();
|
||||
expect(DOM.getAttribute(view.nodes[0], 'aria-label')).toEqual('Initial aria label');
|
||||
view.detectChanges();
|
||||
expect(DOM.getAttribute(view.rootNodes[0], 'aria-label')).toEqual('Initial aria label');
|
||||
|
||||
ctx.ctxProp = 'Changed aria label';
|
||||
cd.detectChanges();
|
||||
expect(DOM.getAttribute(view.nodes[0], 'aria-label')).toEqual('Changed aria label');
|
||||
view.detectChanges();
|
||||
expect(DOM.getAttribute(view.rootNodes[0], 'aria-label')).toEqual('Changed aria label');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should consume binding to property names where attr name and property name do not match', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: '<div [tabindex]="ctxNumProp"></div>'}));
|
||||
it('should consume binding to property names where attr name and property name do not match', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({inline: '<div [tabindex]="ctxNumProp"></div>'}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
cd.detectChanges();
|
||||
expect(view.nodes[0].tabIndex).toEqual(0);
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes[0].tabIndex).toEqual(0);
|
||||
|
||||
ctx.ctxNumProp = 5;
|
||||
cd.detectChanges();
|
||||
expect(view.nodes[0].tabIndex).toEqual(5);
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes[0].tabIndex).toEqual(5);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should consume binding to camel-cased properties using dash-cased syntax in templates', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: '<input [read-only]="ctxBoolProp">'}));
|
||||
it('should consume binding to camel-cased properties using dash-cased syntax in templates', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({inline: '<input [read-only]="ctxBoolProp">'}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
cd.detectChanges();
|
||||
expect(view.nodes[0].readOnly).toBeFalsy();
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes[0].readOnly).toBeFalsy();
|
||||
|
||||
ctx.ctxBoolProp = true;
|
||||
cd.detectChanges();
|
||||
expect(view.nodes[0].readOnly).toBeTruthy();
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes[0].readOnly).toBeTruthy();
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should consume binding to inner-html', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: '<div inner-html="{{ctxProp}}"></div>'}));
|
||||
it('should consume binding to inner-html', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({inline: '<div inner-html="{{ctxProp}}"></div>'}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
ctx.ctxProp = 'Some <span>HTML</span>';
|
||||
cd.detectChanges();
|
||||
expect(DOM.getInnerHTML(view.nodes[0])).toEqual('Some <span>HTML</span>');
|
||||
view.detectChanges();
|
||||
expect(DOM.getInnerHTML(view.rootNodes[0])).toEqual('Some <span>HTML</span>');
|
||||
|
||||
ctx.ctxProp = 'Some other <div>HTML</div>';
|
||||
cd.detectChanges();
|
||||
expect(DOM.getInnerHTML(view.nodes[0])).toEqual('Some other <div>HTML</div>');
|
||||
view.detectChanges();
|
||||
expect(DOM.getInnerHTML(view.rootNodes[0])).toEqual('Some other <div>HTML</div>');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should ignore bindings to unknown properties', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: '<div unknown="{{ctxProp}}"></div>'}));
|
||||
it('should ignore bindings to unknown properties', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({inline: '<div unknown="{{ctxProp}}"></div>'}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
ctx.ctxProp = 'Some value';
|
||||
cd.detectChanges();
|
||||
expect(DOM.hasProperty(view.nodes[0], 'unknown')).toBeFalsy();
|
||||
view.detectChanges();
|
||||
expect(DOM.hasProperty(view.rootNodes[0], 'unknown')).toBeFalsy();
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should consume directive watch expression change.', inject([AsyncTestCompleter], (async) => {
|
||||
it('should consume directive watch expression change.', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
var tpl =
|
||||
'<div>' +
|
||||
'<div my-dir [elprop]="ctxProp"></div>' +
|
||||
|
@ -205,80 +156,81 @@ export function main() {
|
|||
'<div my-dir elprop="Hi {{\'there!\'}}"></div>' +
|
||||
'<div my-dir elprop="One more {{ctxProp}}"></div>' +
|
||||
'</div>'
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: tpl, directives: [MyDir]}));
|
||||
tb.overrideTemplate(MyComp, new Template({inline: tpl, directives: [MyDir]}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
ctx.ctxProp = 'Hello World!';
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
|
||||
expect(view.elementInjectors[0].get(MyDir).dirProp).toEqual('Hello World!');
|
||||
expect(view.elementInjectors[1].get(MyDir).dirProp).toEqual('Hi there!');
|
||||
expect(view.elementInjectors[2].get(MyDir).dirProp).toEqual('Hi there!');
|
||||
expect(view.elementInjectors[3].get(MyDir).dirProp).toEqual('One more Hello World!');
|
||||
expect(view.rawView.elementInjectors[0].get(MyDir).dirProp).toEqual('Hello World!');
|
||||
expect(view.rawView.elementInjectors[1].get(MyDir).dirProp).toEqual('Hi there!');
|
||||
expect(view.rawView.elementInjectors[2].get(MyDir).dirProp).toEqual('Hi there!');
|
||||
expect(view.rawView.elementInjectors[3].get(MyDir).dirProp).toEqual('One more Hello World!');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support pipes in bindings and bind config", inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp,
|
||||
new Template({
|
||||
inline: '<component-with-pipes #comp [prop]="ctxProp | double"></component-with-pipes>',
|
||||
directives: [ComponentWithPipes]
|
||||
}));
|
||||
|
||||
|
||||
var registry = new PipeRegistry({
|
||||
"double" : [new DoublePipeFactory()]
|
||||
describe('pipes', () => {
|
||||
beforeEachBindings(() => {
|
||||
return [bind(ChangeDetection).toFactory(
|
||||
() => new DynamicChangeDetection(new PipeRegistry({
|
||||
"double" : [new DoublePipeFactory()]
|
||||
})),
|
||||
[]
|
||||
)];
|
||||
});
|
||||
var changeDetection = new DynamicChangeDetection(registry);
|
||||
var compiler = createCompiler(tplResolver, changeDetection);
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
|
||||
ctx.ctxProp = 'a';
|
||||
cd.detectChanges();
|
||||
it("should support pipes in bindings and bind config", inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp,
|
||||
new Template({
|
||||
inline: '<component-with-pipes #comp [prop]="ctxProp | double"></component-with-pipes>',
|
||||
directives: [ComponentWithPipes]
|
||||
}));
|
||||
|
||||
var comp = view.locals.get("comp");
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
// it is doubled twice: once in the binding, second time in the bind config
|
||||
expect(comp.prop).toEqual('aaaa');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
ctx.ctxProp = 'a';
|
||||
view.detectChanges();
|
||||
|
||||
it('should support nested components.', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
var comp = view.rawView.locals.get("comp");
|
||||
|
||||
// it is doubled twice: once in the binding, second time in the bind config
|
||||
expect(comp.prop).toEqual('aaaa');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
it('should support nested components.', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<child-cmp></child-cmp>',
|
||||
directives: [ChildComp]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
|
||||
expect(view.nodes).toHaveText('hello');
|
||||
expect(view.rootNodes).toHaveText('hello');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
// GH issue 328 - https://github.com/angular/angular/issues/328
|
||||
it('should support different directive types on a single node', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp,
|
||||
it('should support different directive types on a single node', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp,
|
||||
new Template({
|
||||
inline: '<child-cmp my-dir [elprop]="ctxProp"></child-cmp>',
|
||||
directives: [MyDir, ChildComp]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
ctx.ctxProp = 'Hello World!';
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
|
||||
var elInj = view.elementInjectors[0];
|
||||
var elInj = view.rawView.elementInjectors[0];
|
||||
expect(elInj.get(MyDir).dirProp).toEqual('Hello World!');
|
||||
expect(elInj.get(ChildComp).dirProp).toEqual(null);
|
||||
|
||||
|
@ -286,57 +238,54 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should support directives where a binding attribute is not given', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp,
|
||||
it('should support directives where a binding attribute is not given', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp,
|
||||
new Template({
|
||||
// No attribute "el-prop" specified.
|
||||
inline: '<p my-dir></p>',
|
||||
directives: [MyDir]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support directives where a selector matches property binding', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp,
|
||||
it('should support directives where a selector matches property binding', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp,
|
||||
new Template({
|
||||
inline: '<p [id]="ctxProp"></p>',
|
||||
directives: [IdComponent]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
ctx.ctxProp = 'some_id';
|
||||
cd.detectChanges();
|
||||
expect(view.nodes[0].id).toEqual('some_id');
|
||||
expect(view.nodes).toHaveText('Matched on id with some_id');
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes[0].id).toEqual('some_id');
|
||||
expect(view.rootNodes).toHaveText('Matched on id with some_id');
|
||||
|
||||
ctx.ctxProp = 'other_id';
|
||||
cd.detectChanges();
|
||||
expect(view.nodes[0].id).toEqual('other_id');
|
||||
expect(view.nodes).toHaveText('Matched on id with other_id');
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes[0].id).toEqual('other_id');
|
||||
expect(view.rootNodes).toHaveText('Matched on id with other_id');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support template directives via `<template>` elements.', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp,
|
||||
it('should support template directives via `<template>` elements.', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp,
|
||||
new Template({
|
||||
inline: '<div><template some-viewport var-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template></div>',
|
||||
directives: [SomeViewport]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
|
||||
var childNodesOfWrapper = view.nodes[0].childNodes;
|
||||
var childNodesOfWrapper = view.rootNodes[0].childNodes;
|
||||
// 1 template + 2 copies.
|
||||
expect(childNodesOfWrapper.length).toBe(3);
|
||||
expect(childNodesOfWrapper[1].childNodes[0].nodeValue).toEqual('hello');
|
||||
|
@ -345,18 +294,17 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should support template directives via `template` attribute.', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should support template directives via `template` attribute.', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<div><copy-me template="some-viewport: var greeting=some-tmpl">{{greeting}}</copy-me></div>',
|
||||
directives: [SomeViewport]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
|
||||
var childNodesOfWrapper = view.nodes[0].childNodes;
|
||||
var childNodesOfWrapper = view.rootNodes[0].childNodes;
|
||||
// 1 template + 2 copies.
|
||||
expect(childNodesOfWrapper.length).toBe(3);
|
||||
expect(childNodesOfWrapper[1].childNodes[0].nodeValue).toEqual('hello');
|
||||
|
@ -365,84 +313,79 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should assign the component instance to a var-', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should assign the component instance to a var-', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<p><child-cmp var-alice></child-cmp></p>',
|
||||
directives: [ChildComp]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
expect(view.locals).not.toBe(null);
|
||||
expect(view.locals.get('alice')).toBeAnInstanceOf(ChildComp);
|
||||
expect(view.rawView.locals).not.toBe(null);
|
||||
expect(view.rawView.locals.get('alice')).toBeAnInstanceOf(ChildComp);
|
||||
|
||||
async.done();
|
||||
})
|
||||
}));
|
||||
|
||||
it('should assign two component instances each with a var-', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should assign two component instances each with a var-', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<p><child-cmp var-alice></child-cmp><child-cmp var-bob></p>',
|
||||
directives: [ChildComp]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
expect(view.locals).not.toBe(null);
|
||||
expect(view.locals.get('alice')).toBeAnInstanceOf(ChildComp);
|
||||
expect(view.locals.get('bob')).toBeAnInstanceOf(ChildComp);
|
||||
expect(view.locals.get('alice')).not.toBe(view.locals.get('bob'));
|
||||
expect(view.rawView.locals).not.toBe(null);
|
||||
expect(view.rawView.locals.get('alice')).toBeAnInstanceOf(ChildComp);
|
||||
expect(view.rawView.locals.get('bob')).toBeAnInstanceOf(ChildComp);
|
||||
expect(view.rawView.locals.get('alice')).not.toBe(view.rawView.locals.get('bob'));
|
||||
|
||||
async.done();
|
||||
})
|
||||
}));
|
||||
|
||||
it('should assign the component instance to a var- with shorthand syntax', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should assign the component instance to a var- with shorthand syntax', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<child-cmp #alice></child-cmp>',
|
||||
directives: [ChildComp]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
expect(view.locals).not.toBe(null);
|
||||
expect(view.locals.get('alice')).toBeAnInstanceOf(ChildComp);
|
||||
expect(view.rawView.locals).not.toBe(null);
|
||||
expect(view.rawView.locals.get('alice')).toBeAnInstanceOf(ChildComp);
|
||||
|
||||
async.done();
|
||||
})
|
||||
}));
|
||||
|
||||
it('should assign the element instance to a user-defined variable', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp,
|
||||
it('should assign the element instance to a user-defined variable', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp,
|
||||
new Template({inline: '<p><div var-alice><i>Hello</i></div></p>'}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
expect(view.locals).not.toBe(null);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
expect(view.rawView.locals).not.toBe(null);
|
||||
|
||||
var value = view.locals.get('alice');
|
||||
var value = view.rawView.locals.get('alice');
|
||||
expect(value).not.toBe(null);
|
||||
expect(value.tagName.toLowerCase()).toEqual('div');
|
||||
expect(value.domElement.tagName.toLowerCase()).toEqual('div');
|
||||
|
||||
async.done();
|
||||
})
|
||||
}));
|
||||
|
||||
|
||||
it('should assign the element instance to a user-defined variable with camelCase using dash-case', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp,
|
||||
it('should assign the element instance to a user-defined variable with camelCase using dash-case', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp,
|
||||
new Template({inline: '<p><div var-super-alice><i>Hello</i></div></p>'}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
expect(view.locals).not.toBe(null);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
expect(view.rawView.locals).not.toBe(null);
|
||||
|
||||
var value = view.locals.get('superAlice');
|
||||
var value = view.rawView.locals.get('superAlice');
|
||||
expect(value).not.toBe(null);
|
||||
expect(value.tagName.toLowerCase()).toEqual('div');
|
||||
expect(value.domElement.tagName.toLowerCase()).toEqual('div');
|
||||
|
||||
async.done();
|
||||
})
|
||||
|
@ -450,49 +393,47 @@ export function main() {
|
|||
|
||||
describe("BindingPropagationConfig", () => {
|
||||
it("can be used to disable the change detection of the component's template",
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<push-cmp #cmp></push-cmp>',
|
||||
directives: [[[PushBasedComp]]]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
var cmp = view.locals.get('cmp');
|
||||
var cmp = view.rawView.locals.get('cmp');
|
||||
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
expect(cmp.numberOfChecks).toEqual(1);
|
||||
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
expect(cmp.numberOfChecks).toEqual(1);
|
||||
|
||||
cmp.propagate();
|
||||
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
expect(cmp.numberOfChecks).toEqual(2);
|
||||
async.done();
|
||||
})
|
||||
}));
|
||||
|
||||
it('should not affect updating properties on the component', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should not affect updating properties on the component', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<push-cmp [prop]="ctxProp" #cmp></push-cmp>',
|
||||
directives: [[[PushBasedComp]]]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
var cmp = view.locals.get('cmp');
|
||||
var cmp = view.rawView.locals.get('cmp');
|
||||
|
||||
ctx.ctxProp = "one";
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
expect(cmp.prop).toEqual("one");
|
||||
|
||||
ctx.ctxProp = "two";
|
||||
cd.detectChanges();
|
||||
view.detectChanges();
|
||||
expect(cmp.prop).toEqual("two");
|
||||
|
||||
async.done();
|
||||
|
@ -500,24 +441,23 @@ export function main() {
|
|||
}));
|
||||
});
|
||||
|
||||
it('should create a component that injects a @Parent', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should create a component that injects a @Parent', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<some-directive><cmp-with-parent #child></cmp-with-parent></some-directive>',
|
||||
directives: [SomeDirective, CompWithParent]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
var childComponent = view.locals.get('child');
|
||||
var childComponent = view.rawView.locals.get('child');
|
||||
expect(childComponent.myParent).toBeAnInstanceOf(SomeDirective);
|
||||
|
||||
async.done();
|
||||
})
|
||||
}));
|
||||
|
||||
it('should create a component that injects an @Ancestor', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should create a component that injects an @Ancestor', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: `
|
||||
<some-directive>
|
||||
<p>
|
||||
|
@ -527,18 +467,17 @@ export function main() {
|
|||
directives: [SomeDirective, CompWithAncestor]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
var childComponent = view.locals.get('child');
|
||||
var childComponent = view.rawView.locals.get('child');
|
||||
expect(childComponent.myAncestor).toBeAnInstanceOf(SomeDirective);
|
||||
|
||||
async.done();
|
||||
})
|
||||
}));
|
||||
|
||||
it('should create a component that injects an @Ancestor through viewport directive', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should create a component that injects an @Ancestor through viewport directive', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: `
|
||||
<some-directive>
|
||||
<p *if="true">
|
||||
|
@ -548,11 +487,10 @@ export function main() {
|
|||
directives: [SomeDirective, CompWithAncestor, If]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
cd.detectChanges();
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
view.detectChanges();
|
||||
|
||||
var subview = view.viewContainers[1].get(0);
|
||||
var subview = view.rawView.viewContainers[1].get(0);
|
||||
var childComponent = subview.locals.get('child');
|
||||
expect(childComponent.myAncestor).toBeAnInstanceOf(SomeDirective);
|
||||
|
||||
|
@ -560,16 +498,15 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should support events', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should support events via EventEmitter', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<div emitter listener></div>',
|
||||
directives: [DecoratorEmitingEvent, DecoratorListeningEvent]
|
||||
}));
|
||||
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
var injector = view.elementInjectors[0];
|
||||
var injector = view.rawView.elementInjectors[0];
|
||||
|
||||
var emitter = injector.get(DecoratorEmitingEvent);
|
||||
var listener = injector.get(DecoratorListeningEvent);
|
||||
|
@ -585,34 +522,54 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should support dynamic components', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
if (DOM.supportsDOMEvents()) {
|
||||
it('should support render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<div listener></div>',
|
||||
directives: [DecoratorListeningDomEvent]
|
||||
}));
|
||||
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
var injector = view.rawView.elementInjectors[0];
|
||||
|
||||
var listener = injector.get(DecoratorListeningDomEvent);
|
||||
|
||||
dispatchEvent(view.rootNodes[0], 'domEvent');
|
||||
|
||||
expect(listener.eventType).toEqual('domEvent');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
it('should support dynamic components', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<dynamic-comp #dynamic></dynamic-comp>',
|
||||
directives: [DynamicComp]
|
||||
}));
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
var dynamicComponent = view.locals.get("dynamic");
|
||||
var dynamicComponent = view.rawView.locals.get("dynamic");
|
||||
expect(dynamicComponent).toBeAnInstanceOf(DynamicComp);
|
||||
|
||||
dynamicComponent.done.then((_) => {
|
||||
cd.detectChanges();
|
||||
expect(view.nodes).toHaveText('hello');
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes).toHaveText('hello');
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support static attributes', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
it('should support static attributes', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideTemplate(MyComp, new Template({
|
||||
inline: '<input static type="text" title></input>',
|
||||
directives: [NeedsAttribute]
|
||||
}));
|
||||
compiler.compile(MyComp).then((pv) => {
|
||||
createView(pv);
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
var injector = view.elementInjectors[0];
|
||||
var injector = view.rawView.elementInjectors[0];
|
||||
var needsAttribute = injector.get(NeedsAttribute);
|
||||
expect(needsAttribute.typeAttribute).toEqual('text');
|
||||
expect(needsAttribute.titleAttribute).toEqual('');
|
||||
|
@ -632,9 +589,9 @@ export function main() {
|
|||
|
||||
if (assertionsEnabled()) {
|
||||
|
||||
function expectCompileError(inlineTpl, errMessage, done) {
|
||||
tplResolver.setTemplate(MyComp, new Template({inline: inlineTpl}));
|
||||
PromiseWrapper.then(compiler.compile(MyComp),
|
||||
function expectCompileError(tb, inlineTpl, errMessage, done) {
|
||||
tb.overrideTemplate(MyComp, new Template({inline: inlineTpl}));
|
||||
PromiseWrapper.then(tb.createView(MyComp),
|
||||
(value) => {
|
||||
throw new BaseException("Test failure: should not have come here as an exception was expected");
|
||||
},
|
||||
|
@ -645,32 +602,36 @@ export function main() {
|
|||
);
|
||||
}
|
||||
|
||||
it('should raise an error if no directive is registered for a template with template bindings', inject([AsyncTestCompleter], (async) => {
|
||||
it('should raise an error if no directive is registered for a template with template bindings', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
expectCompileError(
|
||||
tb,
|
||||
'<div><div template="if: foo"></div></div>',
|
||||
'Missing directive to handle \'if\' in <div template="if: foo">',
|
||||
() => async.done()
|
||||
);
|
||||
}));
|
||||
|
||||
it('should raise an error for missing template directive (1)', inject([AsyncTestCompleter], (async) => {
|
||||
it('should raise an error for missing template directive (1)', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
expectCompileError(
|
||||
tb,
|
||||
'<div><template foo></template></div>',
|
||||
'Missing directive to handle: <template foo>',
|
||||
() => async.done()
|
||||
);
|
||||
}));
|
||||
|
||||
it('should raise an error for missing template directive (2)', inject([AsyncTestCompleter], (async) => {
|
||||
it('should raise an error for missing template directive (2)', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
expectCompileError(
|
||||
tb,
|
||||
'<div><template *if="condition"></template></div>',
|
||||
'Missing directive to handle: <template *if="condition">',
|
||||
() => async.done()
|
||||
);
|
||||
}));
|
||||
|
||||
it('should raise an error for missing template directive (3)', inject([AsyncTestCompleter], (async) => {
|
||||
it('should raise an error for missing template directive (3)', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
expectCompileError(
|
||||
tb,
|
||||
'<div *if="condition"></div>',
|
||||
'Missing directive to handle \'if\' in MyComp: <div *if="condition">',
|
||||
() => async.done()
|
||||
|
@ -746,6 +707,8 @@ class PushBasedComp {
|
|||
}
|
||||
|
||||
@Component()
|
||||
@Template({directives: [
|
||||
]})
|
||||
class MyComp {
|
||||
ctxProp:string;
|
||||
ctxNumProp;
|
||||
|
@ -909,6 +872,22 @@ class DecoratorListeningEvent {
|
|||
}
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
selector: '[listener]',
|
||||
events: {'domEvent': 'onEvent($event.type)'}
|
||||
})
|
||||
class DecoratorListeningDomEvent {
|
||||
eventType: string;
|
||||
|
||||
constructor() {
|
||||
this.eventType = '';
|
||||
}
|
||||
|
||||
onEvent(eventType: string) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: '[id]',
|
||||
bind: {'id': 'id'}
|
||||
|
|
|
@ -14,7 +14,7 @@ export function main() {
|
|||
var loader;
|
||||
|
||||
beforeEach(() => {
|
||||
loader = new PrivateComponentLoader(null, null, null, new DirectiveMetadataReader());
|
||||
loader = new PrivateComponentLoader(null, new DirectiveMetadataReader(), null);
|
||||
});
|
||||
|
||||
describe('Load errors', () => {
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el, proxy} from 'angular2/test_lib';
|
||||
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
|
||||
import {LightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(LightDom)
|
||||
class DummyLightDom extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
|
||||
|
||||
var _scriptStart = `<script start=""></script>`;
|
||||
var _scriptEnd = `<script end=""></script>`;
|
||||
|
||||
export function main() {
|
||||
describe('Content', function() {
|
||||
var parent;
|
||||
var content;
|
||||
|
||||
beforeEach(() => {
|
||||
parent = el(`<div>${_scriptStart}${_scriptEnd}`);
|
||||
content = DOM.firstChild(parent);
|
||||
});
|
||||
|
||||
it("should insert the nodes", () => {
|
||||
var c = new Content(null, content, '');
|
||||
c.insert([el("<a></a>"), el("<b></b>")])
|
||||
|
||||
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}<a></a><b></b>${_scriptEnd}`);
|
||||
});
|
||||
|
||||
it("should remove the nodes from the previous insertion", () => {
|
||||
var c = new Content(null, content, '');
|
||||
c.insert([el("<a></a>")]);
|
||||
c.insert([el("<b></b>")]);
|
||||
|
||||
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}<b></b>${_scriptEnd}`);
|
||||
});
|
||||
|
||||
it("should insert empty list", () => {
|
||||
var c = new Content(null, content, '');
|
||||
c.insert([el("<a></a>")]);
|
||||
c.insert([]);
|
||||
|
||||
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}${_scriptEnd}`);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el, proxy} from 'angular2/test_lib';
|
||||
import {IMPLEMENTS, isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
|
||||
import {LightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
import {View} from 'angular2/src/core/compiler/view';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(View)
|
||||
class FakeView {
|
||||
contentTags;
|
||||
viewContainers;
|
||||
|
||||
constructor(containers = null) {
|
||||
this.contentTags = [];
|
||||
this.viewContainers = [];
|
||||
if (isPresent(containers)) {
|
||||
ListWrapper.forEach(containers, (c) => {
|
||||
if (c instanceof FakeContentTag) {
|
||||
ListWrapper.push(this.contentTags, c);
|
||||
} else {
|
||||
ListWrapper.push(this.contentTags, null);
|
||||
}
|
||||
if (c instanceof FakeViewContainer) {
|
||||
ListWrapper.push(this.viewContainers, c);
|
||||
} else {
|
||||
ListWrapper.push(this.viewContainers, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
noSuchMethod(i) {
|
||||
super.noSuchMethod(i);
|
||||
}
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(ViewContainer)
|
||||
class FakeViewContainer {
|
||||
templateElement;
|
||||
_nodes;
|
||||
_contentTagContainers;
|
||||
|
||||
constructor(templateEl, nodes = null, views = null) {
|
||||
this.templateElement = templateEl;
|
||||
this._nodes = nodes;
|
||||
this._contentTagContainers = views;
|
||||
}
|
||||
|
||||
nodes(){
|
||||
return this._nodes;
|
||||
}
|
||||
|
||||
contentTagContainers(){
|
||||
return this._contentTagContainers;
|
||||
}
|
||||
|
||||
noSuchMethod(i) {
|
||||
super.noSuchMethod(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(Content)
|
||||
class FakeContentTag {
|
||||
select;
|
||||
_nodes;
|
||||
contentStartElement;
|
||||
|
||||
constructor(contentEl, select = '', nodes = null) {
|
||||
this.contentStartElement = contentEl;
|
||||
this.select = select;
|
||||
this._nodes = nodes;
|
||||
}
|
||||
|
||||
insert(nodes){
|
||||
this._nodes = ListWrapper.clone(nodes);
|
||||
}
|
||||
|
||||
nodes() {
|
||||
return this._nodes;
|
||||
}
|
||||
|
||||
noSuchMethod(i) {
|
||||
super.noSuchMethod(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function main() {
|
||||
describe('LightDom', function() {
|
||||
var lightDomView;
|
||||
|
||||
beforeEach(() => {
|
||||
lightDomView = new FakeView();
|
||||
});
|
||||
|
||||
describe("contentTags", () => {
|
||||
it("should collect content tags from element injectors", () => {
|
||||
var tag = new FakeContentTag(el('<script></script>'));
|
||||
var shadowDomView = new FakeView([tag]);
|
||||
|
||||
var lightDom = new LightDom(lightDomView, shadowDomView,
|
||||
el("<div></div>"));
|
||||
|
||||
expect(lightDom.contentTags()).toEqual([tag]);
|
||||
});
|
||||
|
||||
it("should collect content tags from ViewContainers", () => {
|
||||
var tag = new FakeContentTag(el('<script></script>'));
|
||||
var vc = new FakeViewContainer(null, null, [
|
||||
new FakeView([tag])
|
||||
]);
|
||||
var shadowDomView = new FakeView([vc]);
|
||||
var lightDom = new LightDom(lightDomView, shadowDomView,
|
||||
el("<div></div>"));
|
||||
|
||||
expect(lightDom.contentTags()).toEqual([tag]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("expandedDomNodes", () => {
|
||||
it("should contain root nodes", () => {
|
||||
var lightDomEl = el("<div><a></a></div>")
|
||||
var lightDom = new LightDom(lightDomView, new FakeView(), lightDomEl);
|
||||
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
|
||||
});
|
||||
|
||||
it("should include view container nodes", () => {
|
||||
var lightDomEl = el("<div><template></template></div>");
|
||||
var lightDom = new LightDom(
|
||||
new FakeView([
|
||||
new FakeViewContainer(
|
||||
DOM.firstChild(lightDomEl), // template element
|
||||
[el('<a></a>')] // light DOM nodes of view container
|
||||
)
|
||||
]),
|
||||
null,
|
||||
lightDomEl);
|
||||
|
||||
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
|
||||
});
|
||||
|
||||
it("should include content nodes", () => {
|
||||
var lightDomEl = el("<div><content></content></div>");
|
||||
var lightDom = new LightDom(
|
||||
new FakeView([
|
||||
new FakeContentTag(
|
||||
DOM.firstChild(lightDomEl), // content element
|
||||
'', // selector
|
||||
[el('<a></a>')] // light DOM nodes of content tag
|
||||
)
|
||||
]),
|
||||
null,
|
||||
lightDomEl);
|
||||
|
||||
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
|
||||
});
|
||||
|
||||
it("should work when the element injector array contains nulls", () => {
|
||||
var lightDomEl = el("<div><a></a></div>")
|
||||
|
||||
var lightDomView = new FakeView();
|
||||
|
||||
var lightDom = new LightDom(
|
||||
lightDomView,
|
||||
new FakeView(),
|
||||
lightDomEl);
|
||||
|
||||
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("redistribute", () => {
|
||||
it("should redistribute nodes between content tags with select property set", () => {
|
||||
var contentA = new FakeContentTag(null, "a");
|
||||
var contentB = new FakeContentTag(null, "b");
|
||||
|
||||
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
|
||||
|
||||
var lightDom = new LightDom(lightDomView, new FakeView([
|
||||
contentA,
|
||||
contentB
|
||||
]), lightDomEl);
|
||||
|
||||
lightDom.redistribute();
|
||||
|
||||
expect(toHtml(contentA.nodes())).toEqual(["<a>1</a>", "<a>3</a>"]);
|
||||
expect(toHtml(contentB.nodes())).toEqual(["<b>2</b>"]);
|
||||
});
|
||||
|
||||
it("should support wildcard content tags", () => {
|
||||
var wildcard = new FakeContentTag(null, '');
|
||||
var contentB = new FakeContentTag(null, "b");
|
||||
|
||||
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
|
||||
|
||||
var lightDom = new LightDom(lightDomView, new FakeView([
|
||||
wildcard,
|
||||
contentB
|
||||
]), lightDomEl);
|
||||
|
||||
lightDom.redistribute();
|
||||
|
||||
expect(toHtml(wildcard.nodes())).toEqual(["<a>1</a>", "<b>2</b>", "<a>3</a>"]);
|
||||
expect(toHtml(contentB.nodes())).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function toHtml(nodes) {
|
||||
if (isBlank(nodes)) return [];
|
||||
return ListWrapper.map(nodes, DOM.getOuterHTML);
|
||||
}
|
|
@ -1,384 +0,0 @@
|
|||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xit,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
|
||||
import {Injector} from 'angular2/di';
|
||||
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
|
||||
import {ExceptionHandler} from 'angular2/src/core/exception_handler';
|
||||
|
||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {ShadowDomStrategy,
|
||||
NativeShadowDomStrategy,
|
||||
EmulatedScopedShadowDomStrategy,
|
||||
EmulatedUnscopedShadowDomStrategy,
|
||||
} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
|
||||
import {UrlResolver} from 'angular2/src/services/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 {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
|
||||
|
||||
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
|
||||
import {Template} from 'angular2/src/core/annotations/template';
|
||||
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
|
||||
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
||||
|
||||
export function main() {
|
||||
BrowserDomAdapter.makeCurrent();
|
||||
describe('integration tests', function() {
|
||||
var urlResolver;
|
||||
var styleUrlResolver;
|
||||
var styleInliner;
|
||||
var strategies = {
|
||||
"scoped" : () => new EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, DOM.createElement('div')),
|
||||
"unscoped" : () => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, DOM.createElement('div'))
|
||||
}
|
||||
if (DOM.supportsNativeShadowDOM()) {
|
||||
StringMapWrapper.set(strategies, "native", () => new NativeShadowDomStrategy(styleUrlResolver));
|
||||
}
|
||||
|
||||
StringMapWrapper.forEach(strategies,
|
||||
(strategyFactory, name) => {
|
||||
|
||||
describe(`${name} shadow dom strategy`, () => {
|
||||
var compiler, tplResolver;
|
||||
|
||||
beforeEach(() => {
|
||||
urlResolver = new UrlResolver();
|
||||
styleUrlResolver = new StyleUrlResolver(urlResolver);
|
||||
styleInliner = new StyleInliner(null, styleUrlResolver, urlResolver);
|
||||
tplResolver = new MockTemplateResolver();
|
||||
compiler = new Compiler(dynamicChangeDetection,
|
||||
new TemplateLoader(null, null),
|
||||
new DirectiveMetadataReader(),
|
||||
new Parser(new Lexer()),
|
||||
new CompilerCache(),
|
||||
strategyFactory(),
|
||||
tplResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver
|
||||
);
|
||||
});
|
||||
|
||||
function compile(template, directives: List<Type>, assertions) {
|
||||
tplResolver.setTemplate(MyComp, new Template({
|
||||
inline: template,
|
||||
directives: directives
|
||||
}));
|
||||
compiler.compile(MyComp)
|
||||
.then(createView)
|
||||
.then((view) => {
|
||||
var lc = new LifeCycle(new ExceptionHandler(), view.changeDetector, false);
|
||||
assertions(view, lc);
|
||||
});
|
||||
}
|
||||
|
||||
it('should support simple components', inject([AsyncTestCompleter], (async) => {
|
||||
var temp = '<simple>' +
|
||||
'<div>A</div>' +
|
||||
'</simple>';
|
||||
|
||||
compile(temp, [Simple], (view, lc) => {
|
||||
expect(view.nodes).toHaveText('SIMPLE(A)');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support multiple content tags', inject([AsyncTestCompleter], (async) => {
|
||||
var temp = '<multiple-content-tags>' +
|
||||
'<div>B</div>' +
|
||||
'<div>C</div>' +
|
||||
'<div class="left">A</div>' +
|
||||
'</multiple-content-tags>';
|
||||
|
||||
compile(temp, [MultipleContentTagsComponent], (view, lc) => {
|
||||
expect(view.nodes).toHaveText('(A, BC)');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should redistribute only direct children', inject([AsyncTestCompleter], (async) => {
|
||||
var temp = '<multiple-content-tags>' +
|
||||
'<div>B<div class="left">A</div></div>' +
|
||||
'<div>C</div>' +
|
||||
'</multiple-content-tags>';
|
||||
|
||||
compile(temp, [MultipleContentTagsComponent], (view, lc) => {
|
||||
expect(view.nodes).toHaveText('(, BAC)');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should redistribute direct child viewcontainers when the light dom changes", inject([AsyncTestCompleter], (async) => {
|
||||
var temp = '<multiple-content-tags>' +
|
||||
'<div><div template="manual" class="left">A</div></div>' +
|
||||
'<div>B</div>' +
|
||||
'</multiple-content-tags>';
|
||||
|
||||
compile(temp, [MultipleContentTagsComponent, ManualViewportDirective], (view, lc) => {
|
||||
var dir = view.elementInjectors[1].get(ManualViewportDirective);
|
||||
|
||||
expect(view.nodes).toHaveText('(, B)');
|
||||
|
||||
dir.show();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('(, AB)');
|
||||
|
||||
dir.hide();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('(, B)');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should redistribute when the light dom changes", inject([AsyncTestCompleter], (async) => {
|
||||
var temp = '<multiple-content-tags>' +
|
||||
'<div template="manual" class="left">A</div>' +
|
||||
'<div>B</div>' +
|
||||
'</multiple-content-tags>';
|
||||
|
||||
compile(temp, [MultipleContentTagsComponent, ManualViewportDirective], (view, lc) => {
|
||||
var dir = view.elementInjectors[1].get(ManualViewportDirective);
|
||||
|
||||
expect(view.nodes).toHaveText('(, B)');
|
||||
|
||||
dir.show();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('(A, B)');
|
||||
|
||||
dir.hide();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('(, B)');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support nested components", inject([AsyncTestCompleter], (async) => {
|
||||
var temp = '<outer-with-indirect-nested>' +
|
||||
'<div>A</div>' +
|
||||
'<div>B</div>' +
|
||||
'</outer-with-indirect-nested>';
|
||||
|
||||
compile(temp, [OuterWithIndirectNestedComponent], (view, lc) => {
|
||||
expect(view.nodes).toHaveText('OUTER(SIMPLE(AB))');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support nesting with content being direct child of a nested component", inject([AsyncTestCompleter], (async) => {
|
||||
var temp = '<outer>' +
|
||||
'<div template="manual" class="left">A</div>' +
|
||||
'<div>B</div>' +
|
||||
'<div>C</div>' +
|
||||
'</outer>';
|
||||
|
||||
compile(temp, [OuterComponent, ManualViewportDirective], (view, lc) => {
|
||||
var dir = view.elementInjectors[1].get(ManualViewportDirective);
|
||||
|
||||
expect(view.nodes).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
|
||||
|
||||
dir.show();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should redistribute when the shadow dom changes', inject([AsyncTestCompleter], (async) => {
|
||||
var temp = '<conditional-content>' +
|
||||
'<div class="left">A</div>' +
|
||||
'<div>B</div>' +
|
||||
'<div>C</div>' +
|
||||
'</conditional-content>';
|
||||
|
||||
|
||||
compile(temp, [ConditionalContentComponent, AutoViewportDirective], (view, lc) => {
|
||||
var cmp = view.elementInjectors[0].get(ConditionalContentComponent);
|
||||
|
||||
expect(view.nodes).toHaveText('(, ABC)');
|
||||
|
||||
cmp.showLeft();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('(A, BC)');
|
||||
|
||||
cmp.hideLeft();
|
||||
lc.tick();
|
||||
|
||||
expect(view.nodes).toHaveText('(, ABC)');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
//Implement once NgElement support changing a class
|
||||
//it("should redistribute when a class has been added or removed");
|
||||
//it('should not lose focus', () => {
|
||||
// var temp = `<simple>aaa<input type="text" id="focused-input" ng-class="{'aClass' : showClass}"> bbb</simple>`;
|
||||
//
|
||||
// compile(temp, (view, lc) => {
|
||||
// var input = view.nodes[1];
|
||||
// input.focus();
|
||||
//
|
||||
// expect(document.activeElement.id).toEqual("focused-input");
|
||||
//
|
||||
// // update class of input
|
||||
//
|
||||
// expect(document.activeElement.id).toEqual("focused-input");
|
||||
// });
|
||||
//});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
class TestDirectiveMetadataReader extends DirectiveMetadataReader {
|
||||
shadowDomStrategy;
|
||||
|
||||
constructor(shadowDomStrategy) {
|
||||
super();
|
||||
this.shadowDomStrategy = shadowDomStrategy;
|
||||
}
|
||||
|
||||
parseShadowDomStrategy(annotation:Component):ShadowDomStrategy{
|
||||
return this.shadowDomStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
@Viewport({
|
||||
selector: '[manual]'
|
||||
})
|
||||
class ManualViewportDirective {
|
||||
viewContainer;
|
||||
constructor(viewContainer:ViewContainer) {
|
||||
this.viewContainer = viewContainer;
|
||||
}
|
||||
|
||||
show() { this.viewContainer.create(); }
|
||||
hide() { this.viewContainer.remove(0); }
|
||||
}
|
||||
|
||||
@Viewport({
|
||||
selector: '[auto]',
|
||||
bind: {
|
||||
'auto': 'auto'
|
||||
}
|
||||
})
|
||||
class AutoViewportDirective {
|
||||
viewContainer;
|
||||
constructor(viewContainer:ViewContainer) {
|
||||
this.viewContainer = viewContainer;
|
||||
}
|
||||
|
||||
set auto(newValue:boolean) {
|
||||
if (newValue) {
|
||||
this.viewContainer.create();
|
||||
} else {
|
||||
this.viewContainer.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'simple'})
|
||||
@Template({inline: 'SIMPLE(<content></content>)'})
|
||||
class Simple {
|
||||
}
|
||||
|
||||
@Component({selector: 'multiple-content-tags'})
|
||||
@Template({
|
||||
inline: '(<content select=".left"></content>, <content></content>)'
|
||||
})
|
||||
class MultipleContentTagsComponent {
|
||||
}
|
||||
|
||||
|
||||
@Component({selector: 'conditional-content'})
|
||||
@Template({
|
||||
inline: '<div>(<div *auto="cond"><content select=".left"></content></div>, <content></content>)</div>',
|
||||
directives: [AutoViewportDirective]
|
||||
})
|
||||
class ConditionalContentComponent {
|
||||
cond:boolean;
|
||||
|
||||
constructor() {
|
||||
this.cond = false;
|
||||
}
|
||||
|
||||
showLeft() { this.cond = true; }
|
||||
hideLeft() { this.cond = false; }
|
||||
}
|
||||
|
||||
@Component({selector: 'outer-with-indirect-nested'})
|
||||
@Template({
|
||||
inline: 'OUTER(<simple><div><content></content></div></simple>)',
|
||||
directives: [Simple]
|
||||
})
|
||||
class OuterWithIndirectNestedComponent {
|
||||
}
|
||||
|
||||
@Component({selector: 'outer'})
|
||||
@Template({
|
||||
inline: 'OUTER(<inner><content></content></inner>)',
|
||||
directives: [InnerComponent]
|
||||
})
|
||||
class OuterComponent {
|
||||
}
|
||||
|
||||
@Component({selector: 'inner'})
|
||||
@Template({
|
||||
inline: 'INNER(<innerinner><content></content></innerinner>)',
|
||||
directives: [InnerInnerComponent]
|
||||
})
|
||||
class InnerComponent {
|
||||
}
|
||||
|
||||
@Component({selector: 'innerinner'})
|
||||
@Template({
|
||||
inline: 'INNERINNER(<content select=".left"></content>,<content></content>)'
|
||||
})
|
||||
class InnerInnerComponent {
|
||||
}
|
||||
|
||||
|
||||
@Component({selector: 'my-comp'})
|
||||
@Template({
|
||||
directives: [MultipleContentTagsComponent, ManualViewportDirective,
|
||||
ConditionalContentComponent, OuterWithIndirectNestedComponent, OuterComponent]
|
||||
})
|
||||
class MyComp {
|
||||
}
|
||||
|
||||
function createView(pv) {
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(new Injector([]), null, null, {}, null);
|
||||
return view;
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
SpyObject,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {
|
||||
NativeShadowDomStrategy,
|
||||
EmulatedScopedShadowDomStrategy,
|
||||
EmulatedUnscopedShadowDomStrategy
|
||||
} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {UrlResolver} from 'angular2/src/services/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 {ProtoView} from 'angular2/src/core/compiler/view';
|
||||
|
||||
import {XHR} from 'angular2/src/services/xhr';
|
||||
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {Map, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
|
||||
import {DynamicProtoChangeDetector} from 'angular2/change_detection';
|
||||
|
||||
export function main() {
|
||||
var strategy;
|
||||
|
||||
describe('NativeShadowDomStratgey', () => {
|
||||
beforeEach(() => {
|
||||
var urlResolver = new UrlResolver();
|
||||
var styleUrlResolver = new StyleUrlResolver(urlResolver);
|
||||
strategy = new NativeShadowDomStrategy(styleUrlResolver);
|
||||
});
|
||||
|
||||
it('should attach the view nodes to the shadow root', () => {
|
||||
var host = el('<div></div>');
|
||||
var nodes = el('<div>view</div>');
|
||||
var pv = new ProtoView(null, nodes, new DynamicProtoChangeDetector(null, null), null);
|
||||
var view = pv.instantiate(null, null);
|
||||
|
||||
strategy.attachTemplate(host, view);
|
||||
var shadowRoot = DOM.getShadowRoot(host);
|
||||
expect(isPresent(shadowRoot)).toBeTruthy();
|
||||
expect(shadowRoot).toHaveText('view');
|
||||
});
|
||||
});
|
||||
|
||||
describe('EmulatedScopedShadowDomStratgey', () => {
|
||||
var xhr, styleHost;
|
||||
|
||||
beforeEach(() => {
|
||||
var urlResolver = new UrlResolver();
|
||||
var styleUrlResolver = new StyleUrlResolver(urlResolver);
|
||||
xhr = new FakeXHR();
|
||||
var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
|
||||
styleHost = el('<div></div>');
|
||||
strategy = new EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, styleHost);
|
||||
});
|
||||
|
||||
it('should attach the view nodes as child of the host element', () => {
|
||||
var host = el('<div><span>original content</span></div>');
|
||||
var nodes = el('<div>view</div>');
|
||||
var pv = new ProtoView(null, nodes, new DynamicProtoChangeDetector(null, null), null);
|
||||
var view = pv.instantiate(null, null);
|
||||
|
||||
strategy.attachTemplate(host, view);
|
||||
var firstChild = DOM.firstChild(host);
|
||||
expect(DOM.tagName(firstChild).toLowerCase()).toEqual('div');
|
||||
expect(firstChild).toHaveText('view');
|
||||
expect(host).toHaveText('view');
|
||||
});
|
||||
});
|
||||
|
||||
describe('EmulatedUnscopedShadowDomStratgey', () => {
|
||||
var styleHost;
|
||||
|
||||
beforeEach(() => {
|
||||
var urlResolver = new UrlResolver();
|
||||
var styleUrlResolver = new StyleUrlResolver(urlResolver);
|
||||
styleHost = el('<div></div>');
|
||||
strategy = new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, styleHost);
|
||||
});
|
||||
|
||||
it('should attach the view nodes as child of the host element', () => {
|
||||
var host = el('<div><span>original content</span></div>');
|
||||
var nodes = el('<div>view</div>');
|
||||
var pv = new ProtoView(null, nodes, new DynamicProtoChangeDetector(null, null), null);
|
||||
var view = pv.instantiate(null, null);
|
||||
|
||||
strategy.attachTemplate(host, view);
|
||||
var firstChild = DOM.firstChild(host);
|
||||
expect(DOM.tagName(firstChild).toLowerCase()).toEqual('div');
|
||||
expect(firstChild).toHaveText('view');
|
||||
expect(host).toHaveText('view');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class FakeXHR extends XHR {
|
||||
_responses: Map;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._responses = MapWrapper.create();
|
||||
}
|
||||
|
||||
get(url: string): Promise<string> {
|
||||
var response = MapWrapper.get(this._responses, url);
|
||||
if (isBlank(response)) {
|
||||
return PromiseWrapper.reject('xhr error');
|
||||
}
|
||||
|
||||
return PromiseWrapper.resolve(response);
|
||||
}
|
||||
|
||||
reply(url: string, response: string) {
|
||||
MapWrapper.set(this._responses, url, response);
|
||||
}
|
||||
}
|
||||
|
||||
class SomeComponent {}
|
||||
class SomeOtherComponent {}
|
|
@ -1,251 +0,0 @@
|
|||
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el, proxy} from 'angular2/test_lib';
|
||||
import {View, ProtoView} from 'angular2/src/core/compiler/view';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {Injector} from 'angular2/di';
|
||||
import {ProtoElementInjector, ElementInjector} from 'angular2/src/core/compiler/element_injector';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {DynamicProtoChangeDetector, ChangeDetector, Lexer, Parser} from 'angular2/change_detection';
|
||||
|
||||
function createView(nodes) {
|
||||
var view = new View(null, nodes, MapWrapper.create());
|
||||
var cd = new DynamicProtoChangeDetector(null, null).instantiate(view, [], null, []);
|
||||
view.init(cd, [], [], [], [], [], [], [], [], []);
|
||||
return view;
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(ChangeDetector)
|
||||
class AttachableChangeDetector {
|
||||
parent;
|
||||
constructor() {
|
||||
}
|
||||
remove() {
|
||||
this.parent = null;
|
||||
}
|
||||
noSuchMethod(i) {
|
||||
super.noSuchMethod(i);
|
||||
}
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(View)
|
||||
class HydrateAwareFakeView {
|
||||
isHydrated: boolean;
|
||||
nodes: List;
|
||||
changeDetector: ChangeDetector;
|
||||
rootElementInjectors;
|
||||
constructor(isHydrated) {
|
||||
this.isHydrated = isHydrated;
|
||||
this.nodes = [DOM.createElement('div')];
|
||||
this.rootElementInjectors = [];
|
||||
this.changeDetector = new AttachableChangeDetector();
|
||||
}
|
||||
|
||||
hydrated() {
|
||||
return this.isHydrated;
|
||||
}
|
||||
|
||||
|
||||
hydrate(_, __, ___, ____, _____) {
|
||||
this.isHydrated = true;
|
||||
}
|
||||
|
||||
dehydrate() {
|
||||
this.isHydrated = false;
|
||||
}
|
||||
|
||||
noSuchMethod(i) {
|
||||
super.noSuchMethod(i);
|
||||
}
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe('ViewContainer', () => {
|
||||
var viewContainer, parentView, protoView, dom, customViewWithOneNode,
|
||||
customViewWithTwoNodes, elementInjector;
|
||||
|
||||
beforeEach(() => {
|
||||
dom = el(`<div><stuff></stuff><div insert-after-me></div><stuff></stuff></div>`);
|
||||
var insertionElement = dom.childNodes[1];
|
||||
parentView = createView([dom.childNodes[0]]);
|
||||
protoView = new ProtoView(null, el('<div>hi</div>'), new DynamicProtoChangeDetector(null, null),
|
||||
new NativeShadowDomStrategy(null));
|
||||
elementInjector = new ElementInjector(null, null, null);
|
||||
viewContainer = new ViewContainer(parentView, insertionElement, protoView, elementInjector,
|
||||
null);
|
||||
customViewWithOneNode = createView([el('<div>single</div>')]);
|
||||
customViewWithTwoNodes = createView([el('<div>one</div>'), el('<div>two</div>')]);
|
||||
});
|
||||
|
||||
describe('when dehydrated', () => {
|
||||
it('should throw if create is called', () => {
|
||||
expect(() => viewContainer.create()).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when hydrated', () => {
|
||||
function textInViewContainer() {
|
||||
var out = '';
|
||||
// skipping starting filler, insert-me and final filler.
|
||||
for (var i = 2; i < dom.childNodes.length - 1; i++) {
|
||||
if (i != 2) out += ' ';
|
||||
out += DOM.getInnerHTML(dom.childNodes[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
viewContainer.hydrate(new Injector([]), null, null);
|
||||
var fillerView = createView([el('<filler>filler</filler>')]);
|
||||
viewContainer.insert(fillerView);
|
||||
});
|
||||
|
||||
it('should create new views from protoView', () => {
|
||||
viewContainer.create();
|
||||
expect(textInViewContainer()).toEqual('filler hi');
|
||||
expect(viewContainer.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should create new views from protoView at index', () => {
|
||||
viewContainer.create(0);
|
||||
expect(textInViewContainer()).toEqual('hi filler');
|
||||
expect(viewContainer.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should insert new views at the end by default', () => {
|
||||
viewContainer.insert(customViewWithOneNode);
|
||||
expect(textInViewContainer()).toEqual('filler single');
|
||||
expect(viewContainer.get(1)).toBe(customViewWithOneNode);
|
||||
expect(viewContainer.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should insert new views at the given index', () => {
|
||||
viewContainer.insert(customViewWithOneNode, 0);
|
||||
expect(textInViewContainer()).toEqual('single filler');
|
||||
expect(viewContainer.get(0)).toBe(customViewWithOneNode);
|
||||
expect(viewContainer.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should remove the last view by default', () => {
|
||||
viewContainer.insert(customViewWithOneNode);
|
||||
|
||||
viewContainer.remove();
|
||||
|
||||
expect(textInViewContainer()).toEqual('filler');
|
||||
expect(viewContainer.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should remove the view at a given index', () => {
|
||||
viewContainer.insert(customViewWithOneNode);
|
||||
viewContainer.insert(customViewWithTwoNodes);
|
||||
|
||||
viewContainer.remove(1);
|
||||
|
||||
expect(textInViewContainer()).toEqual('filler one two');
|
||||
expect(viewContainer.get(1)).toBe(customViewWithTwoNodes);
|
||||
expect(viewContainer.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should detach the last view by default', () => {
|
||||
viewContainer.insert(customViewWithOneNode);
|
||||
expect(viewContainer.length).toBe(2);
|
||||
|
||||
var detachedView = viewContainer.detach();
|
||||
|
||||
expect(detachedView).toBe(customViewWithOneNode);
|
||||
expect(textInViewContainer()).toEqual('filler');
|
||||
expect(viewContainer.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should detach the view at a given index', () => {
|
||||
viewContainer.insert(customViewWithOneNode);
|
||||
viewContainer.insert(customViewWithTwoNodes);
|
||||
expect(viewContainer.length).toBe(3);
|
||||
|
||||
var detachedView = viewContainer.detach(1);
|
||||
expect(detachedView).toBe(customViewWithOneNode);
|
||||
expect(textInViewContainer()).toEqual('filler one two');
|
||||
expect(viewContainer.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should keep views hydration state during insert', () => {
|
||||
var hydratedView = new HydrateAwareFakeView(true);
|
||||
var dehydratedView = new HydrateAwareFakeView(false);
|
||||
viewContainer.insert(hydratedView);
|
||||
viewContainer.insert(dehydratedView);
|
||||
|
||||
expect(hydratedView.hydrated()).toBe(true);
|
||||
expect(dehydratedView.hydrated()).toBe(false);
|
||||
});
|
||||
|
||||
it('should dehydrate on remove', () => {
|
||||
var hydratedView = new HydrateAwareFakeView(true);
|
||||
viewContainer.insert(hydratedView);
|
||||
viewContainer.remove();
|
||||
|
||||
expect(hydratedView.hydrated()).toBe(false);
|
||||
});
|
||||
|
||||
it('should keep views hydration state during detach', () => {
|
||||
var hydratedView = new HydrateAwareFakeView(true);
|
||||
var dehydratedView = new HydrateAwareFakeView(false);
|
||||
viewContainer.insert(hydratedView);
|
||||
viewContainer.insert(dehydratedView);
|
||||
|
||||
expect(viewContainer.detach().hydrated()).toBe(false);
|
||||
expect(viewContainer.detach().hydrated()).toBe(true);
|
||||
});
|
||||
|
||||
it('should support adding/removing views with more than one node', () => {
|
||||
viewContainer.insert(customViewWithTwoNodes);
|
||||
viewContainer.insert(customViewWithOneNode);
|
||||
|
||||
expect(textInViewContainer()).toEqual('filler one two single');
|
||||
|
||||
viewContainer.remove(1);
|
||||
expect(textInViewContainer()).toEqual('filler single');
|
||||
});
|
||||
});
|
||||
|
||||
describe('should update injectors and parent views.', () => {
|
||||
var fancyView;
|
||||
beforeEach(() => {
|
||||
var parser = new Parser(new Lexer());
|
||||
viewContainer.hydrate(new Injector([]), null, null);
|
||||
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding">{{}}</div>'),
|
||||
new DynamicProtoChangeDetector(null, null), new NativeShadowDomStrategy(null));
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 1, [SomeDirective]));
|
||||
pv.bindTextNode(0, parser.parseBinding('foo', null));
|
||||
fancyView = pv.instantiate(null, null);
|
||||
});
|
||||
|
||||
it('hydrating should update rootElementInjectors and parent change detector', () => {
|
||||
viewContainer.insert(fancyView);
|
||||
ListWrapper.forEach(fancyView.rootElementInjectors, (inj) =>
|
||||
expect(inj.parent).toBe(elementInjector));
|
||||
|
||||
expect(parentView.changeDetector.lightDomChildren.length).toBe(1);
|
||||
});
|
||||
|
||||
it('dehydrating should update rootElementInjectors and parent change detector', () => {
|
||||
viewContainer.insert(fancyView);
|
||||
viewContainer.remove();
|
||||
ListWrapper.forEach(fancyView.rootElementInjectors, (inj) =>
|
||||
expect(inj.parent).toBe(null));
|
||||
expect(parentView.changeDetector.lightDomChildren.length).toBe(0);
|
||||
expect(viewContainer.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class SomeDirective {
|
||||
prop;
|
||||
constructor() {
|
||||
this.prop = 'foo';
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el, proxy} from 'angular2/test_lib';
|
||||
|
||||
import {View} from 'angular2/src/core/compiler/view';
|
||||
import {ViewPool} from 'angular2/src/core/compiler/view_pool';
|
||||
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(View)
|
||||
class FakeView {
|
||||
noSuchMethod(i) {
|
||||
super.noSuchMethod(i);
|
||||
}
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe('ViewPool', () => {
|
||||
var viewPool, capacity = 3;
|
||||
beforeEach(() => {
|
||||
viewPool = new ViewPool(capacity);
|
||||
})
|
||||
|
||||
it('should return null when there are no views', () => {
|
||||
expect(viewPool.pop()).toBeNull();
|
||||
expect(viewPool.length()).toBe(0);
|
||||
})
|
||||
|
||||
it('should support storing and retrieving a view', () => {
|
||||
var view = new FakeView();
|
||||
viewPool.push(view);
|
||||
expect(viewPool.length()).toBe(1);
|
||||
|
||||
expect(viewPool.pop()).toBe(view);
|
||||
expect(viewPool.length()).toBe(0);
|
||||
})
|
||||
|
||||
it('should not store more views that its capacity', () => {
|
||||
for (var i = 0; i < capacity * 2; i++) viewPool.push(new FakeView());
|
||||
expect(viewPool.length()).toBe(capacity);
|
||||
|
||||
for (var i = 0; i < capacity; i++) {
|
||||
expect(viewPool.pop()).not.toBe(null);
|
||||
}
|
||||
expect(viewPool.pop()).toBeNull();
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,787 +0,0 @@
|
|||
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el, proxy} from 'angular2/test_lib';
|
||||
import {ProtoView, ElementPropertyMemento, DirectivePropertyMemento} from 'angular2/src/core/compiler/view';
|
||||
import {ProtoElementInjector, ElementInjector, DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {EmulatedScopedShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {Component, Decorator, Viewport, Directive, onChange, onAllChangesDone} from 'angular2/src/core/annotations/annotations';
|
||||
import {Lexer, Parser, DynamicProtoChangeDetector,
|
||||
ChangeDetector} from 'angular2/change_detection';
|
||||
import {EventEmitter} from 'angular2/src/core/annotations/di';
|
||||
import {List, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {int, IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||
import {Injector} from 'angular2/di';
|
||||
import {View} from 'angular2/src/core/compiler/view';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
|
||||
import {EventManager, DomEventsPlugin} from 'angular2/src/render/dom/events/event_manager';
|
||||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
|
||||
class DummyDirective extends Directive {
|
||||
constructor({lifecycle} = {}) { super({lifecycle: lifecycle}); }
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(ViewContainer)
|
||||
class FakeViewContainer {
|
||||
templateElement;
|
||||
|
||||
constructor(templateElement) {
|
||||
this.templateElement = templateElement;
|
||||
}
|
||||
|
||||
noSuchMethod(i) {
|
||||
super.noSuchMethod(i);
|
||||
}
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(View)
|
||||
class FakeView {
|
||||
noSuchMethod(i) {
|
||||
super.noSuchMethod(i);
|
||||
}
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe('view', function() {
|
||||
var parser, someComponentDirective, someViewportDirective;
|
||||
|
||||
function createView(protoView, eventManager: EventManager = null) {
|
||||
var ctx = new MyEvaluationContext();
|
||||
var view = protoView.instantiate(null, eventManager);
|
||||
view.hydrate(null, null, null, ctx, null);
|
||||
return view;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
parser = new Parser(new Lexer());
|
||||
someComponentDirective = readDirectiveBinding(SomeComponent);
|
||||
someViewportDirective = readDirectiveBinding(SomeViewport);
|
||||
});
|
||||
|
||||
describe('instantiated from protoView', () => {
|
||||
var view;
|
||||
beforeEach(() => {
|
||||
var pv = new ProtoView(null, el('<div id="1"></div>'), new DynamicProtoChangeDetector(null, null), null);
|
||||
view = pv.instantiate(null, null);
|
||||
});
|
||||
|
||||
it('should be dehydrated by default', () => {
|
||||
expect(view.hydrated()).toBe(false);
|
||||
});
|
||||
|
||||
it('should be able to be hydrated and dehydrated', () => {
|
||||
var ctx = new Object();
|
||||
view.hydrate(null, null, null, ctx, null);
|
||||
expect(view.hydrated()).toBe(true);
|
||||
|
||||
view.dehydrate();
|
||||
expect(view.hydrated()).toBe(false);
|
||||
});
|
||||
|
||||
it('should hydrate and dehydrate the change detector', () => {
|
||||
var ctx = new Object();
|
||||
view.hydrate(null, null, null, ctx, null);
|
||||
expect(view.changeDetector.hydrated()).toBe(true);
|
||||
|
||||
view.dehydrate();
|
||||
expect(view.changeDetector.hydrated()).toBe(false);
|
||||
});
|
||||
|
||||
it('should use the view pool to reuse views', () => {
|
||||
var pv = new ProtoView(null, el('<div id="1"></div>'), new DynamicProtoChangeDetector(null, null), null);
|
||||
var fakeView = new FakeView();
|
||||
pv.returnToPool(fakeView);
|
||||
|
||||
expect(pv.instantiate(null, null)).toBe(fakeView);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with locals', function() {
|
||||
var view;
|
||||
beforeEach(() => {
|
||||
var pv = new ProtoView(null, el('<div id="1"></div>'), new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindVariable('context-foo', 'template-foo');
|
||||
view = createView(pv);
|
||||
});
|
||||
|
||||
it('should support setting of declared locals', () => {
|
||||
view.setLocal('context-foo', 'bar');
|
||||
expect(view.locals.get('template-foo')).toBe('bar');
|
||||
});
|
||||
|
||||
it('should not throw on undeclared locals', () => {
|
||||
expect(() => view.setLocal('setMePlease', 'bar')).not.toThrow();
|
||||
});
|
||||
|
||||
it('when dehydrated should set locals to null', () => {
|
||||
view.setLocal('context-foo', 'bar');
|
||||
view.dehydrate();
|
||||
view.hydrate(null, null, null, new Object(), null);
|
||||
expect(view.locals.get('template-foo')).toBe(null);
|
||||
});
|
||||
|
||||
it('should throw when trying to set on dehydrated view', () => {
|
||||
view.dehydrate();
|
||||
expect(() => view.setLocal('context-foo', 'bar')).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('instantiated and hydrated', function() {
|
||||
|
||||
function createCollectDomNodesTestCases(useTemplateElement:boolean) {
|
||||
|
||||
function templateAwareCreateElement(html) {
|
||||
return el(useTemplateElement ? `<template>${html}</template>` : html);
|
||||
}
|
||||
|
||||
it('should collect the root node in the ProtoView element', () => {
|
||||
var pv = new ProtoView(null, templateAwareCreateElement('<div id="1"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.nodes.length).toBe(1);
|
||||
expect(DOM.getAttribute(view.nodes[0], 'id')).toEqual('1');
|
||||
});
|
||||
|
||||
describe('collect elements with property bindings', () => {
|
||||
|
||||
it('should collect property bindings on the root element if it has the ng-binding class', () => {
|
||||
var pv = new ProtoView(null, templateAwareCreateElement('<div [prop]="a" class="ng-binding"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, null);
|
||||
pv.bindElementProperty(parser.parseBinding('a', null), 'prop', reflector.setter('prop'));
|
||||
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.bindElements.length).toEqual(1);
|
||||
expect(view.bindElements[0]).toBe(view.nodes[0]);
|
||||
});
|
||||
|
||||
it('should collect property bindings on child elements with ng-binding class', () => {
|
||||
var pv = new ProtoView(null, templateAwareCreateElement('<div><span></span><span class="ng-binding"></span></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, null);
|
||||
pv.bindElementProperty(parser.parseBinding('b', null), 'a', reflector.setter('a'));
|
||||
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.bindElements.length).toEqual(1);
|
||||
expect(view.bindElements[0]).toBe(view.nodes[0].childNodes[1]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('collect text nodes with bindings', () => {
|
||||
|
||||
it('should collect text nodes under the root element', () => {
|
||||
var pv = new ProtoView(null, templateAwareCreateElement('<div class="ng-binding">{{}}<span></span>{{}}</div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, null);
|
||||
pv.bindTextNode(0, parser.parseBinding('a', null));
|
||||
pv.bindTextNode(2, parser.parseBinding('b', null));
|
||||
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.textNodes.length).toEqual(2);
|
||||
expect(view.textNodes[0]).toBe(view.nodes[0].childNodes[0]);
|
||||
expect(view.textNodes[1]).toBe(view.nodes[0].childNodes[2]);
|
||||
});
|
||||
|
||||
it('should collect text nodes with bindings on child elements with ng-binding class', () => {
|
||||
var pv = new ProtoView(null, templateAwareCreateElement('<div><span> </span><span class="ng-binding">{{}}</span></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, null);
|
||||
pv.bindTextNode(0, parser.parseBinding('b', null));
|
||||
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.textNodes.length).toEqual(1);
|
||||
expect(view.textNodes[0]).toBe(view.nodes[0].childNodes[1].childNodes[0]);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
describe('inplace instantiation', () => {
|
||||
it('should be supported.', () => {
|
||||
var template = el('<div></div>');
|
||||
var pv = new ProtoView(null, template, new DynamicProtoChangeDetector(null, null),
|
||||
new NativeShadowDomStrategy(null));
|
||||
pv.instantiateInPlace = true;
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.nodes[0]).toBe(template);
|
||||
});
|
||||
|
||||
it('should be off by default.', () => {
|
||||
var template = el('<div></div>')
|
||||
var pv = new ProtoView(null, template, new DynamicProtoChangeDetector(null, null),
|
||||
new NativeShadowDomStrategy(null))
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.nodes[0]).not.toBe(template);
|
||||
});
|
||||
});
|
||||
|
||||
describe('collect dom nodes with a regular element as root', () => {
|
||||
createCollectDomNodesTestCases(false);
|
||||
});
|
||||
|
||||
describe('collect dom nodes with a template element as root', () => {
|
||||
createCollectDomNodesTestCases(true);
|
||||
});
|
||||
|
||||
describe('create ElementInjectors', () => {
|
||||
it('should use the directives of the ProtoElementInjector', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 1, [SomeDirective]));
|
||||
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.elementInjectors.length).toBe(1);
|
||||
expect(view.elementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
|
||||
});
|
||||
|
||||
it('should use the correct parent', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
|
||||
pv.bindElement(null, 0, protoParent);
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
|
||||
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.elementInjectors.length).toBe(2);
|
||||
expect(view.elementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
|
||||
expect(view.elementInjectors[1].parent).toBe(view.elementInjectors[0]);
|
||||
});
|
||||
|
||||
it('should not pass the host injector when a parent injector exists', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
|
||||
pv.bindElement(null, 0, protoParent);
|
||||
var testProtoElementInjector = new TestProtoElementInjector(protoParent, 1, [AnotherDirective]);
|
||||
pv.bindElement(null, 0, testProtoElementInjector);
|
||||
|
||||
var hostProtoInjector = new ProtoElementInjector(null, 0, []);
|
||||
var hostInjector = hostProtoInjector.instantiate(null, null);
|
||||
var view;
|
||||
expect(() => view = pv.instantiate(hostInjector, null)).not.toThrow();
|
||||
expect(testProtoElementInjector.parentElementInjector).toBe(view.elementInjectors[0]);
|
||||
expect(testProtoElementInjector.hostElementInjector).toBeNull();
|
||||
});
|
||||
|
||||
it('should pass the host injector when there is no parent injector', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeDirective]));
|
||||
var testProtoElementInjector = new TestProtoElementInjector(null, 1, [AnotherDirective]);
|
||||
pv.bindElement(null, 0, testProtoElementInjector);
|
||||
|
||||
var hostProtoInjector = new ProtoElementInjector(null, 0, []);
|
||||
var hostInjector = hostProtoInjector.instantiate(null, null);
|
||||
expect(() => pv.instantiate(hostInjector, null)).not.toThrow();
|
||||
expect(testProtoElementInjector.parentElementInjector).toBeNull();
|
||||
expect(testProtoElementInjector.hostElementInjector).toBe(hostInjector);
|
||||
});
|
||||
});
|
||||
|
||||
describe('collect root element injectors', () => {
|
||||
|
||||
it('should collect a single root element injector', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
|
||||
pv.bindElement(null, 0, protoParent);
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
|
||||
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.rootElementInjectors.length).toBe(1);
|
||||
expect(view.rootElementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
|
||||
});
|
||||
|
||||
it('should collect multiple root element injectors', () => {
|
||||
var pv = new ProtoView(null, el('<div><span class="ng-binding"></span><span class="ng-binding"></span></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 1, [SomeDirective]));
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 2, [AnotherDirective]));
|
||||
|
||||
var view = pv.instantiate(null, null);
|
||||
view.hydrate(null, null, null, null, null);
|
||||
expect(view.rootElementInjectors.length).toBe(2)
|
||||
expect(view.rootElementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
|
||||
expect(view.rootElementInjectors[1].get(AnotherDirective) instanceof AnotherDirective).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('with component views', () => {
|
||||
var ctx;
|
||||
|
||||
function createComponentWithSubPV(subProtoView) {
|
||||
var pv = new ProtoView(null, el('<cmp class="ng-binding"></cmp>'),
|
||||
new DynamicProtoChangeDetector(null, null), new NativeShadowDomStrategy(null));
|
||||
var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeComponent], true));
|
||||
binder.componentDirective = someComponentDirective;
|
||||
binder.nestedProtoView = subProtoView;
|
||||
return pv;
|
||||
}
|
||||
|
||||
function createNestedView(protoView) {
|
||||
ctx = new MyEvaluationContext();
|
||||
var view = protoView.instantiate(null, null);
|
||||
view.hydrate(new Injector([]), null, null, ctx, null);
|
||||
return view;
|
||||
}
|
||||
|
||||
it('should expose component services to the component', () => {
|
||||
var subpv = new ProtoView(null, el('<span></span>'), new DynamicProtoChangeDetector(null, null), null);
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
|
||||
var view = createNestedView(pv);
|
||||
|
||||
var comp = view.rootElementInjectors[0].get(SomeComponent);
|
||||
expect(comp.service).toBeAnInstanceOf(SomeService);
|
||||
});
|
||||
|
||||
it('should expose component services and component instance to directives in the shadow Dom',
|
||||
() => {
|
||||
var subpv = new ProtoView(null,
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'),
|
||||
new DynamicProtoChangeDetector(null, null),
|
||||
null);
|
||||
subpv.bindElement(null, 0,
|
||||
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
|
||||
var view = createNestedView(pv);
|
||||
|
||||
var subView = view.componentChildViews[0];
|
||||
var subInj = subView.rootElementInjectors[0];
|
||||
var subDecorator = subInj.get(ServiceDependentDecorator);
|
||||
var comp = view.rootElementInjectors[0].get(SomeComponent);
|
||||
|
||||
expect(subDecorator).toBeAnInstanceOf(ServiceDependentDecorator);
|
||||
expect(subDecorator.service).toBe(comp.service);
|
||||
expect(subDecorator.component).toBe(comp);
|
||||
});
|
||||
|
||||
function expectViewHasNoDirectiveInstances(view) {
|
||||
view.elementInjectors.forEach((inj) => expect(inj.hasInstances()).toBe(false));
|
||||
}
|
||||
|
||||
it('dehydration should dehydrate child component views too', () => {
|
||||
var subpv = new ProtoView(null,
|
||||
el('<div dec class="ng-binding">hello shadow dom</div>'),
|
||||
new DynamicProtoChangeDetector(null, null),
|
||||
null);
|
||||
subpv.bindElement(null, 0,
|
||||
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
|
||||
var view = createNestedView(pv);
|
||||
view.dehydrate();
|
||||
|
||||
expect(view.hydrated()).toBe(false);
|
||||
expectViewHasNoDirectiveInstances(view);
|
||||
view.componentChildViews.forEach(
|
||||
(view) => expectViewHasNoDirectiveInstances(view));
|
||||
});
|
||||
|
||||
it('should create shadow dom (Native Strategy)', () => {
|
||||
var subpv = new ProtoView(null, el('<span>hello shadow dom</span>'),
|
||||
new DynamicProtoChangeDetector(null, null),
|
||||
null);
|
||||
var pv = createComponentWithSubPV(subpv);
|
||||
|
||||
var view = createNestedView(pv);
|
||||
|
||||
expect(view.nodes[0].shadowRoot.childNodes[0].childNodes[0].nodeValue).toEqual('hello shadow dom');
|
||||
});
|
||||
|
||||
it('should emulate shadow dom (Emulated Strategy)', () => {
|
||||
var subpv = new ProtoView(null, el('<span>hello shadow dom</span>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
|
||||
var pv = new ProtoView(null, el('<cmp class="ng-binding"></cmp>'),
|
||||
new DynamicProtoChangeDetector(null, null), new EmulatedScopedShadowDomStrategy(null, null, null));
|
||||
var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeComponent], true));
|
||||
binder.componentDirective = readDirectiveBinding(SomeComponent);
|
||||
binder.nestedProtoView = subpv;
|
||||
|
||||
var view = createNestedView(pv);
|
||||
expect(view.nodes[0].childNodes[0].childNodes[0].nodeValue).toEqual('hello shadow dom');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('with template views', () => {
|
||||
function createViewWithViewport() {
|
||||
var templateProtoView = new ProtoView(null,
|
||||
el('<div id="1"></div>'), new DynamicProtoChangeDetector(null, null), null);
|
||||
var pv = new ProtoView(null, el('<someTmpl class="ng-binding"></someTmpl>'),
|
||||
new DynamicProtoChangeDetector(null, null), new NativeShadowDomStrategy(null));
|
||||
var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeViewport]));
|
||||
binder.viewportDirective = someViewportDirective;
|
||||
binder.nestedProtoView = templateProtoView;
|
||||
|
||||
return createView(pv);
|
||||
}
|
||||
|
||||
it('should create a ViewContainer for the Viewport directive', () => {
|
||||
var view = createViewWithViewport();
|
||||
|
||||
var tmplComp = view.rootElementInjectors[0].get(SomeViewport);
|
||||
expect(tmplComp.viewContainer).not.toBe(null);
|
||||
});
|
||||
|
||||
it('dehydration should dehydrate viewcontainers', () => {
|
||||
var view = createViewWithViewport();
|
||||
|
||||
var tmplComp = view.rootElementInjectors[0].get(SomeViewport);
|
||||
expect(tmplComp.viewContainer.hydrated()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
if (DOM.supportsDOMEvents()) {
|
||||
describe('event handlers', () => {
|
||||
var view, ctx, called, receivedEvent, dispatchedEvent;
|
||||
|
||||
function createViewAndContext(protoView) {
|
||||
view = createView(protoView,
|
||||
new EventManager([new DomEventsPlugin()], new FakeVmTurnZone()));
|
||||
ctx = view.context;
|
||||
called = 0;
|
||||
receivedEvent = null;
|
||||
ctx.callMe = (event) => {
|
||||
called += 1;
|
||||
receivedEvent = event;
|
||||
}
|
||||
}
|
||||
|
||||
function dispatchClick(el) {
|
||||
dispatchedEvent = DOM.createMouseEvent('click');
|
||||
DOM.dispatchEvent(el, dispatchedEvent);
|
||||
}
|
||||
|
||||
function createProtoView() {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"><div></div></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, new TestProtoElementInjector(null, 0, []));
|
||||
pv.bindEvent('click', parser.parseBinding('callMe($event)', null));
|
||||
return pv;
|
||||
}
|
||||
|
||||
it('should fire on non-bubbling native events', () => {
|
||||
createViewAndContext(createProtoView());
|
||||
|
||||
dispatchClick(view.nodes[0]);
|
||||
|
||||
expect(called).toEqual(1);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
});
|
||||
|
||||
it('should not fire on a bubbled native events', () => {
|
||||
createViewAndContext(createProtoView());
|
||||
|
||||
dispatchClick(view.nodes[0].firstChild);
|
||||
|
||||
// This test passes trivially on webkit browsers due to
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=122755
|
||||
expect(called).toEqual(0);
|
||||
});
|
||||
|
||||
it('should not throw if the view is dehydrated', () => {
|
||||
createViewAndContext(createProtoView());
|
||||
|
||||
view.dehydrate();
|
||||
expect(() => dispatchClick(view.nodes[0])).not.toThrow();
|
||||
expect(called).toEqual(0);
|
||||
});
|
||||
|
||||
it('should support custom event emitters', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"><div></div></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, new TestProtoElementInjector(null, 0, [EventEmitterDirective]));
|
||||
pv.bindEvent('click', parser.parseBinding('callMe($event)', null));
|
||||
|
||||
createViewAndContext(pv);
|
||||
var dir = view.elementInjectors[0].get(EventEmitterDirective);
|
||||
|
||||
var dispatchedEvent = new Object();
|
||||
|
||||
dir.click(dispatchedEvent);
|
||||
expect(receivedEvent).toBe(dispatchedEvent);
|
||||
expect(called).toEqual(1);
|
||||
|
||||
// Should not eval the binding, because custom emitter takes over.
|
||||
dispatchClick(view.nodes[0]);
|
||||
|
||||
expect(called).toEqual(1);
|
||||
});
|
||||
|
||||
it('should bind to directive events', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeDirectiveWithEventHandler]));
|
||||
pv.bindEvent('click', parser.parseAction('onEvent($event)', null), 0);
|
||||
view = createView(pv, new EventManager([new DomEventsPlugin()], new FakeVmTurnZone()));
|
||||
|
||||
var directive = view.elementInjectors[0].get(SomeDirectiveWithEventHandler);
|
||||
expect(directive.event).toEqual(null);
|
||||
|
||||
dispatchClick(view.nodes[0]);
|
||||
expect(directive.event).toBe(dispatchedEvent);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('react to record changes', () => {
|
||||
var view, cd, ctx;
|
||||
|
||||
function createViewAndChangeDetector(protoView) {
|
||||
view = createView(protoView);
|
||||
ctx = view.context;
|
||||
cd = view.changeDetector;
|
||||
}
|
||||
|
||||
it('should consume text node changes', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding">{{}}</div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, null);
|
||||
pv.bindTextNode(0, parser.parseBinding('foo', null));
|
||||
createViewAndChangeDetector(pv);
|
||||
|
||||
ctx.foo = 'buz';
|
||||
cd.detectChanges();
|
||||
expect(view.textNodes[0].nodeValue).toEqual('buz');
|
||||
});
|
||||
|
||||
it('should consume element binding changes', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, null);
|
||||
pv.bindElementProperty(parser.parseBinding('foo', null), 'id', reflector.setter('id'));
|
||||
createViewAndChangeDetector(pv);
|
||||
|
||||
ctx.foo = 'buz';
|
||||
cd.detectChanges();
|
||||
expect(view.bindElements[0].id).toEqual('buz');
|
||||
});
|
||||
|
||||
it('should consume directive watch expression change', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeDirective]));
|
||||
pv.bindDirectiveProperty(0, parser.parseBinding('foo', null), 'prop', reflector.setter('prop'));
|
||||
createViewAndChangeDetector(pv);
|
||||
|
||||
ctx.foo = 'buz';
|
||||
cd.detectChanges();
|
||||
expect(view.elementInjectors[0].get(SomeDirective).prop).toEqual('buz');
|
||||
});
|
||||
|
||||
it('should notify a directive about changes after all its properties have been set', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [
|
||||
DirectiveBinding.createFromType(DirectiveImplementingOnChange,
|
||||
new DummyDirective({lifecycle: [onChange]}))
|
||||
]));
|
||||
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'));
|
||||
pv.bindDirectiveProperty( 0, parser.parseBinding('b', null), 'b', reflector.setter('b'));
|
||||
createViewAndChangeDetector(pv);
|
||||
|
||||
ctx.a = 100;
|
||||
ctx.b = 200;
|
||||
cd.detectChanges();
|
||||
|
||||
var directive = view.elementInjectors[0].get(DirectiveImplementingOnChange);
|
||||
expect(directive.c).toEqual(300);
|
||||
});
|
||||
|
||||
it('should provide a map of updated properties using onChange callback', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [
|
||||
DirectiveBinding.createFromType(DirectiveImplementingOnChange,
|
||||
new DummyDirective({lifecycle: [onChange]}))
|
||||
]));
|
||||
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'));
|
||||
pv.bindDirectiveProperty( 0, parser.parseBinding('b', null), 'b', reflector.setter('b'));
|
||||
createViewAndChangeDetector(pv);
|
||||
|
||||
var directive = view.elementInjectors[0].get(DirectiveImplementingOnChange);
|
||||
|
||||
ctx.a = 0;
|
||||
ctx.b = 0;
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive.changes["a"].currentValue).toEqual(0);
|
||||
expect(directive.changes["b"].currentValue).toEqual(0);
|
||||
|
||||
ctx.a = 100;
|
||||
cd.detectChanges();
|
||||
expect(directive.changes["a"].currentValue).toEqual(100);
|
||||
expect(StringMapWrapper.contains(directive.changes, "b")).toBe(false);
|
||||
});
|
||||
|
||||
it('should invoke the onAllChangesDone callback', () => {
|
||||
var pv = new ProtoView(null, el('<div class="ng-binding"></div>'),
|
||||
new DynamicProtoChangeDetector(null, null), null);
|
||||
|
||||
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [
|
||||
DirectiveBinding.createFromType(DirectiveImplementingOnAllChangesDone,
|
||||
new DummyDirective({lifecycle: [onAllChangesDone]}))
|
||||
]));
|
||||
|
||||
createViewAndChangeDetector(pv);
|
||||
cd.detectChanges();
|
||||
|
||||
var directive = view.elementInjectors[0].get(DirectiveImplementingOnAllChangesDone);
|
||||
expect(directive.onAllChangesDoneCalled).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function readDirectiveBinding(type) {
|
||||
var meta = new DirectiveMetadataReader().read(type);
|
||||
return DirectiveBinding.createFromType(type, meta.annotation);
|
||||
}
|
||||
|
||||
class SomeDirective {
|
||||
prop;
|
||||
constructor() {
|
||||
this.prop = 'foo';
|
||||
}
|
||||
}
|
||||
|
||||
class DirectiveImplementingOnChange {
|
||||
a;
|
||||
b;
|
||||
c;
|
||||
changes;
|
||||
|
||||
onChange(changes) {
|
||||
this.c = this.a + this.b;
|
||||
this.changes = changes;
|
||||
}
|
||||
}
|
||||
|
||||
class DirectiveImplementingOnAllChangesDone {
|
||||
onAllChangesDoneCalled;
|
||||
|
||||
onAllChangesDone() {
|
||||
this.onAllChangesDoneCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
class SomeService {}
|
||||
|
||||
@Component({services: [SomeService]})
|
||||
class SomeComponent {
|
||||
service: SomeService;
|
||||
constructor(service: SomeService) {
|
||||
this.service = service;
|
||||
}
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
selector: '[dec]'
|
||||
})
|
||||
class ServiceDependentDecorator {
|
||||
component: SomeComponent;
|
||||
service: SomeService;
|
||||
constructor(component: SomeComponent, service: SomeService) {
|
||||
this.component = component;
|
||||
this.service = service;
|
||||
}
|
||||
}
|
||||
|
||||
@Viewport({
|
||||
selector: 'someTmpl'
|
||||
})
|
||||
class SomeViewport {
|
||||
viewContainer: ViewContainer;
|
||||
constructor(viewContainer: ViewContainer) {
|
||||
this.viewContainer = viewContainer;
|
||||
}
|
||||
}
|
||||
|
||||
class AnotherDirective {
|
||||
prop:string;
|
||||
constructor() {
|
||||
this.prop = 'anotherFoo';
|
||||
}
|
||||
}
|
||||
|
||||
class EventEmitterDirective {
|
||||
_clicker:Function;
|
||||
constructor(@EventEmitter('click') clicker:Function) {
|
||||
this._clicker = clicker;
|
||||
}
|
||||
click(eventData) {
|
||||
this._clicker(eventData);
|
||||
}
|
||||
}
|
||||
|
||||
class SomeDirectiveWithEventHandler {
|
||||
event;
|
||||
|
||||
constructor() {
|
||||
this.event = null;
|
||||
}
|
||||
|
||||
onEvent(event) {
|
||||
this.event = event;
|
||||
}
|
||||
}
|
||||
|
||||
class MyEvaluationContext {
|
||||
foo:string;
|
||||
a;
|
||||
b;
|
||||
callMe;
|
||||
constructor() {
|
||||
this.foo = 'bar';
|
||||
};
|
||||
}
|
||||
|
||||
class TestProtoElementInjector extends ProtoElementInjector {
|
||||
parentElementInjector: ElementInjector;
|
||||
hostElementInjector: ElementInjector;
|
||||
|
||||
constructor(parent:ProtoElementInjector, index:int, bindings:List, firstBindingIsComponent:boolean = false) {
|
||||
super(parent, index, bindings, firstBindingIsComponent);
|
||||
}
|
||||
|
||||
instantiate(parent:ElementInjector, host:ElementInjector):ElementInjector {
|
||||
this.parentElementInjector = parent;
|
||||
this.hostElementInjector = host;
|
||||
return super.instantiate(parent, host);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeVmTurnZone extends VmTurnZone {
|
||||
constructor() {
|
||||
super({enableLongStackTrace: false});
|
||||
}
|
||||
|
||||
run(fn) {
|
||||
fn();
|
||||
}
|
||||
|
||||
runOutsideAngular(fn) {
|
||||
fn();
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding foo');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding foo');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -43,11 +43,11 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding foo');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding foo');
|
||||
|
||||
view.context.condition = false;
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding bar');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -59,19 +59,19 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding foo');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding foo');
|
||||
|
||||
StringMapWrapper.set(view.context.expr, 'bar', true);
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding foo bar');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding foo bar');
|
||||
|
||||
StringMapWrapper.set(view.context.expr, 'baz', true);
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding foo bar baz');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding foo bar baz');
|
||||
|
||||
StringMapWrapper.delete(view.context.expr, 'bar');
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding foo baz');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding foo baz');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -83,15 +83,15 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding foo');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding foo');
|
||||
|
||||
view.context.expr = null;
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding foo');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding foo');
|
||||
|
||||
view.context.expr = {'foo': false, 'bar': true};
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('ng-binding bar');
|
||||
expect(view.rootNodes[0].className).toEqual('ng-binding bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -104,11 +104,11 @@ export function main() {
|
|||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
StringMapWrapper.set(view.context.expr, 'bar', true);
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('init foo ng-binding bar');
|
||||
expect(view.rootNodes[0].className).toEqual('init foo ng-binding bar');
|
||||
|
||||
StringMapWrapper.set(view.context.expr, 'foo', false);
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('init ng-binding bar');
|
||||
expect(view.rootNodes[0].className).toEqual('init ng-binding bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -120,19 +120,19 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('init foo ng-binding baz');
|
||||
expect(view.rootNodes[0].className).toEqual('init foo ng-binding baz');
|
||||
|
||||
StringMapWrapper.set(view.context.expr, 'bar', true);
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('init foo ng-binding baz bar');
|
||||
expect(view.rootNodes[0].className).toEqual('init foo ng-binding baz bar');
|
||||
|
||||
StringMapWrapper.set(view.context.expr, 'foo', false);
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('init ng-binding baz bar');
|
||||
expect(view.rootNodes[0].className).toEqual('init ng-binding baz bar');
|
||||
|
||||
view.context.condition = false;
|
||||
view.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('init ng-binding bar');
|
||||
expect(view.rootNodes[0].className).toEqual('init ng-binding bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ export function main() {
|
|||
it('should reflect initial elements', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.createView(TestComponent, {html: TEMPLATE}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('1;2;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('1;2;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -42,7 +42,7 @@ export function main() {
|
|||
ListWrapper.push(view.context.items, 3);
|
||||
view.detectChanges();
|
||||
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('1;2;3;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('1;2;3;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -54,7 +54,7 @@ export function main() {
|
|||
ListWrapper.removeAt(view.context.items, 1);
|
||||
view.detectChanges();
|
||||
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('1;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('1;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -67,7 +67,7 @@ export function main() {
|
|||
ListWrapper.push(view.context.items, 1);
|
||||
view.detectChanges();
|
||||
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('2;1;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('2;1;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -81,7 +81,7 @@ export function main() {
|
|||
view.context.items = [6, 2, 7, 0, 4, 8];
|
||||
view.detectChanges();
|
||||
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('6;2;7;0;4;8;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('6;2;7;0;4;8;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -94,20 +94,20 @@ export function main() {
|
|||
// INIT
|
||||
view.context.items = [{'name': 'misko'}, {'name':'shyam'}];
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('misko;shyam;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('misko;shyam;');
|
||||
|
||||
// GROW
|
||||
ListWrapper.push(view.context.items, {'name': 'adam'});
|
||||
view.detectChanges();
|
||||
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('misko;shyam;adam;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('misko;shyam;adam;');
|
||||
|
||||
// SHRINK
|
||||
ListWrapper.removeAt(view.context.items, 2);
|
||||
ListWrapper.removeAt(view.context.items, 0);
|
||||
view.detectChanges();
|
||||
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('shyam;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('shyam;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -116,7 +116,7 @@ export function main() {
|
|||
var template = '<ul><li template="for #item of null">{{item}};</li></ul>';
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -125,15 +125,15 @@ export function main() {
|
|||
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.createView(TestComponent, {html: TEMPLATE}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('1;2;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('1;2;');
|
||||
|
||||
view.context.items = null;
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
|
||||
view.context.items = [1, 2, 3];
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('1;2;3;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('1;2;3;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -141,7 +141,7 @@ export function main() {
|
|||
it('should throw on ref changing to string', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.createView(TestComponent, {html: TEMPLATE}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('1;2;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('1;2;');
|
||||
|
||||
view.context.items = 'whaaa';
|
||||
expect(() => view.detectChanges()).toThrowError();
|
||||
|
@ -154,7 +154,7 @@ export function main() {
|
|||
var a = new Foo();
|
||||
view.context.items = [a, a];
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('foo;foo;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('foo;foo;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -174,11 +174,11 @@ export function main() {
|
|||
view.detectChanges();
|
||||
view.detectChanges();
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('a-2;b-2;|c-1;|');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('a-2;b-2;|c-1;|');
|
||||
|
||||
view.context.items = [['e'], ['f', 'g']];
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('e-1;|f-2;g-2;|');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('e-1;|f-2;g-2;|');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -195,11 +195,11 @@ export function main() {
|
|||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.context.items = [['a', 'b'], ['c']];
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('a-2;b-2;c-1;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('a-2;b-2;c-1;');
|
||||
|
||||
view.context.items = [['e'], ['f', 'g']];
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('e-1;f-2;g-2;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('e-1;f-2;g-2;');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -212,11 +212,11 @@ export function main() {
|
|||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.context.items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('0123456789');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('0123456789');
|
||||
|
||||
view.context.items = [1, 2, 6, 7, 4, 3, 5, 8, 9, 0];
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('0123456789');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('0123456789');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
|
|
@ -28,8 +28,8 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: html}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('hello');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('hello');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -39,8 +39,8 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: html}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('hello2');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('hello2');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -51,18 +51,18 @@ export function main() {
|
|||
tb.createView(TestComponent, {html: html}).then((view) => {
|
||||
view.context.booleanCondition = false;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
|
||||
view.context.booleanCondition = true;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('hello');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('hello');
|
||||
|
||||
view.context.booleanCondition = false;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -74,28 +74,28 @@ export function main() {
|
|||
tb.createView(TestComponent, {html: html}).then((view) => {
|
||||
view.context.booleanCondition = false;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
|
||||
view.context.booleanCondition = true;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('hello');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('hello');
|
||||
|
||||
view.context.nestedBooleanCondition = false;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
|
||||
view.context.nestedBooleanCondition = true;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('hello');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('hello');
|
||||
|
||||
view.context.booleanCondition = false;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -111,19 +111,19 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: html}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(3);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('helloNumberhelloStringhelloFunction');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(3);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('helloNumberhelloStringhelloFunction');
|
||||
|
||||
view.context.numberCondition = 0;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('helloString');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('helloString');
|
||||
|
||||
view.context.numberCondition = 1;
|
||||
view.context.stringCondition = "bar";
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('helloNumber');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('helloNumber');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -136,13 +136,13 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: html}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('hello');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('hello');
|
||||
|
||||
view.context.numberCondition = 2;
|
||||
view.detectChanges();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('hello');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(1);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('hello');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -154,11 +154,11 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: html}).then((view) => {
|
||||
view.detectChanges();
|
||||
DOM.addClass(view.nodes[0].childNodes[1], "foo");
|
||||
DOM.addClass(view.rootNodes[0].childNodes[1], "foo");
|
||||
|
||||
view.context.numberCondition = 2;
|
||||
view.detectChanges();
|
||||
expect(DOM.hasClass(view.nodes[0].childNodes[1], "foo")).toBe(true);
|
||||
expect(DOM.hasClass(view.rootNodes[0].childNodes[1], "foo")).toBe(true);
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -172,8 +172,8 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: html}).then((view) => {
|
||||
expect(() => view.detectChanges()).toThrowError();
|
||||
expect(DOM.querySelectorAll(view.nodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.querySelectorAll(view.rootNodes[0], 'copy-me').length).toEqual(0);
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
|
|
@ -15,7 +15,7 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
|
|||
import {Decorator, Component} from 'angular2/src/core/annotations/annotations';
|
||||
import {Template} from 'angular2/src/core/annotations/template';
|
||||
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {NgElement} from 'angular2/src/core/compiler/ng_element';
|
||||
|
||||
import {NonBindable} from 'angular2/src/directives/non_bindable';
|
||||
|
||||
|
@ -27,7 +27,7 @@ export function main() {
|
|||
var template = '<div>{{text}}<span non-bindable>{{text}}</span></div>';
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('foo{{text}}');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('foo{{text}}');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
@ -36,7 +36,7 @@ export function main() {
|
|||
var template = '<div non-bindable><span id=child test-dec>{{text}}</span></div>';
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
var span = DOM.querySelector(view.nodes[0], '#child');
|
||||
var span = DOM.querySelector(view.rootNodes[0], '#child');
|
||||
expect(DOM.hasClass(span, 'compiled')).toBeFalsy();
|
||||
async.done();
|
||||
});
|
||||
|
@ -46,7 +46,7 @@ export function main() {
|
|||
var template = '<div><span id=child non-bindable test-dec>{{text}}</span></div>';
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
var span = DOM.querySelector(view.nodes[0], '#child');
|
||||
var span = DOM.querySelector(view.rootNodes[0], '#child');
|
||||
expect(DOM.hasClass(span, 'compiled')).toBeTruthy();
|
||||
async.done();
|
||||
});
|
||||
|
|
|
@ -31,15 +31,15 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('');
|
||||
|
||||
view.context.switchValue = 'a';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when a');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when a');
|
||||
|
||||
view.context.switchValue = 'b';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when b');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when b');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -55,15 +55,15 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when default');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when default');
|
||||
|
||||
view.context.switchValue = 'a';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when a');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when a');
|
||||
|
||||
view.context.switchValue = 'b';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when default');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when default');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -83,15 +83,15 @@ export function main() {
|
|||
|
||||
tb.createView(TestComponent, {html: template}).then((view) => {
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when default1;when default2;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when default1;when default2;');
|
||||
|
||||
view.context.switchValue = 'a';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when a1;when a2;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when a1;when a2;');
|
||||
|
||||
view.context.switchValue = 'b';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when b1;when b2;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when b1;when b2;');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
@ -113,23 +113,23 @@ export function main() {
|
|||
view.context.when2 = 'b';
|
||||
view.context.switchValue = 'a';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when 1;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when 1;');
|
||||
|
||||
view.context.switchValue = 'b';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when 2;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when 2;');
|
||||
|
||||
view.context.switchValue = 'c';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when default;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when default;');
|
||||
|
||||
view.context.when1 = 'c';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when 1;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when 1;');
|
||||
|
||||
view.context.when1 = 'd';
|
||||
view.detectChanges();
|
||||
expect(DOM.getText(view.nodes[0])).toEqual('when default;');
|
||||
expect(DOM.getText(view.rootNodes[0])).toEqual('when default;');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
|
|
@ -25,8 +25,8 @@ import {ControlGroupDirective, ControlDirective, Control, ControlGroup, Optional
|
|||
DefaultValueAccessor, Validators} from 'angular2/forms';
|
||||
|
||||
export function main() {
|
||||
if (DOM.supportsDOMEvents()) {
|
||||
describe("integration tests", () => {
|
||||
describe("integration tests", () => {
|
||||
if (DOM.supportsDOMEvents()) {
|
||||
it("should initialize DOM elements with the given form object",
|
||||
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
var ctx = new MyComp(new ControlGroup({
|
||||
|
@ -362,8 +362,8 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Component({selector: "my-comp"})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {isBlank, isPresent, BaseException} from 'angular2/src/facade/lang';
|
||||
import {MapWrapper, ListWrapper, List} from 'angular2/src/facade/collection';
|
||||
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';
|
||||
|
||||
|
@ -177,7 +177,7 @@ export class LoggingEventDispatcher extends EventDispatcher {
|
|||
this.log = [];
|
||||
}
|
||||
dispatchEvent(
|
||||
elementIndex:number, eventName:string, locals:List<any>
|
||||
elementIndex:number, eventName:string, locals:Map<string, any>
|
||||
) {
|
||||
ListWrapper.push(this.log, [elementIndex, eventName, locals]);
|
||||
}
|
||||
|
|
|
@ -279,7 +279,7 @@ export function main() {
|
|||
// var temp = `<simple>aaa<input type="text" id="focused-input" ng-class="{'aClass' : showClass}"> bbb</simple>`;
|
||||
//
|
||||
// compile(temp, (view, lc) => {
|
||||
// var input = view.nodes[1];
|
||||
// var input = view.rootNodes[1];
|
||||
// input.focus();
|
||||
//
|
||||
// expect(document.activeElement.id).toEqual("focused-input");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {AsyncTestCompleter, inject, ddescribe, describe, it, iit, xit, expect, SpyObject} from 'angular2/test_lib';
|
||||
|
||||
import {DOM, DomAdapter} from 'angular2/src/dom/dom_adapter';
|
||||
import {NgElement} from 'angular2/src/core/dom/element';
|
||||
import {NgElement} from 'angular2/src/core/compiler/ng_element';
|
||||
|
||||
import {Ruler, Rectangle} from 'angular2/src/services/ruler';
|
||||
import {createRectangle} from './rectangle_mock';
|
||||
|
@ -35,7 +35,7 @@ export function main() {
|
|||
inject([AsyncTestCompleter], (async) => {
|
||||
var ruler = new Ruler(new DomAdapterMock(createRectangle(10, 20, 200, 100)));
|
||||
|
||||
ruler.measure(new NgElement(null)).then((rect) => {
|
||||
ruler.measure(new FakeNgElement(null)).then((rect) => {
|
||||
assertDimensions(rect, 10, 210, 20, 120, 200, 100);
|
||||
async.done();
|
||||
});
|
||||
|
@ -46,7 +46,7 @@ export function main() {
|
|||
inject([AsyncTestCompleter], (async) => {
|
||||
var ruler = new Ruler(DOM);
|
||||
|
||||
ruler.measure(new NgElement(DOM.createElement('div'))).then((rect) => {
|
||||
ruler.measure(new FakeNgElement(DOM.createElement('div'))).then((rect) => {
|
||||
//here we are using an element created in a doc fragment so all the measures will come back as 0
|
||||
assertDimensions(rect, 0, 0, 0, 0, 0, 0);
|
||||
async.done();
|
||||
|
@ -55,3 +55,16 @@ export function main() {
|
|||
|
||||
});
|
||||
}
|
||||
|
||||
class FakeNgElement extends NgElement {
|
||||
_domElement;
|
||||
|
||||
constructor(domElement) {
|
||||
super(null, null);
|
||||
this._domElement = domElement;
|
||||
}
|
||||
|
||||
get domElement() {
|
||||
return this._domElement;
|
||||
}
|
||||
}
|
|
@ -185,11 +185,11 @@ function setUpChangeDetection(changeDetection:ChangeDetection, iterations, objec
|
|||
var dispatcher = new DummyDispatcher();
|
||||
var parser = new Parser(new Lexer());
|
||||
|
||||
var parentProto = changeDetection.createProtoChangeDetector('parent');
|
||||
var parentProto = changeDetection.createProtoChangeDetector('parent', null);
|
||||
var parentCd = parentProto.instantiate(dispatcher, [], [], []);
|
||||
|
||||
var targetObj = new Obj();
|
||||
var proto = changeDetection.createProtoChangeDetector("proto");
|
||||
var proto = changeDetection.createProtoChangeDetector("proto", null);
|
||||
var bindingRecords = [
|
||||
new BindingRecord(parser.parseBinding('field0', null), new FakeBindingMemento(targetObj, reflector.setter("field0")), null),
|
||||
new BindingRecord(parser.parseBinding('field1', null), new FakeBindingMemento(targetObj, reflector.setter("field1")), null),
|
||||
|
@ -240,7 +240,7 @@ export function main () {
|
|||
|
||||
// -- BASELINE
|
||||
var baselineHead = setUpBaseline(numberOfDetectors, object);
|
||||
|
||||
|
||||
runBaselineReads(baselineHead, 1); //warmup
|
||||
|
||||
bindAction(
|
||||
|
|
|
@ -4,7 +4,7 @@ import {isBlank, Type} from 'angular2/src/facade/lang';
|
|||
import {document} from 'angular2/src/facade/browser';
|
||||
import {MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||
|
||||
import {Parser, Lexer, ProtoRecordRange, dynamicChangeDetection} from 'angular2/change_detection';
|
||||
|
||||
|
@ -23,6 +23,11 @@ import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mappe
|
|||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
|
||||
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
|
||||
function setupReflector() {
|
||||
reflector.registerType(BenchmarkComponent, {
|
||||
"factory": () => new BenchmarkComponent(),
|
||||
|
@ -94,16 +99,22 @@ export function main() {
|
|||
var templateResolver = new FakeTemplateResolver();
|
||||
var urlResolver = new UrlResolver();
|
||||
var styleUrlResolver = new StyleUrlResolver(urlResolver);
|
||||
var shadowDomStrategy = new NativeShadowDomStrategy(styleUrlResolver);
|
||||
var renderer = new DirectDomRenderer(
|
||||
new rc.DefaultCompiler(
|
||||
new Parser(new Lexer()), shadowDomStrategy, new TemplateLoader(null, urlResolver)
|
||||
),
|
||||
null,
|
||||
shadowDomStrategy
|
||||
);
|
||||
var compiler = new Compiler(
|
||||
dynamicChangeDetection,
|
||||
new TemplateLoader(null, urlResolver),
|
||||
reader,
|
||||
new Parser(new Lexer()),
|
||||
cache,
|
||||
new NativeShadowDomStrategy(styleUrlResolver),
|
||||
templateResolver,
|
||||
new ComponentUrlMapper(),
|
||||
urlResolver
|
||||
urlResolver,
|
||||
renderer,
|
||||
new ProtoViewFactory(dynamicChangeDetection, renderer)
|
||||
);
|
||||
var templateNoBindings = createTemplateHtml('templateNoBindings', count);
|
||||
var templateWithBindings = createTemplateHtml('templateWithBindings', count);
|
||||
|
|
|
@ -33,19 +33,19 @@ export function main() {
|
|||
|
||||
var bindings = [A, B, C];
|
||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
||||
var elementInjector = proto.instantiate(null, null);
|
||||
var elementInjector = proto.instantiate(null);
|
||||
|
||||
function instantiate () {
|
||||
for (var i = 0; i < iterations; ++i) {
|
||||
var ei = proto.instantiate(null, null);
|
||||
ei.instantiateDirectives(appInjector, null, null);
|
||||
var ei = proto.instantiate(null);
|
||||
ei.instantiateDirectives(appInjector, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
function instantiateDirectives () {
|
||||
for (var i = 0; i < iterations; ++i) {
|
||||
elementInjector.clearDirectives();
|
||||
elementInjector.instantiateDirectives(appInjector, null, null);
|
||||
elementInjector.instantiateDirectives(appInjector, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ import {CompilerCache} from 'angular2/src/core/compiler/compiler';
|
|||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
|
||||
import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||
|
@ -36,6 +36,14 @@ import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
|||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Parent} from 'angular2/src/core/annotations/visibility';
|
||||
|
||||
import {ViewFactory, VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_factory';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
||||
import {Inject} from 'angular2/di';
|
||||
|
||||
var BASELINE_LARGETABLE_TEMPLATE;
|
||||
|
||||
function setupReflector() {
|
||||
|
@ -139,8 +147,8 @@ function setupReflector() {
|
|||
});
|
||||
|
||||
reflector.registerType(SwitchWhen, {
|
||||
'factory': (el, vc, ss) => new SwitchWhen(el, vc, ss),
|
||||
'parameters': [[NgElement],[ViewContainer],[Switch, new Parent()]],
|
||||
'factory': (vc, ss) => new SwitchWhen(vc, ss),
|
||||
'parameters': [[ViewContainer],[Switch, new Parent()]],
|
||||
'annotations' : [new Viewport({
|
||||
selector: '[switch-when]',
|
||||
bind: {
|
||||
|
@ -158,14 +166,13 @@ function setupReflector() {
|
|||
});
|
||||
|
||||
reflector.registerType(Compiler, {
|
||||
'factory': (cd, templateLoader, reader, parser, compilerCache, strategy, tplResolver,
|
||||
cmpUrlMapper, urlResolver) =>
|
||||
new Compiler(cd, templateLoader, reader, parser, compilerCache, strategy, tplResolver,
|
||||
cmpUrlMapper, urlResolver),
|
||||
'parameters': [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader],
|
||||
[Parser], [CompilerCache], [ShadowDomStrategy], [TemplateResolver],
|
||||
[ComponentUrlMapper], [UrlResolver]],
|
||||
'annotations': []
|
||||
"factory": (reader, compilerCache, tplResolver, cmpUrlMapper, urlResolver, renderer,
|
||||
protoViewFactory) =>
|
||||
new Compiler(reader, compilerCache, tplResolver, cmpUrlMapper, urlResolver, renderer,
|
||||
protoViewFactory),
|
||||
"parameters": [[DirectiveMetadataReader], [CompilerCache], [TemplateResolver], [ComponentUrlMapper],
|
||||
[UrlResolver], [Renderer], [ProtoViewFactory]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(CompilerCache, {
|
||||
|
@ -240,12 +247,6 @@ function setupReflector() {
|
|||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(Content, {
|
||||
"factory": (lightDom, el) => new Content(lightDom, el),
|
||||
"parameters": [[DestinationLightDom], [NgElement]],
|
||||
"annotations" : [new Decorator({selector: '[content]'})]
|
||||
});
|
||||
|
||||
reflector.registerType(UrlResolver, {
|
||||
"factory": () => new UrlResolver(),
|
||||
"parameters": [],
|
||||
|
@ -290,12 +291,58 @@ function setupReflector() {
|
|||
});
|
||||
|
||||
reflector.registerType(PrivateComponentLoader, {
|
||||
"factory": (compiler, strategy, eventMgr, reader) =>
|
||||
new PrivateComponentLoader(compiler, strategy, eventMgr, reader),
|
||||
"parameters": [[Compiler], [ShadowDomStrategy], [EventManager], [DirectiveMetadataReader]],
|
||||
"factory": (compiler, reader, viewFactory) =>
|
||||
new PrivateComponentLoader(compiler, reader, viewFactory),
|
||||
"parameters": [[Compiler], [DirectiveMetadataReader], [ViewFactory]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(DirectDomRenderer, {
|
||||
"factory": (renderCompiler, renderViewFactory, shadowDomStrategy) =>
|
||||
new DirectDomRenderer(renderCompiler, renderViewFactory, shadowDomStrategy),
|
||||
"parameters": [[rc.Compiler], [rvf.ViewFactory], [ShadowDomStrategy]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rc.DefaultCompiler, {
|
||||
"factory": (parser, shadowDomStrategy, templateLoader) =>
|
||||
new rc.DefaultCompiler(parser, shadowDomStrategy, templateLoader),
|
||||
"parameters": [[Parser], [ShadowDomStrategy], [TemplateLoader]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rvf.ViewFactory, {
|
||||
"factory": (capacity, eventManager, shadowDomStrategy) =>
|
||||
new rvf.ViewFactory(capacity, eventManager, shadowDomStrategy),
|
||||
"parameters": [[new Inject(rvf.VIEW_POOL_CAPACITY)], [EventManager], [ShadowDomStrategy]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rvf.VIEW_POOL_CAPACITY, {
|
||||
"factory": () => 100000,
|
||||
"parameters": [],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(ProtoViewFactory, {
|
||||
"factory": (changeDetection, renderer) =>
|
||||
new ProtoViewFactory(changeDetection, renderer),
|
||||
"parameters": [[ChangeDetection], [Renderer]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(ViewFactory, {
|
||||
"factory": (capacity) =>
|
||||
new ViewFactory(capacity),
|
||||
"parameters": [[new Inject(VIEW_POOL_CAPACITY)]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(VIEW_POOL_CAPACITY, {
|
||||
"factory": () => 100000,
|
||||
"parameters": [],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerGetters({
|
||||
'data': (a) => a.data,
|
||||
|
|
|
@ -11,9 +11,9 @@ import {
|
|||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
import {CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
|
||||
import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||
|
@ -36,6 +36,13 @@ import {CompanyNameComponent, OpportunityNameComponent, OfferingNameComponent,
|
|||
from './cells';
|
||||
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
import {ViewFactory, VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_factory';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
||||
import {Inject} from 'angular2/di';
|
||||
|
||||
export function main() {
|
||||
setupReflector();
|
||||
|
@ -188,13 +195,12 @@ export function setupReflectorForAngular() {
|
|||
});
|
||||
|
||||
reflector.registerType(Compiler, {
|
||||
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
|
||||
tplResolver, cmpUrlMapper, urlResolver) =>
|
||||
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
|
||||
tplResolver, cmpUrlMapper, urlResolver),
|
||||
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
|
||||
[CompilerCache], [ShadowDomStrategy], [TemplateResolver], [ComponentUrlMapper],
|
||||
[UrlResolver]],
|
||||
"factory": (reader, compilerCache, tplResolver, cmpUrlMapper, urlResolver, renderer,
|
||||
protoViewFactory) =>
|
||||
new Compiler(reader, compilerCache, tplResolver, cmpUrlMapper, urlResolver, renderer,
|
||||
protoViewFactory),
|
||||
"parameters": [[DirectiveMetadataReader], [CompilerCache], [TemplateResolver], [ComponentUrlMapper],
|
||||
[UrlResolver], [Renderer], [ProtoViewFactory]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
|
@ -288,12 +294,6 @@ export function setupReflectorForAngular() {
|
|||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(Content, {
|
||||
"factory": (lightDom, el) => new Content(lightDom, el),
|
||||
"parameters": [[DestinationLightDom], [NgElement]],
|
||||
"annotations" : [new Decorator({selector: '[content]'})]
|
||||
});
|
||||
|
||||
reflector.registerType(TestabilityRegistry, {
|
||||
"factory": () => new TestabilityRegistry(),
|
||||
"parameters": [],
|
||||
|
@ -320,9 +320,56 @@ export function setupReflectorForAngular() {
|
|||
});
|
||||
|
||||
reflector.registerType(PrivateComponentLoader, {
|
||||
"factory": (compiler, strategy, eventMgr, reader) =>
|
||||
new PrivateComponentLoader(compiler, strategy, eventMgr, reader),
|
||||
"parameters": [[Compiler], [ShadowDomStrategy], [EventManager], [DirectiveMetadataReader]],
|
||||
"factory": (compiler, reader, viewFactory) =>
|
||||
new PrivateComponentLoader(compiler, reader, viewFactory),
|
||||
"parameters": [[Compiler], [DirectiveMetadataReader], [ViewFactory]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(DirectDomRenderer, {
|
||||
"factory": (renderCompiler, renderViewFactory, shadowDomStrategy) =>
|
||||
new DirectDomRenderer(renderCompiler, renderViewFactory, shadowDomStrategy),
|
||||
"parameters": [[rc.Compiler], [rvf.ViewFactory], [ShadowDomStrategy]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rc.DefaultCompiler, {
|
||||
"factory": (parser, shadowDomStrategy, templateLoader) =>
|
||||
new rc.DefaultCompiler(parser, shadowDomStrategy, templateLoader),
|
||||
"parameters": [[Parser], [ShadowDomStrategy], [TemplateLoader]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rvf.ViewFactory, {
|
||||
"factory": (capacity, eventManager, shadowDomStrategy) =>
|
||||
new rvf.ViewFactory(capacity, eventManager, shadowDomStrategy),
|
||||
"parameters": [[new Inject(rvf.VIEW_POOL_CAPACITY)], [EventManager], [ShadowDomStrategy]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rvf.VIEW_POOL_CAPACITY, {
|
||||
"factory": () => 100000,
|
||||
"parameters": [],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(ProtoViewFactory, {
|
||||
"factory": (changeDetection, renderer) =>
|
||||
new ProtoViewFactory(changeDetection, renderer),
|
||||
"parameters": [[ChangeDetection], [Renderer]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(ViewFactory, {
|
||||
"factory": (capacity) =>
|
||||
new ViewFactory(capacity),
|
||||
"parameters": [[new Inject(VIEW_POOL_CAPACITY)]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(VIEW_POOL_CAPACITY, {
|
||||
"factory": () => 100000,
|
||||
"parameters": [],
|
||||
"annotations": []
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ import {CompilerCache} from 'angular2/src/core/compiler/compiler';
|
|||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
|
||||
import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
|
||||
|
@ -32,6 +32,13 @@ import {If} from 'angular2/directives';
|
|||
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
||||
|
||||
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
||||
import {ViewFactory, VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_factory';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
||||
import {Inject} from 'angular2/di';
|
||||
|
||||
function setupReflector() {
|
||||
// TODO: Put the general calls to reflector.register... in a shared file
|
||||
|
@ -74,14 +81,13 @@ function setupReflector() {
|
|||
});
|
||||
|
||||
reflector.registerType(Compiler, {
|
||||
'factory': (cd, templateLoader, reader, parser, compilerCache, strategy, tplResolver,
|
||||
cmpUrlMapper, urlResolver) =>
|
||||
new Compiler(cd, templateLoader, reader, parser, compilerCache, strategy, tplResolver,
|
||||
cmpUrlMapper, urlResolver),
|
||||
'parameters': [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader],
|
||||
[Parser], [CompilerCache], [ShadowDomStrategy], [TemplateResolver],
|
||||
[ComponentUrlMapper], [UrlResolver]],
|
||||
'annotations': []
|
||||
"factory": (reader, compilerCache, tplResolver, cmpUrlMapper, urlResolver, renderer,
|
||||
protoViewFactory) =>
|
||||
new Compiler(reader, compilerCache, tplResolver, cmpUrlMapper, urlResolver, renderer,
|
||||
protoViewFactory),
|
||||
"parameters": [[DirectiveMetadataReader], [CompilerCache], [TemplateResolver], [ComponentUrlMapper],
|
||||
[UrlResolver], [Renderer], [ProtoViewFactory]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(CompilerCache, {
|
||||
|
@ -156,12 +162,6 @@ function setupReflector() {
|
|||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(Content, {
|
||||
"factory": (lightDom, el) => new Content(lightDom, el),
|
||||
"parameters": [[DestinationLightDom], [NgElement]],
|
||||
"annotations" : [new Decorator({selector: '[content]'})]
|
||||
});
|
||||
|
||||
reflector.registerType(UrlResolver, {
|
||||
"factory": () => new UrlResolver(),
|
||||
"parameters": [],
|
||||
|
@ -206,9 +206,56 @@ function setupReflector() {
|
|||
});
|
||||
|
||||
reflector.registerType(PrivateComponentLoader, {
|
||||
"factory": (compiler, strategy, eventMgr, reader) =>
|
||||
new PrivateComponentLoader(compiler, strategy, eventMgr, reader),
|
||||
"parameters": [[Compiler], [ShadowDomStrategy], [EventManager], [DirectiveMetadataReader]],
|
||||
"factory": (compiler, reader, viewFactory) =>
|
||||
new PrivateComponentLoader(compiler, reader, viewFactory),
|
||||
"parameters": [[Compiler], [DirectiveMetadataReader], [ViewFactory]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(DirectDomRenderer, {
|
||||
"factory": (renderCompiler, renderViewFactory, shadowDomStrategy) =>
|
||||
new DirectDomRenderer(renderCompiler, renderViewFactory, shadowDomStrategy),
|
||||
"parameters": [[rc.Compiler], [rvf.ViewFactory], [ShadowDomStrategy]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rc.DefaultCompiler, {
|
||||
"factory": (parser, shadowDomStrategy, templateLoader) =>
|
||||
new rc.DefaultCompiler(parser, shadowDomStrategy, templateLoader),
|
||||
"parameters": [[Parser], [ShadowDomStrategy], [TemplateLoader]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rvf.ViewFactory, {
|
||||
"factory": (capacity, eventManager, shadowDomStrategy) =>
|
||||
new rvf.ViewFactory(capacity, eventManager, shadowDomStrategy),
|
||||
"parameters": [[new Inject(rvf.VIEW_POOL_CAPACITY)], [EventManager], [ShadowDomStrategy]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rvf.VIEW_POOL_CAPACITY, {
|
||||
"factory": () => 100000,
|
||||
"parameters": [],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(ProtoViewFactory, {
|
||||
"factory": (changeDetection, renderer) =>
|
||||
new ProtoViewFactory(changeDetection, renderer),
|
||||
"parameters": [[ChangeDetection], [Renderer]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(ViewFactory, {
|
||||
"factory": (capacity) =>
|
||||
new ViewFactory(capacity),
|
||||
"parameters": [[new Inject(VIEW_POOL_CAPACITY)]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(VIEW_POOL_CAPACITY, {
|
||||
"factory": () => 100000,
|
||||
"parameters": [],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
|
|||
|
||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {ShadowDomStrategy, NativeShadowDomStrategy, EmulatedUnscopedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
|
||||
import {Content} from 'angular2/src/core/compiler/shadow_dom_emulation/content_tag';
|
||||
import {DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
|
||||
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
|
||||
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
|
||||
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
|
||||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
import {XHR} from 'angular2/src/services/xhr';
|
||||
|
@ -24,6 +24,14 @@ import {TestabilityRegistry, Testability} from 'angular2/src/core/testability/te
|
|||
|
||||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
|
||||
import {ViewFactory, VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_factory';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
import * as rc from 'angular2/src/render/dom/compiler/compiler';
|
||||
import * as rvf from 'angular2/src/render/dom/view/view_factory';
|
||||
import {Inject} from 'angular2/di';
|
||||
|
||||
function setup() {
|
||||
reflector.registerType(app.HelloCmp, {
|
||||
"factory": (service) => new app.HelloCmp(service),
|
||||
|
@ -53,13 +61,12 @@ function setup() {
|
|||
});
|
||||
|
||||
reflector.registerType(Compiler, {
|
||||
"factory": (changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
|
||||
tplResolver, cmpUrlMapper, urlResolver) =>
|
||||
new Compiler(changeDetection, templateLoader, reader, parser, compilerCache, shadowDomStrategy,
|
||||
tplResolver, cmpUrlMapper, urlResolver),
|
||||
"parameters": [[ChangeDetection], [TemplateLoader], [DirectiveMetadataReader], [Parser],
|
||||
[CompilerCache], [ShadowDomStrategy], [TemplateResolver], [ComponentUrlMapper],
|
||||
[UrlResolver]],
|
||||
"factory": (reader, compilerCache, tplResolver, cmpUrlMapper, urlResolver, renderer,
|
||||
protoViewFactory) =>
|
||||
new Compiler(reader, compilerCache, tplResolver, cmpUrlMapper, urlResolver, renderer,
|
||||
protoViewFactory),
|
||||
"parameters": [[DirectiveMetadataReader], [CompilerCache], [TemplateResolver], [ComponentUrlMapper],
|
||||
[UrlResolver], [Renderer], [ProtoViewFactory]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
|
@ -153,12 +160,6 @@ function setup() {
|
|||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(Content, {
|
||||
"factory": (lightDom, el, selector) => new Content(lightDom, el, selector),
|
||||
"parameters": [[DestinationLightDom], [NgElement], [String]],
|
||||
"annotations" : []
|
||||
});
|
||||
|
||||
reflector.registerType(StyleInliner, {
|
||||
"factory": (xhr, styleUrlResolver, urlResolver) =>
|
||||
new StyleInliner(xhr, styleUrlResolver, urlResolver),
|
||||
|
@ -173,9 +174,9 @@ function setup() {
|
|||
});
|
||||
|
||||
reflector.registerType(PrivateComponentLoader, {
|
||||
"factory": (compiler, strategy, eventMgr, reader) =>
|
||||
new PrivateComponentLoader(compiler, strategy, eventMgr, reader),
|
||||
"parameters": [[Compiler], [ShadowDomStrategy], [EventManager], [DirectiveMetadataReader]],
|
||||
"factory": (compiler, reader, viewFactory) =>
|
||||
new PrivateComponentLoader(compiler, reader, viewFactory),
|
||||
"parameters": [[Compiler], [DirectiveMetadataReader], [ViewFactory]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
|
@ -191,6 +192,53 @@ function setup() {
|
|||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(DirectDomRenderer, {
|
||||
"factory": (renderCompiler, renderViewFactory, shadowDomStrategy) =>
|
||||
new DirectDomRenderer(renderCompiler, renderViewFactory, shadowDomStrategy),
|
||||
"parameters": [[rc.Compiler], [rvf.ViewFactory], [ShadowDomStrategy]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rc.DefaultCompiler, {
|
||||
"factory": (parser, shadowDomStrategy, templateLoader) =>
|
||||
new rc.DefaultCompiler(parser, shadowDomStrategy, templateLoader),
|
||||
"parameters": [[Parser], [ShadowDomStrategy], [TemplateLoader]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rvf.ViewFactory, {
|
||||
"factory": (capacity, eventManager, shadowDomStrategy) =>
|
||||
new rvf.ViewFactory(capacity, eventManager, shadowDomStrategy),
|
||||
"parameters": [[new Inject(rvf.VIEW_POOL_CAPACITY)], [EventManager], [ShadowDomStrategy]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(rvf.VIEW_POOL_CAPACITY, {
|
||||
"factory": () => 100000,
|
||||
"parameters": [],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(ProtoViewFactory, {
|
||||
"factory": (changeDetection, renderer) =>
|
||||
new ProtoViewFactory(changeDetection, renderer),
|
||||
"parameters": [[ChangeDetection], [Renderer]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(ViewFactory, {
|
||||
"factory": (capacity) =>
|
||||
new ViewFactory(capacity),
|
||||
"parameters": [[new Inject(VIEW_POOL_CAPACITY)]],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerType(VIEW_POOL_CAPACITY, {
|
||||
"factory": () => 100000,
|
||||
"parameters": [],
|
||||
"annotations": []
|
||||
});
|
||||
|
||||
reflector.registerGetters({
|
||||
"greeting": (a) => a.greeting
|
||||
});
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import 'package:angular2/src/dom/browser_adapter.dart';
|
||||
|
||||
main() {
|
||||
BrowserDomAdapter.makeCurrent();
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
import 'package:guinness/guinness.dart';
|
||||
import 'package:unittest/unittest.dart' as unit;
|
||||
import 'package:angular2/src/dom/browser_adapter.dart';
|
||||
|
||||
import 'package:angular2/src/test_lib/test_lib.dart' show testSetup;
|
||||
|
||||
main() {
|
||||
BrowserDomAdapter.makeCurrent();
|
||||
unit.filterStacks = true;
|
||||
unit.formatStacks = false;
|
||||
unit.unittestConfiguration.timeout = new Duration(milliseconds: 100);
|
||||
|
|
Loading…
Reference in New Issue