2015-03-23 14:10:55 -07:00
|
|
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
|
|
|
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
|
|
|
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
|
|
|
|
|
|
|
import * as viewModule from '../view/view';
|
|
|
|
import {Content} from './content_tag';
|
|
|
|
|
|
|
|
export class DestinationLightDom {}
|
|
|
|
|
|
|
|
class _Root {
|
|
|
|
node;
|
2015-04-16 15:38:28 -07:00
|
|
|
boundElementIndex:number;
|
2015-03-23 14:10:55 -07:00
|
|
|
|
2015-04-16 15:38:28 -07:00
|
|
|
constructor(node, boundElementIndex) {
|
2015-03-23 14:10:55 -07:00
|
|
|
this.node = node;
|
2015-04-16 15:38:28 -07:00
|
|
|
this.boundElementIndex = boundElementIndex;
|
2015-03-23 14:10:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: LightDom should implement DestinationLightDom
|
|
|
|
// once interfaces are supported
|
|
|
|
export class LightDom {
|
|
|
|
// The light DOM of the element is enclosed inside the lightDomView
|
2015-04-09 21:20:11 +02:00
|
|
|
lightDomView:viewModule.RenderView;
|
2015-03-23 14:10:55 -07:00
|
|
|
// The shadow DOM
|
2015-04-09 21:20:11 +02:00
|
|
|
shadowDomView:viewModule.RenderView;
|
2015-03-23 14:10:55 -07:00
|
|
|
// The nodes of the light DOM
|
|
|
|
nodes:List;
|
|
|
|
roots:List<_Root>;
|
|
|
|
|
2015-04-09 21:20:11 +02:00
|
|
|
constructor(lightDomView:viewModule.RenderView, shadowDomView:viewModule.RenderView, element) {
|
2015-03-23 14:10:55 -07:00
|
|
|
this.lightDomView = lightDomView;
|
|
|
|
this.shadowDomView = shadowDomView;
|
|
|
|
this.nodes = DOM.childNodesAsList(element);
|
|
|
|
|
|
|
|
this.roots = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
redistribute() {
|
|
|
|
var tags = this.contentTags();
|
|
|
|
if (tags.length > 0) {
|
|
|
|
redistributeNodes(tags, this.expandedDomNodes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
contentTags(): List<Content> {
|
|
|
|
return this._collectAllContentTags(this.shadowDomView, []);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Collects the Content directives from the view and all its child views
|
2015-04-09 21:20:11 +02:00
|
|
|
_collectAllContentTags(view: viewModule.RenderView, acc:List<Content>):List<Content> {
|
2015-03-23 14:10:55 -07:00
|
|
|
var contentTags = view.contentTags;
|
|
|
|
var vcs = view.viewContainers;
|
|
|
|
for (var i=0; i<vcs.length; i++) {
|
|
|
|
var vc = vcs[i];
|
|
|
|
var contentTag = contentTags[i];
|
|
|
|
if (isPresent(contentTag)) {
|
|
|
|
ListWrapper.push(acc, contentTag);
|
|
|
|
}
|
|
|
|
if (isPresent(vc)) {
|
|
|
|
ListWrapper.forEach(vc.contentTagContainers(), (view) => {
|
|
|
|
this._collectAllContentTags(view, acc);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return acc;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Collects the nodes of the light DOM by merging:
|
|
|
|
// - nodes from enclosed ViewContainers,
|
|
|
|
// - nodes from enclosed content tags,
|
|
|
|
// - plain DOM nodes
|
|
|
|
expandedDomNodes():List {
|
|
|
|
var res = [];
|
|
|
|
|
|
|
|
var roots = this._roots();
|
|
|
|
for (var i = 0; i < roots.length; ++i) {
|
|
|
|
|
|
|
|
var root = roots[i];
|
2015-04-16 15:38:28 -07:00
|
|
|
if (isPresent(root.boundElementIndex)) {
|
|
|
|
var vc = this.lightDomView.viewContainers[root.boundElementIndex];
|
|
|
|
var content = this.lightDomView.contentTags[root.boundElementIndex];
|
|
|
|
if (isPresent(vc)) {
|
|
|
|
res = ListWrapper.concat(res, vc.nodes());
|
|
|
|
} else if (isPresent(content)) {
|
|
|
|
res = ListWrapper.concat(res, content.nodes());
|
|
|
|
} else {
|
|
|
|
ListWrapper.push(res, root.node);
|
|
|
|
}
|
2015-03-23 14:10:55 -07:00
|
|
|
} else {
|
|
|
|
ListWrapper.push(res, root.node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a list of Roots for all the nodes of the light DOM.
|
2015-04-16 15:38:28 -07:00
|
|
|
// The Root object contains the DOM node and its corresponding boundElementIndex
|
2015-03-23 14:10:55 -07:00
|
|
|
_roots() {
|
|
|
|
if (isPresent(this.roots)) return this.roots;
|
|
|
|
|
2015-04-16 15:38:28 -07:00
|
|
|
var boundElements = this.lightDomView.boundElements;
|
2015-03-23 14:10:55 -07:00
|
|
|
|
|
|
|
this.roots = ListWrapper.map(this.nodes, (n) => {
|
2015-04-16 15:38:28 -07:00
|
|
|
var boundElementIndex = null;
|
|
|
|
for (var i=0; i<boundElements.length; i++) {
|
|
|
|
var boundEl = boundElements[i];
|
|
|
|
if (isPresent(boundEl) && boundEl === n) {
|
|
|
|
boundElementIndex = i;
|
|
|
|
break;
|
2015-03-23 14:10:55 -07:00
|
|
|
}
|
|
|
|
}
|
2015-04-16 15:38:28 -07:00
|
|
|
return new _Root(n, boundElementIndex);
|
2015-03-23 14:10:55 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
return this.roots;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Projects the light DOM into the shadow DOM
|
|
|
|
function redistributeNodes(contents:List<Content>, nodes:List) {
|
|
|
|
for (var i = 0; i < contents.length; ++i) {
|
|
|
|
var content = contents[i];
|
|
|
|
var select = content.select;
|
|
|
|
var matchSelector = (n) => DOM.elementMatches(n, select);
|
|
|
|
|
|
|
|
// Empty selector is identical to <content/>
|
|
|
|
if (select.length === 0) {
|
|
|
|
content.insert(nodes);
|
|
|
|
ListWrapper.clear(nodes);
|
|
|
|
} else {
|
|
|
|
var matchingNodes = ListWrapper.filter(nodes, matchSelector);
|
|
|
|
content.insert(matchingNodes);
|
|
|
|
ListWrapper.removeAll(nodes, matchingNodes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|