fix(TemplateParser): match element and attributes regardless the namespace

This commit is contained in:
Victor Berchet 2015-12-09 09:32:15 -08:00
parent 778677ba75
commit 7c13372721
5 changed files with 37 additions and 15 deletions

View File

@ -16,7 +16,7 @@ import {HtmlAst, HtmlAttrAst, HtmlTextAst, HtmlElementAst} from './html_ast';
import {Injectable} from 'angular2/src/core/di';
import {HtmlToken, HtmlTokenType, tokenizeHtml} from './html_lexer';
import {ParseError, ParseLocation, ParseSourceSpan} from './parse_util';
import {HtmlTagDefinition, getHtmlTagDefinition, getHtmlTagNamespacePrefix} from './html_tags';
import {HtmlTagDefinition, getHtmlTagDefinition, getNsPrefix} from './html_tags';
export class HtmlTreeError extends ParseError {
static create(elementName: string, location: ParseLocation, msg: string): HtmlTreeError {
@ -144,7 +144,7 @@ class TreeBuilder {
if (this.peek.type === HtmlTokenType.TAG_OPEN_END_VOID) {
this._advance();
selfClosing = true;
if (getHtmlTagNamespacePrefix(fullName) == null && !getHtmlTagDefinition(fullName).isVoid) {
if (getNsPrefix(fullName) == null && !getHtmlTagDefinition(fullName).isVoid) {
this.errors.push(HtmlTreeError.create(
fullName, startTagToken.sourceSpan.start,
`Only void and foreign elements can be self closed "${startTagToken.parts[1]}"`));
@ -247,7 +247,7 @@ function getElementFullName(prefix: string, localName: string,
if (isBlank(prefix)) {
prefix = getHtmlTagDefinition(localName).implicitNamespacePrefix;
if (isBlank(prefix) && isPresent(parentElement)) {
prefix = getHtmlTagNamespacePrefix(parentElement.name);
prefix = getNsPrefix(parentElement.name);
}
}

View File

@ -409,7 +409,7 @@ export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
var NS_PREFIX_RE = /^@([^:]+):(.+)/g;
export function splitHtmlTagNamespace(elementName: string): string[] {
export function splitNsName(elementName: string): string[] {
if (elementName[0] != '@') {
return [null, elementName];
}
@ -417,6 +417,6 @@ export function splitHtmlTagNamespace(elementName: string): string[] {
return [match[1], match[2]];
}
export function getHtmlTagNamespacePrefix(elementName: string): string {
return splitHtmlTagNamespace(elementName)[0];
export function getNsPrefix(elementName: string): string {
return splitNsName(elementName)[0];
}

View File

@ -2,7 +2,7 @@ import {Injectable} from 'angular2/src/core/di';
import {isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
import {StringMapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {splitHtmlTagNamespace} from 'angular2/src/compiler/html_tags';
import {splitNsName} from 'angular2/src/compiler/html_tags';
import {ElementSchemaRegistry} from './element_schema_registry';
@ -16,7 +16,7 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
private _getProtoElement(tagName: string): Element {
var element = this._protoElements.get(tagName);
if (isBlank(element)) {
var nsAndName = splitHtmlTagNamespace(tagName);
var nsAndName = splitNsName(tagName);
element = isPresent(nsAndName[0]) ?
DOM.createElementNS(NAMESPACE_URIS[nsAndName[0]], nsAndName[1]) :
DOM.createElement(nsAndName[1]);

View File

@ -7,7 +7,7 @@ import {Parser, AST, ASTWithSource} from 'angular2/src/core/change_detection/cha
import {TemplateBinding} from 'angular2/src/core/change_detection/parser/ast';
import {CompileDirectiveMetadata} from './directive_metadata';
import {HtmlParser} from './html_parser';
import {splitHtmlTagNamespace} from './html_tags';
import {splitNsName} from './html_tags';
import {ParseSourceSpan, ParseError, ParseLocation} from './parse_util';
@ -216,7 +216,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
}
});
var lcElName = splitHtmlTagNamespace(nodeName.toLowerCase())[1];
var lcElName = splitNsName(nodeName.toLowerCase())[1];
var isTemplateElement = lcElName == TEMPLATE_ELEMENT;
var elementCssSelector = createElementCssSelector(nodeName, matchableAttrs);
var directives = this._createDirectiveAsts(
@ -687,13 +687,17 @@ class Component {
function createElementCssSelector(elementName: string, matchableAttrs: string[][]): CssSelector {
var cssSelector = new CssSelector();
let elNameNoNs = splitNsName(elementName)[1];
cssSelector.setElement(elNameNoNs);
cssSelector.setElement(elementName);
for (var i = 0; i < matchableAttrs.length; i++) {
var attrName = matchableAttrs[i][0];
var attrValue = matchableAttrs[i][1];
cssSelector.addAttribute(attrName, attrValue);
if (attrName == CLASS_ATTR) {
let attrName = matchableAttrs[i][0];
let attrNameNoNs = splitNsName(attrName)[1];
let attrValue = matchableAttrs[i][1];
cssSelector.addAttribute(attrNameNoNs, attrValue);
if (attrName.toLowerCase() == CLASS_ATTR) {
var classes = splitClasses(attrValue);
classes.forEach(className => cssSelector.addClassName(className));
}

View File

@ -908,6 +908,24 @@ Property binding a not used by any directive on an embedded template ("[ERROR ->
]);
});
it('should support directive in namespace', () => {
var tagSel = CompileDirectiveMetadata.create(
{selector: 'circle', type: new CompileTypeMetadata({name: 'elDir'})});
var attrSel = CompileDirectiveMetadata.create(
{selector: '[href]', type: new CompileTypeMetadata({name: 'attrDir'})});
expect(humanizeTplAstSourceSpans(
parse('<svg><circle /><use xlink:href="Port" /></svg>', [tagSel, attrSel])))
.toEqual([
[ElementAst, '@svg:svg', '<svg>'],
[ElementAst, '@svg:circle', '<circle />'],
[DirectiveAst, tagSel, '<circle />'],
[ElementAst, '@svg:use', '<use xlink:href="Port" />'],
[AttrAst, '@xlink:href', 'Port', 'xlink:href="Port"'],
[DirectiveAst, attrSel, '<use xlink:href="Port" />'],
]);
});
it('should support directive property', () => {
var dirA = CompileDirectiveMetadata.create(
{selector: 'div', type: new CompileTypeMetadata({name: 'DirA'}), inputs: ['aProp']});