refactor(shadow dom): do not use injectors nor directives

This prepares us for the app/render split in the compiler.
This commit is contained in:
Yegor Jbanov 2015-03-16 11:31:58 -07:00
parent 115ac5f290
commit 70c875ee14
31 changed files with 367 additions and 343 deletions

View File

@ -67,7 +67,7 @@ function _injectorBindings(appComponentType): List<Binding> {
// the angular application. Thus the context and lightDomInjector are
// empty.
var view = appProtoView.instantiate(null, eventManager);
view.hydrate(injector, null, new Object());
view.hydrate(injector, null, null, new Object());
return view;
});
}, [ChangeDetection, Compiler, Injector, appElementToken, appComponentAnnotatedTypeToken,

View File

@ -11,7 +11,6 @@ import {CompileElement} from './pipeline/compile_element';
import {createDefaultSteps} from './pipeline/default_steps';
import {TemplateLoader} from './template_loader';
import {TemplateResolver} from './template_resolver';
import {DirectiveMetadata} from './directive_metadata';
import {Template} from '../annotations/template';
import {ShadowDomStrategy} from './shadow_dom_strategy';
import {CompileStep} from './pipeline/compile_step';
@ -56,7 +55,6 @@ export class Compiler {
_templateLoader:TemplateLoader;
_compiling:Map<Type, Promise>;
_shadowDomStrategy: ShadowDomStrategy;
_shadowDomDirectives: List<DirectiveMetadata>;
_templateResolver: TemplateResolver;
_componentUrlMapper: ComponentUrlMapper;
_urlResolver: UrlResolver;
@ -80,11 +78,6 @@ export class Compiler {
this._templateLoader = templateLoader;
this._compiling = MapWrapper.create();
this._shadowDomStrategy = shadowDomStrategy;
this._shadowDomDirectives = [];
var types = shadowDomStrategy.polyfillDirectives();
for (var i = 0; i < types.length; i++) {
ListWrapper.push(this._shadowDomDirectives, reader.read(types[i]));
}
this._templateResolver = templateResolver;
this._componentUrlMapper = componentUrlMapper;
this._urlResolver = urlResolver;
@ -93,12 +86,8 @@ export class Compiler {
}
createSteps(component:Type, template: Template):List<CompileStep> {
// Merge directive metadata (from the template and from the shadow dom strategy)
var dirMetadata = [];
var tplMetadata = ListWrapper.map(this._flattenDirectives(template),
var dirMetadata = ListWrapper.map(this._flattenDirectives(template),
(d) => this._reader.read(d));
dirMetadata = ListWrapper.concat(dirMetadata, tplMetadata);
dirMetadata = ListWrapper.concat(dirMetadata, this._shadowDomDirectives);
var cmpMetadata = this._reader.read(component);

View File

@ -1,3 +1,4 @@
import {int, isBlank, BaseException} from 'angular2/src/facade/lang';
import {ProtoElementInjector} from './element_injector';
import {DirectiveMetadata} from './directive_metadata';
import {List, StringMap} from 'angular2/src/facade/collection';
@ -11,12 +12,24 @@ export class ElementBinder {
hasElementPropertyBindings:boolean;
nestedProtoView: ProtoView;
events:StringMap;
contentTagSelector:string;
parent:ElementBinder;
index:int;
distanceToParent:int;
constructor(
index:int, parent:ElementBinder, distanceToParent: int,
protoElementInjector: ProtoElementInjector, componentDirective:DirectiveMetadata,
viewportDirective:DirectiveMetadata) {
if (isBlank(index)) {
throw new BaseException('null index not allowed.');
}
this.protoElementInjector = protoElementInjector;
this.componentDirective = componentDirective;
this.viewportDirective = viewportDirective;
this.parent = parent;
this.index = index;
this.distanceToParent = distanceToParent;
// updated later when events are bound
this.events = null;
// updated later when text nodes are bound
@ -25,5 +38,7 @@ export class ElementBinder {
this.hasElementPropertyBindings = false;
// updated later, so we are able to resolve cycles
this.nestedProtoView = null;
// updated later in the compilation pipeline
this.contentTagSelector = null;
}
}

View File

@ -5,7 +5,6 @@ import {Injector, Key, Dependency, bind, Binding, NoProviderError, ProviderError
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
import {EventEmitter, PropertySetter} from 'angular2/src/core/annotations/di';
import * as viewModule from 'angular2/src/core/compiler/view';
import {LightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
import {NgElement} from 'angular2/src/core/dom/element';
import {Directive, onChange, onDestroy} from 'angular2/src/core/annotations/annotations'
@ -24,8 +23,6 @@ class StaticKeys {
viewId:number;
ngElementId:number;
viewContainerId:number;
destinationLightDomId:number;
lightDomId:number;
bindingPropagationConfigId:number;
constructor() {
@ -33,8 +30,6 @@ class StaticKeys {
this.viewId = Key.get(viewModule.View).id;
this.ngElementId = Key.get(NgElement).id;
this.viewContainerId = Key.get(ViewContainer).id;
this.destinationLightDomId = Key.get(DestinationLightDom).id;
this.lightDomId = Key.get(LightDom).id;
this.bindingPropagationConfigId = Key.get(BindingPropagationConfig).id;
}
@ -166,14 +161,12 @@ export class PreBuiltObjects {
view:viewModule.View;
element:NgElement;
viewContainer:ViewContainer;
lightDom:LightDom;
bindingPropagationConfig:BindingPropagationConfig;
constructor(view, element:NgElement, viewContainer:ViewContainer, lightDom:LightDom,
constructor(view, element:NgElement, viewContainer:ViewContainer,
bindingPropagationConfig:BindingPropagationConfig) {
this.view = view;
this.element = element;
this.viewContainer = viewContainer;
this.lightDom = lightDom;
this.bindingPropagationConfig = bindingPropagationConfig;
}
}
@ -577,13 +570,6 @@ export class ElementInjector extends TreeNode {
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
if (keyId === staticKeys.viewContainerId) return this._preBuiltObjects.viewContainer;
if (keyId === staticKeys.bindingPropagationConfigId) return this._preBuiltObjects.bindingPropagationConfig;
if (keyId === staticKeys.destinationLightDomId) {
var p:ElementInjector = this.directParent();
return isPresent(p) ? p._preBuiltObjects.lightDom : null;
}
if (keyId === staticKeys.lightDomId) {
return this._preBuiltObjects.lightDom;
}
//TODO add other objects as needed
return _undefined;

View File

@ -36,10 +36,12 @@ export class CompileElement {
inheritedProtoView:ProtoView;
inheritedProtoElementInjector:ProtoElementInjector;
inheritedElementBinder:ElementBinder;
distanceToParentInjector:number;
distanceToParentInjector:int;
distanceToParentBinder:int;
compileChildren: boolean;
ignoreBindings: boolean;
elementDescription: string; // e.g. '<div [class]="foo">' : used to provide context in case of error
contentTagSelector: string;
constructor(element, compilationUnit = '') {
this.element = element;
@ -65,9 +67,11 @@ export class CompileElement {
// an own elementBinder
this.inheritedElementBinder = null;
this.distanceToParentInjector = 0;
this.distanceToParentBinder = 0;
this.compileChildren = true;
// set to true to ignore all the bindings on the element
this.ignoreBindings = false;
this.contentTagSelector = null;
// description is calculated here as compilation steps may change the element
var tplDesc = assertionsEnabled()? getElementDescription(element) : null;
if (compilationUnit !== '') {

View File

@ -1,6 +1,5 @@
import {ChangeDetection, Parser} from 'angular2/change_detection';
import {List, ListWrapper} from 'angular2/src/facade/collection';
import {isPresent} from 'angular2/src/facade/lang';
import {PropertyBindingParser} from './property_binding_parser';
import {TextInterpolationParser} from './text_interpolation_parser';
@ -32,6 +31,7 @@ export function createDefaultSteps(
var steps = [
new ViewSplitter(parser),
cssProcessor.getCompileStep(compiledComponent, shadowDomStrategy, templateUrl),
shadowDomStrategy.getTemplateCompileStep(compiledComponent),
new PropertyBindingParser(parser),
new DirectiveParser(directives),
new TextInterpolationParser(parser),
@ -41,10 +41,5 @@ export function createDefaultSteps(
new ElementBinderBuilder(parser),
];
var shadowDomStep = shadowDomStrategy.getTemplateCompileStep(compiledComponent);
if (isPresent(shadowDomStep)) {
ListWrapper.push(steps, shadowDomStep);
}
return steps;
}

View File

@ -49,7 +49,8 @@ export class DirectiveParser extends CompileStep {
var classList = current.classList();
var cssSelector = new CssSelector();
cssSelector.setElement(DOM.nodeName(current.element));
var nodeName = DOM.nodeName(current.element);
cssSelector.setElement(nodeName);
for (var i=0; i < classList.length; i++) {
cssSelector.addClassName(classList[i]);
}

View File

@ -135,6 +135,11 @@ export class ElementBinderBuilder extends CompileStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
var elementBinder = null;
var parentElementBinder = null;
var distanceToParentBinder = this._getDistanceToParentBinder(parent, current);
if (isPresent(parent)) {
parentElementBinder = parent.inheritedElementBinder;
}
if (current.hasBindings) {
var protoView = current.inheritedProtoView;
var protoInjectorWasBuilt = isBlank(parent) ? true :
@ -143,8 +148,9 @@ export class ElementBinderBuilder extends CompileStep {
var currentProtoElementInjector = protoInjectorWasBuilt ?
current.inheritedProtoElementInjector : null;
elementBinder = protoView.bindElement(currentProtoElementInjector,
current.componentDirective, current.viewportDirective);
elementBinder = protoView.bindElement(parentElementBinder, distanceToParentBinder,
currentProtoElementInjector, current.componentDirective, current.viewportDirective);
current.distanceToParentBinder = 0;
if (isPresent(current.textNodeBindings)) {
this._bindTextNodes(protoView, current);
@ -155,15 +161,23 @@ export class ElementBinderBuilder extends CompileStep {
if (isPresent(current.eventBindings)) {
this._bindEvents(protoView, current);
}
if (isPresent(current.contentTagSelector)) {
elementBinder.contentTagSelector = current.contentTagSelector;
}
var directives = current.getAllDirectives();
this._bindDirectiveProperties(directives, current);
this._bindDirectiveEvents(directives, current);
} else if (isPresent(parent)) {
elementBinder = parent.inheritedElementBinder;
elementBinder = parentElementBinder;
current.distanceToParentBinder = distanceToParentBinder;
}
current.inheritedElementBinder = elementBinder;
}
_getDistanceToParentBinder(parent, current) {
return isPresent(parent) ? parent.distanceToParentBinder + 1 : 0;
}
_bindTextNodes(protoView, compileElement) {
MapWrapper.forEach(compileElement.textNodeBindings, (expression, indexInParent) => {
protoView.bindTextNode(indexInParent, expression);

View File

@ -37,7 +37,8 @@ export class ElementBindingMarker extends CompileStep {
(isPresent(current.eventBindings) && MapWrapper.size(current.eventBindings)>0) ||
(isPresent(current.decoratorDirectives) && current.decoratorDirectives.length > 0) ||
isPresent(current.viewportDirective) ||
isPresent(current.componentDirective);
isPresent(current.componentDirective) ||
isPresent(current.contentTagSelector);
if (hasBindings) {
var element = current.element;

View File

@ -1,10 +1,7 @@
import {Decorator} from '../../annotations/annotations';
import * as ldModule from './light_dom';
import {Inject} 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';
import {NgElement} from 'angular2/src/core/dom/element';
class ContentStrategy {
nodes:List;
@ -17,23 +14,16 @@ class ContentStrategy {
* and thus does not affect redistribution.
*/
class RenderedContent extends ContentStrategy {
static _lazyScriptTemplate;
beginScript;
endScript;
constructor(contentEl) {
super();
this._replaceContentElementWithScriptTags(contentEl);
this.beginScript = contentEl;
this.endScript = DOM.nextSibling(this.beginScript);
this.nodes = [];
}
_scriptTemplate() {
if (!isPresent(RenderedContent._lazyScriptTemplate)) {
RenderedContent._lazyScriptTemplate = DOM.createScriptTag('type', 'ng/content');
}
return RenderedContent._lazyScriptTemplate;
}
// Inserts the nodes in between the start and end scripts.
// Previous content is removed.
insert(nodes:List) {
@ -42,16 +32,6 @@ class RenderedContent extends ContentStrategy {
this._removeNodesUntil(ListWrapper.isEmpty(nodes) ? this.endScript : nodes[0]);
}
// Replaces the content tag with a pair of script tags
_replaceContentElementWithScriptTags(contentEl) {
this.beginScript = DOM.clone(this._scriptTemplate());
this.endScript = DOM.clone(this._scriptTemplate());
DOM.insertBefore(contentEl, this.beginScript);
DOM.insertBefore(contentEl, this.endScript);
DOM.removeChild(DOM.parentElement(contentEl), contentEl);
}
_removeNodesUntil(node) {
var p = DOM.parentElement(this.beginScript);
for (var next = DOM.nextSibling(this.beginScript);
@ -83,18 +63,17 @@ class IntermediateContent extends ContentStrategy {
}
@Decorator({
selector: 'content'
})
export class Content {
select:string;
_strategy:ContentStrategy;
contentStartElement;
constructor(@Inject(ldModule.DestinationLightDom) destinationLightDom, contentEl:NgElement) {
this.select = contentEl.getAttribute('select');
constructor(destinationLightDom:ldModule.LightDom, contentStartEl, selector:string) {
this.select = selector;
this.contentStartElement = contentStartEl;
this._strategy = isPresent(destinationLightDom) ?
new IntermediateContent(destinationLightDom) :
new RenderedContent(contentEl.domElement);
new RenderedContent(contentStartEl);
}
nodes():List {

View File

@ -3,8 +3,6 @@ import {List, ListWrapper} from 'angular2/src/facade/collection';
import {isBlank, isPresent} from 'angular2/src/facade/lang';
import * as viewModule from '../view';
import {ElementInjector} from '../element_injector';
import {ViewContainer} from '../view_container';
import {Content} from './content_tag';
export class DestinationLightDom {}
@ -12,11 +10,13 @@ export class DestinationLightDom {}
class _Root {
node;
injector:ElementInjector;
viewContainer;
content;
constructor(node, injector) {
constructor(node, viewContainer, content) {
this.node = node;
this.injector = injector;
this.viewContainer = viewContainer;
this.content = content;
}
}
@ -52,19 +52,18 @@ export class LightDom {
// Collects the Content directives from the view and all its child views
_collectAllContentTags(view: viewModule.View, acc:List<Content>):List<Content> {
var eis = view.elementInjectors;
for (var i = 0; i < eis.length; ++i) {
var ei = eis[i];
if (isBlank(ei)) continue;
if (ei.hasDirective(Content)) {
ListWrapper.push(acc, ei.get(Content));
} else if (ei.hasPreBuiltObject(ViewContainer)) {
var vc = ei.get(ViewContainer);
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;
@ -76,21 +75,16 @@ export class LightDom {
// - plain DOM nodes
expandedDomNodes():List {
var res = [];
var roots = this._roots();
for (var i = 0; i < roots.length; ++i) {
var root = roots[i];
var ei = root.injector;
if (isPresent(ei) && ei.hasPreBuiltObject(ViewContainer)) {
var vc = root.injector.get(ViewContainer);
res = ListWrapper.concat(res, vc.nodes());
} else if (isPresent(ei) && ei.hasDirective(Content)) {
var content = root.injector.get(Content);
res = ListWrapper.concat(res, content.nodes());
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);
}
@ -103,10 +97,24 @@ export class LightDom {
_roots() {
if (isPresent(this.roots)) return this.roots;
var viewInj = this.lightDomView.elementInjectors;
this.roots = ListWrapper.map(this.nodes, (n) =>
new _Root(n, ListWrapper.find(viewInj,
(inj) => isPresent(inj) ? inj.forElement(n) : false)));
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;
}
@ -119,10 +127,10 @@ function redistributeNodes(contents:List<Content>, nodes:List) {
var select = content.select;
var matchSelector = (n) => DOM.elementMatches(n, select);
if (isBlank(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);

View File

@ -1,4 +1,4 @@
import {Type, isBlank, isPresent, int} from 'angular2/src/facade/lang';
import {Type, isBlank, isPresent, int, StringWrapper, assertionsEnabled} from 'angular2/src/facade/lang';
import {List, ListWrapper, MapWrapper, Map} from 'angular2/src/facade/collection';
import {PromiseWrapper} from 'angular2/src/facade/async';
@ -6,7 +6,6 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
import * as viewModule from './view';
import {Content} from './shadow_dom_emulation/content_tag';
import {LightDom} from './shadow_dom_emulation/light_dom';
import {ShadowCss} from './shadow_dom_emulation/shadow_css';
@ -19,20 +18,30 @@ import * as NS from './pipeline/compile_step';
import {CompileElement} from './pipeline/compile_element';
import {CompileControl} from './pipeline/compile_control';
var _EMPTY_STEP;
// Note: fill _EMPTY_STEP to prevent
// problems from cyclic dependencies
function _emptyStep() {
if (isBlank(_EMPTY_STEP)) {
_EMPTY_STEP = new _EmptyCompileStep();
}
return _EMPTY_STEP;
}
export class ShadowDomStrategy {
attachTemplate(el, view:viewModule.View) {}
constructLightDom(lightDomView:viewModule.View, shadowDomView:viewModule.View, el): LightDom { return null; }
polyfillDirectives():List<Type> { return []; }
/**
* An optional step that can modify the template style elements.
*
* @param {DirectiveMetadata} cmpMetadata
* @param {string} templateUrl the template base URL
* @returns {CompileStep} a compile step to append to the compiler pipeline, null if not required.
* @returns {CompileStep} a compile step to append to the compiler pipeline
*/
getStyleCompileStep(cmpMetadata: DirectiveMetadata, templateUrl: string): NS.CompileStep {
return null;
return _emptyStep();
}
/**
@ -41,9 +50,9 @@ export class ShadowDomStrategy {
* This step could be used to modify the template in order to scope the styles.
*
* @param {DirectiveMetadata} cmpMetadata
* @returns {CompileStep} a compile step to append to the compiler pipeline, null if not required.
* @returns {CompileStep} a compile step to append to the compiler pipeline
*/
getTemplateCompileStep(cmpMetadata: DirectiveMetadata): NS.CompileStep { return null; }
getTemplateCompileStep(cmpMetadata: DirectiveMetadata): NS.CompileStep { return _emptyStep(); }
/**
* The application element does not go through the compiler pipeline.
@ -87,14 +96,14 @@ export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy {
return new LightDom(lightDomView, shadowDomView, el);
}
polyfillDirectives():List<Type> {
return [Content];
}
getStyleCompileStep(cmpMetadata: DirectiveMetadata, templateUrl: string): NS.CompileStep {
return new _EmulatedUnscopedCssStep(cmpMetadata, templateUrl, this._styleUrlResolver,
this._styleHost);
}
getTemplateCompileStep(cmpMetadata: DirectiveMetadata): NS.CompileStep {
return new _BaseEmulatedShadowDomStep();
}
}
/**
@ -156,7 +165,39 @@ export class NativeShadowDomStrategy extends ShadowDomStrategy {
}
}
class _ShimShadowDomStep extends NS.CompileStep {
class _BaseEmulatedShadowDomStep extends NS.CompileStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
if (current.ignoreBindings) {
return;
}
var nodeName = DOM.nodeName(current.element);
if (StringWrapper.equals(nodeName.toUpperCase(), 'CONTENT')) {
var attrs = current.attrs();
var selector = MapWrapper.get(attrs, 'select');
current.contentTagSelector = isPresent(selector) ? selector : '';
var contentStart = DOM.createScriptTag('type', 'ng/contentStart');
if (assertionsEnabled()) {
DOM.setAttribute(contentStart, 'select', current.contentTagSelector);
}
var contentEnd = DOM.createScriptTag('type', 'ng/contentEnd');
DOM.insertBefore(current.element, contentStart);
DOM.insertBefore(current.element, contentEnd);
DOM.remove(current.element);
current.element = contentStart;
}
}
}
class _EmptyCompileStep extends NS.CompileStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
}
}
class _ShimShadowDomStep extends _BaseEmulatedShadowDomStep {
_contentAttribute: string;
constructor(cmpMetadata: DirectiveMetadata) {
@ -167,6 +208,7 @@ class _ShimShadowDomStep extends NS.CompileStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
super.process(parent, current, control);
if (current.ignoreBindings) {
return;
}

View File

@ -13,7 +13,8 @@ import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/f
import {Injector} from 'angular2/di';
import {NgElement} from 'angular2/src/core/dom/element';
import {ViewContainer} from './view_container';
import {LightDom, DestinationLightDom} from './shadow_dom_emulation/light_dom';
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/core/events/event_manager';
@ -41,7 +42,9 @@ export class View {
nodes:List;
componentChildViews: List<View>;
viewContainers: List<ViewContainer>;
contentTags: List<Content>;
preBuiltObjects: List<PreBuiltObjects>;
lightDoms: List<LightDom>;
proto: ProtoView;
context: any;
contextWithLocals:ContextWithVariableBindings;
@ -56,7 +59,9 @@ export class View {
this.bindElements = null;
this.componentChildViews = null;
this.viewContainers = null;
this.contentTags = null;
this.preBuiltObjects = null;
this.lightDoms = null;
this.context = null;
this.contextWithLocals = (MapWrapper.size(protoContextLocals) > 0)
? new ContextWithVariableBindings(null, MapWrapper.clone(protoContextLocals))
@ -64,15 +69,17 @@ export class View {
}
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List,
viewContainers:List, preBuiltObjects:List, componentChildViews:List) {
viewContainers:List, contentTags:List, preBuiltObjects:List, componentChildViews:List, lightDoms:List<LightDom>) {
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) {
@ -125,14 +132,17 @@ export class View {
* A call to hydrate/dehydrate does not attach/detach the view from the view
* tree.
*/
hydrate(appInjector: Injector, hostElementInjector: ElementInjector,
hydrate(appInjector: Injector, hostElementInjector: ElementInjector, hostLightDom: LightDom,
context: Object) {
if (this.hydrated()) throw new BaseException('The view is already hydrated.');
this._hydrateContext(context);
// viewContainers
for (var i = 0; i < this.viewContainers.length; i++) {
this.viewContainers[i].hydrate(appInjector, hostElementInjector);
var vc = this.viewContainers[i];
if (isPresent(vc)) {
vc.hydrate(appInjector, hostElementInjector, hostLightDom);
}
}
var binders = this.proto.elementBinders;
@ -171,18 +181,14 @@ export class View {
if (isPresent(componentDirective)) {
this.componentChildViews[componentChildViewIndex++].hydrate(shadowDomAppInjector,
elementInjector, elementInjector.getComponent());
elementInjector, this.lightDoms[i], elementInjector.getComponent());
}
}
// this should be moved into DOM write queue
for (var i = 0; i < binders.length; ++i) {
var componentDirective = binders[i].componentDirective;
if (isPresent(componentDirective)) {
var lightDom = this.preBuiltObjects[i].lightDom;
if (isPresent(lightDom)) {
lightDom.redistribute();
}
for (var i = 0; i < this.lightDoms.length; ++i) {
var lightDom = this.lightDoms[i];
if (isPresent(lightDom)) {
lightDom.redistribute();
}
}
}
@ -205,7 +211,10 @@ export class View {
// viewContainers
if (isPresent(this.viewContainers)) {
for (var i = 0; i < this.viewContainers.length; i++) {
this.viewContainers[i].dehydrate();
var vc = this.viewContainers[i];
if (isPresent(vc)) {
vc.dehydrate();
}
}
}
@ -370,8 +379,10 @@ export class ProtoView {
var textNodes = [];
var elementsWithPropertyBindings = [];
var preBuiltObjects = ListWrapper.createFixedSize(binders.length);
var viewContainers = [];
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];
@ -427,20 +438,32 @@ export class ProtoView {
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)) {
var destLightDom = this._directParentElementLightDom(protoElementInjector, preBuiltObjects);
viewContainer = new ViewContainer(view, element, binder.nestedProtoView, elementInjector,
eventManager, destLightDom);
ListWrapper.push(viewContainers, viewContainer);
}
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,
lightDom, bindingPropagationConfig);
bindingPropagationConfig);
}
// events
@ -460,7 +483,7 @@ export class ProtoView {
this.eventHandlers = eventHandlers;
view.init(changeDetector, elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
viewContainers, preBuiltObjects, componentChildViews);
viewContainers, contentTags, preBuiltObjects, componentChildViews, lightDoms);
return view;
}
@ -497,19 +520,15 @@ export class ProtoView {
}
}
_directParentElementLightDom(protoElementInjector:ProtoElementInjector, preBuiltObjects:List):LightDom {
var p = protoElementInjector.directParent();
return isPresent(p) ? preBuiltObjects[p.index].lightDom : null;
}
bindVariable(contextName:string, templateName:string) {
MapWrapper.set(this.variableBindings, contextName, templateName);
MapWrapper.set(this.protoContextLocals, templateName, null);
}
bindElement(protoElementInjector:ProtoElementInjector,
bindElement(parent:ElementBinder, distanceToParent:int, protoElementInjector:ProtoElementInjector,
componentDirective:DirectiveMetadata = null, viewportDirective:DirectiveMetadata = null):ElementBinder {
var elBinder = new ElementBinder(protoElementInjector, componentDirective, viewportDirective);
var elBinder = new ElementBinder(this.elementBinders.length, parent, distanceToParent,
protoElementInjector, componentDirective, viewportDirective);
ListWrapper.push(this.elementBinders, elBinder);
return elBinder;
}
@ -601,7 +620,7 @@ export class ProtoView {
var cmpType = rootComponentAnnotatedType.type;
var rootProtoView = new ProtoView(insertionElement, protoChangeDetector, shadowDomStrategy);
rootProtoView.instantiateInPlace = true;
var binder = rootProtoView.bindElement(
var binder = rootProtoView.bindElement(null, 0,
new ProtoElementInjector(null, 0, [cmpType], true));
binder.componentDirective = rootComponentAnnotatedType;
binder.nestedProtoView = protoView;

View File

@ -40,10 +40,10 @@ export class ViewContainer {
this._eventManager = eventManager;
}
hydrate(appInjector: Injector, hostElementInjector: eiModule.ElementInjector) {
hydrate(appInjector: Injector, hostElementInjector: eiModule.ElementInjector, hostLightDom: ldModule.LightDom) {
this.appInjector = appInjector;
this.hostElementInjector = hostElementInjector;
this.hostLightDom = isPresent(hostElementInjector) ? hostElementInjector.get(ldModule.LightDom) : null;
this.hostLightDom = hostLightDom;
}
dehydrate() {
@ -85,7 +85,7 @@ export class ViewContainer {
var newView = this.defaultProtoView.instantiate(this.hostElementInjector, this._eventManager);
// insertion must come before hydration so that element injector trees are attached.
this.insert(newView, atIndex);
newView.hydrate(this.appInjector, this.hostElementInjector, this.parentView.context);
newView.hydrate(this.appInjector, this.hostElementInjector, this.hostLightDom, this.parentView.context);
// new content tags might have appeared, we need to redistrubute.
if (isPresent(this.hostLightDom)) {

View File

@ -208,6 +208,10 @@ export class RegExpWrapper {
return input.match(regExp.single);
}
static matcher(regExp, input) {
// Reset regex state for the case
// someone did not loop over all matches
// last time.
regExp.multiple.lastIndex = 0;
return {
re: regExp.multiple,
input: input

View File

@ -115,7 +115,7 @@ export function runCompilerCommonTests() {
if (DOM.hasClass(current.element, 'nested')) {
current.componentDirective = reader.read(NestedComponent);
current.inheritedProtoView = parent.inheritedProtoView;
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null, 0, null);
} else {
current.inheritedProtoView = new ProtoView(current.element, null, null);
}
@ -148,7 +148,7 @@ export function runCompilerCommonTests() {
var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
if (DOM.hasClass(current.element, 'nested')) {
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null, 0, null);
current.componentDirective = reader.read(NestedComponent);
ListWrapper.push(nestedElBinders, current.inheritedElementBinder);
}
@ -164,7 +164,7 @@ export function runCompilerCommonTests() {
it('should allow recursive components', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null, 0, null);
current.componentDirective = reader.read(RecursiveComponent);
});
compiler.compile(RecursiveComponent).then( (protoView) => {
@ -193,7 +193,7 @@ export function runCompilerCommonTests() {
if (DOM.hasClass(current.element, 'parent')) {
current.componentDirective = reader.read(NestedComponent);
current.inheritedProtoView = parent.inheritedProtoView;
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null, 0, null);
} else {
current.inheritedProtoView = new ProtoView(current.element, null, null);
}

View File

@ -113,7 +113,7 @@ class DirectiveWithDestroy {
}
export function main() {
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null, null);
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null);
function humanize(tree, names:List) {
var lookupName = (item) =>
@ -283,7 +283,7 @@ export function main() {
it("should instantiate directives that depend on pre built objects", function () {
var view = new DummyView();
var inj = injector([NeedsView], null, null, new PreBuiltObjects(view, null, null, null, null));
var inj = injector([NeedsView], null, null, new PreBuiltObjects(view, null, null, null));
expect(inj.get(NeedsView).view).toBe(view);
});
@ -420,52 +420,31 @@ export function main() {
describe("pre built objects", function () {
it("should return view", function () {
var view = new DummyView();
var inj = injector([], null, null, new PreBuiltObjects(view, null, null, null, null));
var inj = injector([], null, null, new PreBuiltObjects(view, null, null, null));
expect(inj.get(View)).toEqual(view);
});
it("should return element", function () {
var element = new NgElement(null);
var inj = injector([], null, null, new PreBuiltObjects(null, element, null, 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 inj = injector([], null, null, new PreBuiltObjects(null, null, viewContainer, null, null));
var inj = injector([], null, null, new PreBuiltObjects(null, null, viewContainer, null));
expect(inj.get(ViewContainer)).toEqual(viewContainer);
});
it('should return bindingPropagationConfig', function () {
var config = new BindingPropagationConfig(null);
var inj = injector([], null, null, new PreBuiltObjects(null, null, null, null, config));
var inj = injector([], null, null, new PreBuiltObjects(null, null, null, config));
expect(inj.get(BindingPropagationConfig)).toEqual(config);
});
describe("light DOM", () => {
var lightDom, parentPreBuiltObjects;
beforeEach(() => {
lightDom = new DummyLightDom();
parentPreBuiltObjects = new PreBuiltObjects(null, null, null, lightDom, null);
});
it("should return light DOM from the current injector", function () {
var inj = injector([], null, null, parentPreBuiltObjects);
expect(inj.get(LightDom)).toEqual(lightDom);
});
it("should return null when parent's injector is a component boundary", function () {
var child = hostShadowInjectors([], [], parentPreBuiltObjects);
expect(child.get(DestinationLightDom)).toBeNull();
});
});
});
describe('event emitters', () => {
@ -476,7 +455,7 @@ export function main() {
var pv = new ProtoView(null, null, null);
pv.eventHandlers = [handlers];
var view = new View(pv, null, MapWrapper.create());
var preBuildObject = new PreBuiltObjects(view, null, null, null, null);
var preBuildObject = new PreBuiltObjects(view, null, null, null);
var inj = injector([NeedsEventEmitter], null, null, preBuildObject);
inj.get(NeedsEventEmitter).click();
expect(called).toEqual(true);
@ -494,7 +473,7 @@ export function main() {
var div = el('<div></div>');
var ngElement = new NgElement(div);
var preBuildObject = new PreBuiltObjects(null, ngElement, null, null, null);
var preBuildObject = new PreBuiltObjects(null, ngElement, null, null);
var inj = injector([NeedsPropertySetter], null, null, preBuildObject);
inj.get(NeedsPropertySetter).setProp('foobar');

View File

@ -68,7 +68,7 @@ export function main() {
function createView(pv) {
ctx = new MyComp();
view = pv.instantiate(null, null);
view.hydrate(new Injector([]), null, ctx);
view.hydrate(new Injector([]), null, null, ctx);
cd = view.changeDetector;
}
@ -479,7 +479,8 @@ export function main() {
createView(pv);
cd.detectChanges();
var subview = view.viewContainers[0].get(0);
// Note: viewContainers is a sparse array!
var subview = view.viewContainers[1].get(0);
var childComponent = subview.contextWithLocals.get('child');
expect(childComponent.myAncestor).toBeAnInstanceOf(SomeDirective);

View File

@ -83,7 +83,7 @@ export function main() {
function instantiateView(protoView) {
evalContext = new Context();
view = protoView.instantiate(null, null);
view.hydrate(new Injector([]), null, evalContext);
view.hydrate(new Injector([]), null, null, evalContext);
changeDetector = view.changeDetector;
}

View File

@ -21,7 +21,7 @@ export function main() {
if (isPresent(DOM.getAttribute(current.element, 'var-binding'))) {
current.variableBindings = MapWrapper.createFromStringMap(variableBindings);
}
current.inheritedElementBinder = new ElementBinder(null, null, null);
current.inheritedElementBinder = new ElementBinder(0, null, 0, null, null, null);
}), new ProtoViewBuilder(dynamicChangeDetection, new NativeShadowDomStrategy(null))]);
}

View File

@ -2,47 +2,46 @@ import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el, proxy}
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 {NgElement} from 'angular2/src/core/dom/element';
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 _script = `<script type="ng/content"></script>`;
var _scriptStart = `<script start=""></script>`;
var _scriptEnd = `<script end=""></script>`;
export function main() {
describe('Content', function() {
it("should insert the nodes", () => {
var parent = el("<div><content></content></div>");
var content = DOM.firstChild(parent);
var parent;
var content;
var c = new Content(null, new NgElement(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(`${_script}<a></a><b></b>${_script}`);
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}<a></a><b></b>${_scriptEnd}`);
});
it("should remove the nodes from the previous insertion", () => {
var parent = el("<div><content></content></div>");
var content = DOM.firstChild(parent);
var c = new Content(null, new NgElement(content));
var c = new Content(null, content, '');
c.insert([el("<a></a>")]);
c.insert([el("<b></b>")]);
expect(DOM.getInnerHTML(parent)).toEqual(`${_script}<b></b>${_script}`);
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}<b></b>${_scriptEnd}`);
});
it("should insert empty list", () => {
var parent = el("<div><content></content></div>");
var content = DOM.firstChild(parent);
var c = new Content(null, new NgElement(content));
var c = new Content(null, content, '');
c.insert([el("<a></a>")]);
c.insert([]);
expect(DOM.getInnerHTML(parent)).toEqual(`${_script}${_script}`);
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}${_scriptEnd}`);
});
});
}
}

View File

@ -1,56 +1,35 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el, proxy} from 'angular2/test_lib';
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
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';
import {ElementInjector} from 'angular2/src/core/compiler/element_injector';
@proxy
@IMPLEMENTS(ElementInjector)
class FakeElementInjector {
content;
viewContainer;
element;
constructor(content = null, viewContainer = null, element = null) {
this.content = content;
this.viewContainer = viewContainer;
this.element = element;
}
hasDirective(type) {
return this.content != null;
}
hasPreBuiltObject(type) {
return this.viewContainer != null;
}
forElement(n) {
return this.element == n;
}
get(t) {
if (t === Content) return this.content;
if (t === ViewContainer) return this.viewContainer;
return null;
}
noSuchMethod(i) {
super.noSuchMethod(i);
}
}
@proxy
@IMPLEMENTS(View)
class FakeView {
elementInjectors;
contentTags;
viewContainers;
constructor(elementInjectors = null) {
this.elementInjectors = elementInjectors;
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) {
@ -61,10 +40,12 @@ class FakeView {
@proxy
@IMPLEMENTS(ViewContainer)
class FakeViewContainer {
templateElement;
_nodes;
_contentTagContainers;
constructor(nodes = null, views = null) {
constructor(templateEl, nodes = null, views = null) {
this.templateElement = templateEl;
this._nodes = nodes;
this._contentTagContainers = views;
}
@ -88,8 +69,10 @@ class FakeViewContainer {
class FakeContentTag {
select;
_nodes;
contentStartElement;
constructor(select = null, nodes = null) {
constructor(contentEl, select = '', nodes = null) {
this.contentStartElement = contentEl;
this.select = select;
this._nodes = nodes;
}
@ -113,69 +96,66 @@ export function main() {
var lightDomView;
beforeEach(() => {
lightDomView = new FakeView([]);
lightDomView = new FakeView();
});
describe("contentTags", () => {
it("should collect content tags from element injectors", () => {
var tag = new FakeContentTag();
var shadowDomView = new FakeView([new FakeElementInjector(tag)]);
var tag = new FakeContentTag(el('<script></script>'));
var shadowDomView = new FakeView([tag]);
var lightDom = new LightDom(lightDomView, shadowDomView, el("<div></div>"));
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();
var vp = new FakeViewContainer(null, [
new FakeView([new FakeElementInjector(tag, null)])
var tag = new FakeContentTag(el('<script></script>'));
var vc = new FakeViewContainer(null, null, [
new FakeView([tag])
]);
var shadowDomView = new FakeView([new FakeElementInjector(null, vp)]);
var lightDom = new LightDom(lightDomView, shadowDomView, el("<div></div>"));
var shadowDomView = new FakeView([vc]);
var lightDom = new LightDom(lightDomView, shadowDomView,
el("<div></div>"));
expect(lightDom.contentTags()).toEqual([tag]);
});
});
describe("expanded roots", () => {
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 ViewContainer nodes", () => {
var lightDomEl = el("<div><template></template></div>")
var lightDomView = new FakeView([
new FakeElementInjector(
null,
new FakeViewContainer([el("<a></a>")]),
DOM.firstChild(lightDomEl))]);
it("should include view container nodes", () => {
var lightDomEl = el("<div><template></template></div>");
var lightDom = new LightDom(
lightDomView,
new FakeView(),
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 lightDomView = new FakeView([
new FakeElementInjector(
new FakeContentTag(null, [el("<a></a>")]),
null,
DOM.firstChild(lightDomEl))]);
var lightDomEl = el("<div><content></content></div>");
var lightDom = new LightDom(
lightDomView,
new FakeView(),
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>"]);
@ -184,7 +164,7 @@ export function main() {
it("should work when the element injector array contains nulls", () => {
var lightDomEl = el("<div><a></a></div>")
var lightDomView = new FakeView([null]);
var lightDomView = new FakeView();
var lightDom = new LightDom(
lightDomView,
@ -197,14 +177,14 @@ export function main() {
describe("redistribute", () => {
it("should redistribute nodes between content tags with select property set", () => {
var contentA = new FakeContentTag("a");
var contentB = new FakeContentTag("b");
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([
new FakeElementInjector(contentA, null),
new FakeElementInjector(contentB, null)
contentA,
contentB
]), lightDomEl);
lightDom.redistribute();
@ -214,14 +194,14 @@ export function main() {
});
it("should support wildcard content tags", () => {
var wildcard = new FakeContentTag(null);
var contentB = new FakeContentTag("b");
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([
new FakeElementInjector(wildcard, null),
new FakeElementInjector(contentB, null)
wildcard,
contentB
]), lightDomEl);
lightDom.redistribute();

View File

@ -92,6 +92,18 @@ export function main() {
});
}
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>' +
@ -367,6 +379,6 @@ class MyComp {
function createView(pv) {
var view = pv.instantiate(null, null);
view.hydrate(new Injector([]), null, {});
view.hydrate(new Injector([]), null, null, {});
return view;
}

View File

@ -56,10 +56,6 @@ export function main() {
expect(shadowRoot).toHaveText('view');
});
it('should should not transform template elements', () => {
expect(strategy.getTemplateCompileStep(null)).toBe(null);
});
it('should rewrite style urls', () => {
var step = strategy.getStyleCompileStep(null, 'http://base');
var styleElement = DOM.createStyleElement('.one {background-image: url("img.jpg");}');

View File

@ -12,7 +12,7 @@ import {DynamicProtoChangeDetector, ChangeDetector, Lexer, Parser} from 'angular
function createView(nodes) {
var view = new View(null, nodes, MapWrapper.create());
var cd = new DynamicProtoChangeDetector(null).instantiate(view, []);
view.init(cd, [], [], [], [], [], [], []);
view.init(cd, [], [], [], [], [], [], [], [], []);
return view;
}
@ -48,7 +48,7 @@ class HydrateAwareFakeView {
return this.isHydrated;
}
hydrate(_, __, ___) {
hydrate(_, __, ___, ____) {
this.isHydrated = true;
}
@ -97,7 +97,7 @@ export function main() {
}
beforeEach(() => {
viewContainer.hydrate(new Injector([]), null);
viewContainer.hydrate(new Injector([]), null, null);
var fillerView = createView([el('<filler>filler</filler>')]);
viewContainer.insert(fillerView);
});
@ -213,11 +213,11 @@ export function main() {
var fancyView;
beforeEach(() => {
var parser = new Parser(new Lexer());
viewContainer.hydrate(new Injector([]), null);
viewContainer.hydrate(new Injector([]), null, null);
var pv = new ProtoView(el('<div class="ng-binding">{{}}</div>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
pv.bindElement(null, 0, new ProtoElementInjector(null, 1, [SomeDirective]));
pv.bindTextNode(0, parser.parseBinding('foo', null));
fancyView = pv.instantiate(null, null);
});

View File

@ -46,7 +46,7 @@ export function main() {
function createView(protoView, eventManager: EventManager = null) {
var ctx = new MyEvaluationContext();
var view = protoView.instantiate(null, eventManager);
view.hydrate(null, null, ctx);
view.hydrate(null, null, null, ctx);
return view;
}
@ -69,7 +69,7 @@ export function main() {
it('should be able to be hydrated and dehydrated', () => {
var ctx = new Object();
view.hydrate(null, null, ctx);
view.hydrate(null, null, null, ctx);
expect(view.hydrated()).toBe(true);
view.dehydrate();
@ -78,7 +78,7 @@ export function main() {
it('should hydrate and dehydrate the change detector', () => {
var ctx = new Object();
view.hydrate(null, null, ctx);
view.hydrate(null, null, null, ctx);
expect(view.changeDetector.hydrated()).toBe(true);
view.dehydrate();
@ -114,7 +114,7 @@ export function main() {
it('when dehydrated should set locals to null', () => {
view.setLocal('context-foo', 'bar');
view.dehydrate();
view.hydrate(null, null, new Object());
view.hydrate(null, null, null, new Object());
expect(view.context.get('template-foo')).toBe(null);
});
@ -136,7 +136,7 @@ export function main() {
var pv = new ProtoView(templateAwareCreateElement('<div id="1"></div>'),
new DynamicProtoChangeDetector(null), null);
var view = pv.instantiate(null, null);
view.hydrate(null, null, null);
view.hydrate(null, null, null, null);
expect(view.nodes.length).toBe(1);
expect(DOM.getAttribute(view.nodes[0], 'id')).toEqual('1');
});
@ -146,11 +146,11 @@ export function main() {
it('should collect property bindings on the root element if it has the ng-binding class', () => {
var pv = new ProtoView(templateAwareCreateElement('<div [prop]="a" class="ng-binding"></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(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);
view.hydrate(null, null, null, null);
expect(view.bindElements.length).toEqual(1);
expect(view.bindElements[0]).toBe(view.nodes[0]);
});
@ -158,11 +158,11 @@ export function main() {
it('should collect property bindings on child elements with ng-binding class', () => {
var pv = new ProtoView(templateAwareCreateElement('<div><span></span><span class="ng-binding"></span></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(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);
view.hydrate(null, null, null, null);
expect(view.bindElements.length).toEqual(1);
expect(view.bindElements[0]).toBe(view.nodes[0].childNodes[1]);
});
@ -174,12 +174,12 @@ export function main() {
it('should collect text nodes under the root element', () => {
var pv = new ProtoView(templateAwareCreateElement('<div class="ng-binding">{{}}<span></span>{{}}</div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(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);
view.hydrate(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]);
@ -188,11 +188,11 @@ export function main() {
it('should collect text nodes with bindings on child elements with ng-binding class', () => {
var pv = new ProtoView(templateAwareCreateElement('<div><span> </span><span class="ng-binding">{{}}</span></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(null);
pv.bindElement(null, 0, null);
pv.bindTextNode(0, parser.parseBinding('b', null));
var view = pv.instantiate(null, null);
view.hydrate(null, null, null);
view.hydrate(null, null, null, null);
expect(view.textNodes.length).toEqual(1);
expect(view.textNodes[0]).toBe(view.nodes[0].childNodes[1].childNodes[0]);
});
@ -207,7 +207,7 @@ export function main() {
new NativeShadowDomStrategy(null));
pv.instantiateInPlace = true;
var view = pv.instantiate(null, null);
view.hydrate(null, null, null);
view.hydrate(null, null, null, null);
expect(view.nodes[0]).toBe(template);
});
@ -216,7 +216,7 @@ export function main() {
var pv = new ProtoView(template, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null))
var view = pv.instantiate(null, null);
view.hydrate(null, null, null);
view.hydrate(null, null, null, null);
expect(view.nodes[0]).not.toBe(template);
});
});
@ -233,10 +233,10 @@ export function main() {
it('should use the directives of the ProtoElementInjector', () => {
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
pv.bindElement(null, 0, new ProtoElementInjector(null, 1, [SomeDirective]));
var view = pv.instantiate(null, null);
view.hydrate(null, null, null);
view.hydrate(null, null, null, null);
expect(view.elementInjectors.length).toBe(1);
expect(view.elementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
});
@ -245,11 +245,11 @@ export function main() {
var pv = new ProtoView(el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
new DynamicProtoChangeDetector(null), null);
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
pv.bindElement(protoParent);
pv.bindElement(new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
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);
view.hydrate(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]);
@ -259,9 +259,9 @@ export function main() {
var pv = new ProtoView(el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
new DynamicProtoChangeDetector(null), null);
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
pv.bindElement(protoParent);
pv.bindElement(null, 0, protoParent);
var testProtoElementInjector = new TestProtoElementInjector(protoParent, 1, [AnotherDirective]);
pv.bindElement(testProtoElementInjector);
pv.bindElement(null, 0, testProtoElementInjector);
var hostProtoInjector = new ProtoElementInjector(null, 0, []);
var hostInjector = hostProtoInjector.instantiate(null, null);
@ -274,9 +274,9 @@ export function main() {
it('should pass the host injector when there is no parent injector', () => {
var pv = new ProtoView(el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new ProtoElementInjector(null, 0, [SomeDirective]));
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeDirective]));
var testProtoElementInjector = new TestProtoElementInjector(null, 1, [AnotherDirective]);
pv.bindElement(testProtoElementInjector);
pv.bindElement(null, 0, testProtoElementInjector);
var hostProtoInjector = new ProtoElementInjector(null, 0, []);
var hostInjector = hostProtoInjector.instantiate(null, null);
@ -292,11 +292,11 @@ export function main() {
var pv = new ProtoView(el('<div class="ng-binding"><span class="ng-binding"></span></div>'),
new DynamicProtoChangeDetector(null), null);
var protoParent = new ProtoElementInjector(null, 0, [SomeDirective]);
pv.bindElement(protoParent);
pv.bindElement(new ProtoElementInjector(protoParent, 1, [AnotherDirective]));
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);
view.hydrate(null, null, null, null);
expect(view.rootElementInjectors.length).toBe(1);
expect(view.rootElementInjectors[0].get(SomeDirective) instanceof SomeDirective).toBe(true);
});
@ -304,11 +304,11 @@ export function main() {
it('should collect multiple root element injectors', () => {
var pv = new ProtoView(el('<div><span class="ng-binding"></span><span class="ng-binding"></span></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
pv.bindElement(new ProtoElementInjector(null, 2, [AnotherDirective]));
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);
view.hydrate(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);
@ -322,7 +322,7 @@ export function main() {
function createComponentWithSubPV(subProtoView) {
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeComponent], true));
binder.componentDirective = someComponentDirective;
binder.nestedProtoView = subProtoView;
return pv;
@ -331,7 +331,7 @@ export function main() {
function createNestedView(protoView) {
ctx = new MyEvaluationContext();
var view = protoView.instantiate(null, null);
view.hydrate(new Injector([]), null, ctx);
view.hydrate(new Injector([]), null, null, ctx);
return view;
}
@ -351,7 +351,7 @@ export function main() {
el('<div dec class="ng-binding">hello shadow dom</div>'),
new DynamicProtoChangeDetector(null),
null);
subpv.bindElement(
subpv.bindElement(null, 0,
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
var pv = createComponentWithSubPV(subpv);
@ -376,7 +376,7 @@ export function main() {
el('<div dec class="ng-binding">hello shadow dom</div>'),
new DynamicProtoChangeDetector(null),
null);
subpv.bindElement(
subpv.bindElement(null, 0,
new ProtoElementInjector(null, 0, [ServiceDependentDecorator]));
var pv = createComponentWithSubPV(subpv);
@ -406,7 +406,7 @@ export function main() {
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'),
new DynamicProtoChangeDetector(null), new EmulatedScopedShadowDomStrategy(null, null, null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeComponent], true));
binder.componentDirective = new DirectiveMetadataReader().read(SomeComponent);
binder.nestedProtoView = subpv;
@ -422,7 +422,7 @@ export function main() {
el('<div id="1"></div>'), new DynamicProtoChangeDetector(null), null);
var pv = new ProtoView(el('<someTmpl class="ng-binding"></someTmpl>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeViewport]));
var binder = pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeViewport]));
binder.viewportDirective = someViewportDirective;
binder.nestedProtoView = templateProtoView;
@ -468,7 +468,7 @@ export function main() {
function createProtoView() {
var pv = new ProtoView(el('<div class="ng-binding"><div></div></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new TestProtoElementInjector(null, 0, []));
pv.bindElement(null, 0, new TestProtoElementInjector(null, 0, []));
pv.bindEvent('click', parser.parseBinding('callMe($event)', null));
return pv;
}
@ -503,7 +503,7 @@ export function main() {
it('should support custom event emitters', () => {
var pv = new ProtoView(el('<div class="ng-binding"><div></div></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new TestProtoElementInjector(null, 0, [EventEmitterDirective]));
pv.bindElement(null, 0, new TestProtoElementInjector(null, 0, [EventEmitterDirective]));
pv.bindEvent('click', parser.parseBinding('callMe($event)', null));
createViewAndContext(pv);
@ -524,7 +524,7 @@ export function main() {
it('should bind to directive events', () => {
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new ProtoElementInjector(null, 0, [SomeDirectiveWithEventHandler]));
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()));
@ -549,7 +549,7 @@ export function main() {
it('should consume text node changes', () => {
var pv = new ProtoView(el('<div class="ng-binding">{{}}</div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(null);
pv.bindElement(null, 0, null);
pv.bindTextNode(0, parser.parseBinding('foo', null));
createViewAndChangeDetector(pv);
@ -561,7 +561,7 @@ export function main() {
it('should consume element binding changes', () => {
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(null);
pv.bindElement(null, 0, null);
pv.bindElementProperty(parser.parseBinding('foo', null), 'id', reflector.setter('id'));
createViewAndChangeDetector(pv);
@ -573,7 +573,7 @@ export function main() {
it('should consume directive watch expression change', () => {
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new ProtoElementInjector(null, 0, [SomeDirective]));
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [SomeDirective]));
pv.bindDirectiveProperty(0, parser.parseBinding('foo', null), 'prop', reflector.setter('prop'));
createViewAndChangeDetector(pv);
@ -586,7 +586,7 @@ export function main() {
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new ProtoElementInjector(null, 0, [
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [
DirectiveBinding.createFromType(DirectiveImplementingOnChange, new Directive({lifecycle: [onChange]}))
]));
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'));
@ -605,7 +605,7 @@ export function main() {
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
new DynamicProtoChangeDetector(null), null);
pv.bindElement(new ProtoElementInjector(null, 0, [
pv.bindElement(null, 0, new ProtoElementInjector(null, 0, [
DirectiveBinding.createFromType(DirectiveImplementingOnChange, new Directive({lifecycle: [onChange]}))
]));
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'));
@ -643,7 +643,7 @@ export function main() {
someComponentDirective, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
var view = rootProtoView.instantiate(null, null);
view.hydrate(new Injector([]), null, null);
view.hydrate(new Injector([]), null, null, null);
expect(view.rootElementInjectors[0].get(SomeComponent)).not.toBe(null);
});
@ -652,7 +652,7 @@ export function main() {
someComponentDirective, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
var view = rootProtoView.instantiate(null, null);
view.hydrate(new Injector([]), null, null);
view.hydrate(new Injector([]), null, null, null);
expect(element.shadowRoot.childNodes[0].childNodes[0].nodeValue).toEqual('hi');
});
});

View File

@ -45,7 +45,7 @@ export function main() {
function createView(pv) {
component = new TestComponent();
view = pv.instantiate(null, null);
view.hydrate(new Injector([]), null, component);
view.hydrate(new Injector([]), null, null, component);
cd = view.changeDetector;
}

View File

@ -57,7 +57,7 @@ export function main() {
function createView(pv) {
component = new TestComponent();
view = pv.instantiate(null, null);
view.hydrate(new Injector([]), null, component);
view.hydrate(new Injector([]), null, null, component);
cd = view.changeDetector;
}

View File

@ -54,7 +54,7 @@ export function main() {
function createView(pv) {
component = new TestComponent();
view = pv.instantiate(null, null);
view.hydrate(new Injector([]), null, component);
view.hydrate(new Injector([]), null, null, component);
cd = view.changeDetector;
}

View File

@ -51,7 +51,7 @@ export function main() {
function createView(pv) {
component = new TestComponent();
view = pv.instantiate(null, null);
view.hydrate(new Injector([]), null, component);
view.hydrate(new Injector([]), null, null, component);
cd = view.changeDetector;
}

View File

@ -63,7 +63,7 @@ export function main() {
compiler.compile(componentType).then((pv) => {
var view = pv.instantiate(null, null);
view.hydrate(new Injector([]), null, context);
view.hydrate(new Injector([]), null, null, context);
detectChanges(view);
callback(view);
});