108 lines
3.6 KiB
TypeScript
Raw Normal View History

import {List, Map, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {isBlank, isPresent, Type, StringJoiner, assertionsEnabled} from 'angular2/src/facade/lang';
import {ProtoViewBuilder, ElementBinderBuilder} from '../view/proto_view_builder';
/**
* Collects all data that is needed to process an element
* in the compile process. Fields are filled
* by the CompileSteps starting out with the pure HTMLElement.
*/
export class CompileElement {
2015-06-12 23:11:11 +02:00
_attrs: Map<string, string> = null;
_classList: List<string> = null;
isViewRoot: boolean = false;
// inherited down to children if they don't have an own protoView
inheritedProtoView: ProtoViewBuilder = null;
distanceToInheritedBinder: number = 0;
// inherited down to children if they don't have an own elementBinder
inheritedElementBinder: ElementBinderBuilder = null;
compileChildren: boolean = true;
2015-05-18 11:57:20 -07:00
elementDescription: string; // e.g. '<div [class]="foo">' : used to provide context in case of
// error
2015-06-12 23:11:11 +02:00
constructor(public element, compilationUnit: string = '') {
// description is calculated here as compilation steps may change the element
2015-05-18 11:57:20 -07:00
var tplDesc = assertionsEnabled() ? getElementDescription(element) : null;
if (compilationUnit !== '') {
this.elementDescription = compilationUnit;
if (isPresent(tplDesc)) this.elementDescription += ": " + tplDesc;
} else {
this.elementDescription = tplDesc;
}
}
isBound(): boolean {
return isPresent(this.inheritedElementBinder) && this.distanceToInheritedBinder === 0;
}
bindElement(): ElementBinderBuilder {
if (!this.isBound()) {
var parentBinder = this.inheritedElementBinder;
2015-05-18 11:57:20 -07:00
this.inheritedElementBinder =
this.inheritedProtoView.bindElement(this.element, this.elementDescription);
if (isPresent(parentBinder)) {
this.inheritedElementBinder.setParent(parentBinder, this.distanceToInheritedBinder);
}
this.distanceToInheritedBinder = 0;
}
return this.inheritedElementBinder;
}
2015-05-18 11:57:20 -07:00
refreshAttrs() { this._attrs = null; }
2015-05-18 11:57:20 -07:00
attrs(): Map<string, string> {
if (isBlank(this._attrs)) {
this._attrs = DOM.attributeMap(this.element);
}
return this._attrs;
}
2015-05-18 11:57:20 -07:00
refreshClassList() { this._classList = null; }
2015-05-18 11:57:20 -07:00
classList(): List<string> {
if (isBlank(this._classList)) {
this._classList = [];
var elClassList = DOM.classList(this.element);
for (var i = 0; i < elClassList.length; i++) {
this._classList.push(elClassList[i]);
}
}
return this._classList;
}
}
// return an HTML representation of an element start tag - without its content
// this is used to give contextual information in case of errors
2015-05-18 11:57:20 -07:00
function getElementDescription(domElement): string {
var buf = new StringJoiner();
var atts = DOM.attributeMap(domElement);
buf.add("<");
buf.add(DOM.tagName(domElement).toLowerCase());
// show id and class first to ease element identification
addDescriptionAttribute(buf, "id", atts.get("id"));
addDescriptionAttribute(buf, "class", atts.get("class"));
MapWrapper.forEach(atts, (attValue, attName) => {
2015-05-18 11:57:20 -07:00
if (attName !== "id" && attName !== "class") {
addDescriptionAttribute(buf, attName, attValue);
}
});
buf.add(">");
return buf.toString();
}
2015-05-18 11:57:20 -07:00
function addDescriptionAttribute(buffer: StringJoiner, attName: string, attValue) {
if (isPresent(attValue)) {
2015-05-18 11:57:20 -07:00
if (attValue.length === 0) {
buffer.add(' ' + attName);
} else {
buffer.add(' ' + attName + '="' + attValue + '"');
}
}
}