angular-cn/packages/core/src/debug/debug_node.ts

202 lines
5.5 KiB
TypeScript
Raw Normal View History

/**
* @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 {Injector} from '../di';
import {RenderDebugInfo} from '../render/api';
export class EventListener { constructor(public name: string, public callback: Function){}; }
/**
* @experimental All debugging apis are currently experimental.
*/
export class DebugNode {
nativeNode: any;
listeners: EventListener[];
parent: DebugElement;
constructor(nativeNode: any, parent: DebugNode, private _debugInfo: RenderDebugInfo) {
this.nativeNode = nativeNode;
if (parent && parent instanceof DebugElement) {
parent.addChild(this);
} else {
this.parent = null;
}
this.listeners = [];
}
get injector(): Injector { return this._debugInfo ? this._debugInfo.injector : null; }
get componentInstance(): any { return this._debugInfo ? this._debugInfo.component : null; }
get context(): any { return this._debugInfo ? this._debugInfo.context : null; }
get references(): {[key: string]: any} {
return this._debugInfo ? this._debugInfo.references : null;
}
get providerTokens(): any[] { return this._debugInfo ? this._debugInfo.providerTokens : null; }
get source(): string { return this._debugInfo ? this._debugInfo.source : null; }
}
/**
* @experimental All debugging apis are currently experimental.
*/
export class DebugElement extends DebugNode {
name: string;
properties: {[key: string]: any};
attributes: {[key: string]: string};
classes: {[key: string]: boolean};
styles: {[key: string]: string};
childNodes: DebugNode[];
nativeElement: any;
constructor(nativeNode: any, parent: any, _debugInfo: RenderDebugInfo) {
super(nativeNode, parent, _debugInfo);
this.properties = {};
this.attributes = {};
this.classes = {};
this.styles = {};
this.childNodes = [];
this.nativeElement = nativeNode;
}
addChild(child: DebugNode) {
if (child) {
this.childNodes.push(child);
child.parent = this;
}
}
removeChild(child: DebugNode) {
const childIndex = this.childNodes.indexOf(child);
if (childIndex !== -1) {
child.parent = null;
this.childNodes.splice(childIndex, 1);
}
}
insertChildrenAfter(child: DebugNode, newChildren: DebugNode[]) {
const siblingIndex = this.childNodes.indexOf(child);
if (siblingIndex !== -1) {
2017-02-14 21:03:18 -08:00
this.childNodes.splice(siblingIndex + 1, 0, ...newChildren);
newChildren.forEach(c => {
if (c.parent) {
c.parent.removeChild(c);
}
2017-02-14 21:03:18 -08:00
c.parent = this;
});
}
}
insertBefore(refChild: DebugNode, newChild: DebugNode): void {
const refIndex = this.childNodes.indexOf(refChild);
if (refIndex === -1) {
this.addChild(newChild);
} else {
if (newChild.parent) {
newChild.parent.removeChild(newChild);
}
2017-02-14 21:03:18 -08:00
newChild.parent = this;
this.childNodes.splice(refIndex, 0, newChild);
}
}
query(predicate: Predicate<DebugElement>): DebugElement {
const results = this.queryAll(predicate);
return results[0] || null;
}
queryAll(predicate: Predicate<DebugElement>): DebugElement[] {
const matches: DebugElement[] = [];
_queryElementChildren(this, predicate, matches);
return matches;
}
queryAllNodes(predicate: Predicate<DebugNode>): DebugNode[] {
const matches: DebugNode[] = [];
_queryNodeChildren(this, predicate, matches);
return matches;
}
get children(): DebugElement[] {
return this.childNodes.filter((node) => node instanceof DebugElement) as DebugElement[];
}
triggerEventHandler(eventName: string, eventObj: any) {
this.listeners.forEach((listener) => {
if (listener.name == eventName) {
listener.callback(eventObj);
}
});
}
}
/**
* @experimental
*/
export function asNativeElements(debugEls: DebugElement[]): any {
return debugEls.map((el) => el.nativeElement);
}
function _queryElementChildren(
element: DebugElement, predicate: Predicate<DebugElement>, matches: DebugElement[]) {
element.childNodes.forEach(node => {
if (node instanceof DebugElement) {
if (predicate(node)) {
matches.push(node);
}
_queryElementChildren(node, predicate, matches);
}
});
}
function _queryNodeChildren(
parentNode: DebugNode, predicate: Predicate<DebugNode>, matches: DebugNode[]) {
if (parentNode instanceof DebugElement) {
parentNode.childNodes.forEach(node => {
if (predicate(node)) {
matches.push(node);
}
if (node instanceof DebugElement) {
_queryNodeChildren(node, predicate, matches);
}
});
}
}
// Need to keep the nodes in a global Map so that multiple angular apps are supported.
const _nativeNodeToDebugNode = new Map<any, DebugNode>();
/**
* @experimental
*/
export function getDebugNode(nativeNode: any): DebugNode {
return _nativeNodeToDebugNode.get(nativeNode);
}
export function getAllDebugNodes(): DebugNode[] {
return Array.from(_nativeNodeToDebugNode.values());
}
export function indexDebugNode(node: DebugNode) {
_nativeNodeToDebugNode.set(node.nativeNode, node);
}
export function removeDebugNodeFromIndex(node: DebugNode) {
_nativeNodeToDebugNode.delete(node.nativeNode);
}
/**
* A boolean-valued function over a value, possibly including context information
* regarding that value's position in an array.
*
* @experimental All debugging apis are currently experimental.
*/
export interface Predicate<T> { (value: T, index?: number, array?: T[]): boolean; }