2017-02-03 15:20:50 -08:00
|
|
|
/**
|
|
|
|
|
* @license
|
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import {isDevMode} from '../application_ref';
|
|
|
|
|
import {Injectable, Injector} from '../di';
|
|
|
|
|
import {looseIdentical} from '../facade/lang';
|
|
|
|
|
import {ElementRef} from '../linker/element_ref';
|
|
|
|
|
import * as v1renderer from '../render/api';
|
|
|
|
|
import {Sanitizer, SecurityContext} from '../security';
|
|
|
|
|
import {Type} from '../type';
|
|
|
|
|
|
|
|
|
|
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
|
|
|
|
|
import {resolveDep} from './provider';
|
|
|
|
|
import {getQueryValue} from './query';
|
|
|
|
|
import {createInjector} from './refs';
|
|
|
|
|
import {DirectDomRenderer, LegacyRendererAdapter} from './renderer';
|
2017-02-09 14:59:57 -08:00
|
|
|
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RendererV2, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, ViewUpdateFn, asElementData, asProviderData} from './types';
|
|
|
|
|
import {checkBinding, isComponentView, queryIdIsReference, renderNode, resolveViewDefinition, rootRenderNodes, viewParentElIndex} from './util';
|
2017-02-03 15:20:50 -08:00
|
|
|
import {checkAndUpdateView, checkNoChangesView, createEmbeddedView, createRootView, destroyView} from './view';
|
|
|
|
|
import {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
|
|
|
|
|
|
|
|
|
let initialized = false;
|
|
|
|
|
|
|
|
|
|
export function initServicesIfNeeded() {
|
|
|
|
|
if (initialized) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
initialized = true;
|
|
|
|
|
const services = isDevMode() ? createDebugServices() : createProdServices();
|
|
|
|
|
Services.setCurrentNode = services.setCurrentNode;
|
|
|
|
|
Services.createRootView = services.createRootView;
|
|
|
|
|
Services.createEmbeddedView = services.createEmbeddedView;
|
|
|
|
|
Services.checkAndUpdateView = services.checkAndUpdateView;
|
|
|
|
|
Services.checkNoChangesView = services.checkNoChangesView;
|
|
|
|
|
Services.destroyView = services.destroyView;
|
|
|
|
|
Services.attachEmbeddedView = services.attachEmbeddedView,
|
|
|
|
|
Services.detachEmbeddedView = services.detachEmbeddedView,
|
|
|
|
|
Services.moveEmbeddedView = services.moveEmbeddedView;
|
|
|
|
|
Services.resolveDep = services.resolveDep;
|
|
|
|
|
Services.createDebugContext = services.createDebugContext;
|
|
|
|
|
Services.handleEvent = services.handleEvent;
|
2017-02-09 14:59:57 -08:00
|
|
|
Services.updateDirectives = services.updateDirectives;
|
|
|
|
|
Services.updateRenderer = services.updateRenderer;
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createProdServices() {
|
|
|
|
|
return {
|
|
|
|
|
setCurrentNode: () => {},
|
|
|
|
|
createRootView: createProdRootView,
|
|
|
|
|
createEmbeddedView: createEmbeddedView,
|
|
|
|
|
checkAndUpdateView: checkAndUpdateView,
|
|
|
|
|
checkNoChangesView: checkNoChangesView,
|
|
|
|
|
destroyView: destroyView,
|
|
|
|
|
attachEmbeddedView: attachEmbeddedView,
|
|
|
|
|
detachEmbeddedView: detachEmbeddedView,
|
|
|
|
|
moveEmbeddedView: moveEmbeddedView,
|
|
|
|
|
resolveDep: resolveDep,
|
|
|
|
|
createDebugContext: (view: ViewData, nodeIndex: number) => new DebugContext_(view, nodeIndex),
|
|
|
|
|
handleEvent: (view: ViewData, nodeIndex: number, eventName: string, event: any) =>
|
|
|
|
|
view.def.handleEvent(view, nodeIndex, eventName, event),
|
2017-02-09 14:59:57 -08:00
|
|
|
updateDirectives: (check: NodeCheckFn, view: ViewData) =>
|
|
|
|
|
view.def.updateDirectives(check, view),
|
|
|
|
|
updateRenderer: (check: NodeCheckFn, view: ViewData) => view.def.updateRenderer(check, view),
|
2017-02-03 15:20:50 -08:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createDebugServices() {
|
|
|
|
|
return {
|
|
|
|
|
setCurrentNode: debugSetCurrentNode,
|
|
|
|
|
createRootView: debugCreateRootView,
|
|
|
|
|
createEmbeddedView: debugCreateEmbeddedView,
|
|
|
|
|
checkAndUpdateView: debugCheckAndUpdateView,
|
|
|
|
|
checkNoChangesView: debugCheckNoChangesView,
|
|
|
|
|
destroyView: debugDestroyView,
|
|
|
|
|
attachEmbeddedView: attachEmbeddedView,
|
|
|
|
|
detachEmbeddedView: detachEmbeddedView,
|
|
|
|
|
moveEmbeddedView: moveEmbeddedView,
|
|
|
|
|
resolveDep: resolveDep,
|
|
|
|
|
createDebugContext: (view: ViewData, nodeIndex: number) => new DebugContext_(view, nodeIndex),
|
|
|
|
|
handleEvent: debugHandleEvent,
|
2017-02-09 14:59:57 -08:00
|
|
|
updateDirectives: debugUpdateDirectives,
|
|
|
|
|
updateRenderer: debugUpdateRenderer
|
2017-02-03 15:20:50 -08:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createProdRootView(
|
|
|
|
|
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any,
|
|
|
|
|
def: ViewDefinition, context?: any): ViewData {
|
|
|
|
|
return createRootView(
|
|
|
|
|
createRootData(injector, projectableNodes, rootSelectorOrNode), def, context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function debugCreateRootView(
|
|
|
|
|
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any,
|
|
|
|
|
def: ViewDefinition, context?: any): ViewData {
|
|
|
|
|
const root = createRootData(injector, projectableNodes, rootSelectorOrNode);
|
|
|
|
|
const debugRoot: RootData = {
|
|
|
|
|
injector: root.injector,
|
|
|
|
|
projectableNodes: root.projectableNodes,
|
2017-02-02 15:01:35 -08:00
|
|
|
selectorOrNode: root.selectorOrNode,
|
2017-02-03 15:20:50 -08:00
|
|
|
renderer: new DebugRenderer(root.renderer),
|
|
|
|
|
sanitizer: root.sanitizer
|
|
|
|
|
};
|
|
|
|
|
return callWithDebugContext('create', createRootView, null, [debugRoot, def, context]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createRootData(
|
|
|
|
|
injector: Injector, projectableNodes: any[][], rootSelectorOrNode: any): RootData {
|
|
|
|
|
const sanitizer = injector.get(Sanitizer);
|
|
|
|
|
// TODO(tbosch): once the new renderer interface is implemented via platform-browser,
|
|
|
|
|
// just get it via the injector and drop LegacyRendererAdapter and DirectDomRenderer.
|
|
|
|
|
const renderer = isDevMode() ? new LegacyRendererAdapter(injector.get(v1renderer.RootRenderer)) :
|
|
|
|
|
new DirectDomRenderer();
|
|
|
|
|
const rootElement =
|
|
|
|
|
rootSelectorOrNode ? renderer.selectRootElement(rootSelectorOrNode) : undefined;
|
2017-02-02 15:01:35 -08:00
|
|
|
return {injector, projectableNodes, selectorOrNode: rootSelectorOrNode, sanitizer, renderer};
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function debugCreateEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData {
|
|
|
|
|
return callWithDebugContext('create', createEmbeddedView, null, [parent, anchorDef, context]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function debugCheckAndUpdateView(view: ViewData) {
|
|
|
|
|
return callWithDebugContext('detectChanges', checkAndUpdateView, null, [view]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function debugCheckNoChangesView(view: ViewData) {
|
|
|
|
|
return callWithDebugContext('checkNoChanges', checkNoChangesView, null, [view]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function debugDestroyView(view: ViewData) {
|
|
|
|
|
return callWithDebugContext('destroyView', destroyView, null, [view]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let _currentAction: string;
|
|
|
|
|
let _currentView: ViewData;
|
|
|
|
|
let _currentNodeIndex: number;
|
|
|
|
|
|
|
|
|
|
function debugSetCurrentNode(view: ViewData, nodeIndex: number) {
|
|
|
|
|
_currentView = view;
|
|
|
|
|
_currentNodeIndex = nodeIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function debugHandleEvent(view: ViewData, nodeIndex: number, eventName: string, event: any) {
|
|
|
|
|
if (view.state & ViewState.Destroyed) {
|
|
|
|
|
throw viewDestroyedError(_currentAction);
|
|
|
|
|
}
|
|
|
|
|
debugSetCurrentNode(view, nodeIndex);
|
|
|
|
|
return callWithDebugContext(
|
|
|
|
|
'handleEvent', view.def.handleEvent, null, [view, nodeIndex, eventName, event]);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 14:59:57 -08:00
|
|
|
function debugUpdateDirectives(check: NodeCheckFn, view: ViewData) {
|
2017-02-03 15:20:50 -08:00
|
|
|
if (view.state & ViewState.Destroyed) {
|
|
|
|
|
throw viewDestroyedError(_currentAction);
|
|
|
|
|
}
|
2017-02-09 14:59:57 -08:00
|
|
|
debugSetCurrentNode(view, nextDirectiveWithBinding(view, 0));
|
|
|
|
|
return view.def.updateDirectives(debugCheckDirectivesFn, view);
|
|
|
|
|
|
|
|
|
|
function debugCheckDirectivesFn(
|
|
|
|
|
view: ViewData, nodeIndex: number, argStyle: ArgumentType, ...values: any[]) {
|
|
|
|
|
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
|
|
|
|
debugSetCurrentNode(view, nextDirectiveWithBinding(view, nodeIndex));
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
|
|
|
|
|
if (view.state & ViewState.Destroyed) {
|
|
|
|
|
throw viewDestroyedError(_currentAction);
|
|
|
|
|
}
|
|
|
|
|
debugSetCurrentNode(view, nextRenderNodeWithBinding(view, 0));
|
|
|
|
|
return view.def.updateRenderer(debugCheckRenderNodeFn, view);
|
2017-02-03 15:20:50 -08:00
|
|
|
|
2017-02-09 14:59:57 -08:00
|
|
|
function debugCheckRenderNodeFn(
|
|
|
|
|
view: ViewData, nodeIndex: number, argStyle: ArgumentType, ...values: any[]) {
|
|
|
|
|
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
|
|
|
|
debugSetCurrentNode(view, nextRenderNodeWithBinding(view, nodeIndex));
|
2017-02-03 15:20:50 -08:00
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 14:59:57 -08:00
|
|
|
function debugCheckFn(
|
|
|
|
|
delegate: NodeCheckFn, view: ViewData, nodeIndex: number, argStyle: ArgumentType,
|
|
|
|
|
givenValues: any[]) {
|
|
|
|
|
const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues;
|
|
|
|
|
const nodeDef = view.def.nodes[nodeIndex];
|
|
|
|
|
for (let i = 0; i < nodeDef.bindings.length; i++) {
|
|
|
|
|
const binding = nodeDef.bindings[i];
|
|
|
|
|
const value = values[i];
|
|
|
|
|
if ((binding.type === BindingType.ElementProperty ||
|
|
|
|
|
binding.type === BindingType.DirectiveProperty) &&
|
|
|
|
|
checkBinding(view, nodeDef, i, value)) {
|
|
|
|
|
const elIndex = nodeDef.type === NodeType.Directive ? nodeDef.parent : nodeDef.index;
|
|
|
|
|
setBindingDebugInfo(
|
|
|
|
|
view.root.renderer, asElementData(view, elIndex).renderElement, binding.nonMinifiedName,
|
|
|
|
|
value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (<any>delegate)(view, nodeIndex, argStyle, ...givenValues);
|
|
|
|
|
};
|
|
|
|
|
|
2017-02-03 15:20:50 -08:00
|
|
|
function setBindingDebugInfo(renderer: RendererV2, renderNode: any, propName: string, value: any) {
|
2017-02-02 15:01:35 -08:00
|
|
|
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);
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CAMEL_CASE_REGEXP = /([A-Z])/g;
|
|
|
|
|
|
|
|
|
|
function camelCaseToDashCase(input: string): string {
|
|
|
|
|
return input.replace(CAMEL_CASE_REGEXP, (...m: any[]) => '-' + m[1].toLowerCase());
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 14:59:57 -08:00
|
|
|
function nextDirectiveWithBinding(view: ViewData, nodeIndex: number): number {
|
2017-02-03 15:20:50 -08:00
|
|
|
for (let i = nodeIndex; i < view.def.nodes.length; i++) {
|
|
|
|
|
const nodeDef = view.def.nodes[i];
|
2017-02-09 14:59:57 -08:00
|
|
|
if (nodeDef.type === NodeType.Directive && nodeDef.bindings && nodeDef.bindings.length) {
|
2017-02-03 15:20:50 -08:00
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 14:59:57 -08:00
|
|
|
function nextRenderNodeWithBinding(view: ViewData, nodeIndex: number): number {
|
|
|
|
|
for (let i = nodeIndex; i < view.def.nodes.length; i++) {
|
|
|
|
|
const nodeDef = view.def.nodes[i];
|
|
|
|
|
if ((nodeDef.type === NodeType.Element || nodeDef.type === NodeType.Text) && nodeDef.bindings &&
|
|
|
|
|
nodeDef.bindings.length) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
2017-02-03 15:20:50 -08:00
|
|
|
|
|
|
|
|
class DebugRenderer implements RendererV2 {
|
|
|
|
|
constructor(private _delegate: RendererV2) {}
|
|
|
|
|
createElement(name: string): any {
|
|
|
|
|
return this._delegate.createElement(name, getCurrentDebugContext());
|
|
|
|
|
}
|
|
|
|
|
createComment(value: string): any {
|
|
|
|
|
return this._delegate.createComment(value, getCurrentDebugContext());
|
|
|
|
|
}
|
|
|
|
|
createText(value: string): any {
|
|
|
|
|
return this._delegate.createText(value, getCurrentDebugContext());
|
|
|
|
|
}
|
|
|
|
|
appendChild(parent: any, newChild: any): void {
|
|
|
|
|
return this._delegate.appendChild(parent, newChild);
|
|
|
|
|
}
|
|
|
|
|
insertBefore(parent: any, newChild: any, refChild: any): void {
|
|
|
|
|
return this._delegate.insertBefore(parent, newChild, refChild);
|
|
|
|
|
}
|
|
|
|
|
removeChild(parent: any, oldChild: any): void {
|
|
|
|
|
return this._delegate.removeChild(parent, oldChild);
|
|
|
|
|
}
|
|
|
|
|
selectRootElement(selectorOrNode: string|any): any {
|
|
|
|
|
return this._delegate.selectRootElement(selectorOrNode, getCurrentDebugContext());
|
|
|
|
|
}
|
|
|
|
|
parentNode(node: any): any { return this._delegate.parentNode(node); }
|
|
|
|
|
nextSibling(node: any): any { return this._delegate.nextSibling(node); }
|
|
|
|
|
setAttribute(el: any, name: string, value: string): void {
|
|
|
|
|
return this._delegate.setAttribute(el, name, value);
|
|
|
|
|
}
|
|
|
|
|
removeAttribute(el: any, name: string): void { return this._delegate.removeAttribute(el, name); }
|
2017-02-02 15:01:35 -08:00
|
|
|
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);
|
|
|
|
|
}
|
2017-02-03 15:20:50 -08:00
|
|
|
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 {
|
|
|
|
|
return this._delegate.setStyle(el, style, value);
|
|
|
|
|
}
|
|
|
|
|
removeStyle(el: any, style: string): void { return this._delegate.removeStyle(el, style); }
|
|
|
|
|
setProperty(el: any, name: string, value: any): void {
|
|
|
|
|
return this._delegate.setProperty(el, name, value);
|
|
|
|
|
}
|
|
|
|
|
setText(node: any, value: string): void { return this._delegate.setText(node, value); }
|
|
|
|
|
listen(target: 'window'|'document'|any, eventName: string, callback: (event: any) => boolean):
|
|
|
|
|
() => void {
|
|
|
|
|
return this._delegate.listen(target, eventName, callback);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class DebugContext_ implements DebugContext {
|
|
|
|
|
private nodeDef: NodeDef;
|
2017-02-02 15:01:35 -08:00
|
|
|
private elView: ViewData;
|
2017-02-03 15:20:50 -08:00
|
|
|
private elDef: NodeDef;
|
2017-02-02 15:01:35 -08:00
|
|
|
private compProviderIndex: number;
|
2017-02-03 15:20:50 -08:00
|
|
|
constructor(public view: ViewData, public nodeIndex: number) {
|
|
|
|
|
if (nodeIndex == null) {
|
2017-02-02 15:01:35 -08:00
|
|
|
this.nodeIndex = 0;
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
|
|
|
|
this.nodeDef = view.def.nodes[nodeIndex];
|
2017-02-02 15:01:35 -08:00
|
|
|
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) {
|
2017-02-09 14:59:57 -08:00
|
|
|
elIndex = viewParentElIndex(elView);
|
2017-02-02 15:01:35 -08:00
|
|
|
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;
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
|
|
|
|
get providerTokens(): any[] {
|
|
|
|
|
const tokens: any[] = [];
|
|
|
|
|
if (this.elDef) {
|
|
|
|
|
for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) {
|
2017-02-02 15:01:35 -08:00
|
|
|
const childDef = this.elView.def.nodes[i];
|
2017-02-09 14:59:57 -08:00
|
|
|
if (childDef.type === NodeType.Provider || childDef.type === NodeType.Directive) {
|
2017-02-03 15:20:50 -08:00
|
|
|
tokens.push(childDef.provider.token);
|
|
|
|
|
}
|
2017-02-02 15:01:35 -08:00
|
|
|
i += childDef.childCount;
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return tokens;
|
|
|
|
|
}
|
|
|
|
|
get references(): {[key: string]: any} {
|
|
|
|
|
const references: {[key: string]: any} = {};
|
|
|
|
|
if (this.elDef) {
|
2017-02-02 15:01:35 -08:00
|
|
|
collectReferences(this.elView, this.elDef, references);
|
2017-02-03 15:20:50 -08:00
|
|
|
|
|
|
|
|
for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) {
|
2017-02-02 15:01:35 -08:00
|
|
|
const childDef = this.elView.def.nodes[i];
|
2017-02-09 14:59:57 -08:00
|
|
|
if (childDef.type === NodeType.Provider || childDef.type === NodeType.Directive) {
|
2017-02-02 15:01:35 -08:00
|
|
|
collectReferences(this.elView, childDef, references);
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
2017-02-02 15:01:35 -08:00
|
|
|
i += childDef.childCount;
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return references;
|
|
|
|
|
}
|
|
|
|
|
get source(): string {
|
|
|
|
|
if (this.nodeDef.type === NodeType.Text) {
|
|
|
|
|
return this.nodeDef.text.source;
|
|
|
|
|
} else {
|
|
|
|
|
return this.elDef.element.source;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
get componentRenderElement() {
|
2017-02-02 15:01:35 -08:00
|
|
|
const view = this.compProviderIndex != null ?
|
|
|
|
|
asProviderData(this.elView, this.compProviderIndex).componentView :
|
|
|
|
|
this.view;
|
|
|
|
|
const elData = findHostElement(view);
|
2017-02-03 15:20:50 -08:00
|
|
|
return elData ? elData.renderElement : undefined;
|
|
|
|
|
}
|
|
|
|
|
get renderNode(): any {
|
2017-02-02 15:01:35 -08:00
|
|
|
return this.nodeDef.type === NodeType.Text ? renderNode(this.view, this.nodeDef) :
|
|
|
|
|
renderNode(this.elView, this.elDef);
|
2017-02-03 15:20:50 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findHostElement(view: ViewData): ElementData {
|
|
|
|
|
while (view && !isComponentView(view)) {
|
|
|
|
|
view = view.parent;
|
|
|
|
|
}
|
|
|
|
|
if (view.parent) {
|
2017-02-09 14:59:57 -08:00
|
|
|
const hostData = asElementData(view.parent, viewParentElIndex(view));
|
2017-02-03 15:20:50 -08:00
|
|
|
return hostData;
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function collectReferences(view: ViewData, nodeDef: NodeDef, references: {[key: string]: any}) {
|
|
|
|
|
for (let queryId in nodeDef.matchedQueries) {
|
2017-02-02 15:01:35 -08:00
|
|
|
if (queryIdIsReference(queryId)) {
|
2017-02-03 15:20:50 -08:00
|
|
|
references[queryId.slice(1)] = getQueryValue(view, nodeDef, queryId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function callWithDebugContext(action: string, fn: any, self: any, args: any[]) {
|
|
|
|
|
const oldAction = _currentAction;
|
|
|
|
|
const oldView = _currentView;
|
|
|
|
|
const oldNodeIndex = _currentNodeIndex;
|
|
|
|
|
try {
|
|
|
|
|
_currentAction = action;
|
|
|
|
|
const result = fn.apply(self, args);
|
|
|
|
|
_currentView = oldView;
|
|
|
|
|
_currentNodeIndex = oldNodeIndex;
|
|
|
|
|
_currentAction = oldAction;
|
|
|
|
|
return result;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (isViewDebugError(e) || !_currentView) {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
2017-02-09 14:59:57 -08:00
|
|
|
_currentView.state |= ViewState.Errored;
|
2017-02-03 15:20:50 -08:00
|
|
|
throw viewWrappedDebugError(e, getCurrentDebugContext());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getCurrentDebugContext() {
|
|
|
|
|
return new DebugContext_(_currentView, _currentNodeIndex);
|
|
|
|
|
}
|