refactor(ViewPort): @Template -> @Viewport, ViewPort -> ViewContainer

fixes #595
This commit is contained in:
Victor Berchet
2015-02-12 11:54:22 +01:00
parent 3519714f64
commit 6d23d00057
36 changed files with 408 additions and 376 deletions

View File

@ -111,7 +111,7 @@ export class Decorator extends Directive {
}
}
export class Template extends Directive {
export class Viewport extends Directive {
@CONST()
constructor({
selector,

View File

@ -8,16 +8,17 @@ import {ProtoView} from './view';
export class ElementBinder {
protoElementInjector:ProtoElementInjector;
componentDirective:DirectiveMetadata;
templateDirective:DirectiveMetadata;
viewportDirective:DirectiveMetadata;
textNodeIndices:List<int>;
hasElementPropertyBindings:boolean;
nestedProtoView: ProtoView;
events:Map;
constructor(
protoElementInjector: ProtoElementInjector, componentDirective:DirectiveMetadata, templateDirective:DirectiveMetadata) {
protoElementInjector: ProtoElementInjector, componentDirective:DirectiveMetadata,
viewportDirective:DirectiveMetadata) {
this.protoElementInjector = protoElementInjector;
this.componentDirective = componentDirective;
this.templateDirective = templateDirective;
this.viewportDirective = viewportDirective;
// updated later when events are bound
this.events = null;
// updated later when text nodes are bound

View File

@ -6,7 +6,7 @@ import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
import {EventEmitter} from 'angular2/src/core/annotations/events';
import {View, ProtoView} from 'angular2/src/core/compiler/view';
import {LightDom, SourceLightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
import {ViewPort} from 'angular2/src/core/compiler/viewport';
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
import {NgElement} from 'angular2/src/core/dom/element';
import {Directive, onChange, onDestroy} from 'angular2/src/core/annotations/annotations'
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config'
@ -22,7 +22,7 @@ var _staticKeys;
class StaticKeys {
viewId:number;
ngElementId:number;
viewPortId:number;
viewContainerId:number;
destinationLightDomId:number;
sourceLightDomId:number;
bindingPropagationConfigId:number;
@ -31,7 +31,7 @@ class StaticKeys {
//TODO: vsavkin Key.annotate(Key.get(View), 'static')
this.viewId = Key.get(View).id;
this.ngElementId = Key.get(NgElement).id;
this.viewPortId = Key.get(ViewPort).id;
this.viewContainerId = Key.get(ViewContainer).id;
this.destinationLightDomId = Key.get(DestinationLightDom).id;
this.sourceLightDomId = Key.get(SourceLightDom).id;
this.bindingPropagationConfigId = Key.get(BindingPropagationConfig).id;
@ -152,14 +152,14 @@ export class DirectiveBinding extends Binding {
export class PreBuiltObjects {
view:View;
element:NgElement;
viewPort:ViewPort;
viewContainer:ViewContainer;
lightDom:LightDom;
bindingPropagationConfig:BindingPropagationConfig;
constructor(view, element:NgElement, viewPort:ViewPort, lightDom:LightDom,
constructor(view, element:NgElement, viewContainer:ViewContainer, lightDom:LightDom,
bindingPropagationConfig:BindingPropagationConfig) {
this.view = view;
this.element = element;
this.viewPort = viewPort;
this.viewContainer = viewContainer;
this.lightDom = lightDom;
this.bindingPropagationConfig = bindingPropagationConfig;
}
@ -557,7 +557,7 @@ export class ElementInjector extends TreeNode {
var staticKeys = StaticKeys.instance();
if (keyId === staticKeys.viewId) return this._preBuiltObjects.view;
if (keyId === staticKeys.ngElementId) return this._preBuiltObjects.element;
if (keyId === staticKeys.viewPortId) return this._preBuiltObjects.viewPort;
if (keyId === staticKeys.viewContainerId) return this._preBuiltObjects.viewContainer;
if (keyId === staticKeys.bindingPropagationConfigId) return this._preBuiltObjects.bindingPropagationConfig;
if (keyId === staticKeys.destinationLightDomId) {
var p:ElementInjector = this.directParent();

View File

@ -2,9 +2,7 @@ import {List, Map, ListWrapper, MapWrapper} from 'angular2/src/facade/collection
import {Element, DOM} from 'angular2/src/facade/dom';
import {int, isBlank, isPresent, Type} from 'angular2/src/facade/lang';
import {DirectiveMetadata} from '../directive_metadata';
import {Decorator} from '../../annotations/annotations';
import {Component} from '../../annotations/annotations';
import {Template} from '../../annotations/annotations';
import {Decorator, Component, Viewport} from '../../annotations/annotations';
import {ElementBinder} from '../element_binder';
import {ProtoElementInjector} from '../element_injector';
import {ProtoView} from '../view';
@ -29,7 +27,7 @@ export class CompileElement {
/// Template name is how it is reffered to it in template
variableBindings:Map;
decoratorDirectives:List<DirectiveMetadata>;
templateDirective:DirectiveMetadata;
viewportDirective:DirectiveMetadata;
componentDirective:DirectiveMetadata;
_allDirectives:List<DirectiveMetadata>;
isViewRoot:boolean;
@ -50,7 +48,7 @@ export class CompileElement {
this.eventBindings = null;
this.variableBindings = null;
this.decoratorDirectives = null;
this.templateDirective = null;
this.viewportDirective = null;
this.componentDirective = null;
this._allDirectives = null;
this.isViewRoot = false;
@ -141,8 +139,8 @@ export class CompileElement {
if (!annotation.compileChildren) {
this.compileChildren = false;
}
} else if (annotation instanceof Template) {
this.templateDirective = directive;
} else if (annotation instanceof Viewport) {
this.viewportDirective = directive;
} else if (annotation instanceof Component) {
this.componentDirective = directive;
}
@ -156,8 +154,8 @@ export class CompileElement {
if (isPresent(this.componentDirective)) {
ListWrapper.push(directives, this.componentDirective);
}
if (isPresent(this.templateDirective)) {
ListWrapper.push(directives, this.templateDirective);
if (isPresent(this.viewportDirective)) {
ListWrapper.push(directives, this.viewportDirective);
}
if (isPresent(this.decoratorDirectives)) {
directives = ListWrapper.concat(directives, this.decoratorDirectives);

View File

@ -5,8 +5,7 @@ import {SelectorMatcher} from '../selector';
import {CssSelector} from '../selector';
import {DirectiveMetadata} from '../directive_metadata';
import {Template} from '../../annotations/annotations';
import {Component} from '../../annotations/annotations';
import {Component, Viewport} from '../../annotations/annotations';
import {CompileStep} from './compile_step';
import {CompileElement} from './compile_element';
import {CompileControl} from './compile_control';
@ -70,10 +69,10 @@ export class DirectiveParser extends CompileStep {
// only be present on <template> elements any more!
var isTemplateElement = current.element instanceof TemplateElement;
this._selectorMatcher.match(cssSelector, (directive) => {
if (directive.annotation instanceof Template) {
if (directive.annotation instanceof Viewport) {
if (!isTemplateElement) {
throw new BaseException('Template directives need to be placed on <template> elements or elements with template attribute!');
} else if (isPresent(current.templateDirective)) {
throw new BaseException('Viewport directives need to be placed on <template> elements or elements with template attribute!');
} else if (isPresent(current.viewportDirective)) {
throw new BaseException('Only one template directive per element is allowed!');
}
} else if (isTemplateElement) {

View File

@ -78,7 +78,7 @@ function styleSetterFactory(styleName:string, stylesuffix:string) {
* - CompileElement#eventBindings
* - CompileElement#decoratorDirectives
* - CompileElement#componentDirective
* - CompileElement#templateDirective
* - CompileElement#viewportDirective
*
* Note: This actually only needs the CompileElements with the flags
* `hasBindings` and `isViewRoot`,
@ -105,7 +105,7 @@ export class ElementBinderBuilder extends CompileStep {
current.inheritedProtoElementInjector : null;
elementBinder = protoView.bindElement(currentProtoElementInjector,
current.componentDirective, current.templateDirective);
current.componentDirective, current.viewportDirective);
if (isPresent(current.textNodeBindings)) {
this._bindTextNodes(protoView, current);

View File

@ -22,7 +22,7 @@ const NG_BINDING_CLASS = 'ng-binding';
* - CompileElement#eventBindings
* - CompileElement#decoratorDirectives
* - CompileElement#componentDirective
* - CompileElement#templateDirective
* - CompileElement#viewportDirective
*/
export class ElementBindingMarker extends CompileStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
@ -36,7 +36,7 @@ export class ElementBindingMarker extends CompileStep {
(isPresent(current.variableBindings) && MapWrapper.size(current.variableBindings)>0) ||
(isPresent(current.eventBindings) && MapWrapper.size(current.eventBindings)>0) ||
(isPresent(current.decoratorDirectives) && current.decoratorDirectives.length > 0) ||
isPresent(current.templateDirective) ||
isPresent(current.viewportDirective) ||
isPresent(current.componentDirective);
if (hasBindings) {

View File

@ -23,7 +23,7 @@ import {DirectiveMetadata} from '../directive_metadata';
* - CompileElement#inheritedProtoView
* - CompileElement#decoratorDirectives
* - CompileElement#componentDirective
* - CompileElement#templateDirective
* - CompileElement#viewportDirective
*/
export class ProtoElementInjectorBuilder extends CompileStep {
// public so that we can overwrite it in tests
@ -52,8 +52,8 @@ export class ProtoElementInjectorBuilder extends CompileStep {
);
current.distanceToParentInjector = 0;
// Template directives are treated differently than other element with var- definitions.
if (isPresent(current.variableBindings) && !isPresent(current.templateDirective)) {
// Viewport directives are treated differently than other element with var- definitions.
if (isPresent(current.variableBindings) && !isPresent(current.viewportDirective)) {
current.inheritedProtoElementInjector.exportComponent = hasComponent;
current.inheritedProtoElementInjector.exportElement = !hasComponent;

View File

@ -4,7 +4,7 @@ import {isBlank, isPresent} from 'angular2/src/facade/lang';
import {View} from '../view';
import {ElementInjector} from '../element_injector';
import {ViewPort} from '../viewport';
import {ViewContainer} from '../view_container';
import {Content} from './content_tag';
export class SourceLightDom {}
@ -60,9 +60,9 @@ export class LightDom {
if (ei.hasDirective(Content)) {
ListWrapper.push(acc, ei.get(Content));
} else if (ei.hasPreBuiltObject(ViewPort)) {
var vp = ei.get(ViewPort);
ListWrapper.forEach(vp.contentTagContainers(), (view) => {
} else if (ei.hasPreBuiltObject(ViewContainer)) {
var vc = ei.get(ViewContainer);
ListWrapper.forEach(vc.contentTagContainers(), (view) => {
this._collectAllContentTags(view, acc);
});
}
@ -71,7 +71,7 @@ export class LightDom {
}
// Collects the nodes of the light DOM by merging:
// - nodes from enclosed ViewPorts,
// - nodes from enclosed ViewContainers,
// - nodes from enclosed content tags,
// - plain DOM nodes
expandedDomNodes():List {
@ -83,9 +83,9 @@ export class LightDom {
var root = roots[i];
var ei = root.injector;
if (isPresent(ei) && ei.hasPreBuiltObject(ViewPort)) {
var vp = root.injector.get(ViewPort);
res = ListWrapper.concat(res, vp.nodes());
if (isPresent(ei) && ei.hasPreBuiltObject(ViewContainer)) {
var vc = root.injector.get(ViewContainer);
res = ListWrapper.concat(res, vc.nodes());
} else if (isPresent(ei) && ei.hasDirective(Content)) {
var content = root.injector.get(Content);

View File

@ -11,7 +11,7 @@ import {SetterFn} from 'angular2/src/reflection/types';
import {FIELD, IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import {Injector} from 'angular2/di';
import {NgElement} from 'angular2/src/core/dom/element';
import {ViewPort} from './viewport';
import {ViewContainer} from './view_container';
import {Content} from './shadow_dom_emulation/content_tag';
import {LightDom, DestinationLightDom} from './shadow_dom_emulation/light_dom';
import {ShadowDomStrategy} from './shadow_dom_strategy';
@ -42,7 +42,7 @@ export class View {
/// to keep track of the nodes.
nodes:List<Node>;
componentChildViews: List<View>;
viewPorts: List<ViewPort>;
viewContainers: List<ViewContainer>;
preBuiltObjects: List<PreBuiltObjects>;
proto: ProtoView;
context: any;
@ -57,7 +57,7 @@ export class View {
this.textNodes = null;
this.bindElements = null;
this.componentChildViews = null;
this.viewPorts = null;
this.viewContainers = null;
this.preBuiltObjects = null;
this.context = null;
this.contextWithLocals = (MapWrapper.size(protoContextLocals) > 0)
@ -65,12 +65,13 @@ export class View {
: null;
}
init(elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List, viewPorts:List, preBuiltObjects:List, componentChildViews:List) {
init(elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List,
viewContainers:List, preBuiltObjects:List, componentChildViews:List) {
this.elementInjectors = elementInjectors;
this.rootElementInjectors = rootElementInjectors;
this.textNodes = textNodes;
this.bindElements = bindElements;
this.viewPorts = viewPorts;
this.viewContainers = viewContainers;
this.preBuiltObjects = preBuiltObjects;
this.componentChildViews = componentChildViews;
}
@ -117,7 +118,7 @@ export class View {
*
* - all element injectors are empty.
* - all appInjectors are released.
* - all viewports are empty.
* - all viewcontainers are empty.
* - all context locals are set to null.
* - the view context is null.
*
@ -129,9 +130,9 @@ export class View {
if (this.hydrated()) throw new BaseException('The view is already hydrated.');
this._hydrateContext(context);
// viewPorts
for (var i = 0; i < this.viewPorts.length; i++) {
this.viewPorts[i].hydrate(appInjector, hostElementInjector);
// viewContainers
for (var i = 0; i < this.viewContainers.length; i++) {
this.viewContainers[i].hydrate(appInjector, hostElementInjector);
}
var binders = this.proto.elementBinders;
@ -201,10 +202,10 @@ export class View {
}
}
// viewPorts
if (isPresent(this.viewPorts)) {
for (var i = 0; i < this.viewPorts.length; i++) {
this.viewPorts[i].dehydrate();
// viewContainers
if (isPresent(this.viewContainers)) {
for (var i = 0; i < this.viewContainers.length; i++) {
this.viewContainers[i].dehydrate();
}
}
@ -341,7 +342,7 @@ export class ProtoView {
var textNodes = [];
var elementsWithPropertyBindings = [];
var preBuiltObjects = ListWrapper.createFixedSize(binders.length);
var viewPorts = [];
var viewContainers = [];
var componentChildViews = [];
for (var i = 0; i < binders.length; i++) {
@ -399,18 +400,18 @@ export class ProtoView {
ListWrapper.push(componentChildViews, childView);
}
// viewPorts
var viewPort = null;
if (isPresent(binder.templateDirective)) {
// viewContainers
var viewContainer = null;
if (isPresent(binder.viewportDirective)) {
var destLightDom = this._directParentElementLightDom(protoElementInjector, preBuiltObjects);
viewPort = new ViewPort(view, element, binder.nestedProtoView, elementInjector,
viewContainer = new ViewContainer(view, element, binder.nestedProtoView, elementInjector,
eventManager, destLightDom);
ListWrapper.push(viewPorts, viewPort);
ListWrapper.push(viewContainers, viewContainer);
}
// preBuiltObjects
if (isPresent(elementInjector)) {
preBuiltObjects[i] = new PreBuiltObjects(view, new NgElement(element), viewPort,
preBuiltObjects[i] = new PreBuiltObjects(view, new NgElement(element), viewContainer,
lightDom, bindingPropagationConfig);
}
@ -426,7 +427,7 @@ export class ProtoView {
}
view.init(elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
viewPorts, preBuiltObjects, componentChildViews);
viewContainers, preBuiltObjects, componentChildViews);
return view;
}
@ -461,8 +462,8 @@ export class ProtoView {
}
bindElement(protoElementInjector:ProtoElementInjector,
componentDirective:DirectiveMetadata = null, templateDirective:DirectiveMetadata = null):ElementBinder {
var elBinder = new ElementBinder(protoElementInjector, componentDirective, templateDirective);
componentDirective:DirectiveMetadata = null, viewportDirective:DirectiveMetadata = null):ElementBinder {
var elBinder = new ElementBinder(protoElementInjector, componentDirective, viewportDirective);
ListWrapper.push(this.elementBinders, elBinder);
return elBinder;
}

View File

@ -7,7 +7,7 @@ import {ElementInjector} from 'angular2/src/core/compiler/element_injector';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {EventManager} from 'angular2/src/core/events/event_manager';
export class ViewPort {
export class ViewContainer {
parentView: View;
templateElement: Element;
defaultProtoView: ProtoView;
@ -71,7 +71,7 @@ export class ViewPort {
// to the methods below.
create(atIndex=-1): View {
if (!this.hydrated()) throw new BaseException(
'Cannot create views on a dehydrated view port');
'Cannot create views on a dehydrated ViewContainer');
// TODO(rado): replace with viewFactory.
var newView = this.defaultProtoView.instantiate(this.hostElementInjector, this._eventManager);
newView.hydrate(this.appInjector, this.hostElementInjector, this.parentView.context);
@ -82,7 +82,7 @@ export class ViewPort {
if (atIndex == -1) atIndex = this._views.length;
ListWrapper.insert(this._views, atIndex, view);
if (isBlank(this._lightDom)) {
ViewPort.moveViewNodesAfterSibling(this._siblingToInsertAfter(atIndex), view);
ViewContainer.moveViewNodesAfterSibling(this._siblingToInsertAfter(atIndex), view);
} else {
this._lightDom.redistribute();
}
@ -109,7 +109,7 @@ export class ViewPort {
var detachedView = this.get(atIndex);
ListWrapper.removeAt(this._views, atIndex);
if (isBlank(this._lightDom)) {
ViewPort.removeViewNodesFromParent(this.templateElement.parentNode, detachedView);
ViewContainer.removeViewNodesFromParent(this.templateElement.parentNode, detachedView);
} else {
this._lightDom.redistribute();
}

View File

@ -1,11 +1,11 @@
import {Template, onChange} from 'angular2/src/core/annotations/annotations';
import {Viewport, onChange} from 'angular2/src/core/annotations/annotations';
import {OnChange} from 'angular2/src/core/compiler/interfaces';
import {ViewPort} from 'angular2/src/core/compiler/viewport';
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
import {View} from 'angular2/src/core/compiler/view';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection';
@Template({
@Viewport({
selector: '[foreach][in]',
lifecycle: [onChange],
bind: {
@ -13,16 +13,16 @@ import {ListWrapper} from 'angular2/src/facade/collection';
}
})
export class Foreach extends OnChange {
viewPort: ViewPort;
viewContainer: ViewContainer;
iterable;
constructor(viewPort: ViewPort) {
constructor(viewContainer: ViewContainer) {
super();
this.viewPort = viewPort;
this.viewContainer = viewContainer;
}
onChange(changes) {
var iteratorChanges = changes['iterable'];
if (isBlank(iteratorChanges) || isBlank(iteratorChanges.currentValue)) {
this.viewPort.clear();
this.viewContainer.clear();
return;
}
@ -37,13 +37,13 @@ export class Foreach extends OnChange {
(movedRecord) => ListWrapper.push(recordViewTuples, new RecordViewTuple(movedRecord, null))
);
var insertTuples = Foreach.bulkRemove(recordViewTuples, this.viewPort);
var insertTuples = Foreach.bulkRemove(recordViewTuples, this.viewContainer);
iteratorChanges.currentValue.forEachAddedItem(
(addedRecord) => ListWrapper.push(insertTuples, new RecordViewTuple(addedRecord, null))
);
Foreach.bulkInsert(insertTuples, this.viewPort);
Foreach.bulkInsert(insertTuples, this.viewContainer);
for (var i = 0; i < insertTuples.length; i++) {
this.perViewChange(insertTuples[i].view, insertTuples[i].record);
@ -55,30 +55,30 @@ export class Foreach extends OnChange {
view.setLocal('index', record.currentIndex);
}
static bulkRemove(tuples, viewPort) {
static bulkRemove(tuples, viewContainer) {
tuples.sort((a, b) => a.record.previousIndex - b.record.previousIndex);
var movedTuples = [];
for (var i = tuples.length - 1; i >= 0; i--) {
var tuple = tuples[i];
// separate moved views from removed views.
if (isPresent(tuple.record.currentIndex)) {
tuple.view = viewPort.detach(tuple.record.previousIndex);
tuple.view = viewContainer.detach(tuple.record.previousIndex);
ListWrapper.push(movedTuples, tuple);
} else {
viewPort.remove(tuple.record.previousIndex);
viewContainer.remove(tuple.record.previousIndex);
}
}
return movedTuples;
}
static bulkInsert(tuples, viewPort) {
static bulkInsert(tuples, viewContainer) {
tuples.sort((a, b) => a.record.currentIndex - b.record.currentIndex);
for (var i = 0; i < tuples.length; i++) {
var tuple = tuples[i];
if (isPresent(tuple.view)) {
viewPort.insert(tuple.view, tuple.record.currentIndex);
viewContainer.insert(tuple.view, tuple.record.currentIndex);
} else {
tuple.view = viewPort.create(tuple.record.currentIndex);
tuple.view = viewContainer.create(tuple.record.currentIndex);
}
}
return tuples;

View File

@ -1,29 +1,29 @@
import {Template} from 'angular2/src/core/annotations/annotations';
import {ViewPort} from 'angular2/src/core/compiler/viewport';
import {Viewport} from 'angular2/src/core/annotations/annotations';
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
import {isBlank} from 'angular2/src/facade/lang';
@Template({
@Viewport({
selector: '[if]',
bind: {
'if': 'condition'
}
})
export class If {
viewPort: ViewPort;
viewContainer: ViewContainer;
prevCondition: boolean;
constructor(viewPort: ViewPort) {
this.viewPort = viewPort;
constructor(viewContainer: ViewContainer) {
this.viewContainer = viewContainer;
this.prevCondition = null;
}
set condition(newCondition) {
if (newCondition && (isBlank(this.prevCondition) || !this.prevCondition)) {
this.prevCondition = true;
this.viewPort.create();
this.viewContainer.create();
} else if (!newCondition && (isBlank(this.prevCondition) || this.prevCondition)) {
this.prevCondition = false;
this.viewPort.clear();
this.viewContainer.clear();
}
}
}

View File

@ -1,8 +1,8 @@
import {Decorator, Template} from 'angular2/src/core/annotations/annotations';
import {ViewPort} from 'angular2/src/core/compiler/viewport';
import {Decorator, Viewport} from 'angular2/src/core/annotations/annotations';
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
import {NgElement} from 'angular2/src/core/dom/element';
import {DOM} from 'angular2/src/facade/dom';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang';
import {ListWrapper, List, MapWrapper, Map} from 'angular2/src/facade/collection';
import {Parent} from 'angular2/src/core/annotations/visibility';
@ -40,89 +40,89 @@ import {Parent} from 'angular2/src/core/annotations/visibility';
export class Switch {
_switchValue: any;
_useDefault: boolean;
_valueViewPorts: Map;
_activeViewPorts: List;
_valueViewContainers: Map;
_activeViewContainers: List<ViewContainer>;
constructor() {
this._valueViewPorts = MapWrapper.create();
this._activeViewPorts = ListWrapper.create();
this._valueViewContainers = MapWrapper.create();
this._activeViewContainers = ListWrapper.create();
this._useDefault = false;
}
set value(value) {
// Remove the currently active viewports
this._removeAllActiveViewPorts();
// Empty the currently active ViewContainers
this._emptyAllActiveViewContainers();
// Add the viewports matching the value (with a fallback to default)
// Add the ViewContainers matching the value (with a fallback to default)
this._useDefault = false;
var viewPorts = MapWrapper.get(this._valueViewPorts, value);
if (isBlank(viewPorts)) {
var containers = MapWrapper.get(this._valueViewContainers, value);
if (isBlank(containers)) {
this._useDefault = true;
viewPorts = MapWrapper.get(this._valueViewPorts, _whenDefault);
containers = normalizeBlank(MapWrapper.get(this._valueViewContainers, _whenDefault));
}
this._activateViewPorts(viewPorts);
this._activateViewContainers(containers);
this._switchValue = value;
}
_onWhenValueChanged(oldWhen, newWhen, viewPort: ViewPort) {
this._deregisterViewPort(oldWhen, viewPort);
this._registerViewPort(newWhen, viewPort);
_onWhenValueChanged(oldWhen, newWhen, viewContainer: ViewContainer) {
this._deregisterViewContainer(oldWhen, viewContainer);
this._registerViewContainer(newWhen, viewContainer);
if (oldWhen === this._switchValue) {
viewPort.remove();
ListWrapper.remove(this._activeViewPorts, viewPort);
viewContainer.remove();
ListWrapper.remove(this._activeViewContainers, viewContainer);
} else if (newWhen === this._switchValue) {
if (this._useDefault) {
this._useDefault = false;
this._removeAllActiveViewPorts();
this._emptyAllActiveViewContainers();
}
viewPort.create();
ListWrapper.push(this._activeViewPorts, viewPort);
viewContainer.create();
ListWrapper.push(this._activeViewContainers, viewContainer);
}
// Switch to default when there is no more active viewports
if (this._activeViewPorts.length === 0 && !this._useDefault) {
// Switch to default when there is no more active ViewContainers
if (this._activeViewContainers.length === 0 && !this._useDefault) {
this._useDefault = true;
this._activateViewPorts(MapWrapper.get(this._valueViewPorts, _whenDefault));
this._activateViewContainers(MapWrapper.get(this._valueViewContainers, _whenDefault));
}
}
_removeAllActiveViewPorts() {
var activeViewPorts = this._activeViewPorts;
for (var i = 0; i < activeViewPorts.length; i++) {
activeViewPorts[i].remove();
_emptyAllActiveViewContainers() {
var activeContainers = this._activeViewContainers;
for (var i = 0; i < activeContainers.length; i++) {
activeContainers[i].remove();
}
this._activeViewPorts = ListWrapper.create();
this._activeViewContainers = ListWrapper.create();
}
_activateViewPorts(viewPorts) {
// TODO(vicb): assert(this._activeViewPorts.length === 0);
if (isPresent(viewPorts)) {
for (var i = 0; i < viewPorts.length; i++) {
viewPorts[i].create();
_activateViewContainers(containers: List<ViewContainer>) {
// TODO(vicb): assert(this._activeViewContainers.length === 0);
if (isPresent(containers)) {
for (var i = 0; i < containers.length; i++) {
containers[i].create();
}
this._activeViewPorts = viewPorts;
this._activeViewContainers = containers;
}
}
_registerViewPort(value, viewPort: ViewPort) {
var viewPorts = MapWrapper.get(this._valueViewPorts, value);
if (isBlank(viewPorts)) {
viewPorts = ListWrapper.create();
MapWrapper.set(this._valueViewPorts, value, viewPorts);
_registerViewContainer(value, container: ViewContainer) {
var containers = MapWrapper.get(this._valueViewContainers, value);
if (isBlank(containers)) {
containers = ListWrapper.create();
MapWrapper.set(this._valueViewContainers, value, containers);
}
ListWrapper.push(viewPorts, viewPort);
ListWrapper.push(containers, container);
}
_deregisterViewPort(value, viewPort: ViewPort) {
_deregisterViewContainer(value, container: ViewContainer) {
// `_whenDefault` is used a marker for non-registered whens
if (value == _whenDefault) return;
var viewPorts = MapWrapper.get(this._valueViewPorts, value);
if (viewPorts.length == 1) {
MapWrapper.delete(this._valueViewPorts, value);
var containers = MapWrapper.get(this._valueViewContainers, value);
if (containers.length == 1) {
MapWrapper.delete(this._valueViewContainers, value);
} else {
ListWrapper.remove(viewPorts, viewPort);
ListWrapper.remove(containers, container);
}
}
}
@ -142,7 +142,7 @@ export class Switch {
* <template [switch-when]="'stringValue'">...</template>
* ```
*/
@Template({
@Viewport({
selector: '[switch-when]',
bind: {
'switch-when' : 'when'
@ -151,17 +151,17 @@ export class Switch {
export class SwitchWhen {
_value: any;
_switch: Switch;
_viewPort: ViewPort;
_viewContainer: ViewContainer;
constructor(el: NgElement, viewPort: ViewPort, @Parent() sswitch: Switch) {
constructor(el: NgElement, viewContainer: ViewContainer, @Parent() sswitch: Switch) {
// `_whenDefault` is used as a marker for a not yet initialized value
this._value = _whenDefault;
this._switch = sswitch;
this._viewPort = viewPort;
this._viewContainer = viewContainer;
}
set when(value) {
this._switch._onWhenValueChanged(this._value, value, this._viewPort);
this._switch._onWhenValueChanged(this._value, value, this._viewContainer);
this._value = value;
}
}
@ -178,12 +178,12 @@ export class SwitchWhen {
* <template [switch-default]>...</template>
* ```
*/
@Template({
@Viewport({
selector: '[switch-default]'
})
export class SwitchDefault {
constructor(viewPort: ViewPort, @Parent() sswitch: Switch) {
sswitch._registerViewPort(_whenDefault, viewPort);
constructor(viewContainer: ViewContainer, @Parent() sswitch: Switch) {
sswitch._registerViewContainer(_whenDefault, viewContainer);
}
}