refactor(compiler): various cleanups
- use `$implicit` variable value correctly - handle `ng-non-bindable` correctly - add some more assertions to `TemplateCompiler` - make `CompiledTemplate` const - fix default value for `@Directive.moduleId` - add new compiler to application bindings BREAKING CHANGE: - `Compiler.compileInHost` and all methods of `DynamicComponentLoader` don’t take `Binding` any more, only `Type`s. This is in preparation for the new compiler which does not support this. Part of #3605 Closes #4346
This commit is contained in:
@@ -35,7 +35,8 @@ import {escapeSingleQuoteString} from './util';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
|
||||
export var TEMPLATE_COMMANDS_MODULE_REF = moduleRef('angular2/src/core/compiler/template_commands');
|
||||
const IMPLICIT_VAR = '%implicit';
|
||||
|
||||
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
|
||||
|
||||
@Injectable()
|
||||
export class CommandCompiler {
|
||||
@@ -207,7 +208,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
|
||||
var variableNameAndValues = [];
|
||||
ast.vars.forEach((varAst) => {
|
||||
variableNameAndValues.push(varAst.name);
|
||||
variableNameAndValues.push(varAst.value);
|
||||
variableNameAndValues.push(varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR);
|
||||
});
|
||||
var directives = [];
|
||||
ListWrapper.forEachWithIndex(ast.directives, (directiveAst: DirectiveAst, index: number) => {
|
||||
@@ -227,7 +228,7 @@ class CommandBuilderVisitor<R> implements TemplateAstVisitor {
|
||||
if (isBlank(component)) {
|
||||
ast.exportAsVars.forEach((varAst) => {
|
||||
variableNameAndValues.push(varAst.name);
|
||||
variableNameAndValues.push(IMPLICIT_VAR);
|
||||
variableNameAndValues.push(null);
|
||||
});
|
||||
}
|
||||
var directives = [];
|
||||
|
||||
@@ -5,3 +5,31 @@ export {
|
||||
CompileTemplateMetadata
|
||||
} from './directive_metadata';
|
||||
export {SourceModule, SourceWithImports} from './source_module';
|
||||
|
||||
import {assertionsEnabled, Type} from 'angular2/src/core/facade/lang';
|
||||
import {bind, Binding} from 'angular2/src/core/di';
|
||||
import {TemplateParser} from 'angular2/src/compiler/template_parser';
|
||||
import {HtmlParser} from 'angular2/src/compiler/html_parser';
|
||||
import {TemplateNormalizer} from 'angular2/src/compiler/template_normalizer';
|
||||
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
|
||||
import {ChangeDetectionCompiler} from 'angular2/src/compiler/change_detector_compiler';
|
||||
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
|
||||
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
|
||||
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
|
||||
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';
|
||||
|
||||
export function compilerBindings(): Array<Type | Binding | any[]> {
|
||||
return [
|
||||
HtmlParser,
|
||||
TemplateParser,
|
||||
TemplateNormalizer,
|
||||
RuntimeMetadataResolver,
|
||||
StyleCompiler,
|
||||
CommandCompiler,
|
||||
ChangeDetectionCompiler,
|
||||
bind(ChangeDetectorGenConfig)
|
||||
.toValue(
|
||||
new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), false, true)),
|
||||
TemplateCompiler,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -57,12 +57,7 @@ function parseElement(element: Element, indexInParent: number, parentSourceInfo:
|
||||
var sourceInfo = `${parentSourceInfo} > ${nodeName}:nth-child(${indexInParent})`;
|
||||
var attrs = parseAttrs(element, sourceInfo);
|
||||
|
||||
var childNodes;
|
||||
if (ignoreChildren(attrs)) {
|
||||
childNodes = [];
|
||||
} else {
|
||||
childNodes = parseChildNodes(element, sourceInfo);
|
||||
}
|
||||
var childNodes = parseChildNodes(element, sourceInfo);
|
||||
return new HtmlElementAst(nodeName, attrs, childNodes, sourceInfo);
|
||||
}
|
||||
|
||||
@@ -100,16 +95,6 @@ function parseChildNodes(element: Element, parentSourceInfo: string): HtmlAst[]
|
||||
return result;
|
||||
}
|
||||
|
||||
function ignoreChildren(attrs: HtmlAttrAst[]): boolean {
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
var a = attrs[i];
|
||||
if (a.name == NG_NON_BINDABLE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class UnparseVisitor implements HtmlAstVisitor {
|
||||
visitElement(ast: HtmlElementAst, parts: string[]): any {
|
||||
parts.push(`<${ast.name}`);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {CompileTypeMetadata, CompileDirectiveMetadata} from './directive_metadata';
|
||||
import {CompileTypeMetadata, CompileTemplateMetadata} from './directive_metadata';
|
||||
import {SourceModule, SourceExpression, moduleRef} from './source_module';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/render/api';
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
@@ -29,27 +29,28 @@ export class StyleCompiler {
|
||||
|
||||
constructor(private _xhr: XHR, private _urlResolver: UrlResolver) {}
|
||||
|
||||
compileComponentRuntime(component: CompileDirectiveMetadata): Promise<string[]> {
|
||||
var styles = component.template.styles;
|
||||
var styleAbsUrls = component.template.styleUrls;
|
||||
compileComponentRuntime(type: CompileTypeMetadata,
|
||||
template: CompileTemplateMetadata): Promise<string[]> {
|
||||
var styles = template.styles;
|
||||
var styleAbsUrls = template.styleUrls;
|
||||
return this._loadStyles(styles, styleAbsUrls,
|
||||
component.template.encapsulation === ViewEncapsulation.Emulated)
|
||||
.then(styles => styles.map(style => StringWrapper.replaceAll(style, COMPONENT_REGEX,
|
||||
`${component.type.id}`)));
|
||||
template.encapsulation === ViewEncapsulation.Emulated)
|
||||
.then(styles => styles.map(
|
||||
style => StringWrapper.replaceAll(style, COMPONENT_REGEX, `${type.id}`)));
|
||||
}
|
||||
|
||||
compileComponentCodeGen(component: CompileDirectiveMetadata): SourceExpression {
|
||||
var shim = component.template.encapsulation === ViewEncapsulation.Emulated;
|
||||
compileComponentCodeGen(type: CompileTypeMetadata,
|
||||
template: CompileTemplateMetadata): SourceExpression {
|
||||
var shim = template.encapsulation === ViewEncapsulation.Emulated;
|
||||
var suffix;
|
||||
if (shim) {
|
||||
var componentId = `${ component.type.id}`;
|
||||
var componentId = `${ type.id}`;
|
||||
suffix =
|
||||
codeGenMapArray(['style'], `style${codeGenReplaceAll(COMPONENT_VARIABLE, componentId)}`);
|
||||
} else {
|
||||
suffix = '';
|
||||
}
|
||||
return this._styleCodeGen(component.template.styles, component.template.styleUrls, shim,
|
||||
suffix);
|
||||
return this._styleCodeGen(template.styles, template.styleUrls, shim, suffix);
|
||||
}
|
||||
|
||||
compileStylesheetCodeGen(moduleId: string, cssText: string): SourceModule[] {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {Type, Json, isBlank, stringify} from 'angular2/src/core/facade/lang';
|
||||
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
||||
import {ListWrapper, SetWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
|
||||
import {CompiledTemplate, TemplateCmd} from 'angular2/src/core/compiler/template_commands';
|
||||
@@ -58,18 +59,12 @@ export class TemplateCompiler {
|
||||
}));
|
||||
}
|
||||
|
||||
serializeDirectiveMetadata(metadata: CompileDirectiveMetadata): string {
|
||||
return Json.stringify(metadata.toJson());
|
||||
}
|
||||
|
||||
deserializeDirectiveMetadata(data: string): CompileDirectiveMetadata {
|
||||
return CompileDirectiveMetadata.fromJson(Json.parse(data));
|
||||
}
|
||||
|
||||
compileHostComponentRuntime(type: Type): Promise<CompiledTemplate> {
|
||||
var compMeta: CompileDirectiveMetadata = this._runtimeMetadataResolver.getMetadata(type);
|
||||
assertComponent(compMeta);
|
||||
var hostMeta: CompileDirectiveMetadata =
|
||||
createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||
|
||||
this._compileComponentRuntime(hostMeta, [compMeta], new Set());
|
||||
return this._compiledTemplateDone.get(hostMeta.type.id);
|
||||
}
|
||||
@@ -93,28 +88,30 @@ export class TemplateCompiler {
|
||||
new CompiledTemplate(compMeta.type.id, () => [changeDetectorFactory, commands, styles]);
|
||||
this._compiledTemplateCache.set(compMeta.type.id, compiledTemplate);
|
||||
compilingComponentIds.add(compMeta.type.id);
|
||||
done = PromiseWrapper.all([<any>this._styleCompiler.compileComponentRuntime(compMeta)].concat(
|
||||
viewDirectives.map(
|
||||
dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
|
||||
.then((stylesAndNormalizedViewDirMetas: any[]) => {
|
||||
var childPromises = [];
|
||||
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
|
||||
var parsedTemplate = this._templateParser.parse(
|
||||
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
|
||||
done =
|
||||
PromiseWrapper
|
||||
.all([
|
||||
<any>this._styleCompiler.compileComponentRuntime(compMeta.type, compMeta.template)
|
||||
].concat(viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
|
||||
.then((stylesAndNormalizedViewDirMetas: any[]) => {
|
||||
var childPromises = [];
|
||||
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
|
||||
var parsedTemplate = this._templateParser.parse(
|
||||
compMeta.template.template, normalizedViewDirMetas, compMeta.type.name);
|
||||
|
||||
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
|
||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||
changeDetectorFactory = changeDetectorFactories[0];
|
||||
styles = stylesAndNormalizedViewDirMetas[0];
|
||||
commands = this._compileCommandsRuntime(compMeta, parsedTemplate,
|
||||
changeDetectorFactories,
|
||||
compilingComponentIds, childPromises);
|
||||
return PromiseWrapper.all(childPromises);
|
||||
})
|
||||
.then((_) => {
|
||||
SetWrapper.delete(compilingComponentIds, compMeta.type.id);
|
||||
return compiledTemplate;
|
||||
});
|
||||
var changeDetectorFactories = this._cdCompiler.compileComponentRuntime(
|
||||
compMeta.type, compMeta.changeDetection, parsedTemplate);
|
||||
changeDetectorFactory = changeDetectorFactories[0];
|
||||
styles = stylesAndNormalizedViewDirMetas[0];
|
||||
commands =
|
||||
this._compileCommandsRuntime(compMeta, parsedTemplate, changeDetectorFactories,
|
||||
compilingComponentIds, childPromises);
|
||||
return PromiseWrapper.all(childPromises);
|
||||
})
|
||||
.then((_) => {
|
||||
SetWrapper.delete(compilingComponentIds, compMeta.type.id);
|
||||
return compiledTemplate;
|
||||
});
|
||||
this._compiledTemplateDone.set(compMeta.type.id, done);
|
||||
}
|
||||
return compiledTemplate;
|
||||
@@ -148,6 +145,7 @@ export class TemplateCompiler {
|
||||
var componentMetas: CompileDirectiveMetadata[] = [];
|
||||
components.forEach(componentWithDirs => {
|
||||
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
||||
assertComponent(compMeta);
|
||||
componentMetas.push(compMeta);
|
||||
this._processTemplateCodeGen(compMeta,
|
||||
<CompileDirectiveMetadata[]>componentWithDirs.directives,
|
||||
@@ -174,7 +172,7 @@ export class TemplateCompiler {
|
||||
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata,
|
||||
directives: CompileDirectiveMetadata[],
|
||||
targetDeclarations: string[], targetTemplateArguments: any[][]) {
|
||||
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta);
|
||||
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.type, compMeta.template);
|
||||
var parsedTemplate =
|
||||
this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name);
|
||||
var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen(
|
||||
@@ -197,6 +195,12 @@ export class NormalizedComponentWithViewDirectives {
|
||||
public directives: CompileDirectiveMetadata[]) {}
|
||||
}
|
||||
|
||||
function assertComponent(meta: CompileDirectiveMetadata) {
|
||||
if (!meta.isComponent) {
|
||||
throw new BaseException(`Could not compile '${meta.type.name}' because it is not a component.`);
|
||||
}
|
||||
}
|
||||
|
||||
function templateVariableName(type: CompileTypeMetadata): string {
|
||||
return `${type.name}Template`;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
CompileTemplateMetadata
|
||||
} from './directive_metadata';
|
||||
import {isPresent, isBlank} from 'angular2/src/core/facade/lang';
|
||||
import {BaseException} from 'angular2/src/core/facade/exceptions';
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/core/facade/async';
|
||||
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
@@ -34,11 +35,13 @@ export class TemplateNormalizer {
|
||||
if (isPresent(template.template)) {
|
||||
return PromiseWrapper.resolve(this.normalizeLoadedTemplate(
|
||||
directiveType, template, template.template, directiveType.moduleId));
|
||||
} else {
|
||||
} else if (isPresent(template.templateUrl)) {
|
||||
var sourceAbsUrl = this._urlResolver.resolve(directiveType.moduleId, template.templateUrl);
|
||||
return this._xhr.get(sourceAbsUrl)
|
||||
.then(templateContent => this.normalizeLoadedTemplate(directiveType, template,
|
||||
templateContent, sourceAbsUrl));
|
||||
} else {
|
||||
throw new BaseException(`No template specified for component ${directiveType.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,12 +82,15 @@ class TemplatePreparseVisitor implements HtmlAstVisitor {
|
||||
ngContentSelectors: string[] = [];
|
||||
styles: string[] = [];
|
||||
styleUrls: string[] = [];
|
||||
ngNonBindableStackCount: number = 0;
|
||||
|
||||
visitElement(ast: HtmlElementAst, context: any): any {
|
||||
var preparsedElement = preparseElement(ast);
|
||||
switch (preparsedElement.type) {
|
||||
case PreparsedElementType.NG_CONTENT:
|
||||
this.ngContentSelectors.push(preparsedElement.selectAttr);
|
||||
if (this.ngNonBindableStackCount === 0) {
|
||||
this.ngContentSelectors.push(preparsedElement.selectAttr);
|
||||
}
|
||||
break;
|
||||
case PreparsedElementType.STYLE:
|
||||
var textContent = '';
|
||||
@@ -99,8 +105,12 @@ class TemplatePreparseVisitor implements HtmlAstVisitor {
|
||||
this.styleUrls.push(preparsedElement.hrefAttr);
|
||||
break;
|
||||
}
|
||||
if (preparsedElement.type !== PreparsedElementType.NON_BINDABLE) {
|
||||
htmlVisitAll(this, ast.children);
|
||||
if (preparsedElement.nonBindable) {
|
||||
this.ngNonBindableStackCount++;
|
||||
}
|
||||
htmlVisitAll(this, ast.children);
|
||||
if (preparsedElement.nonBindable) {
|
||||
this.ngNonBindableStackCount--;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -164,8 +164,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
var preparsedElement = preparseElement(element);
|
||||
if (preparsedElement.type === PreparsedElementType.SCRIPT ||
|
||||
preparsedElement.type === PreparsedElementType.STYLE ||
|
||||
preparsedElement.type === PreparsedElementType.STYLESHEET ||
|
||||
preparsedElement.type === PreparsedElementType.NON_BINDABLE) {
|
||||
preparsedElement.type === PreparsedElementType.STYLESHEET) {
|
||||
// Skipping <script> for security reasons
|
||||
// Skipping <style> and stylesheets as we already processed them
|
||||
// in the StyleCompiler
|
||||
@@ -196,13 +195,14 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
}
|
||||
});
|
||||
var isTemplateElement = nodeName == TEMPLATE_ELEMENT;
|
||||
var elementCssSelector = this._createElementCssSelector(nodeName, matchableAttrs);
|
||||
var elementCssSelector = createElementCssSelector(nodeName, matchableAttrs);
|
||||
var directives = this._createDirectiveAsts(
|
||||
element.name, this._parseDirectives(this.selectorMatcher, elementCssSelector),
|
||||
elementOrDirectiveProps, isTemplateElement ? [] : vars, element.sourceInfo);
|
||||
var elementProps: BoundElementPropertyAst[] =
|
||||
this._createElementPropertyAsts(element.name, elementOrDirectiveProps, directives);
|
||||
var children = htmlVisitAll(this, element.children, Component.create(directives));
|
||||
var children = htmlVisitAll(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this,
|
||||
element.children, Component.create(directives));
|
||||
var elementNgContentIndex =
|
||||
hasInlineTemplates ? null : component.findNgContentIndex(elementCssSelector);
|
||||
var parsedElement;
|
||||
@@ -221,8 +221,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
children, elementNgContentIndex, element.sourceInfo);
|
||||
}
|
||||
if (hasInlineTemplates) {
|
||||
var templateCssSelector =
|
||||
this._createElementCssSelector(TEMPLATE_ELEMENT, templateMatchableAttrs);
|
||||
var templateCssSelector = createElementCssSelector(TEMPLATE_ELEMENT, templateMatchableAttrs);
|
||||
var templateDirectives = this._createDirectiveAsts(
|
||||
element.name, this._parseDirectives(this.selectorMatcher, templateCssSelector),
|
||||
templateElementOrDirectiveProps, [], element.sourceInfo);
|
||||
@@ -381,22 +380,6 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
sourceInfo));
|
||||
}
|
||||
|
||||
private _createElementCssSelector(elementName: string, matchableAttrs: string[][]): CssSelector {
|
||||
var cssSelector = new CssSelector();
|
||||
|
||||
cssSelector.setElement(elementName);
|
||||
for (var i = 0; i < matchableAttrs.length; i++) {
|
||||
var attrName = matchableAttrs[i][0].toLowerCase();
|
||||
var attrValue = matchableAttrs[i][1];
|
||||
cssSelector.addAttribute(attrName, attrValue);
|
||||
if (attrName == CLASS_ATTR) {
|
||||
var classes = splitClasses(attrValue);
|
||||
classes.forEach(className => cssSelector.addClassName(className));
|
||||
}
|
||||
}
|
||||
return cssSelector;
|
||||
}
|
||||
|
||||
private _parseDirectives(selectorMatcher: SelectorMatcher,
|
||||
elementCssSelector: CssSelector): CompileDirectiveMetadata[] {
|
||||
var directives = [];
|
||||
@@ -480,8 +463,14 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
targetBoundDirectiveProps: BoundDirectivePropertyAst[]) {
|
||||
if (isPresent(directiveProperties)) {
|
||||
var boundPropsByName: Map<string, BoundElementOrDirectiveProperty> = new Map();
|
||||
boundProps.forEach(boundProp =>
|
||||
boundPropsByName.set(dashCaseToCamelCase(boundProp.name), boundProp));
|
||||
boundProps.forEach(boundProp => {
|
||||
var key = dashCaseToCamelCase(boundProp.name);
|
||||
var prevValue = boundPropsByName.get(boundProp.name);
|
||||
if (isBlank(prevValue) || prevValue.isLiteral) {
|
||||
// give [a]="b" a higher precedence thatn a="b" on the same element
|
||||
boundPropsByName.set(key, boundProp);
|
||||
}
|
||||
});
|
||||
|
||||
StringMapWrapper.forEach(directiveProperties, (elProp: string, dirProp: string) => {
|
||||
elProp = dashCaseToCamelCase(elProp);
|
||||
@@ -585,6 +574,34 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
class NonBindableVisitor implements HtmlAstVisitor {
|
||||
visitElement(ast: HtmlElementAst, component: Component): ElementAst {
|
||||
var preparsedElement = preparseElement(ast);
|
||||
if (preparsedElement.type === PreparsedElementType.SCRIPT ||
|
||||
preparsedElement.type === PreparsedElementType.STYLE ||
|
||||
preparsedElement.type === PreparsedElementType.STYLESHEET) {
|
||||
// Skipping <script> for security reasons
|
||||
// Skipping <style> and stylesheets as we already processed them
|
||||
// in the StyleCompiler
|
||||
return null;
|
||||
}
|
||||
|
||||
var attrNameAndValues = ast.attrs.map(attrAst => [attrAst.name, attrAst.value]);
|
||||
var selector = createElementCssSelector(ast.name, attrNameAndValues);
|
||||
var ngContentIndex = component.findNgContentIndex(selector);
|
||||
var children = htmlVisitAll(this, ast.children, EMPTY_COMPONENT);
|
||||
return new ElementAst(ast.name, htmlVisitAll(this, ast.attrs), [], [], [], [], children,
|
||||
ngContentIndex, ast.sourceInfo);
|
||||
}
|
||||
visitAttr(ast: HtmlAttrAst, context: any): AttrAst {
|
||||
return new AttrAst(ast.name, ast.value, ast.sourceInfo);
|
||||
}
|
||||
visitText(ast: HtmlTextAst, component: Component): TextAst {
|
||||
var ngContentIndex = component.findNgContentIndex(TEXT_CSS_SELECTOR);
|
||||
return new TextAst(ast.value, ngContentIndex, ast.sourceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
class BoundElementOrDirectiveProperty {
|
||||
constructor(public name: string, public expression: AST, public isLiteral: boolean,
|
||||
public sourceInfo: string) {}
|
||||
@@ -631,4 +648,21 @@ class Component {
|
||||
}
|
||||
}
|
||||
|
||||
function createElementCssSelector(elementName: string, matchableAttrs: string[][]): CssSelector {
|
||||
var cssSelector = new CssSelector();
|
||||
|
||||
cssSelector.setElement(elementName);
|
||||
for (var i = 0; i < matchableAttrs.length; i++) {
|
||||
var attrName = matchableAttrs[i][0].toLowerCase();
|
||||
var attrValue = matchableAttrs[i][1];
|
||||
cssSelector.addAttribute(attrName, attrValue);
|
||||
if (attrName == CLASS_ATTR) {
|
||||
var classes = splitClasses(attrValue);
|
||||
classes.forEach(className => cssSelector.addClassName(className));
|
||||
}
|
||||
}
|
||||
return cssSelector;
|
||||
}
|
||||
|
||||
var EMPTY_COMPONENT = new Component(new SelectorMatcher(), null);
|
||||
var NON_BINDABLE_VISITOR = new NonBindableVisitor();
|
||||
@@ -30,9 +30,7 @@ export function preparseElement(ast: HtmlElementAst): PreparsedElement {
|
||||
selectAttr = normalizeNgContentSelect(selectAttr);
|
||||
var nodeName = ast.name;
|
||||
var type = PreparsedElementType.OTHER;
|
||||
if (nonBindable) {
|
||||
type = PreparsedElementType.NON_BINDABLE;
|
||||
} else if (nodeName == NG_CONTENT_ELEMENT) {
|
||||
if (nodeName == NG_CONTENT_ELEMENT) {
|
||||
type = PreparsedElementType.NG_CONTENT;
|
||||
} else if (nodeName == STYLE_ELEMENT) {
|
||||
type = PreparsedElementType.STYLE;
|
||||
@@ -41,7 +39,7 @@ export function preparseElement(ast: HtmlElementAst): PreparsedElement {
|
||||
} else if (nodeName == LINK_ELEMENT && relAttr == LINK_STYLE_REL_VALUE) {
|
||||
type = PreparsedElementType.STYLESHEET;
|
||||
}
|
||||
return new PreparsedElement(type, selectAttr, hrefAttr);
|
||||
return new PreparsedElement(type, selectAttr, hrefAttr, nonBindable);
|
||||
}
|
||||
|
||||
export enum PreparsedElementType {
|
||||
@@ -49,13 +47,12 @@ export enum PreparsedElementType {
|
||||
STYLE,
|
||||
STYLESHEET,
|
||||
SCRIPT,
|
||||
NON_BINDABLE,
|
||||
OTHER
|
||||
}
|
||||
|
||||
export class PreparsedElement {
|
||||
constructor(public type: PreparsedElementType, public selectAttr: string,
|
||||
public hrefAttr: string) {}
|
||||
constructor(public type: PreparsedElementType, public selectAttr: string, public hrefAttr: string,
|
||||
public nonBindable: boolean) {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import {StringWrapper, isBlank, isJsObject} from 'angular2/src/core/facade/lang'
|
||||
|
||||
var CAMEL_CASE_REGEXP = /([A-Z])/g;
|
||||
var DASH_CASE_REGEXP = /-([a-z])/g;
|
||||
var SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n/g;
|
||||
var DOUBLE_QUOTE_ESCAPE_STRING_RE = /"|\\|\n/g;
|
||||
var SINGLE_QUOTE_ESCAPE_STRING_RE = /'|\\|\n|\$/g;
|
||||
var DOUBLE_QUOTE_ESCAPE_STRING_RE = /"|\\|\n|\$/g;
|
||||
|
||||
export var IS_DART = !isJsObject({});
|
||||
|
||||
@@ -33,7 +33,9 @@ export function escapeDoubleQuoteString(input: string): string {
|
||||
|
||||
function escapeString(input: string, re: RegExp): string {
|
||||
return StringWrapper.replaceAllMapped(input, re, (match) => {
|
||||
if (match[0] == '\n') {
|
||||
if (match[0] == '$') {
|
||||
return IS_DART ? '\\$' : '$';
|
||||
} else if (match[0] == '\n') {
|
||||
return '\\n';
|
||||
} else {
|
||||
return `\\${match[0]}`;
|
||||
|
||||
Reference in New Issue
Block a user