feat(compiler): integrate compiler with view engine - main integration tests work (#14284)
Part of #14013 PR Close #14284
This commit is contained in:

committed by
Miško Hevery

parent
dfe29934b6
commit
baa654a234
@ -9,18 +9,19 @@
|
||||
import {isDevMode} from '../application_ref';
|
||||
import {SecurityContext} from '../security';
|
||||
|
||||
import {BindingDef, BindingType, DebugContext, DisposableFn, ElementData, ElementOutputDef, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, Services, ViewData, ViewDefinition, ViewFlags, asElementData} from './types';
|
||||
import {checkAndUpdateBinding, dispatchEvent, sliceErrorStack, unwrapValue} from './util';
|
||||
import {BindingDef, BindingType, DebugContext, DisposableFn, ElementData, ElementOutputDef, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, asElementData} from './types';
|
||||
import {checkAndUpdateBinding, dispatchEvent, elementEventFullName, resolveViewDefinition, sliceErrorStack, unwrapValue} from './util';
|
||||
|
||||
export function anchorDef(
|
||||
flags: NodeFlags, matchedQueries: [string, QueryValueType][], ngContentIndex: number,
|
||||
childCount: number, template?: ViewDefinition): NodeDef {
|
||||
childCount: number, templateFactory?: ViewDefinitionFactory): NodeDef {
|
||||
const matchedQueryDefs: {[queryId: string]: QueryValueType} = {};
|
||||
if (matchedQueries) {
|
||||
matchedQueries.forEach(([queryId, valueType]) => { matchedQueryDefs[queryId] = valueType; });
|
||||
}
|
||||
// skip the call to sliceErrorStack itself + the call to this function.
|
||||
const source = isDevMode() ? sliceErrorStack(2, 3) : '';
|
||||
const template = templateFactory ? resolveViewDefinition(templateFactory) : null;
|
||||
return {
|
||||
type: NodeType.Element,
|
||||
// will bet set by the view definition
|
||||
@ -130,10 +131,10 @@ export function elementDef(
|
||||
|
||||
export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData {
|
||||
const elDef = def.element;
|
||||
const rootElement = view.root.element;
|
||||
const rootSelectorOrNode = view.root.selectorOrNode;
|
||||
const renderer = view.root.renderer;
|
||||
let el: any;
|
||||
if (view.parent || !rootElement) {
|
||||
if (view.parent || !rootSelectorOrNode) {
|
||||
const parentNode =
|
||||
def.parent != null ? asElementData(view, def.parent).renderElement : renderHost;
|
||||
el = elDef.name ? renderer.createElement(elDef.name) : renderer.createComment('');
|
||||
@ -141,7 +142,7 @@ export function createElement(view: ViewData, renderHost: any, def: NodeDef): El
|
||||
renderer.appendChild(parentNode, el);
|
||||
}
|
||||
} else {
|
||||
el = rootElement;
|
||||
el = renderer.selectRootElement(rootSelectorOrNode);
|
||||
}
|
||||
if (elDef.attrs) {
|
||||
for (let attrName in elDef.attrs) {
|
||||
@ -151,7 +152,8 @@ export function createElement(view: ViewData, renderHost: any, def: NodeDef): El
|
||||
if (elDef.outputs.length) {
|
||||
for (let i = 0; i < elDef.outputs.length; i++) {
|
||||
const output = elDef.outputs[i];
|
||||
const handleEventClosure = renderEventHandlerClosure(view, def.index, output.eventName);
|
||||
const handleEventClosure = renderEventHandlerClosure(
|
||||
view, def.index, elementEventFullName(output.target, output.eventName));
|
||||
const disposable =
|
||||
<any>renderer.listen(output.target || el, output.eventName, handleEventClosure);
|
||||
view.disposables[def.disposableIndex + i] = disposable;
|
||||
|
@ -14,7 +14,7 @@ export {queryDef} from './query';
|
||||
export {createComponentFactory} from './refs';
|
||||
export {initServicesIfNeeded} from './services';
|
||||
export {textDef} from './text';
|
||||
export {rootRenderNodes} from './util';
|
||||
export {elementEventFullName, nodeValue, rootRenderNodes} from './util';
|
||||
export {viewDef} from './view';
|
||||
export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
||||
|
||||
|
@ -16,7 +16,7 @@ import {Type} from '../type';
|
||||
|
||||
import {createChangeDetectorRef, createInjector, createTemplateRef, createViewContainerRef} from './refs';
|
||||
import {BindingDef, BindingType, DepDef, DepFlags, DisposableFn, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderOutputDef, ProviderType, QueryBindingType, QueryDef, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types';
|
||||
import {checkAndUpdateBinding, dispatchEvent, findElementDef, isComponentView, parentDiIndex, tokenKey, unwrapValue} from './util';
|
||||
import {checkAndUpdateBinding, dispatchEvent, isComponentView, tokenKey, unwrapValue, viewParentDiIndex} from './util';
|
||||
|
||||
const RendererV1TokenKey = tokenKey(v1renderer.Renderer);
|
||||
const ElementRefTokenKey = tokenKey(ElementRef);
|
||||
@ -278,6 +278,9 @@ function callFactory(
|
||||
export function resolveDep(
|
||||
view: ViewData, requestNodeIndex: number, elIndex: number, depDef: DepDef,
|
||||
notFoundValue = Injector.THROW_IF_NOT_FOUND): any {
|
||||
if (depDef.flags & DepFlags.Value) {
|
||||
return depDef.token;
|
||||
}
|
||||
const startView = view;
|
||||
if (depDef.flags & DepFlags.Optional) {
|
||||
notFoundValue = null;
|
||||
@ -288,7 +291,7 @@ export function resolveDep(
|
||||
requestNodeIndex = null;
|
||||
elIndex = view.def.nodes[elIndex].parent;
|
||||
while (elIndex == null && view) {
|
||||
elIndex = parentDiIndex(view);
|
||||
elIndex = viewParentDiIndex(view);
|
||||
view = view.parent;
|
||||
}
|
||||
}
|
||||
@ -337,7 +340,7 @@ export function resolveDep(
|
||||
}
|
||||
}
|
||||
requestNodeIndex = null;
|
||||
elIndex = parentDiIndex(view);
|
||||
elIndex = viewParentDiIndex(view);
|
||||
view = view.parent;
|
||||
}
|
||||
return startView.root.injector.get(depDef.token, notFoundValue);
|
||||
|
@ -20,7 +20,7 @@ import {Type} from '../type';
|
||||
|
||||
import {DirectDomRenderer, LegacyRendererAdapter} from './renderer';
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeType, RendererV2, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData} from './types';
|
||||
import {findElementDef, isComponentView, parentDiIndex, renderNode, resolveViewDefinition, rootRenderNodes, tokenKey} from './util';
|
||||
import {isComponentView, renderNode, resolveViewDefinition, rootRenderNodes, tokenKey, viewParentDiIndex} from './util';
|
||||
|
||||
const EMPTY_CONTEXT = new Object();
|
||||
|
||||
@ -99,7 +99,7 @@ class ViewContainerRef_ implements ViewContainerRef {
|
||||
let view = this._view;
|
||||
let elIndex = view.def.nodes[this._elIndex].parent;
|
||||
while (elIndex == null && view) {
|
||||
elIndex = parentDiIndex(view);
|
||||
elIndex = viewParentDiIndex(view);
|
||||
view = view.parent;
|
||||
}
|
||||
return view ? new Injector_(view, elIndex) : this._view.root.injector;
|
||||
@ -119,7 +119,7 @@ class ViewContainerRef_ implements ViewContainerRef {
|
||||
|
||||
createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number):
|
||||
EmbeddedViewRef<C> {
|
||||
const viewRef = templateRef.createEmbeddedView(context);
|
||||
const viewRef = templateRef.createEmbeddedView(context || <any>{});
|
||||
this.insert(viewRef, index);
|
||||
return viewRef;
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ export class DirectDomRenderer implements RendererV2 {
|
||||
nextSibling(node: any): any { return node.nextSiblibng; }
|
||||
setAttribute(el: any, name: string, value: string): void { return el.setAttribute(name, value); }
|
||||
removeAttribute(el: any, name: string): void { el.removeAttribute(name); }
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {}
|
||||
removeBindingDebugInfo(el: any, propertyName: string): void {}
|
||||
addClass(el: any, name: string): void { el.classList.add(name); }
|
||||
removeClass(el: any, name: string): void { el.classList.remove(name); }
|
||||
setStyle(el: any, style: string, value: any): void { el.style[style] = value; }
|
||||
@ -97,8 +99,11 @@ export class LegacyRendererAdapter implements RendererV2 {
|
||||
}
|
||||
appendChild(parent: any, newChild: any): void { this._delegate.projectNodes(parent, [newChild]); }
|
||||
insertBefore(parent: any, newChild: any, refChild: any): void {
|
||||
const beforeSibling = refChild.nextSiblingOf ? refChild.nextSiblingOf : refChild;
|
||||
this._delegate.attachViewAfter(beforeSibling, [newChild]);
|
||||
if (refChild) {
|
||||
this._delegate.attachViewAfter(refChild.previousSibling, [newChild]);
|
||||
} else {
|
||||
this.appendChild(parent, newChild);
|
||||
}
|
||||
}
|
||||
removeChild(parent: any, oldChild: any): void {
|
||||
if (parent) {
|
||||
@ -108,14 +113,20 @@ export class LegacyRendererAdapter implements RendererV2 {
|
||||
selectRootElement(selectorOrNode: any, debugInfo?: DebugContext): any {
|
||||
return this._delegate.selectRootElement(selectorOrNode, debugInfo);
|
||||
}
|
||||
parentNode(node: any): any { return {parentOf: node}; }
|
||||
nextSibling(node: any): any { return {nextSiblingOf: node}; }
|
||||
parentNode(node: any): any { return node.parentNode; }
|
||||
nextSibling(node: any): any { return node.nextSibling; }
|
||||
setAttribute(el: any, name: string, value: string): void {
|
||||
this._delegate.setElementAttribute(el, name, value);
|
||||
}
|
||||
removeAttribute(el: any, name: string): void {
|
||||
this._delegate.setElementAttribute(el, name, null);
|
||||
}
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
|
||||
this._delegate.setBindingDebugInfo(el, propertyName, propertyValue);
|
||||
}
|
||||
removeBindingDebugInfo(el: any, propertyName: string): void {
|
||||
this._delegate.setBindingDebugInfo(el, propertyName, null);
|
||||
}
|
||||
addClass(el: any, name: string): void { this._delegate.setElementClass(el, name, true); }
|
||||
removeClass(el: any, name: string): void { this._delegate.setElementClass(el, name, false); }
|
||||
setStyle(el: any, style: string, value: any): void {
|
||||
|
@ -19,8 +19,8 @@ import {resolveDep} from './provider';
|
||||
import {getQueryValue} from './query';
|
||||
import {createInjector} from './refs';
|
||||
import {DirectDomRenderer, LegacyRendererAdapter} from './renderer';
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeType, RendererV2, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData} from './types';
|
||||
import {checkBinding, findElementDef, isComponentView, parentDiIndex, renderNode, resolveViewDefinition, rootRenderNodes} from './util';
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RendererV2, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData} from './types';
|
||||
import {checkBinding, isComponentView, queryIdIsReference, renderNode, resolveViewDefinition, rootRenderNodes, viewParentDiIndex} from './util';
|
||||
import {checkAndUpdateView, checkNoChangesView, createEmbeddedView, createRootView, destroyView} from './view';
|
||||
import {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
||||
|
||||
@ -98,7 +98,7 @@ function debugCreateRootView(
|
||||
const debugRoot: RootData = {
|
||||
injector: root.injector,
|
||||
projectableNodes: root.projectableNodes,
|
||||
element: root.element,
|
||||
selectorOrNode: root.selectorOrNode,
|
||||
renderer: new DebugRenderer(root.renderer),
|
||||
sanitizer: root.sanitizer
|
||||
};
|
||||
@ -114,7 +114,7 @@ function createRootData(
|
||||
new DirectDomRenderer();
|
||||
const rootElement =
|
||||
rootSelectorOrNode ? renderer.selectRootElement(rootSelectorOrNode) : undefined;
|
||||
return {injector, projectableNodes, element: rootElement, sanitizer, renderer};
|
||||
return {injector, projectableNodes, selectorOrNode: rootSelectorOrNode, sanitizer, renderer};
|
||||
}
|
||||
|
||||
function debugCreateEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData {
|
||||
@ -184,13 +184,16 @@ function debugUpdateView(check: NodeCheckFn, view: ViewData) {
|
||||
}
|
||||
|
||||
function setBindingDebugInfo(renderer: RendererV2, renderNode: any, propName: string, value: any) {
|
||||
try {
|
||||
renderer.setAttribute(
|
||||
renderNode, `ng-reflect-${camelCaseToDashCase(propName)}`, value ? value.toString() : null);
|
||||
} catch (e) {
|
||||
renderer.setAttribute(
|
||||
renderNode, `ng-reflect-${camelCaseToDashCase(propName)}`,
|
||||
'[ERROR] Exception while trying to serialize the value');
|
||||
const renderName = `ng-reflect-${camelCaseToDashCase(propName)}`;
|
||||
if (value) {
|
||||
try {
|
||||
renderer.setBindingDebugInfo(renderNode, renderName, value.toString());
|
||||
} catch (e) {
|
||||
renderer.setBindingDebugInfo(
|
||||
renderNode, renderName, '[ERROR] Exception while trying to serialize the value');
|
||||
}
|
||||
} else {
|
||||
renderer.removeBindingDebugInfo(renderNode, renderName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,6 +243,12 @@ class DebugRenderer implements RendererV2 {
|
||||
return this._delegate.setAttribute(el, name, value);
|
||||
}
|
||||
removeAttribute(el: any, name: string): void { return this._delegate.removeAttribute(el, name); }
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void {
|
||||
this._delegate.setBindingDebugInfo(el, propertyName, propertyValue);
|
||||
}
|
||||
removeBindingDebugInfo(el: any, propertyName: string): void {
|
||||
this._delegate.removeBindingDebugInfo(el, propertyName);
|
||||
}
|
||||
addClass(el: any, name: string): void { return this._delegate.addClass(el, name); }
|
||||
removeClass(el: any, name: string): void { return this._delegate.removeClass(el, name); }
|
||||
setStyle(el: any, style: string, value: any): void {
|
||||
@ -258,27 +267,63 @@ class DebugRenderer implements RendererV2 {
|
||||
|
||||
class DebugContext_ implements DebugContext {
|
||||
private nodeDef: NodeDef;
|
||||
private elView: ViewData;
|
||||
private elDef: NodeDef;
|
||||
private compProviderIndex: number;
|
||||
constructor(public view: ViewData, public nodeIndex: number) {
|
||||
if (nodeIndex == null) {
|
||||
this.nodeIndex = nodeIndex = view.parentIndex;
|
||||
this.view = view = view.parent;
|
||||
this.nodeIndex = 0;
|
||||
}
|
||||
this.nodeDef = view.def.nodes[nodeIndex];
|
||||
this.elDef = findElementDef(view, nodeIndex);
|
||||
let elIndex = nodeIndex;
|
||||
let elView = view;
|
||||
while (elIndex != null && view.def.nodes[elIndex].type !== NodeType.Element) {
|
||||
elIndex = view.def.nodes[elIndex].parent;
|
||||
}
|
||||
if (elIndex == null) {
|
||||
while (elIndex == null && elView) {
|
||||
elIndex = viewParentDiIndex(elView);
|
||||
elView = elView.parent;
|
||||
}
|
||||
}
|
||||
this.elView = elView;
|
||||
if (elView) {
|
||||
this.elDef = elView.def.nodes[elIndex];
|
||||
|
||||
for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) {
|
||||
const childDef = this.elView.def.nodes[i];
|
||||
if (childDef.flags & NodeFlags.HasComponent) {
|
||||
this.compProviderIndex = i;
|
||||
break;
|
||||
}
|
||||
i += childDef.childCount;
|
||||
}
|
||||
} else {
|
||||
this.elDef = null;
|
||||
}
|
||||
}
|
||||
get injector(): Injector { return createInjector(this.elView, this.elDef.index); }
|
||||
get component(): any {
|
||||
if (this.compProviderIndex != null) {
|
||||
return asProviderData(this.elView, this.compProviderIndex).instance;
|
||||
}
|
||||
return this.view.component;
|
||||
}
|
||||
get context(): any {
|
||||
if (this.compProviderIndex != null) {
|
||||
return asProviderData(this.elView, this.compProviderIndex).instance;
|
||||
}
|
||||
return this.view.context;
|
||||
}
|
||||
get injector(): Injector { return createInjector(this.view, this.elDef.index); }
|
||||
get component(): any { return this.view.component; }
|
||||
get providerTokens(): any[] {
|
||||
const tokens: any[] = [];
|
||||
if (this.elDef) {
|
||||
for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) {
|
||||
const childDef = this.view.def.nodes[i];
|
||||
const childDef = this.elView.def.nodes[i];
|
||||
if (childDef.type === NodeType.Provider) {
|
||||
tokens.push(childDef.provider.token);
|
||||
} else {
|
||||
i += childDef.childCount;
|
||||
}
|
||||
i += childDef.childCount;
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
@ -286,20 +331,18 @@ class DebugContext_ implements DebugContext {
|
||||
get references(): {[key: string]: any} {
|
||||
const references: {[key: string]: any} = {};
|
||||
if (this.elDef) {
|
||||
collectReferences(this.view, this.elDef, references);
|
||||
collectReferences(this.elView, this.elDef, references);
|
||||
|
||||
for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) {
|
||||
const childDef = this.view.def.nodes[i];
|
||||
const childDef = this.elView.def.nodes[i];
|
||||
if (childDef.type === NodeType.Provider) {
|
||||
collectReferences(this.view, childDef, references);
|
||||
} else {
|
||||
i += childDef.childCount;
|
||||
collectReferences(this.elView, childDef, references);
|
||||
}
|
||||
i += childDef.childCount;
|
||||
}
|
||||
}
|
||||
return references;
|
||||
}
|
||||
get context(): any { return this.view.context; }
|
||||
get source(): string {
|
||||
if (this.nodeDef.type === NodeType.Text) {
|
||||
return this.nodeDef.text.source;
|
||||
@ -308,12 +351,15 @@ class DebugContext_ implements DebugContext {
|
||||
}
|
||||
}
|
||||
get componentRenderElement() {
|
||||
const elData = findHostElement(this.view);
|
||||
const view = this.compProviderIndex != null ?
|
||||
asProviderData(this.elView, this.compProviderIndex).componentView :
|
||||
this.view;
|
||||
const elData = findHostElement(view);
|
||||
return elData ? elData.renderElement : undefined;
|
||||
}
|
||||
get renderNode(): any {
|
||||
let nodeDef = this.nodeDef.type === NodeType.Text ? this.nodeDef : this.elDef;
|
||||
return renderNode(this.view, nodeDef);
|
||||
return this.nodeDef.type === NodeType.Text ? renderNode(this.view, this.nodeDef) :
|
||||
renderNode(this.elView, this.elDef);
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,7 +376,7 @@ function findHostElement(view: ViewData): ElementData {
|
||||
|
||||
function collectReferences(view: ViewData, nodeDef: NodeDef, references: {[key: string]: any}) {
|
||||
for (let queryId in nodeDef.matchedQueries) {
|
||||
if (queryId.startsWith('#')) {
|
||||
if (queryIdIsReference(queryId)) {
|
||||
references[queryId.slice(1)] = getQueryValue(view, nodeDef, queryId);
|
||||
}
|
||||
}
|
||||
|
@ -72,8 +72,7 @@ export enum ArgumentType {
|
||||
*/
|
||||
export enum ViewFlags {
|
||||
None = 0,
|
||||
DirectDom = 1 << 1,
|
||||
OnPush = 1 << 2
|
||||
OnPush = 1 << 1
|
||||
}
|
||||
|
||||
export interface ComponentDefinition {
|
||||
@ -225,7 +224,8 @@ export interface DepDef {
|
||||
export enum DepFlags {
|
||||
None = 0,
|
||||
SkipSelf = 1 << 0,
|
||||
Optional = 1 << 1
|
||||
Optional = 1 << 1,
|
||||
Value = 2 << 2
|
||||
}
|
||||
|
||||
export interface ProviderOutputDef {
|
||||
@ -407,7 +407,7 @@ export function asQueryList(view: ViewData, index: number): QueryList<any> {
|
||||
export interface RootData {
|
||||
injector: Injector;
|
||||
projectableNodes: any[][];
|
||||
element: any;
|
||||
selectorOrNode: any;
|
||||
renderer: RendererV2;
|
||||
sanitizer: Sanitizer;
|
||||
}
|
||||
@ -436,6 +436,14 @@ export interface RendererV2 {
|
||||
* the caller can't rely on checking whether this is null or not.
|
||||
*/
|
||||
nextSibling(node: any): any;
|
||||
/**
|
||||
* Used only in debug mode to serialize property changes to dom nodes as attributes.
|
||||
*/
|
||||
setBindingDebugInfo(el: any, propertyName: string, propertyValue: string): void;
|
||||
/**
|
||||
* Used only in debug mode to serialize property changes to dom nodes as attributes.
|
||||
*/
|
||||
removeBindingDebugInfo(el: any, propertyName: string): void;
|
||||
setAttribute(el: any, name: string, value: string): void;
|
||||
removeAttribute(el: any, name: string): void;
|
||||
addClass(el: any, name: string): void;
|
||||
|
@ -95,27 +95,14 @@ export function declaredViewContainer(view: ViewData): ElementData {
|
||||
* for embedded views, this is the index of the parent node
|
||||
* that contains the view container.
|
||||
*/
|
||||
export function parentDiIndex(view: ViewData): number {
|
||||
if (view.parent) {
|
||||
const parentNodeDef = view.def.nodes[view.parentIndex];
|
||||
return parentNodeDef.element && parentNodeDef.element.template ? parentNodeDef.parent :
|
||||
parentNodeDef.index;
|
||||
export function viewParentDiIndex(view: ViewData): number {
|
||||
if (view.parent && view.context !== view.component) {
|
||||
const parentNodeDef = view.parent.def.nodes[view.parentIndex];
|
||||
return parentNodeDef.parent;
|
||||
}
|
||||
return view.parentIndex;
|
||||
}
|
||||
|
||||
export function findElementDef(view: ViewData, nodeIndex: number): NodeDef {
|
||||
const viewDef = view.def;
|
||||
let nodeDef = viewDef.nodes[nodeIndex];
|
||||
while (nodeDef) {
|
||||
if (nodeDef.type === NodeType.Element) {
|
||||
return nodeDef;
|
||||
}
|
||||
nodeDef = nodeDef.parent != null ? viewDef.nodes[nodeDef.parent] : undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function renderNode(view: ViewData, def: NodeDef): any {
|
||||
switch (def.type) {
|
||||
case NodeType.Element:
|
||||
@ -125,6 +112,27 @@ export function renderNode(view: ViewData, def: NodeDef): any {
|
||||
}
|
||||
}
|
||||
|
||||
export function nodeValue(view: ViewData, index: number): any {
|
||||
const def = view.def.nodes[index];
|
||||
switch (def.type) {
|
||||
case NodeType.Element:
|
||||
return asElementData(view, def.index).renderElement;
|
||||
case NodeType.Text:
|
||||
return asTextData(view, def.index).renderText;
|
||||
case NodeType.Provider:
|
||||
return asProviderData(view, def.index).instance;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function queryIdIsReference(queryId: string): boolean {
|
||||
return queryId.startsWith('#');
|
||||
}
|
||||
|
||||
export function elementEventFullName(target: string, name: string): string {
|
||||
return target ? `${target}:${name}` : name;
|
||||
}
|
||||
|
||||
export function isComponentView(view: ViewData): boolean {
|
||||
return view.component === view.context && !!view.parent;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import {ViewEncapsulation} from '../metadata/view';
|
||||
|
||||
import {checkAndUpdateElementDynamic, checkAndUpdateElementInline, createElement} from './element';
|
||||
import {expressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||
import {appendNgContent} from './ng_content';
|
||||
@ -15,7 +16,7 @@ import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline,
|
||||
import {checkAndUpdateQuery, createQuery, queryDef} from './query';
|
||||
import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text';
|
||||
import {ArgumentType, ComponentDefinition, ElementDef, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderDef, RootData, Services, TextDef, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asProviderData, asPureExpressionData, asQueryList} from './types';
|
||||
import {checkBindingNoChanges, isComponentView, resolveViewDefinition} from './util';
|
||||
import {checkBindingNoChanges, isComponentView, queryIdIsReference, resolveViewDefinition} from './util';
|
||||
|
||||
const NOOP = (): any => undefined;
|
||||
|
||||
@ -41,7 +42,7 @@ export function viewDef(
|
||||
const newParent = nodes[currentParent.parent];
|
||||
if (newParent) {
|
||||
newParent.childFlags |= currentParent.childFlags;
|
||||
copyInto(currentParent.childMatchedQueries, newParent.childMatchedQueries);
|
||||
copyQueryMatchesInto(currentParent.childMatchedQueries, newParent.childMatchedQueries);
|
||||
}
|
||||
currentParent = newParent;
|
||||
}
|
||||
@ -64,17 +65,18 @@ export function viewDef(
|
||||
}
|
||||
nodes[i] = node;
|
||||
reverseChildNodes[reverseChildIndex] = node;
|
||||
validateNode(currentParent, node);
|
||||
validateNode(currentParent, node, nodesWithoutIndices.length);
|
||||
|
||||
viewNodeFlags |= node.flags;
|
||||
copyInto(node.matchedQueries, viewMatchedQueries);
|
||||
copyQueryMatchesInto(node.matchedQueries, viewMatchedQueries);
|
||||
viewBindingCount += node.bindings.length;
|
||||
viewDisposableCount += node.disposableCount;
|
||||
if (currentParent) {
|
||||
currentParent.childFlags |= node.flags;
|
||||
copyInto(node.matchedQueries, currentParent.childMatchedQueries);
|
||||
copyQueryMatchesInto(node.matchedQueries, currentParent.childMatchedQueries);
|
||||
if (node.element && node.element.template) {
|
||||
copyInto(node.element.template.nodeMatchedQueries, currentParent.childMatchedQueries);
|
||||
copyQueryMatchesInto(
|
||||
node.element.template.nodeMatchedQueries, currentParent.childMatchedQueries);
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,7 +98,7 @@ export function viewDef(
|
||||
const newParent = nodes[currentParent.parent];
|
||||
if (newParent) {
|
||||
newParent.childFlags |= currentParent.childFlags;
|
||||
copyInto(currentParent.childMatchedQueries, newParent.childMatchedQueries);
|
||||
copyQueryMatchesInto(currentParent.childMatchedQueries, newParent.childMatchedQueries);
|
||||
}
|
||||
currentParent = newParent;
|
||||
}
|
||||
@ -114,9 +116,12 @@ export function viewDef(
|
||||
};
|
||||
}
|
||||
|
||||
function copyInto(source: any, target: any) {
|
||||
function copyQueryMatchesInto(
|
||||
source: {[queryId: string]: any}, target: {[queryId: string]: boolean}) {
|
||||
for (let prop in source) {
|
||||
target[prop] = source[prop];
|
||||
if (!queryIdIsReference(prop)) {
|
||||
target[prop] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +164,7 @@ function calculateReverseChildIndex(
|
||||
return parentEndIndexInReverseChildOrder - lastChildOffsetRelativeToParentInDfsOrder;
|
||||
}
|
||||
|
||||
function validateNode(parent: NodeDef, node: NodeDef) {
|
||||
function validateNode(parent: NodeDef, node: NodeDef, nodeCount: number) {
|
||||
const template = node.element && node.element.template;
|
||||
if (template) {
|
||||
if (template.lastRootNode && template.lastRootNode.flags & NodeFlags.HasEmbeddedViews) {
|
||||
@ -182,12 +187,10 @@ function validateNode(parent: NodeDef, node: NodeDef) {
|
||||
}
|
||||
}
|
||||
if (node.childCount) {
|
||||
if (parent) {
|
||||
const parentEnd = parent.index + parent.childCount;
|
||||
if (node.index <= parentEnd && node.index + node.childCount > parentEnd) {
|
||||
throw new Error(
|
||||
`Illegal State: childCount of node leads outside of parent, at index ${node.index}!`);
|
||||
}
|
||||
const parentEnd = parent ? parent.index + parent.childCount : nodeCount - 1;
|
||||
if (node.index <= parentEnd && node.index + node.childCount > parentEnd) {
|
||||
throw new Error(
|
||||
`Illegal State: childCount of node leads outside of parent, at index ${node.index}!`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user