Skip to content

Commit

Permalink
refactor(render): use render layer fully
Browse files Browse the repository at this point in the history
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, …
  • Loading branch information
tbosch committed Apr 9, 2015
1 parent de581ea commit 5009876
Show file tree
Hide file tree
Showing 60 changed files with 1,205 additions and 3,340 deletions.
2 changes: 2 additions & 0 deletions karma-dart.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
2 changes: 1 addition & 1 deletion modules/angular2/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

38 changes: 31 additions & 7 deletions modules/angular2/src/core/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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,
Expand Down Expand Up @@ -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.
Expand All @@ -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]),
Expand All @@ -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,
Expand Down
63 changes: 8 additions & 55 deletions modules/angular2/src/core/compiler/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

/**
Expand Down Expand Up @@ -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>;
Expand Down Expand Up @@ -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);
});
}

Expand Down Expand Up @@ -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)
);
}
}
9 changes: 0 additions & 9 deletions modules/angular2/src/core/compiler/element_binder.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
}
45 changes: 19 additions & 26 deletions modules/angular2/src/core/compiler/element_injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand All @@ -371,6 +361,7 @@ export class ElementInjector extends TreeNode {
}

clearDirectives() {
this._host = null;
this._preBuiltObjects = null;
this._lightDomAppInjector = null;
this._shadowDomAppInjector = null;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions modules/angular2/src/core/compiler/ng_element.js
Original file line number Diff line number Diff line change
@@ -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));
}
}
Loading

0 comments on commit 5009876

Please sign in to comment.