fix(TemplateParser): match element and attributes regardless the namespace
This commit is contained in:
parent
778677ba75
commit
7c13372721
@ -16,7 +16,7 @@ import {HtmlAst, HtmlAttrAst, HtmlTextAst, HtmlElementAst} from './html_ast';
|
|||||||
import {Injectable} from 'angular2/src/core/di';
|
import {Injectable} from 'angular2/src/core/di';
|
||||||
import {HtmlToken, HtmlTokenType, tokenizeHtml} from './html_lexer';
|
import {HtmlToken, HtmlTokenType, tokenizeHtml} from './html_lexer';
|
||||||
import {ParseError, ParseLocation, ParseSourceSpan} from './parse_util';
|
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 {
|
export class HtmlTreeError extends ParseError {
|
||||||
static create(elementName: string, location: ParseLocation, msg: string): HtmlTreeError {
|
static create(elementName: string, location: ParseLocation, msg: string): HtmlTreeError {
|
||||||
@ -144,7 +144,7 @@ class TreeBuilder {
|
|||||||
if (this.peek.type === HtmlTokenType.TAG_OPEN_END_VOID) {
|
if (this.peek.type === HtmlTokenType.TAG_OPEN_END_VOID) {
|
||||||
this._advance();
|
this._advance();
|
||||||
selfClosing = true;
|
selfClosing = true;
|
||||||
if (getHtmlTagNamespacePrefix(fullName) == null && !getHtmlTagDefinition(fullName).isVoid) {
|
if (getNsPrefix(fullName) == null && !getHtmlTagDefinition(fullName).isVoid) {
|
||||||
this.errors.push(HtmlTreeError.create(
|
this.errors.push(HtmlTreeError.create(
|
||||||
fullName, startTagToken.sourceSpan.start,
|
fullName, startTagToken.sourceSpan.start,
|
||||||
`Only void and foreign elements can be self closed "${startTagToken.parts[1]}"`));
|
`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)) {
|
if (isBlank(prefix)) {
|
||||||
prefix = getHtmlTagDefinition(localName).implicitNamespacePrefix;
|
prefix = getHtmlTagDefinition(localName).implicitNamespacePrefix;
|
||||||
if (isBlank(prefix) && isPresent(parentElement)) {
|
if (isBlank(prefix) && isPresent(parentElement)) {
|
||||||
prefix = getHtmlTagNamespacePrefix(parentElement.name);
|
prefix = getNsPrefix(parentElement.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,7 +409,7 @@ export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
|
|||||||
|
|
||||||
var NS_PREFIX_RE = /^@([^:]+):(.+)/g;
|
var NS_PREFIX_RE = /^@([^:]+):(.+)/g;
|
||||||
|
|
||||||
export function splitHtmlTagNamespace(elementName: string): string[] {
|
export function splitNsName(elementName: string): string[] {
|
||||||
if (elementName[0] != '@') {
|
if (elementName[0] != '@') {
|
||||||
return [null, elementName];
|
return [null, elementName];
|
||||||
}
|
}
|
||||||
@ -417,6 +417,6 @@ export function splitHtmlTagNamespace(elementName: string): string[] {
|
|||||||
return [match[1], match[2]];
|
return [match[1], match[2]];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHtmlTagNamespacePrefix(elementName: string): string {
|
export function getNsPrefix(elementName: string): string {
|
||||||
return splitHtmlTagNamespace(elementName)[0];
|
return splitNsName(elementName)[0];
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import {Injectable} from 'angular2/src/core/di';
|
|||||||
import {isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
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';
|
import {ElementSchemaRegistry} from './element_schema_registry';
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
|
|||||||
private _getProtoElement(tagName: string): Element {
|
private _getProtoElement(tagName: string): Element {
|
||||||
var element = this._protoElements.get(tagName);
|
var element = this._protoElements.get(tagName);
|
||||||
if (isBlank(element)) {
|
if (isBlank(element)) {
|
||||||
var nsAndName = splitHtmlTagNamespace(tagName);
|
var nsAndName = splitNsName(tagName);
|
||||||
element = isPresent(nsAndName[0]) ?
|
element = isPresent(nsAndName[0]) ?
|
||||||
DOM.createElementNS(NAMESPACE_URIS[nsAndName[0]], nsAndName[1]) :
|
DOM.createElementNS(NAMESPACE_URIS[nsAndName[0]], nsAndName[1]) :
|
||||||
DOM.createElement(nsAndName[1]);
|
DOM.createElement(nsAndName[1]);
|
||||||
|
@ -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 {TemplateBinding} from 'angular2/src/core/change_detection/parser/ast';
|
||||||
import {CompileDirectiveMetadata} from './directive_metadata';
|
import {CompileDirectiveMetadata} from './directive_metadata';
|
||||||
import {HtmlParser} from './html_parser';
|
import {HtmlParser} from './html_parser';
|
||||||
import {splitHtmlTagNamespace} from './html_tags';
|
import {splitNsName} from './html_tags';
|
||||||
import {ParseSourceSpan, ParseError, ParseLocation} from './parse_util';
|
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 isTemplateElement = lcElName == TEMPLATE_ELEMENT;
|
||||||
var elementCssSelector = createElementCssSelector(nodeName, matchableAttrs);
|
var elementCssSelector = createElementCssSelector(nodeName, matchableAttrs);
|
||||||
var directives = this._createDirectiveAsts(
|
var directives = this._createDirectiveAsts(
|
||||||
@ -687,13 +687,17 @@ class Component {
|
|||||||
|
|
||||||
function createElementCssSelector(elementName: string, matchableAttrs: string[][]): CssSelector {
|
function createElementCssSelector(elementName: string, matchableAttrs: string[][]): CssSelector {
|
||||||
var cssSelector = new CssSelector();
|
var cssSelector = new CssSelector();
|
||||||
|
let elNameNoNs = splitNsName(elementName)[1];
|
||||||
|
|
||||||
|
cssSelector.setElement(elNameNoNs);
|
||||||
|
|
||||||
cssSelector.setElement(elementName);
|
|
||||||
for (var i = 0; i < matchableAttrs.length; i++) {
|
for (var i = 0; i < matchableAttrs.length; i++) {
|
||||||
var attrName = matchableAttrs[i][0];
|
let attrName = matchableAttrs[i][0];
|
||||||
var attrValue = matchableAttrs[i][1];
|
let attrNameNoNs = splitNsName(attrName)[1];
|
||||||
cssSelector.addAttribute(attrName, attrValue);
|
let attrValue = matchableAttrs[i][1];
|
||||||
if (attrName == CLASS_ATTR) {
|
|
||||||
|
cssSelector.addAttribute(attrNameNoNs, attrValue);
|
||||||
|
if (attrName.toLowerCase() == CLASS_ATTR) {
|
||||||
var classes = splitClasses(attrValue);
|
var classes = splitClasses(attrValue);
|
||||||
classes.forEach(className => cssSelector.addClassName(className));
|
classes.forEach(className => cssSelector.addClassName(className));
|
||||||
}
|
}
|
||||||
|
@ -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', () => {
|
it('should support directive property', () => {
|
||||||
var dirA = CompileDirectiveMetadata.create(
|
var dirA = CompileDirectiveMetadata.create(
|
||||||
{selector: 'div', type: new CompileTypeMetadata({name: 'DirA'}), inputs: ['aProp']});
|
{selector: 'div', type: new CompileTypeMetadata({name: 'DirA'}), inputs: ['aProp']});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user