2015-07-23 18:01:34 -07:00
|
|
|
import {
|
|
|
|
ListWrapper,
|
|
|
|
MapWrapper,
|
|
|
|
Map,
|
|
|
|
StringMapWrapper,
|
2015-11-06 17:34:07 -08:00
|
|
|
} from 'angular2/src/facade/collection';
|
2015-05-20 09:48:15 -07:00
|
|
|
import {
|
2015-07-28 12:43:41 -07:00
|
|
|
ChangeDetector,
|
|
|
|
ChangeDispatcher,
|
2015-05-20 09:48:15 -07:00
|
|
|
DirectiveIndex,
|
2015-08-19 11:26:45 -07:00
|
|
|
BindingTarget,
|
2015-07-28 12:43:41 -07:00
|
|
|
Locals,
|
|
|
|
ProtoChangeDetector
|
2015-08-20 14:28:25 -07:00
|
|
|
} from 'angular2/src/core/change_detection/change_detection';
|
|
|
|
import {DebugContext} from 'angular2/src/core/change_detection/interfaces';
|
2015-05-20 09:48:15 -07:00
|
|
|
|
|
|
|
import {
|
|
|
|
ProtoElementInjector,
|
|
|
|
ElementInjector,
|
|
|
|
PreBuiltObjects,
|
2015-10-10 22:11:13 -07:00
|
|
|
DirectiveProvider
|
2015-05-20 09:48:15 -07:00
|
|
|
} from './element_injector';
|
2014-11-11 17:33:47 -08:00
|
|
|
import {ElementBinder} from './element_binder';
|
2015-11-06 17:34:07 -08:00
|
|
|
import {isPresent} from 'angular2/src/facade/lang';
|
|
|
|
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
2015-08-20 14:28:25 -07:00
|
|
|
import * as renderApi from 'angular2/src/core/render/api';
|
|
|
|
import {RenderEventDispatcher} from 'angular2/src/core/render/api';
|
2015-07-17 08:03:40 -07:00
|
|
|
import {ViewRef, ProtoViewRef, internalView} from './view_ref';
|
2015-06-23 11:21:56 -07:00
|
|
|
import {ElementRef} from './element_ref';
|
2015-08-07 11:41:38 -07:00
|
|
|
import {ProtoPipes} from 'angular2/src/core/pipes/pipes';
|
2015-11-17 15:24:36 -08:00
|
|
|
import {camelCaseToDashCase} from 'angular2/src/core/render/util';
|
2015-10-01 10:07:49 -07:00
|
|
|
import {TemplateCmd} from './template_commands';
|
2015-10-06 19:39:44 -07:00
|
|
|
import {ViewRef_, ProtoViewRef_} from "./view_ref";
|
2015-04-24 17:53:06 -07:00
|
|
|
|
2015-08-20 14:28:25 -07:00
|
|
|
export {DebugContext} from 'angular2/src/core/change_detection/interfaces';
|
2015-07-28 12:43:41 -07:00
|
|
|
|
2015-08-20 15:11:12 -07:00
|
|
|
const REFLECT_PREFIX: string = 'ng-reflect-';
|
|
|
|
|
2015-10-05 10:10:07 -07:00
|
|
|
export enum ViewType {
|
|
|
|
// A view that contains the host element with bound component directive.
|
|
|
|
// Contains a COMPONENT view
|
|
|
|
HOST,
|
|
|
|
// The view of the component
|
|
|
|
// Can contain 0 to n EMBEDDED views
|
|
|
|
COMPONENT,
|
|
|
|
// A view that is embedded into another View via a <template> element
|
|
|
|
// inside of a COMPONENT view
|
|
|
|
EMBEDDED
|
|
|
|
}
|
|
|
|
|
2015-04-27 09:26:55 -07:00
|
|
|
export class AppViewContainer {
|
2015-06-03 11:02:51 -07:00
|
|
|
// The order in this list matches the DOM order.
|
2015-08-28 11:29:19 -07:00
|
|
|
views: AppView[] = [];
|
2015-04-24 17:53:06 -07:00
|
|
|
}
|
2014-09-28 16:29:11 -07:00
|
|
|
|
2014-11-21 15:13:01 -08:00
|
|
|
/**
|
2015-07-07 08:15:58 +02:00
|
|
|
* Cost of making objects: http://jsperf.com/instantiate-size-of-object
|
2015-03-31 22:47:11 +00:00
|
|
|
*
|
2014-10-10 20:44:55 -07:00
|
|
|
*/
|
2015-06-24 13:46:39 -07:00
|
|
|
export class AppView implements ChangeDispatcher, RenderEventDispatcher {
|
|
|
|
// AppViews that have been merged in depth first order.
|
|
|
|
// This list is shared between all merged views. Use this.elementOffset to get the local
|
|
|
|
// entries.
|
2015-08-28 11:29:19 -07:00
|
|
|
views: AppView[] = null;
|
2015-06-24 13:46:39 -07:00
|
|
|
// root elementInjectors of this AppView
|
|
|
|
// This list is local to this AppView and not shared with other Views.
|
2015-08-28 11:29:19 -07:00
|
|
|
rootElementInjectors: ElementInjector[];
|
2015-06-24 13:46:39 -07:00
|
|
|
// ElementInjectors of all AppViews in views grouped by view.
|
|
|
|
// This list is shared between all merged views. Use this.elementOffset to get the local
|
|
|
|
// entries.
|
2015-08-28 11:29:19 -07:00
|
|
|
elementInjectors: ElementInjector[] = null;
|
2015-06-24 13:46:39 -07:00
|
|
|
// ViewContainers of all AppViews in views grouped by view.
|
|
|
|
// This list is shared between all merged views. Use this.elementOffset to get the local
|
|
|
|
// entries.
|
2015-08-28 11:29:19 -07:00
|
|
|
viewContainers: AppViewContainer[] = null;
|
2015-06-24 13:46:39 -07:00
|
|
|
// PreBuiltObjects of all AppViews in views grouped by view.
|
|
|
|
// This list is shared between all merged views. Use this.elementOffset to get the local
|
|
|
|
// entries.
|
2015-08-28 11:29:19 -07:00
|
|
|
preBuiltObjects: PreBuiltObjects[] = null;
|
2015-06-24 13:46:39 -07:00
|
|
|
// ElementRef of all AppViews in views grouped by view.
|
|
|
|
// This list is shared between all merged views. Use this.elementOffset to get the local
|
|
|
|
// entries.
|
2015-08-28 11:29:19 -07:00
|
|
|
elementRefs: ElementRef[];
|
2015-06-24 13:46:39 -07:00
|
|
|
|
2015-06-23 11:21:56 -07:00
|
|
|
ref: ViewRef;
|
2015-06-24 13:46:39 -07:00
|
|
|
changeDetector: ChangeDetector = null;
|
|
|
|
|
2015-04-06 13:19:30 -07:00
|
|
|
/**
|
|
|
|
* The context against which data-binding expressions in this view are evaluated against.
|
|
|
|
* This is always a component instance.
|
|
|
|
*/
|
2015-04-09 21:20:11 +02:00
|
|
|
|
2015-06-12 22:38:44 +02:00
|
|
|
context: any = null;
|
2015-04-06 13:19:30 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Variables, local to this view, that can be used in binding expressions (in addition to the
|
|
|
|
* context). This is used for thing like `<video #player>` or
|
|
|
|
* `<li template="for #item of items">`, where "player" and "item" are locals, respectively.
|
|
|
|
*/
|
2015-05-20 09:48:15 -07:00
|
|
|
locals: Locals;
|
2015-01-02 14:23:59 -08:00
|
|
|
|
2015-05-20 09:48:15 -07:00
|
|
|
constructor(public renderer: renderApi.Renderer, public proto: AppProtoView,
|
2015-10-01 10:07:49 -07:00
|
|
|
public viewOffset: number, public elementOffset: number, public textOffset: number,
|
2015-06-24 13:46:39 -07:00
|
|
|
protoLocals: Map<string, any>, public render: renderApi.RenderViewRef,
|
2015-10-01 10:07:49 -07:00
|
|
|
public renderFragment: renderApi.RenderFragmentRef,
|
|
|
|
public containerElementInjector: ElementInjector) {
|
2015-10-06 06:53:39 -07:00
|
|
|
this.ref = new ViewRef_(this);
|
2015-06-24 13:46:39 -07:00
|
|
|
|
2015-05-20 09:48:15 -07:00
|
|
|
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); // TODO optimize this
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
2015-08-28 11:29:19 -07:00
|
|
|
init(changeDetector: ChangeDetector, elementInjectors: ElementInjector[],
|
|
|
|
rootElementInjectors: ElementInjector[], preBuiltObjects: PreBuiltObjects[],
|
|
|
|
views: AppView[], elementRefs: ElementRef[], viewContainers: AppViewContainer[]) {
|
2015-03-11 21:43:22 -07:00
|
|
|
this.changeDetector = changeDetector;
|
2014-12-09 10:31:19 -08:00
|
|
|
this.elementInjectors = elementInjectors;
|
|
|
|
this.rootElementInjectors = rootElementInjectors;
|
|
|
|
this.preBuiltObjects = preBuiltObjects;
|
2015-06-24 13:46:39 -07:00
|
|
|
this.views = views;
|
|
|
|
this.elementRefs = elementRefs;
|
|
|
|
this.viewContainers = viewContainers;
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
2015-07-07 20:03:00 -07:00
|
|
|
setLocal(contextName: string, value: any): void {
|
2014-12-01 18:41:55 -08:00
|
|
|
if (!this.hydrated()) throw new BaseException('Cannot set locals on dehydrated view.');
|
2015-10-01 10:07:49 -07:00
|
|
|
if (!this.proto.templateVariableBindings.has(contextName)) {
|
2015-01-28 00:42:08 +01:00
|
|
|
return;
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
2015-10-01 10:07:49 -07:00
|
|
|
var templateName = this.proto.templateVariableBindings.get(contextName);
|
2015-03-11 21:11:39 -07:00
|
|
|
this.locals.set(templateName, value);
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
2015-05-20 09:48:15 -07:00
|
|
|
hydrated(): boolean { return isPresent(this.context); }
|
2014-12-01 18:41:55 -08:00
|
|
|
|
2015-03-10 10:03:26 +01:00
|
|
|
/**
|
|
|
|
* Triggers the event handlers for the element and the directives.
|
|
|
|
*
|
|
|
|
* This method is intended to be called from directive EventEmitters.
|
|
|
|
*
|
|
|
|
* @param {string} eventName
|
|
|
|
* @param {*} eventObj
|
2015-08-20 16:25:34 -07:00
|
|
|
* @param {number} boundElementIndex
|
2015-03-10 10:03:26 +01:00
|
|
|
*/
|
2015-08-20 16:25:34 -07:00
|
|
|
triggerEventHandlers(eventName: string, eventObj: Event, boundElementIndex: number): void {
|
2015-09-29 11:11:06 -07:00
|
|
|
var locals = new Map<string, any>();
|
2015-06-17 16:21:40 -07:00
|
|
|
locals.set('$event', eventObj);
|
2015-06-24 13:46:39 -07:00
|
|
|
this.dispatchEvent(boundElementIndex, eventName, locals);
|
2015-03-10 10:03:26 +01:00
|
|
|
}
|
|
|
|
|
2015-03-31 09:07:01 -07:00
|
|
|
// dispatch to element injector or text nodes based on context
|
2015-08-19 11:26:45 -07:00
|
|
|
notifyOnBinding(b: BindingTarget, currentValue: any): void {
|
2015-06-24 13:46:39 -07:00
|
|
|
if (b.isTextNode()) {
|
2015-10-01 10:07:49 -07:00
|
|
|
this.renderer.setText(this.render, b.elementIndex + this.textOffset, currentValue);
|
2015-06-18 15:44:44 -07:00
|
|
|
} else {
|
2015-06-24 13:46:39 -07:00
|
|
|
var elementRef = this.elementRefs[this.elementOffset + b.elementIndex];
|
|
|
|
if (b.isElementProperty()) {
|
2015-08-19 11:26:45 -07:00
|
|
|
this.renderer.setElementProperty(elementRef, b.name, currentValue);
|
2015-06-24 13:46:39 -07:00
|
|
|
} else if (b.isElementAttribute()) {
|
2015-09-13 19:05:18 +02:00
|
|
|
this.renderer.setElementAttribute(elementRef, b.name,
|
|
|
|
isPresent(currentValue) ? `${currentValue}` : null);
|
2015-06-24 13:46:39 -07:00
|
|
|
} else if (b.isElementClass()) {
|
2015-08-19 11:26:45 -07:00
|
|
|
this.renderer.setElementClass(elementRef, b.name, currentValue);
|
2015-06-24 13:46:39 -07:00
|
|
|
} else if (b.isElementStyle()) {
|
2015-08-19 11:26:45 -07:00
|
|
|
var unit = isPresent(b.unit) ? b.unit : '';
|
2015-11-04 10:16:47 +01:00
|
|
|
this.renderer.setElementStyle(elementRef, b.name,
|
|
|
|
isPresent(currentValue) ? `${currentValue}${unit}` : null);
|
2015-06-24 13:46:39 -07:00
|
|
|
} else {
|
|
|
|
throw new BaseException('Unsupported directive record');
|
|
|
|
}
|
2015-04-07 20:54:20 -07:00
|
|
|
}
|
|
|
|
}
|
2015-04-09 21:20:11 +02:00
|
|
|
|
2015-08-20 15:11:12 -07:00
|
|
|
logBindingUpdate(b: BindingTarget, value: any): void {
|
|
|
|
if (b.isDirective() || b.isElementProperty()) {
|
|
|
|
var elementRef = this.elementRefs[this.elementOffset + b.elementIndex];
|
2015-11-19 11:14:44 -08:00
|
|
|
this.renderer.setBindingDebugInfo(
|
2015-08-20 15:11:12 -07:00
|
|
|
elementRef, `${REFLECT_PREFIX}${camelCaseToDashCase(b.name)}`, `${value}`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-27 21:19:56 -07:00
|
|
|
notifyAfterContentChecked(): void {
|
2015-06-24 13:46:39 -07:00
|
|
|
var eiCount = this.proto.elementBinders.length;
|
2015-06-12 09:45:31 -07:00
|
|
|
var ei = this.elementInjectors;
|
2015-06-24 13:46:39 -07:00
|
|
|
for (var i = eiCount - 1; i >= 0; i--) {
|
refactor(lifecycle): prefix lifecycle methods with "ng"
BREAKING CHANGE:
Previously, components that would implement lifecycle interfaces would include methods
like "onChanges" or "afterViewInit." Given that components were at risk of using such
names without realizing that Angular would call the methods at different points of
the component lifecycle. This change adds an "ng" prefix to all lifecycle hook methods,
far reducing the risk of an accidental name collision.
To fix, just rename these methods:
* onInit
* onDestroy
* doCheck
* onChanges
* afterContentInit
* afterContentChecked
* afterViewInit
* afterViewChecked
* _Router Hooks_
* onActivate
* onReuse
* onDeactivate
* canReuse
* canDeactivate
To:
* ngOnInit,
* ngOnDestroy,
* ngDoCheck,
* ngOnChanges,
* ngAfterContentInit,
* ngAfterContentChecked,
* ngAfterViewInit,
* ngAfterViewChecked
* _Router Hooks_
* routerOnActivate
* routerOnReuse
* routerOnDeactivate
* routerCanReuse
* routerCanDeactivate
The names of lifecycle interfaces and enums have not changed, though interfaces
have been updated to reflect the new method names.
Closes #5036
2015-11-16 17:04:36 -08:00
|
|
|
if (isPresent(ei[i + this.elementOffset])) ei[i + this.elementOffset].ngAfterContentChecked();
|
2015-06-12 09:45:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-28 18:11:04 -07:00
|
|
|
notifyAfterViewChecked(): void {
|
2015-08-18 21:51:28 -07:00
|
|
|
var eiCount = this.proto.elementBinders.length;
|
|
|
|
var ei = this.elementInjectors;
|
|
|
|
for (var i = eiCount - 1; i >= 0; i--) {
|
refactor(lifecycle): prefix lifecycle methods with "ng"
BREAKING CHANGE:
Previously, components that would implement lifecycle interfaces would include methods
like "onChanges" or "afterViewInit." Given that components were at risk of using such
names without realizing that Angular would call the methods at different points of
the component lifecycle. This change adds an "ng" prefix to all lifecycle hook methods,
far reducing the risk of an accidental name collision.
To fix, just rename these methods:
* onInit
* onDestroy
* doCheck
* onChanges
* afterContentInit
* afterContentChecked
* afterViewInit
* afterViewChecked
* _Router Hooks_
* onActivate
* onReuse
* onDeactivate
* canReuse
* canDeactivate
To:
* ngOnInit,
* ngOnDestroy,
* ngDoCheck,
* ngOnChanges,
* ngAfterContentInit,
* ngAfterContentChecked,
* ngAfterViewInit,
* ngAfterViewChecked
* _Router Hooks_
* routerOnActivate
* routerOnReuse
* routerOnDeactivate
* routerCanReuse
* routerCanDeactivate
The names of lifecycle interfaces and enums have not changed, though interfaces
have been updated to reflect the new method names.
Closes #5036
2015-11-16 17:04:36 -08:00
|
|
|
if (isPresent(ei[i + this.elementOffset])) ei[i + this.elementOffset].ngAfterViewChecked();
|
2015-08-18 21:51:28 -07:00
|
|
|
}
|
2015-08-28 18:11:04 -07:00
|
|
|
}
|
|
|
|
|
2015-06-26 11:10:52 -07:00
|
|
|
getDirectiveFor(directive: DirectiveIndex): any {
|
2015-06-24 13:46:39 -07:00
|
|
|
var elementInjector = this.elementInjectors[this.elementOffset + directive.elementIndex];
|
2015-04-09 07:57:33 -07:00
|
|
|
return elementInjector.getDirectiveAtIndex(directive.directiveIndex);
|
|
|
|
}
|
2015-04-07 20:54:20 -07:00
|
|
|
|
2015-06-24 13:46:39 -07:00
|
|
|
getNestedView(boundElementIndex: number): AppView {
|
2015-10-01 10:07:49 -07:00
|
|
|
var eli = this.elementInjectors[boundElementIndex];
|
|
|
|
return isPresent(eli) ? eli.getNestedView() : null;
|
2015-06-24 13:46:39 -07:00
|
|
|
}
|
|
|
|
|
2015-10-01 10:07:49 -07:00
|
|
|
getContainerElement(): ElementRef {
|
|
|
|
return isPresent(this.containerElementInjector) ?
|
|
|
|
this.containerElementInjector.getElementRef() :
|
|
|
|
null;
|
2015-07-23 18:01:34 -07:00
|
|
|
}
|
|
|
|
|
2015-07-27 15:47:42 -07:00
|
|
|
getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext {
|
2015-07-23 18:01:34 -07:00
|
|
|
try {
|
|
|
|
var offsettedIndex = this.elementOffset + elementIndex;
|
|
|
|
var hasRefForIndex = offsettedIndex < this.elementRefs.length;
|
|
|
|
|
|
|
|
var elementRef = hasRefForIndex ? this.elementRefs[this.elementOffset + elementIndex] : null;
|
2015-10-01 10:07:49 -07:00
|
|
|
var container = this.getContainerElement();
|
2015-07-23 18:01:34 -07:00
|
|
|
var ei = hasRefForIndex ? this.elementInjectors[this.elementOffset + elementIndex] : null;
|
|
|
|
|
|
|
|
var element = isPresent(elementRef) ? elementRef.nativeElement : null;
|
2015-10-01 10:07:49 -07:00
|
|
|
var componentElement = isPresent(container) ? container.nativeElement : null;
|
2015-07-23 18:01:34 -07:00
|
|
|
var directive = isPresent(directiveIndex) ? this.getDirectiveFor(directiveIndex) : null;
|
|
|
|
var injector = isPresent(ei) ? ei.getInjector() : null;
|
|
|
|
|
2015-07-27 15:47:42 -07:00
|
|
|
return new DebugContext(element, componentElement, directive, this.context,
|
|
|
|
_localsToStringMap(this.locals), injector);
|
|
|
|
|
2015-07-23 18:01:34 -07:00
|
|
|
} catch (e) {
|
|
|
|
// TODO: vsavkin log the exception once we have a good way to log errors and warnings
|
2015-09-30 15:28:26 -07:00
|
|
|
// if an error happens during getting the debug context, we return null.
|
2015-07-27 15:47:42 -07:00
|
|
|
return null;
|
2015-07-23 18:01:34 -07:00
|
|
|
}
|
2015-07-22 12:00:35 -07:00
|
|
|
}
|
|
|
|
|
2015-06-26 11:10:52 -07:00
|
|
|
getDetectorFor(directive: DirectiveIndex): any {
|
2015-06-24 13:46:39 -07:00
|
|
|
var childView = this.getNestedView(this.elementOffset + directive.elementIndex);
|
2015-04-24 17:53:06 -07:00
|
|
|
return isPresent(childView) ? childView.changeDetector : null;
|
2015-04-14 08:54:09 -07:00
|
|
|
}
|
|
|
|
|
2015-08-28 11:29:19 -07:00
|
|
|
invokeElementMethod(elementIndex: number, methodName: string, args: any[]) {
|
2015-06-23 11:21:56 -07:00
|
|
|
this.renderer.invokeElementMethod(this.elementRefs[elementIndex], methodName, args);
|
2015-05-11 12:31:16 -07:00
|
|
|
}
|
|
|
|
|
2015-06-24 13:46:39 -07:00
|
|
|
// implementation of RenderEventDispatcher#dispatchRenderEvent
|
2015-10-01 10:07:49 -07:00
|
|
|
dispatchRenderEvent(boundElementIndex: number, eventName: string,
|
2015-06-24 13:46:39 -07:00
|
|
|
locals: Map<string, any>): boolean {
|
2015-10-01 10:07:49 -07:00
|
|
|
var elementRef = this.elementRefs[boundElementIndex];
|
2015-06-24 13:46:39 -07:00
|
|
|
var view = internalView(elementRef.parentView);
|
|
|
|
return view.dispatchEvent(elementRef.boundElementIndex, eventName, locals);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-16 18:03:15 +02:00
|
|
|
// returns false if preventDefault must be applied to the DOM event
|
2015-06-24 13:46:39 -07:00
|
|
|
dispatchEvent(boundElementIndex: number, eventName: string, locals: Map<string, any>): boolean {
|
2015-07-27 15:47:42 -07:00
|
|
|
try {
|
|
|
|
if (this.hydrated()) {
|
2015-08-12 16:26:21 -07:00
|
|
|
return !this.changeDetector.handleEvent(eventName, boundElementIndex - this.elementOffset,
|
|
|
|
new Locals(this.locals, locals));
|
|
|
|
} else {
|
|
|
|
return true;
|
2015-07-27 15:47:42 -07:00
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
var c = this.getDebugContext(boundElementIndex - this.elementOffset, null);
|
|
|
|
var context = isPresent(c) ? new _Context(c.element, c.componentElement, c.context, c.locals,
|
|
|
|
c.injector) :
|
|
|
|
null;
|
|
|
|
throw new EventEvaluationError(eventName, e, e.stack, context);
|
2014-12-02 17:09:46 -08:00
|
|
|
}
|
|
|
|
}
|
2015-08-18 21:51:28 -07:00
|
|
|
|
|
|
|
get ownBindersCount(): number { return this.proto.elementBinders.length; }
|
2014-09-28 16:29:11 -07:00
|
|
|
}
|
|
|
|
|
2015-10-02 16:47:54 -07:00
|
|
|
function _localsToStringMap(locals: Locals): {[key: string]: any} {
|
2015-07-23 18:01:34 -07:00
|
|
|
var res = {};
|
|
|
|
var c = locals;
|
|
|
|
while (isPresent(c)) {
|
|
|
|
res = StringMapWrapper.merge(res, MapWrapper.toStringMap(c.current));
|
|
|
|
c = c.parent;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-07-27 15:47:42 -07:00
|
|
|
/**
|
|
|
|
* Error context included when an event handler throws an exception.
|
|
|
|
*/
|
|
|
|
class _Context {
|
|
|
|
constructor(public element: any, public componentElement: any, public context: any,
|
|
|
|
public locals: any, public injector: any) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wraps an exception thrown by an event handler.
|
|
|
|
*/
|
2015-09-10 15:25:36 -07:00
|
|
|
class EventEvaluationError extends WrappedException {
|
2015-07-27 15:47:42 -07:00
|
|
|
constructor(eventName: string, originalException: any, originalStack: any, context: any) {
|
|
|
|
super(`Error during evaluation of "${eventName}"`, originalException, originalStack, context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-01 10:07:49 -07:00
|
|
|
export class AppProtoViewMergeInfo {
|
|
|
|
constructor(public embeddedViewCount: number, public elementCount: number,
|
|
|
|
public viewCount: number) {}
|
|
|
|
}
|
2015-07-27 15:47:42 -07:00
|
|
|
|
2015-03-17 19:22:13 +00:00
|
|
|
/**
|
2015-03-31 22:47:11 +00:00
|
|
|
*
|
2015-03-17 19:22:13 +00:00
|
|
|
*/
|
2015-04-09 21:20:11 +02:00
|
|
|
export class AppProtoView {
|
2015-07-17 08:03:40 -07:00
|
|
|
ref: ProtoViewRef;
|
2015-10-01 10:07:49 -07:00
|
|
|
protoLocals: Map<string, any>;
|
|
|
|
|
|
|
|
elementBinders: ElementBinder[] = null;
|
|
|
|
mergeInfo: AppProtoViewMergeInfo = null;
|
|
|
|
variableLocations: Map<string, number> = null;
|
|
|
|
textBindingCount = null;
|
|
|
|
render: renderApi.RenderProtoViewRef = null;
|
2015-05-20 09:48:15 -07:00
|
|
|
|
2015-11-02 08:39:14 -08:00
|
|
|
constructor(public templateId: string, public templateCmds: TemplateCmd[], public type: ViewType,
|
|
|
|
public isMergable: boolean, public changeDetectorFactory: Function,
|
2015-10-01 10:07:49 -07:00
|
|
|
public templateVariableBindings: Map<string, string>, public pipes: ProtoPipes) {
|
2015-10-06 06:53:39 -07:00
|
|
|
this.ref = new ProtoViewRef_(this);
|
2015-10-01 10:07:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
init(render: renderApi.RenderProtoViewRef, elementBinders: ElementBinder[],
|
|
|
|
textBindingCount: number, mergeInfo: AppProtoViewMergeInfo,
|
|
|
|
variableLocations: Map<string, number>) {
|
|
|
|
this.render = render;
|
|
|
|
this.elementBinders = elementBinders;
|
|
|
|
this.textBindingCount = textBindingCount;
|
|
|
|
this.mergeInfo = mergeInfo;
|
|
|
|
this.variableLocations = variableLocations;
|
|
|
|
this.protoLocals = new Map<string, any>();
|
|
|
|
if (isPresent(this.templateVariableBindings)) {
|
2015-10-08 16:01:18 -07:00
|
|
|
this.templateVariableBindings.forEach(
|
|
|
|
(templateName, _) => { this.protoLocals.set(templateName, null); });
|
2015-05-11 17:59:39 -07:00
|
|
|
}
|
2015-10-01 10:07:49 -07:00
|
|
|
if (isPresent(variableLocations)) {
|
|
|
|
// The view's locals needs to have a full set of variable names at construction time
|
|
|
|
// in order to prevent new variables from being set later in the lifecycle. Since we don't
|
|
|
|
// want
|
|
|
|
// to actually create variable bindings for the $implicit bindings, add to the
|
|
|
|
// protoLocals manually.
|
2015-10-08 16:01:18 -07:00
|
|
|
variableLocations.forEach((_, templateName) => { this.protoLocals.set(templateName, null); });
|
2015-10-01 10:07:49 -07:00
|
|
|
}
|
2014-11-18 16:38:36 -08:00
|
|
|
}
|
|
|
|
|
2015-10-01 10:07:49 -07:00
|
|
|
isInitialized(): boolean { return isPresent(this.elementBinders); }
|
2015-10-02 16:47:54 -07:00
|
|
|
}
|