feat(compiler): attach components and project light dom during compilation.

Closes #2529

BREAKING CHANGES:
- shadow dom emulation no longer
  supports the `<content>` tag. Use the new `<ng-content>` instead
  (works with all shadow dom strategies).
- removed `DomRenderer.setViewRootNodes` and `AppViewManager.getComponentView`
  -> use `DomRenderer.getNativeElementSync(elementRef)` and change shadow dom directly
- the `Renderer` interface has changed:
  * `createView` now also has to support sub views
  * the notion of a container has been removed. Instead, the renderer has
    to implement methods to attach views next to elements or other views.
  * a RenderView now contains multiple RenderFragments. Fragments
    are used to move DOM nodes around.

Internal changes / design changes:
- Introduce notion of view fragments on render side
- DomProtoViews and DomViews on render side are merged,
  AppProtoViews are not merged, AppViews are partially merged
  (they share arrays with the other merged AppViews but we keep
  individual AppView instances for now).
- DomProtoViews always have a `<template>` element as root
  * needed for storing subviews
  * we have less chunks of DOM to clone now
- remove fake ElementBinder / Bound element for root text bindings
  and model them explicitly. This removes a lot of special cases we had!
- AppView shares data with nested component views
- some methods in AppViewManager (create, hydrate, dehydrate) are iterative now
  * now possible as we have all child AppViews / ElementRefs already in an array!
This commit is contained in:
Tobias Bosch
2015-06-24 13:46:39 -07:00
parent d449ea5ca4
commit b1df54501a
82 changed files with 3418 additions and 2806 deletions

View File

@ -63,7 +63,7 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
get attrToPropMap(): any { return _attrToPropMap; }
query(selector: string): any { return document.querySelector(selector); }
querySelector(el, selector: string): Node { return el.querySelector(selector); }
querySelector(el, selector: string): HTMLElement { return el.querySelector(selector); }
querySelectorAll(el, selector: string): List<any> { return el.querySelectorAll(selector); }
on(el, evt, listener) { el.addEventListener(evt, listener, false); }
onAndCancel(el, evt, listener): Function {
@ -112,17 +112,16 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
return res;
}
clearNodes(el) {
for (var i = 0; i < el.childNodes.length; i++) {
this.remove(el.childNodes[i]);
while (el.firstChild) {
el.firstChild.remove();
}
}
appendChild(el, node) { el.appendChild(node); }
removeChild(el, node) { el.removeChild(node); }
replaceChild(el: Node, newChild, oldChild) { el.replaceChild(newChild, oldChild); }
remove(el): Node {
var parent = el.parentNode;
parent.removeChild(el);
return el;
remove(node): Node {
node.remove();
return node;
}
insertBefore(el, node) { el.parentNode.insertBefore(node, el); }
insertAllBefore(el, nodes) {

View File

@ -31,7 +31,7 @@ export class DomAdapter {
parse(templateHtml: string) { throw _abstract(); }
query(selector: string): any { throw _abstract(); }
querySelector(el, selector: string) { throw _abstract(); }
querySelector(el, selector: string): HTMLElement { throw _abstract(); }
querySelectorAll(el, selector: string): List<any> { throw _abstract(); }
on(el, evt, listener) { throw _abstract(); }
onAndCancel(el, evt, listener): Function { throw _abstract(); }
@ -76,7 +76,7 @@ export class DomAdapter {
getShadowRoot(el): any { throw _abstract(); }
getHost(el): any { throw _abstract(); }
getDistributedNodes(el): List<Node> { throw _abstract(); }
clone(node: Node): Node { throw _abstract(); }
clone /*<T extends Node>*/ (node: Node /*T*/): Node /*T*/ { throw _abstract(); }
getElementsByClassName(element, name: string): List<HTMLElement> { throw _abstract(); }
getElementsByTagName(element, name: string): List<HTMLElement> { throw _abstract(); }
classList(element): List<any> { throw _abstract(); }
@ -105,7 +105,7 @@ export class DomAdapter {
isElementNode(node): boolean { throw _abstract(); }
hasShadowRoot(node): boolean { throw _abstract(); }
isShadowRoot(node): boolean { throw _abstract(); }
importIntoDoc(node) { throw _abstract(); }
importIntoDoc /*<T extends Node>*/ (node: Node /*T*/): Node /*T*/ { throw _abstract(); }
isPageRule(rule): boolean { throw _abstract(); }
isStyleRule(rule): boolean { throw _abstract(); }
isMediaRule(rule): boolean { throw _abstract(); }

View File

@ -19,6 +19,8 @@ var _attrToPropMap = {
};
var defDoc = null;
var mapProps = ['attribs', 'x-attribsNamespace', 'x-attribsPrefix'];
function _notImplemented(methodName) {
return new BaseException('This method is not implemented in Parse5DomAdapter: ' + methodName);
}
@ -271,18 +273,45 @@ export class Parse5DomAdapter extends DomAdapter {
getHost(el): string { return el.host; }
getDistributedNodes(el: any): List<Node> { throw _notImplemented('getDistributedNodes'); }
clone(node: Node): Node {
// e.g. document fragment
if ((<any>node).type === 'root') {
var serialized = serializer.serialize(node);
var newParser = new parse5.Parser(parse5.TreeAdapters.htmlparser2);
return newParser.parseFragment(serialized);
} else {
var temp = treeAdapter.createElement("template", null, []);
treeAdapter.appendChild(temp, node);
var serialized = serializer.serialize(temp);
var newParser = new parse5.Parser(parse5.TreeAdapters.htmlparser2);
return newParser.parseFragment(serialized).childNodes[0];
}
var _recursive = (node) => {
var nodeClone = Object.create(Object.getPrototypeOf(node));
for (var prop in node) {
var desc = Object.getOwnPropertyDescriptor(node, prop);
if (desc && 'value' in desc && typeof desc.value !== 'object') {
nodeClone[prop] = node[prop];
}
}
nodeClone.parent = null;
nodeClone.prev = null;
nodeClone.next = null;
nodeClone.children = null;
mapProps.forEach(mapName => {
if (isPresent(node[mapName])) {
nodeClone[mapName] = {};
for (var prop in node[mapName]) {
nodeClone[mapName][prop] = node[mapName][prop];
}
}
});
var cNodes = node.children;
if (cNodes) {
var cNodesClone = new Array(cNodes.length);
for (var i = 0; i < cNodes.length; i++) {
var childNode = cNodes[i];
var childNodeClone = _recursive(childNode);
cNodesClone[i] = childNodeClone;
if (i > 0) {
childNodeClone.prev = cNodesClone[i - 1];
cNodesClone[i - 1].next = childNodeClone;
}
childNodeClone.parent = nodeClone;
}
nodeClone.children = cNodesClone;
}
return nodeClone;
};
return _recursive(node);
}
getElementsByClassName(element, name: string): List<HTMLElement> {
return this.querySelectorAll(element, "." + name);