2015-02-27 14:50:06 -08:00
|
|
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
2015-02-24 16:05:45 +01:00
|
|
|
import {Promise} from 'angular2/src/facade/async';
|
2015-03-06 15:44:59 +01:00
|
|
|
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
2015-03-11 21:11:39 -07:00
|
|
|
import {AST, Locals, ChangeDispatcher, ProtoChangeDetector, ChangeDetector,
|
2015-02-27 13:38:25 -08:00
|
|
|
ChangeRecord, BindingRecord, BindingPropagationConfig, uninitialized} from 'angular2/change_detection';
|
2014-11-13 15:15:55 -08:00
|
|
|
|
2015-04-02 14:40:49 -07:00
|
|
|
import {ProtoElementInjector, ElementInjector, PreBuiltObjects, DirectiveBinding} from './element_injector';
|
2014-11-11 17:33:47 -08:00
|
|
|
import {ElementBinder} from './element_binder';
|
2015-02-05 13:08:05 -08:00
|
|
|
import {SetterFn} from 'angular2/src/reflection/types';
|
2015-03-11 16:45:36 +01:00
|
|
|
import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
2015-02-05 13:08:05 -08:00
|
|
|
import {Injector} from 'angular2/di';
|
|
|
|
import {NgElement} from 'angular2/src/core/dom/element';
|
2015-02-12 11:54:22 +01:00
|
|
|
import {ViewContainer} from './view_container';
|
2015-03-16 11:31:58 -07:00
|
|
|
import {LightDom} from './shadow_dom_emulation/light_dom';
|
|
|
|
import {Content} from './shadow_dom_emulation/content_tag';
|
2015-01-30 09:43:21 +01:00
|
|
|
import {ShadowDomStrategy} from './shadow_dom_strategy';
|
2015-02-06 17:03:40 -08:00
|
|
|
import {ViewPool} from './view_pool';
|
2015-04-02 09:52:00 -07:00
|
|
|
import {EventManager} from 'angular2/src/render/dom/events/event_manager';
|
2015-04-07 17:24:09 -07:00
|
|
|
import * as renderApi from 'angular2/src/render/api';
|
2014-09-28 16:29:11 -07:00
|
|
|
|
2014-11-11 17:33:47 -08:00
|
|
|
const NG_BINDING_CLASS = 'ng-binding';
|
2014-12-09 10:31:19 -08:00
|
|
|
const NG_BINDING_CLASS_SELECTOR = '.ng-binding';
|
2014-11-11 17:33:47 -08:00
|
|
|
|
2015-02-06 17:03:40 -08:00
|
|
|
// TODO(rado): make this configurable/smarter.
|
|
|
|
var VIEW_POOL_CAPACITY = 10000;
|
|
|
|
var VIEW_POOL_PREFILL = 0;
|
|
|
|
|
2014-11-21 15:13:01 -08:00
|
|
|
/**
|
2014-10-10 20:44:55 -07:00
|
|
|
* Const of making objects: http://jsperf.com/instantiate-size-of-object
|
2015-03-31 22:47:11 +00:00
|
|
|
*
|
|
|
|
* @publicModule angular2/template
|
2014-10-10 20:44:55 -07:00
|
|
|
*/
|
2014-12-04 13:16:38 +01:00
|
|
|
@IMPLEMENTS(ChangeDispatcher)
|
2014-09-28 16:29:11 -07:00
|
|
|
export class View {
|
|
|
|
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector
|
2014-11-21 21:19:23 -08:00
|
|
|
rootElementInjectors:List<ElementInjector>;
|
|
|
|
elementInjectors:List<ElementInjector>;
|
2015-02-27 14:50:06 -08:00
|
|
|
bindElements:List;
|
|
|
|
textNodes:List;
|
2015-01-14 13:51:16 -08:00
|
|
|
changeDetector:ChangeDetector;
|
2014-09-28 16:29:11 -07:00
|
|
|
/// When the view is part of render tree, the DocumentFragment is empty, which is why we need
|
|
|
|
/// to keep track of the nodes.
|
2015-02-27 14:50:06 -08:00
|
|
|
nodes:List;
|
2014-11-21 15:13:01 -08:00
|
|
|
componentChildViews: List<View>;
|
2015-02-12 11:54:22 +01:00
|
|
|
viewContainers: List<ViewContainer>;
|
2015-03-16 11:31:58 -07:00
|
|
|
contentTags: List<Content>;
|
2014-12-01 18:41:55 -08:00
|
|
|
preBuiltObjects: List<PreBuiltObjects>;
|
2015-03-16 11:31:58 -07:00
|
|
|
lightDoms: List<LightDom>;
|
2014-12-01 18:41:55 -08:00
|
|
|
proto: ProtoView;
|
2014-12-29 12:12:11 -08:00
|
|
|
context: any;
|
2015-03-11 21:11:39 -07:00
|
|
|
locals:Locals;
|
2015-01-02 14:23:59 -08:00
|
|
|
|
2015-03-11 21:11:39 -07:00
|
|
|
constructor(proto:ProtoView, nodes:List, protoLocals:Map) {
|
2014-12-01 18:41:55 -08:00
|
|
|
this.proto = proto;
|
2014-11-11 17:33:47 -08:00
|
|
|
this.nodes = nodes;
|
2015-03-11 21:43:22 -07:00
|
|
|
this.changeDetector = null;
|
2014-12-09 10:31:19 -08:00
|
|
|
this.elementInjectors = null;
|
|
|
|
this.rootElementInjectors = null;
|
|
|
|
this.textNodes = null;
|
|
|
|
this.bindElements = null;
|
2014-11-21 15:13:01 -08:00
|
|
|
this.componentChildViews = null;
|
2015-02-12 11:54:22 +01:00
|
|
|
this.viewContainers = null;
|
2015-03-16 11:31:58 -07:00
|
|
|
this.contentTags = null;
|
2014-12-01 18:41:55 -08:00
|
|
|
this.preBuiltObjects = null;
|
2015-03-16 11:31:58 -07:00
|
|
|
this.lightDoms = null;
|
2014-12-01 18:41:55 -08:00
|
|
|
this.context = null;
|
2015-03-11 21:11:39 -07:00
|
|
|
this.locals = new Locals(null, MapWrapper.clone(protoLocals)); //TODO optimize this
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
2015-03-11 21:43:22 -07:00
|
|
|
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List,
|
2015-03-16 11:31:58 -07:00
|
|
|
viewContainers:List, contentTags:List, preBuiltObjects:List, componentChildViews:List, lightDoms:List<LightDom>) {
|
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.textNodes = textNodes;
|
|
|
|
this.bindElements = bindElements;
|
2015-02-12 11:54:22 +01:00
|
|
|
this.viewContainers = viewContainers;
|
2015-03-16 11:31:58 -07:00
|
|
|
this.contentTags = contentTags;
|
2014-12-09 10:31:19 -08:00
|
|
|
this.preBuiltObjects = preBuiltObjects;
|
|
|
|
this.componentChildViews = componentChildViews;
|
2015-03-16 11:31:58 -07:00
|
|
|
this.lightDoms = lightDoms;
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
setLocal(contextName: string, value) {
|
|
|
|
if (!this.hydrated()) throw new BaseException('Cannot set locals on dehydrated view.');
|
|
|
|
if (!MapWrapper.contains(this.proto.variableBindings, contextName)) {
|
2015-01-28 00:42:08 +01:00
|
|
|
return;
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
var templateName = MapWrapper.get(this.proto.variableBindings, contextName);
|
2015-03-11 21:11:39 -07:00
|
|
|
this.locals.set(templateName, value);
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
hydrated() {
|
|
|
|
return isPresent(this.context);
|
|
|
|
}
|
|
|
|
|
2015-03-11 21:11:39 -07:00
|
|
|
_hydrateContext(newContext, locals) {
|
|
|
|
this.context = newContext;
|
|
|
|
this.locals.parent = locals;
|
|
|
|
this.changeDetector.hydrate(this.context, this.locals);
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
_dehydrateContext() {
|
2015-03-11 21:11:39 -07:00
|
|
|
if (isPresent(this.locals)) {
|
|
|
|
this.locals.clearValues();
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
this.context = null;
|
2015-02-27 07:56:50 -08:00
|
|
|
this.changeDetector.dehydrate();
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A dehydrated view is a state of the view that allows it to be moved around
|
|
|
|
* the view tree, without incurring the cost of recreating the underlying
|
|
|
|
* injectors and watch records.
|
|
|
|
*
|
|
|
|
* A dehydrated view has the following properties:
|
|
|
|
*
|
|
|
|
* - all element injectors are empty.
|
|
|
|
* - all appInjectors are released.
|
2015-02-12 11:54:22 +01:00
|
|
|
* - all viewcontainers are empty.
|
2014-12-01 18:41:55 -08:00
|
|
|
* - all context locals are set to null.
|
|
|
|
* - the view context is null.
|
|
|
|
*
|
|
|
|
* A call to hydrate/dehydrate does not attach/detach the view from the view
|
|
|
|
* tree.
|
|
|
|
*/
|
2015-03-16 11:31:58 -07:00
|
|
|
hydrate(appInjector: Injector, hostElementInjector: ElementInjector, hostLightDom: LightDom,
|
2015-03-11 21:11:39 -07:00
|
|
|
context: Object, locals:Locals) {
|
2014-12-09 10:31:19 -08:00
|
|
|
if (this.hydrated()) throw new BaseException('The view is already hydrated.');
|
2015-03-11 21:11:39 -07:00
|
|
|
this._hydrateContext(context, locals);
|
2014-12-01 18:41:55 -08:00
|
|
|
|
2015-02-12 11:54:22 +01:00
|
|
|
// viewContainers
|
|
|
|
for (var i = 0; i < this.viewContainers.length; i++) {
|
2015-03-16 11:31:58 -07:00
|
|
|
var vc = this.viewContainers[i];
|
|
|
|
if (isPresent(vc)) {
|
|
|
|
vc.hydrate(appInjector, hostElementInjector, hostLightDom);
|
|
|
|
}
|
2014-12-09 10:31:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
var binders = this.proto.elementBinders;
|
|
|
|
var componentChildViewIndex = 0;
|
|
|
|
for (var i = 0; i < binders.length; ++i) {
|
|
|
|
var componentDirective = binders[i].componentDirective;
|
|
|
|
var shadowDomAppInjector = null;
|
2014-12-01 18:41:55 -08:00
|
|
|
|
2014-12-09 10:31:19 -08:00
|
|
|
// shadowDomAppInjector
|
|
|
|
if (isPresent(componentDirective)) {
|
2015-03-11 16:48:57 -07:00
|
|
|
var services = componentDirective.annotation.services;
|
2014-12-09 10:31:19 -08:00
|
|
|
if (isPresent(services))
|
|
|
|
shadowDomAppInjector = appInjector.createChild(services);
|
|
|
|
else {
|
|
|
|
shadowDomAppInjector = appInjector;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
shadowDomAppInjector = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// elementInjectors
|
|
|
|
var elementInjector = this.elementInjectors[i];
|
|
|
|
if (isPresent(elementInjector)) {
|
|
|
|
elementInjector.instantiateDirectives(appInjector, shadowDomAppInjector, this.preBuiltObjects[i]);
|
2015-02-06 12:17:34 -08:00
|
|
|
|
|
|
|
// The exporting of $implicit is a special case. Since multiple elements will all export
|
|
|
|
// the different values as $implicit, directly assign $implicit bindings to the variable
|
|
|
|
// name.
|
|
|
|
var exportImplicitName = elementInjector.getExportImplicitName();
|
|
|
|
if (elementInjector.isExportingComponent()) {
|
2015-03-11 21:11:39 -07:00
|
|
|
this.locals.set(exportImplicitName, elementInjector.getComponent());
|
2015-02-06 12:17:34 -08:00
|
|
|
} else if (elementInjector.isExportingElement()) {
|
2015-03-11 21:11:39 -07:00
|
|
|
this.locals.set(exportImplicitName, elementInjector.getNgElement().domElement);
|
2015-02-06 12:17:34 -08:00
|
|
|
}
|
2014-12-09 10:31:19 -08:00
|
|
|
}
|
|
|
|
|
2015-03-13 11:33:57 -07:00
|
|
|
if (isPresent(binders[i].nestedProtoView) && isPresent(componentDirective)) {
|
2014-12-09 10:31:19 -08:00
|
|
|
this.componentChildViews[componentChildViewIndex++].hydrate(shadowDomAppInjector,
|
2015-03-11 21:11:39 -07:00
|
|
|
elementInjector, this.lightDoms[i], elementInjector.getComponent(), null);
|
2015-01-08 09:11:33 -08:00
|
|
|
}
|
|
|
|
}
|
2015-01-02 14:23:59 -08:00
|
|
|
|
2015-03-16 11:31:58 -07:00
|
|
|
for (var i = 0; i < this.lightDoms.length; ++i) {
|
|
|
|
var lightDom = this.lightDoms[i];
|
|
|
|
if (isPresent(lightDom)) {
|
|
|
|
lightDom.redistribute();
|
2014-12-09 10:31:19 -08:00
|
|
|
}
|
|
|
|
}
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
dehydrate() {
|
2014-12-09 10:31:19 -08:00
|
|
|
// Note: preserve the opposite order of the hydration process.
|
|
|
|
|
|
|
|
// componentChildViews
|
|
|
|
for (var i = 0; i < this.componentChildViews.length; i++) {
|
|
|
|
this.componentChildViews[i].dehydrate();
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
2014-12-09 10:31:19 -08:00
|
|
|
|
|
|
|
// elementInjectors
|
2014-12-01 18:41:55 -08:00
|
|
|
for (var i = 0; i < this.elementInjectors.length; i++) {
|
2015-01-13 16:17:43 -08:00
|
|
|
if (isPresent(this.elementInjectors[i])) {
|
|
|
|
this.elementInjectors[i].clearDirectives();
|
|
|
|
}
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
2014-12-09 10:31:19 -08:00
|
|
|
|
2015-02-12 11:54:22 +01:00
|
|
|
// viewContainers
|
|
|
|
if (isPresent(this.viewContainers)) {
|
|
|
|
for (var i = 0; i < this.viewContainers.length; i++) {
|
2015-03-16 11:31:58 -07:00
|
|
|
var vc = this.viewContainers[i];
|
|
|
|
if (isPresent(vc)) {
|
|
|
|
vc.dehydrate();
|
|
|
|
}
|
2014-12-01 18:41:55 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-09 10:31:19 -08:00
|
|
|
this._dehydrateContext();
|
2014-09-28 16:29:11 -07: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
|
|
|
|
* @param {int} binderIndex
|
|
|
|
*/
|
|
|
|
triggerEventHandlers(eventName: string, eventObj, binderIndex: int) {
|
|
|
|
var handlers = this.proto.eventHandlers[binderIndex];
|
|
|
|
if (isBlank(handlers)) return;
|
|
|
|
var handler = StringMapWrapper.get(handlers, eventName);
|
|
|
|
if (isBlank(handler)) return;
|
|
|
|
handler(eventObj, this);
|
|
|
|
}
|
|
|
|
|
2015-03-31 09:07:01 -07:00
|
|
|
onAllChangesDone(directiveMemento:DirectiveMemento) {
|
2015-03-26 14:36:25 -07:00
|
|
|
var dir = directiveMemento.directive(this.elementInjectors);
|
|
|
|
dir.onAllChangesDone();
|
|
|
|
}
|
|
|
|
|
2015-03-31 09:07:01 -07:00
|
|
|
onChange(directiveMemento:DirectiveMemento, changes) {
|
2015-02-06 13:35:05 -08:00
|
|
|
var dir = directiveMemento.directive(this.elementInjectors);
|
2015-03-31 09:07:01 -07:00
|
|
|
dir.onChange(changes);
|
2014-12-02 17:09:46 -08:00
|
|
|
}
|
|
|
|
|
2015-03-31 09:07:01 -07:00
|
|
|
// dispatch to element injector or text nodes based on context
|
|
|
|
invokeMementoFor(memento:any, currentValue:any) {
|
2015-02-06 13:35:05 -08:00
|
|
|
if (memento instanceof DirectiveBindingMemento) {
|
|
|
|
var directiveMemento:DirectiveBindingMemento = memento;
|
2015-03-31 09:07:01 -07:00
|
|
|
directiveMemento.invoke(currentValue, this.elementInjectors);
|
2014-12-02 17:09:46 -08:00
|
|
|
|
2015-02-06 13:35:05 -08:00
|
|
|
} else if (memento instanceof ElementBindingMemento) {
|
|
|
|
var elementMemento:ElementBindingMemento = memento;
|
2015-03-31 09:07:01 -07:00
|
|
|
elementMemento.invoke(currentValue, this.bindElements);
|
2014-12-02 17:09:46 -08:00
|
|
|
|
2014-09-28 16:29:11 -07:00
|
|
|
} else {
|
2014-10-10 20:44:55 -07:00
|
|
|
// we know it refers to _textNodes.
|
2014-12-02 17:09:46 -08:00
|
|
|
var textNodeIndex:number = memento;
|
2015-03-31 09:07:01 -07:00
|
|
|
DOM.setText(this.textNodes[textNodeIndex], currentValue);
|
2014-12-02 17:09:46 -08:00
|
|
|
}
|
|
|
|
}
|
2014-09-28 16:29:11 -07:00
|
|
|
}
|
|
|
|
|
2015-03-17 19:22:13 +00:00
|
|
|
/**
|
2015-03-31 22:47:11 +00:00
|
|
|
*
|
|
|
|
* @publicModule angular2/template
|
2015-03-17 19:22:13 +00:00
|
|
|
*/
|
2014-09-28 20:02:32 -07:00
|
|
|
export class ProtoView {
|
2015-02-27 14:50:06 -08:00
|
|
|
element;
|
2014-11-21 21:19:23 -08:00
|
|
|
elementBinders:List<ElementBinder>;
|
2015-01-14 13:51:16 -08:00
|
|
|
protoChangeDetector:ProtoChangeDetector;
|
2014-11-21 21:19:23 -08:00
|
|
|
variableBindings: Map;
|
2015-03-11 21:11:39 -07:00
|
|
|
protoLocals:Map;
|
2014-11-21 21:19:23 -08:00
|
|
|
textNodesWithBindingCount:int;
|
|
|
|
elementsWithBindingCount:int;
|
2014-12-09 10:31:19 -08:00
|
|
|
instantiateInPlace:boolean;
|
|
|
|
rootBindingOffset:int;
|
|
|
|
isTemplateElement:boolean;
|
2015-01-30 09:43:21 +01:00
|
|
|
shadowDomStrategy: ShadowDomStrategy;
|
2015-02-06 17:03:40 -08:00
|
|
|
_viewPool: ViewPool;
|
2015-02-24 16:05:45 +01:00
|
|
|
stylePromises: List<Promise>;
|
2015-03-10 10:03:26 +01:00
|
|
|
// List<Map<eventName, handler>>, indexed by binder index
|
2015-03-11 21:43:22 -07:00
|
|
|
eventHandlers:List;
|
|
|
|
bindingRecords:List;
|
2015-03-11 21:11:39 -07:00
|
|
|
parentProtoView:ProtoView;
|
|
|
|
_variableBindings:List;
|
2015-02-24 16:05:45 +01:00
|
|
|
|
2015-04-02 09:52:00 -07:00
|
|
|
_directiveMementosMap:Map;
|
2015-03-26 14:36:25 -07:00
|
|
|
_directiveMementos:List;
|
2015-04-07 17:24:09 -07:00
|
|
|
render:renderApi.ProtoViewRef;
|
2015-03-26 14:36:25 -07:00
|
|
|
|
2014-09-28 20:02:32 -07:00
|
|
|
constructor(
|
2015-04-07 17:24:09 -07:00
|
|
|
render:renderApi.ProtoViewRef,
|
2015-02-27 14:50:06 -08:00
|
|
|
template,
|
2015-01-30 09:43:21 +01:00
|
|
|
protoChangeDetector:ProtoChangeDetector,
|
2015-03-11 21:11:39 -07:00
|
|
|
shadowDomStrategy:ShadowDomStrategy, parentProtoView:ProtoView = null) {
|
2015-04-07 17:24:09 -07:00
|
|
|
this.render = render;
|
2014-11-11 17:33:47 -08:00
|
|
|
this.element = template;
|
|
|
|
this.elementBinders = [];
|
2014-11-18 16:38:36 -08:00
|
|
|
this.variableBindings = MapWrapper.create();
|
2015-03-11 21:11:39 -07:00
|
|
|
this.protoLocals = MapWrapper.create();
|
2015-01-14 13:51:16 -08:00
|
|
|
this.protoChangeDetector = protoChangeDetector;
|
2015-03-11 21:11:39 -07:00
|
|
|
this.parentProtoView = parentProtoView;
|
2014-11-11 17:33:47 -08:00
|
|
|
this.textNodesWithBindingCount = 0;
|
|
|
|
this.elementsWithBindingCount = 0;
|
2014-12-09 10:31:19 -08:00
|
|
|
this.instantiateInPlace = false;
|
2015-01-08 12:16:37 -08:00
|
|
|
this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS))
|
|
|
|
? 1 : 0;
|
2015-02-19 11:18:23 +01:00
|
|
|
this.isTemplateElement = DOM.isTemplateElement(this.element);
|
2015-01-30 09:43:21 +01:00
|
|
|
this.shadowDomStrategy = shadowDomStrategy;
|
2015-02-06 17:03:40 -08:00
|
|
|
this._viewPool = new ViewPool(VIEW_POOL_CAPACITY);
|
2015-02-24 16:05:45 +01:00
|
|
|
this.stylePromises = [];
|
2015-03-10 10:03:26 +01:00
|
|
|
this.eventHandlers = [];
|
2015-03-11 21:43:22 -07:00
|
|
|
this.bindingRecords = [];
|
2015-03-26 14:36:25 -07:00
|
|
|
this._directiveMementosMap = MapWrapper.create();
|
2015-03-11 21:11:39 -07:00
|
|
|
this._variableBindings = null;
|
2015-03-26 14:36:25 -07:00
|
|
|
this._directiveMementos = null;
|
2014-09-28 20:02:32 -07:00
|
|
|
}
|
|
|
|
|
2014-12-01 18:41:55 -08:00
|
|
|
// TODO(rado): hostElementInjector should be moved to hydrate phase.
|
2015-03-11 19:57:21 +01:00
|
|
|
instantiate(hostElementInjector: ElementInjector, eventManager: EventManager):View {
|
|
|
|
if (this._viewPool.length() == 0) this._preFillPool(hostElementInjector, eventManager);
|
2015-02-06 17:03:40 -08:00
|
|
|
var view = this._viewPool.pop();
|
2015-03-11 19:57:21 +01:00
|
|
|
return isPresent(view) ? view : this._instantiate(hostElementInjector, eventManager);
|
2015-02-06 17:03:40 -08:00
|
|
|
}
|
|
|
|
|
2015-03-11 19:57:21 +01:00
|
|
|
_preFillPool(hostElementInjector: ElementInjector, eventManager: EventManager) {
|
2015-02-06 17:03:40 -08:00
|
|
|
for (var i = 0; i < VIEW_POOL_PREFILL; i++) {
|
2015-03-11 19:57:21 +01:00
|
|
|
this._viewPool.push(this._instantiate(hostElementInjector, eventManager));
|
2015-02-06 17:03:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-27 11:02:55 -07:00
|
|
|
//TODO: Tobias or Victor. Moving it into the constructor.
|
2015-03-11 21:11:39 -07:00
|
|
|
// this work should be done the constructor of ProtoView once we separate
|
|
|
|
// ProtoView and ProtoViewBuilder
|
|
|
|
_getVariableBindings() {
|
|
|
|
if (isPresent(this._variableBindings)) {
|
|
|
|
return this._variableBindings;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._variableBindings = isPresent(this.parentProtoView) ?
|
|
|
|
ListWrapper.clone(this.parentProtoView._getVariableBindings()) : [];
|
|
|
|
|
|
|
|
MapWrapper.forEach(this.protoLocals, (v, local) => {
|
|
|
|
ListWrapper.push(this._variableBindings, local);
|
|
|
|
});
|
|
|
|
|
|
|
|
return this._variableBindings;
|
|
|
|
}
|
|
|
|
|
2015-03-27 11:02:55 -07:00
|
|
|
//TODO: Tobias or Victor. Moving it into the constructor.
|
2015-03-26 14:36:25 -07:00
|
|
|
// this work should be done the constructor of ProtoView once we separate
|
|
|
|
// ProtoView and ProtoViewBuilder
|
|
|
|
_getDirectiveMementos() {
|
|
|
|
if (isPresent(this._directiveMementos)) {
|
|
|
|
return this._directiveMementos;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._directiveMementos = [];
|
|
|
|
|
|
|
|
for (var injectorIndex = 0; injectorIndex < this.elementBinders.length; ++injectorIndex) {
|
|
|
|
var pei = this.elementBinders[injectorIndex].protoElementInjector;
|
|
|
|
if (isPresent(pei)) {
|
|
|
|
for (var directiveIndex = 0; directiveIndex < pei.numberOfDirectives; ++directiveIndex) {
|
|
|
|
ListWrapper.push(this._directiveMementos, this._getDirectiveMemento(injectorIndex, directiveIndex));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this._directiveMementos;
|
|
|
|
}
|
|
|
|
|
2015-03-11 19:57:21 +01:00
|
|
|
_instantiate(hostElementInjector: ElementInjector, eventManager: EventManager): View {
|
2015-02-19 16:18:46 -08:00
|
|
|
var rootElementClone = this.instantiateInPlace ? this.element : DOM.importIntoDoc(this.element);
|
2015-01-02 14:23:59 -08:00
|
|
|
var elementsWithBindingsDynamic;
|
2014-12-09 10:31:19 -08:00
|
|
|
if (this.isTemplateElement) {
|
2015-02-19 11:18:23 +01:00
|
|
|
elementsWithBindingsDynamic = DOM.querySelectorAll(DOM.content(rootElementClone), NG_BINDING_CLASS_SELECTOR);
|
2014-11-14 10:37:42 -08:00
|
|
|
} else {
|
2015-01-02 14:23:59 -08:00
|
|
|
elementsWithBindingsDynamic= DOM.getElementsByClassName(rootElementClone, NG_BINDING_CLASS);
|
2014-11-14 10:37:42 -08:00
|
|
|
}
|
2015-01-02 14:23:59 -08:00
|
|
|
|
|
|
|
var elementsWithBindings = ListWrapper.createFixedSize(elementsWithBindingsDynamic.length);
|
2015-03-06 15:44:59 +01:00
|
|
|
for (var binderIdx = 0; binderIdx < elementsWithBindingsDynamic.length; ++binderIdx) {
|
|
|
|
elementsWithBindings[binderIdx] = elementsWithBindingsDynamic[binderIdx];
|
2015-01-02 14:23:59 -08:00
|
|
|
}
|
|
|
|
|
2014-12-09 10:31:19 -08:00
|
|
|
var viewNodes;
|
|
|
|
if (this.isTemplateElement) {
|
2015-02-19 11:18:23 +01:00
|
|
|
var childNode = DOM.firstChild(DOM.content(rootElementClone));
|
2014-12-11 16:07:49 -08:00
|
|
|
viewNodes = []; // TODO(perf): Should be fixed size, since we could pre-compute in in ProtoView
|
|
|
|
// Note: An explicit loop is the fastest way to convert a DOM array into a JS array!
|
|
|
|
while(childNode != null) {
|
|
|
|
ListWrapper.push(viewNodes, childNode);
|
|
|
|
childNode = DOM.nextSibling(childNode);
|
2014-12-09 10:31:19 -08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
viewNodes = [rootElementClone];
|
2014-11-11 17:33:47 -08:00
|
|
|
}
|
2014-12-09 10:31:19 -08:00
|
|
|
|
2015-03-11 21:11:39 -07:00
|
|
|
var view = new View(this, viewNodes, this.protoLocals);
|
2015-03-26 14:36:25 -07:00
|
|
|
var changeDetector = this.protoChangeDetector.instantiate(view, this.bindingRecords,
|
|
|
|
this._getVariableBindings(), this._getDirectiveMementos());
|
|
|
|
|
2014-11-11 17:33:47 -08:00
|
|
|
var binders = this.elementBinders;
|
2014-12-09 10:31:19 -08:00
|
|
|
var elementInjectors = ListWrapper.createFixedSize(binders.length);
|
2015-03-10 10:03:26 +01:00
|
|
|
var eventHandlers = ListWrapper.createFixedSize(binders.length);
|
2014-12-09 10:31:19 -08:00
|
|
|
var rootElementInjectors = [];
|
|
|
|
var textNodes = [];
|
|
|
|
var elementsWithPropertyBindings = [];
|
|
|
|
var preBuiltObjects = ListWrapper.createFixedSize(binders.length);
|
2015-03-16 11:31:58 -07:00
|
|
|
var viewContainers = ListWrapper.createFixedSize(binders.length);
|
|
|
|
var contentTags = ListWrapper.createFixedSize(binders.length);
|
2014-12-09 10:31:19 -08:00
|
|
|
var componentChildViews = [];
|
2015-03-16 11:31:58 -07:00
|
|
|
var lightDoms = ListWrapper.createFixedSize(binders.length);
|
2014-10-27 11:47:13 -04:00
|
|
|
|
2015-03-06 15:44:59 +01:00
|
|
|
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
|
|
|
|
var binder = binders[binderIdx];
|
2014-12-09 10:31:19 -08:00
|
|
|
var element;
|
2015-03-06 15:44:59 +01:00
|
|
|
if (binderIdx === 0 && this.rootBindingOffset === 1) {
|
2014-12-09 10:31:19 -08:00
|
|
|
element = rootElementClone;
|
|
|
|
} else {
|
2015-03-06 15:44:59 +01:00
|
|
|
element = elementsWithBindings[binderIdx - this.rootBindingOffset];
|
2014-12-09 10:31:19 -08:00
|
|
|
}
|
|
|
|
var elementInjector = null;
|
|
|
|
|
|
|
|
// elementInjectors and rootElementInjectors
|
|
|
|
var protoElementInjector = binder.protoElementInjector;
|
|
|
|
if (isPresent(protoElementInjector)) {
|
2015-01-06 13:30:48 +01:00
|
|
|
if (isPresent(protoElementInjector.parent)) {
|
|
|
|
var parentElementInjector = elementInjectors[protoElementInjector.parent.index];
|
2015-03-11 19:57:21 +01:00
|
|
|
elementInjector = protoElementInjector.instantiate(parentElementInjector, null);
|
2015-01-06 13:30:48 +01:00
|
|
|
} else {
|
2015-03-11 19:57:21 +01:00
|
|
|
elementInjector = protoElementInjector.instantiate(null, hostElementInjector);
|
2014-12-09 10:31:19 -08:00
|
|
|
ListWrapper.push(rootElementInjectors, elementInjector);
|
|
|
|
}
|
|
|
|
}
|
2015-03-06 15:44:59 +01:00
|
|
|
elementInjectors[binderIdx] = elementInjector;
|
2014-12-01 18:41:55 -08:00
|
|
|
|
2014-12-09 10:31:19 -08:00
|
|
|
if (binder.hasElementPropertyBindings) {
|
|
|
|
ListWrapper.push(elementsWithPropertyBindings, element);
|
|
|
|
}
|
2014-11-14 10:58:58 -08:00
|
|
|
|
2014-12-09 10:31:19 -08:00
|
|
|
// textNodes
|
|
|
|
var textNodeIndices = binder.textNodeIndices;
|
|
|
|
if (isPresent(textNodeIndices)) {
|
2014-12-11 16:07:49 -08:00
|
|
|
var childNode = DOM.firstChild(DOM.templateAwareRoot(element));
|
|
|
|
for (var j = 0, k = 0; j < textNodeIndices.length; j++) {
|
|
|
|
for(var index = textNodeIndices[j]; k < index; k++) {
|
|
|
|
childNode = DOM.nextSibling(childNode);
|
|
|
|
}
|
|
|
|
ListWrapper.push(textNodes, childNode);
|
2014-12-09 10:31:19 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// componentChildViews
|
2015-01-02 14:23:59 -08:00
|
|
|
var lightDom = null;
|
2015-02-02 17:31:12 -08:00
|
|
|
var bindingPropagationConfig = null;
|
2015-03-13 11:33:57 -07:00
|
|
|
if (isPresent(binder.nestedProtoView) && isPresent(binder.componentDirective)) {
|
2015-01-30 09:43:21 +01:00
|
|
|
var strategy = this.shadowDomStrategy;
|
2015-03-11 19:57:21 +01:00
|
|
|
var childView = binder.nestedProtoView.instantiate(elementInjector, eventManager);
|
2015-03-11 21:43:22 -07:00
|
|
|
changeDetector.addChild(childView.changeDetector);
|
2014-12-23 10:45:20 -08:00
|
|
|
|
2015-01-30 09:43:21 +01:00
|
|
|
lightDom = strategy.constructLightDom(view, childView, element);
|
|
|
|
strategy.attachTemplate(element, childView);
|
2015-01-02 14:23:59 -08:00
|
|
|
|
2015-03-23 17:14:12 -07:00
|
|
|
bindingPropagationConfig = new BindingPropagationConfig(childView.changeDetector);
|
2015-02-02 17:31:12 -08:00
|
|
|
|
2014-12-09 10:31:19 -08:00
|
|
|
ListWrapper.push(componentChildViews, childView);
|
|
|
|
}
|
2015-03-16 11:31:58 -07:00
|
|
|
lightDoms[binderIdx] = lightDom;
|
2015-04-02 09:52:00 -07:00
|
|
|
|
2015-03-16 11:31:58 -07:00
|
|
|
var destLightDom = null;
|
|
|
|
if (isPresent(binder.parent) && binder.distanceToParent === 1) {
|
|
|
|
destLightDom = lightDoms[binder.parent.index];
|
|
|
|
}
|
2015-01-02 14:23:59 -08:00
|
|
|
|
2015-02-12 11:54:22 +01:00
|
|
|
// viewContainers
|
|
|
|
var viewContainer = null;
|
|
|
|
if (isPresent(binder.viewportDirective)) {
|
|
|
|
viewContainer = new ViewContainer(view, element, binder.nestedProtoView, elementInjector,
|
2015-03-11 19:57:21 +01:00
|
|
|
eventManager, destLightDom);
|
2015-01-02 14:23:59 -08:00
|
|
|
}
|
2015-03-16 11:31:58 -07:00
|
|
|
viewContainers[binderIdx] = viewContainer;
|
|
|
|
|
|
|
|
// contentTags
|
|
|
|
var contentTag = null;
|
|
|
|
if (isPresent(binder.contentTagSelector)) {
|
|
|
|
contentTag = new Content(destLightDom, element, binder.contentTagSelector);
|
|
|
|
}
|
|
|
|
contentTags[binderIdx] = contentTag;
|
2015-01-02 14:23:59 -08:00
|
|
|
|
|
|
|
// preBuiltObjects
|
|
|
|
if (isPresent(elementInjector)) {
|
2015-03-06 15:44:59 +01:00
|
|
|
preBuiltObjects[binderIdx] = new PreBuiltObjects(view, new NgElement(element), viewContainer,
|
2015-03-16 11:31:58 -07:00
|
|
|
bindingPropagationConfig);
|
2015-01-02 14:23:59 -08:00
|
|
|
}
|
2015-01-12 11:50:54 -08:00
|
|
|
|
|
|
|
// events
|
|
|
|
if (isPresent(binder.events)) {
|
2015-03-10 10:03:26 +01:00
|
|
|
eventHandlers[binderIdx] = StringMapWrapper.create();
|
2015-03-06 15:44:59 +01:00
|
|
|
StringMapWrapper.forEach(binder.events, (eventMap, eventName) => {
|
2015-03-10 10:03:26 +01:00
|
|
|
var handler = ProtoView.buildEventHandler(eventMap, binderIdx);
|
|
|
|
StringMapWrapper.set(eventHandlers[binderIdx], eventName, handler);
|
2015-01-16 15:30:22 -08:00
|
|
|
if (isBlank(elementInjector) || !elementInjector.hasEventEmitter(eventName)) {
|
2015-03-10 10:03:26 +01:00
|
|
|
eventManager.addEventListener(element, eventName,
|
|
|
|
(event) => { handler(event, view); });
|
2015-01-16 15:30:22 -08:00
|
|
|
}
|
2015-01-12 11:50:54 -08:00
|
|
|
});
|
|
|
|
}
|
2014-12-09 10:31:19 -08:00
|
|
|
}
|
|
|
|
|
2015-03-10 10:03:26 +01:00
|
|
|
this.eventHandlers = eventHandlers;
|
|
|
|
|
2015-03-11 21:43:22 -07:00
|
|
|
view.init(changeDetector, elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
|
2015-03-16 11:31:58 -07:00
|
|
|
viewContainers, contentTags, preBuiltObjects, componentChildViews, lightDoms);
|
2014-11-14 10:58:58 -08:00
|
|
|
|
|
|
|
return view;
|
2014-11-11 17:33:47 -08:00
|
|
|
}
|
|
|
|
|
2015-02-06 17:03:40 -08:00
|
|
|
returnToPool(view: View) {
|
|
|
|
this._viewPool.push(view);
|
|
|
|
}
|
|
|
|
|
2015-03-06 15:44:59 +01:00
|
|
|
/**
|
2015-03-10 10:03:26 +01:00
|
|
|
* Creates an event handler.
|
2015-03-06 15:44:59 +01:00
|
|
|
*
|
|
|
|
* @param {Map} eventMap Map directiveIndexes to expressions
|
|
|
|
* @param {int} injectorIdx
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
2015-03-10 10:03:26 +01:00
|
|
|
static buildEventHandler(eventMap: Map, injectorIdx: int) {
|
2015-01-19 13:00:27 +01:00
|
|
|
var locals = MapWrapper.create();
|
2015-03-10 10:03:26 +01:00
|
|
|
return (event, view) => {
|
2015-03-06 15:44:59 +01:00
|
|
|
// Most of the time the event will be fired only when the view is in the live document.
|
|
|
|
// However, in a rare circumstance the view might get dehydrated, in between the event
|
|
|
|
// queuing up and firing.
|
2015-01-16 15:30:22 -08:00
|
|
|
if (view.hydrated()) {
|
2015-02-09 15:11:31 +01:00
|
|
|
MapWrapper.set(locals, '$event', event);
|
2015-03-06 15:44:59 +01:00
|
|
|
MapWrapper.forEach(eventMap, (expr, directiveIndex) => {
|
|
|
|
var context;
|
|
|
|
if (directiveIndex === -1) {
|
|
|
|
context = view.context;
|
|
|
|
} else {
|
|
|
|
context = view.elementInjectors[injectorIdx].getDirectiveAtIndex(directiveIndex);
|
|
|
|
}
|
2015-03-11 21:11:39 -07:00
|
|
|
expr.eval(context, new Locals(view.locals, locals));
|
2015-03-06 15:44:59 +01:00
|
|
|
});
|
2015-01-16 15:30:22 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-18 16:38:36 -08:00
|
|
|
bindVariable(contextName:string, templateName:string) {
|
|
|
|
MapWrapper.set(this.variableBindings, contextName, templateName);
|
2015-03-11 21:11:39 -07:00
|
|
|
MapWrapper.set(this.protoLocals, templateName, null);
|
2014-11-18 16:38:36 -08:00
|
|
|
}
|
|
|
|
|
2015-03-16 11:31:58 -07:00
|
|
|
bindElement(parent:ElementBinder, distanceToParent:int, protoElementInjector:ProtoElementInjector,
|
2015-04-02 14:40:49 -07:00
|
|
|
componentDirective:DirectiveBinding = null, viewportDirective:DirectiveBinding = null):ElementBinder {
|
2015-04-02 09:52:00 -07:00
|
|
|
var elBinder = new ElementBinder(this.elementBinders.length, parent, distanceToParent,
|
2015-03-16 11:31:58 -07:00
|
|
|
protoElementInjector, componentDirective, viewportDirective);
|
2014-11-11 17:33:47 -08:00
|
|
|
ListWrapper.push(this.elementBinders, elBinder);
|
|
|
|
return elBinder;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a text node binding for the last created ElementBinder via bindElement
|
|
|
|
*/
|
|
|
|
bindTextNode(indexInParent:int, expression:AST) {
|
|
|
|
var elBinder = this.elementBinders[this.elementBinders.length-1];
|
2014-11-19 14:54:07 -08:00
|
|
|
if (isBlank(elBinder.textNodeIndices)) {
|
|
|
|
elBinder.textNodeIndices = ListWrapper.create();
|
|
|
|
}
|
2014-11-11 17:33:47 -08:00
|
|
|
ListWrapper.push(elBinder.textNodeIndices, indexInParent);
|
2014-12-02 17:09:46 -08:00
|
|
|
var memento = this.textNodesWithBindingCount++;
|
2015-03-11 21:43:22 -07:00
|
|
|
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, memento, null));
|
2014-11-11 17:33:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds an element property binding for the last created ElementBinder via bindElement
|
|
|
|
*/
|
2014-12-09 10:31:19 -08:00
|
|
|
bindElementProperty(expression:AST, setterName:string, setter:SetterFn) {
|
2014-11-11 17:33:47 -08:00
|
|
|
var elBinder = this.elementBinders[this.elementBinders.length-1];
|
|
|
|
if (!elBinder.hasElementPropertyBindings) {
|
|
|
|
elBinder.hasElementPropertyBindings = true;
|
|
|
|
this.elementsWithBindingCount++;
|
|
|
|
}
|
2015-03-31 09:07:01 -07:00
|
|
|
var memento = new ElementBindingMemento(this.elementsWithBindingCount-1, setter);
|
2015-03-11 21:43:22 -07:00
|
|
|
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, memento, null));
|
2014-11-11 17:33:47 -08:00
|
|
|
}
|
|
|
|
|
2014-11-19 14:54:07 -08:00
|
|
|
/**
|
2015-03-06 15:44:59 +01:00
|
|
|
* Adds an event binding for the last created ElementBinder via bindElement.
|
|
|
|
*
|
|
|
|
* If the directive index is a positive integer, the event is evaluated in the context of
|
|
|
|
* the given directive.
|
|
|
|
*
|
|
|
|
* If the directive index is -1, the event is evaluated in the context of the enclosing view.
|
|
|
|
*
|
|
|
|
* @param {string} eventName
|
|
|
|
* @param {AST} expression
|
|
|
|
* @param {int} directiveIndex The directive index in the binder or -1 when the event is not bound
|
|
|
|
* to a directive
|
2014-11-19 14:54:07 -08:00
|
|
|
*/
|
2015-03-06 15:44:59 +01:00
|
|
|
bindEvent(eventName:string, expression:AST, directiveIndex: int = -1) {
|
|
|
|
var elBinder = this.elementBinders[this.elementBinders.length - 1];
|
|
|
|
var events = elBinder.events;
|
|
|
|
if (isBlank(events)) {
|
|
|
|
events = StringMapWrapper.create();
|
|
|
|
elBinder.events = events;
|
|
|
|
}
|
|
|
|
var event = StringMapWrapper.get(events, eventName);
|
|
|
|
if (isBlank(event)) {
|
|
|
|
event = MapWrapper.create();
|
|
|
|
StringMapWrapper.set(events, eventName, event);
|
2014-11-19 14:54:07 -08:00
|
|
|
}
|
2015-03-06 15:44:59 +01:00
|
|
|
MapWrapper.set(event, directiveIndex, expression);
|
2014-11-19 14:54:07 -08:00
|
|
|
}
|
|
|
|
|
2014-11-11 17:33:47 -08:00
|
|
|
/**
|
|
|
|
* Adds a directive property binding for the last created ElementBinder via bindElement
|
|
|
|
*/
|
|
|
|
bindDirectiveProperty(
|
|
|
|
directiveIndex:number,
|
|
|
|
expression:AST,
|
|
|
|
setterName:string,
|
2015-02-19 17:47:25 -08:00
|
|
|
setter:SetterFn) {
|
2014-12-02 17:09:46 -08:00
|
|
|
|
2015-03-26 14:36:25 -07:00
|
|
|
var elementIndex = this.elementBinders.length-1;
|
2015-02-06 13:35:05 -08:00
|
|
|
var bindingMemento = new DirectiveBindingMemento(
|
2015-03-26 14:36:25 -07:00
|
|
|
elementIndex,
|
2014-12-02 17:09:46 -08:00
|
|
|
directiveIndex,
|
|
|
|
setterName,
|
|
|
|
setter
|
2014-11-11 17:33:47 -08:00
|
|
|
);
|
2015-03-26 14:36:25 -07:00
|
|
|
var directiveMemento = this._getDirectiveMemento(elementIndex, directiveIndex);
|
2015-03-11 21:43:22 -07:00
|
|
|
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, bindingMemento, directiveMemento));
|
2014-10-27 11:47:13 -04:00
|
|
|
}
|
2015-04-02 09:52:00 -07:00
|
|
|
|
2015-03-26 14:36:25 -07:00
|
|
|
_getDirectiveMemento(elementInjectorIndex:number, directiveIndex:number) {
|
|
|
|
var id = elementInjectorIndex * 100 + directiveIndex;
|
|
|
|
var protoElementInjector = this.elementBinders[elementInjectorIndex].protoElementInjector;
|
2015-04-02 09:52:00 -07:00
|
|
|
|
2015-03-26 14:36:25 -07:00
|
|
|
if (!MapWrapper.contains(this._directiveMementosMap, id)) {
|
|
|
|
var binding = protoElementInjector.getDirectiveBindingAtIndex(directiveIndex);
|
|
|
|
MapWrapper.set(this._directiveMementosMap, id,
|
2015-03-31 07:47:26 -07:00
|
|
|
new DirectiveMemento(elementInjectorIndex, directiveIndex,
|
|
|
|
binding.callOnAllChangesDone, binding.callOnChange));
|
2015-03-26 14:36:25 -07:00
|
|
|
}
|
2015-04-02 09:52:00 -07:00
|
|
|
|
2015-03-26 14:36:25 -07:00
|
|
|
return MapWrapper.get(this._directiveMementosMap, id);
|
|
|
|
}
|
2014-09-28 20:02:32 -07:00
|
|
|
}
|
|
|
|
|
2015-03-17 19:22:13 +00:00
|
|
|
/**
|
|
|
|
*/
|
2015-02-06 13:35:05 -08:00
|
|
|
export class ElementBindingMemento {
|
2014-11-21 21:19:23 -08:00
|
|
|
_elementIndex:int;
|
2014-12-09 10:31:19 -08:00
|
|
|
_setter:SetterFn;
|
2015-03-31 09:07:01 -07:00
|
|
|
constructor(elementIndex:int, setter:SetterFn) {
|
2014-10-10 20:44:55 -07:00
|
|
|
this._elementIndex = elementIndex;
|
2014-12-09 10:31:19 -08:00
|
|
|
this._setter = setter;
|
2014-10-10 20:44:55 -07:00
|
|
|
}
|
|
|
|
|
2015-03-31 09:07:01 -07:00
|
|
|
invoke(currentValue:any, bindElements:List) {
|
2015-02-27 14:50:06 -08:00
|
|
|
var element = bindElements[this._elementIndex];
|
2015-03-31 09:07:01 -07:00
|
|
|
this._setter(element, currentValue);
|
2014-10-10 20:44:55 -07:00
|
|
|
}
|
|
|
|
}
|
2014-09-28 16:29:11 -07:00
|
|
|
|
2015-03-17 19:22:13 +00:00
|
|
|
/**
|
|
|
|
*/
|
2015-02-06 13:35:05 -08:00
|
|
|
export class DirectiveBindingMemento {
|
2014-11-21 21:19:23 -08:00
|
|
|
_elementInjectorIndex:int;
|
|
|
|
_directiveIndex:int;
|
2015-03-31 09:07:01 -07:00
|
|
|
propertyName:string;
|
2014-11-21 21:19:23 -08:00
|
|
|
_setter:SetterFn;
|
2014-09-28 16:29:11 -07:00
|
|
|
constructor(
|
|
|
|
elementInjectorIndex:number,
|
|
|
|
directiveIndex:number,
|
2015-03-31 09:07:01 -07:00
|
|
|
propertyName:string,
|
2014-10-27 23:16:31 -07:00
|
|
|
setter:SetterFn) {
|
2014-09-28 16:29:11 -07:00
|
|
|
this._elementInjectorIndex = elementInjectorIndex;
|
|
|
|
this._directiveIndex = directiveIndex;
|
2015-03-31 09:07:01 -07:00
|
|
|
this.propertyName = propertyName;
|
2014-09-28 16:29:11 -07:00
|
|
|
this._setter = setter;
|
|
|
|
}
|
|
|
|
|
2015-03-31 09:07:01 -07:00
|
|
|
invoke(currentValue:any, elementInjectors:List<ElementInjector>) {
|
2014-09-28 16:29:11 -07:00
|
|
|
var elementInjector:ElementInjector = elementInjectors[this._elementInjectorIndex];
|
2015-02-06 13:19:47 -08:00
|
|
|
var directive = elementInjector.getDirectiveAtIndex(this._directiveIndex);
|
2015-03-31 09:07:01 -07:00
|
|
|
this._setter(directive, currentValue);
|
2014-09-28 16:29:11 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 13:35:05 -08:00
|
|
|
class DirectiveMemento {
|
2014-12-02 17:09:46 -08:00
|
|
|
_elementInjectorIndex:number;
|
|
|
|
_directiveIndex:number;
|
2015-03-31 07:47:26 -07:00
|
|
|
callOnAllChangesDone:boolean;
|
|
|
|
callOnChange:boolean;
|
2014-12-02 17:09:46 -08:00
|
|
|
|
2015-03-31 07:47:26 -07:00
|
|
|
constructor(elementInjectorIndex:number, directiveIndex:number, callOnAllChangesDone:boolean,
|
|
|
|
callOnChange:boolean) {
|
2014-12-02 17:09:46 -08:00
|
|
|
this._elementInjectorIndex = elementInjectorIndex;
|
|
|
|
this._directiveIndex = directiveIndex;
|
2015-03-31 07:47:26 -07:00
|
|
|
this.callOnAllChangesDone = callOnAllChangesDone;
|
|
|
|
this.callOnChange = callOnChange;
|
2014-12-02 17:09:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
directive(elementInjectors:List<ElementInjector>) {
|
|
|
|
var elementInjector:ElementInjector = elementInjectors[this._elementInjectorIndex];
|
2015-02-06 13:19:47 -08:00
|
|
|
return elementInjector.getDirectiveAtIndex(this._directiveIndex);
|
|
|
|
}
|
2015-03-31 09:07:01 -07:00
|
|
|
}
|