fix(HtmlParser): close void elements on all node types

fixes #5528
This commit is contained in:
Victor Berchet
2015-12-01 13:01:05 -08:00
committed by Jeremy Elbourn
parent 070d818e68
commit 9c6b929c7b
3 changed files with 45 additions and 20 deletions
@@ -61,12 +61,15 @@ class TreeBuilder {
} else if (this.peek.type === HtmlTokenType.TAG_CLOSE) {
this._consumeEndTag(this._advance());
} else if (this.peek.type === HtmlTokenType.CDATA_START) {
this._closeVoidElement();
this._consumeCdata(this._advance());
} else if (this.peek.type === HtmlTokenType.COMMENT_START) {
this._closeVoidElement();
this._consumeComment(this._advance());
} else if (this.peek.type === HtmlTokenType.TEXT ||
this.peek.type === HtmlTokenType.RAW_TEXT ||
this.peek.type === HtmlTokenType.ESCAPABLE_RAW_TEXT) {
this._closeVoidElement();
this._consumeText(this._advance());
} else {
// Skip all other tokens...
@@ -107,6 +110,16 @@ class TreeBuilder {
this._addToParent(new HtmlTextAst(token.parts[0], token.sourceSpan));
}
private _closeVoidElement(): void {
if (this.elementStack.length > 0) {
let el = ListWrapper.last(this.elementStack);
if (getHtmlTagDefinition(el.name).isVoid) {
this.elementStack.pop();
}
}
}
private _consumeStartTag(startTagToken: HtmlToken) {
var prefix = startTagToken.parts[0];
var name = startTagToken.parts[1];
+14 -12
View File
@@ -70,19 +70,22 @@ export class HtmlTagDefinition {
public parentToAdd: string;
public implicitNamespacePrefix: string;
public contentType: HtmlTagContentType;
public isVoid: boolean;
constructor({closedByChildren, requiredParents, implicitNamespacePrefix, contentType,
closedByParent}: {
closedByParent, isVoid}: {
closedByChildren?: string[],
closedByParent?: boolean,
requiredParents?: string[],
implicitNamespacePrefix?: string,
contentType?: HtmlTagContentType
contentType?: HtmlTagContentType,
isVoid?: boolean
} = {}) {
if (isPresent(closedByChildren) && closedByChildren.length > 0) {
closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
}
this.closedByParent = normalizeBool(closedByParent);
this.isVoid = normalizeBool(isVoid);
this.closedByParent = normalizeBool(closedByParent) || this.isVoid;
if (isPresent(requiredParents) && requiredParents.length > 0) {
this.requiredParents = {};
this.parentToAdd = requiredParents[0];
@@ -98,21 +101,20 @@ export class HtmlTagDefinition {
}
isClosedByChild(name: string): boolean {
return normalizeBool(this.closedByChildren['*']) ||
normalizeBool(this.closedByChildren[name.toLowerCase()]);
return this.isVoid || normalizeBool(this.closedByChildren[name.toLowerCase()]);
}
}
// see http://www.w3.org/TR/html51/syntax.html#optional-tags
// This implementation does not fully conform to the HTML5 spec.
var TAG_DEFINITIONS: {[key: string]: HtmlTagDefinition} = {
'link': new HtmlTagDefinition({closedByChildren: ['*'], closedByParent: true}),
'ng-content': new HtmlTagDefinition({closedByChildren: ['*'], closedByParent: true}),
'img': new HtmlTagDefinition({closedByChildren: ['*'], closedByParent: true}),
'input': new HtmlTagDefinition({closedByChildren: ['*'], closedByParent: true}),
'hr': new HtmlTagDefinition({closedByChildren: ['*'], closedByParent: true}),
'br': new HtmlTagDefinition({closedByChildren: ['*'], closedByParent: true}),
'wbr': new HtmlTagDefinition({closedByChildren: ['*'], closedByParent: true}),
'link': new HtmlTagDefinition({isVoid: true}),
'ng-content': new HtmlTagDefinition({isVoid: true}),
'img': new HtmlTagDefinition({isVoid: true}),
'input': new HtmlTagDefinition({isVoid: true}),
'hr': new HtmlTagDefinition({isVoid: true}),
'br': new HtmlTagDefinition({isVoid: true}),
'wbr': new HtmlTagDefinition({isVoid: true}),
'p': new HtmlTagDefinition({
closedByChildren: [
'address',