115 lines
3.3 KiB
JavaScript
115 lines
3.3 KiB
JavaScript
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
|
|
import {ListWrapper, MapWrapper, List} from 'angular2/src/facade/collection';
|
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
|
|
import * as viewModule from './view';
|
|
|
|
export class ViewContainer {
|
|
parentView: viewModule.RenderView;
|
|
boundElementIndex: number;
|
|
views: List<viewModule.RenderView>;
|
|
|
|
constructor(parentView: viewModule.RenderView, boundElementIndex: number) {
|
|
this.parentView = parentView;
|
|
this.boundElementIndex = boundElementIndex;
|
|
// The order in this list matches the DOM order.
|
|
this.views = [];
|
|
}
|
|
|
|
get(index: number): viewModule.RenderView {
|
|
return this.views[index];
|
|
}
|
|
|
|
size() {
|
|
return this.views.length;
|
|
}
|
|
|
|
_siblingToInsertAfter(index: number) {
|
|
if (index == 0) return this.parentView.boundElements[this.boundElementIndex];
|
|
return ListWrapper.last(this.views[index - 1].rootNodes);
|
|
}
|
|
|
|
_checkHydrated() {
|
|
if (!this.parentView.hydrated) throw new BaseException(
|
|
'Cannot change dehydrated ViewContainer');
|
|
}
|
|
|
|
_getDirectParentLightDom() {
|
|
return this.parentView.getDirectParentLightDom(this.boundElementIndex);
|
|
}
|
|
|
|
clear() {
|
|
this._checkHydrated();
|
|
for (var i=this.views.length-1; i>=0; i--) {
|
|
this.detach(i);
|
|
}
|
|
if (isPresent(this._getDirectParentLightDom())) {
|
|
this._getDirectParentLightDom().redistribute();
|
|
}
|
|
}
|
|
|
|
insert(view, atIndex=-1): viewModule.RenderView {
|
|
this._checkHydrated();
|
|
if (atIndex == -1) atIndex = this.views.length;
|
|
ListWrapper.insert(this.views, atIndex, view);
|
|
|
|
if (isBlank(this._getDirectParentLightDom())) {
|
|
ViewContainer.moveViewNodesAfterSibling(this._siblingToInsertAfter(atIndex), view);
|
|
} else {
|
|
this._getDirectParentLightDom().redistribute();
|
|
}
|
|
// new content tags might have appeared, we need to redistribute.
|
|
if (isPresent(this.parentView.hostLightDom)) {
|
|
this.parentView.hostLightDom.redistribute();
|
|
}
|
|
return view;
|
|
}
|
|
|
|
/**
|
|
* The method can be used together with insert to implement a view move, i.e.
|
|
* moving the dom nodes while the directives in the view stay intact.
|
|
*/
|
|
detach(atIndex:number) {
|
|
this._checkHydrated();
|
|
var detachedView = this.get(atIndex);
|
|
ListWrapper.removeAt(this.views, atIndex);
|
|
if (isBlank(this._getDirectParentLightDom())) {
|
|
ViewContainer.removeViewNodes(detachedView);
|
|
} else {
|
|
this._getDirectParentLightDom().redistribute();
|
|
}
|
|
// content tags might have disappeared we need to do redistribution.
|
|
if (isPresent(this.parentView.hostLightDom)) {
|
|
this.parentView.hostLightDom.redistribute();
|
|
}
|
|
return detachedView;
|
|
}
|
|
|
|
contentTagContainers() {
|
|
return this.views;
|
|
}
|
|
|
|
nodes():List {
|
|
var r = [];
|
|
for (var i = 0; i < this.views.length; ++i) {
|
|
r = ListWrapper.concat(r, this.views[i].rootNodes);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static moveViewNodesAfterSibling(sibling, view) {
|
|
for (var i = view.rootNodes.length - 1; i >= 0; --i) {
|
|
DOM.insertAfter(sibling, view.rootNodes[i]);
|
|
}
|
|
}
|
|
|
|
static removeViewNodes(view) {
|
|
var len = view.rootNodes.length;
|
|
if (len == 0) return;
|
|
var parent = view.rootNodes[0].parentNode;
|
|
for (var i = len - 1; i >= 0; --i) {
|
|
DOM.removeChild(parent, view.rootNodes[i]);
|
|
}
|
|
}
|
|
}
|