parent
070d818e68
commit
9c6b929c7b
|
@ -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];
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -31,22 +31,22 @@ export function main() {
|
|||
describe('parse', () => {
|
||||
describe('text nodes', () => {
|
||||
it('should parse root level text nodes', () => {
|
||||
expect(humanizeDom(parser.parse('a', 'TestComp'))).toEqual([[HtmlTextAst, 'a']]);
|
||||
expect(humanizeDom(parser.parse('a', 'TestComp'))).toEqual([[HtmlTextAst, 'a', 0]]);
|
||||
});
|
||||
|
||||
it('should parse text nodes inside regular elements', () => {
|
||||
expect(humanizeDom(parser.parse('<div>a</div>', 'TestComp')))
|
||||
.toEqual([[HtmlElementAst, 'div', 0], [HtmlTextAst, 'a']]);
|
||||
.toEqual([[HtmlElementAst, 'div', 0], [HtmlTextAst, 'a', 1]]);
|
||||
});
|
||||
|
||||
it('should parse text nodes inside template elements', () => {
|
||||
expect(humanizeDom(parser.parse('<template>a</template>', 'TestComp')))
|
||||
.toEqual([[HtmlElementAst, 'template', 0], [HtmlTextAst, 'a']]);
|
||||
.toEqual([[HtmlElementAst, 'template', 0], [HtmlTextAst, 'a', 1]]);
|
||||
});
|
||||
|
||||
it('should parse CDATA', () => {
|
||||
expect(humanizeDom(parser.parse('<![CDATA[text]]>', 'TestComp')))
|
||||
.toEqual([[HtmlTextAst, 'text']]);
|
||||
.toEqual([[HtmlTextAst, 'text', 0]]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -75,14 +75,24 @@ export function main() {
|
|||
]);
|
||||
});
|
||||
|
||||
it('should close void elements on text nodes', () => {
|
||||
expect(humanizeDom(parser.parse('<p>before<br>after</p>', 'TestComp')))
|
||||
.toEqual([
|
||||
[HtmlElementAst, 'p', 0],
|
||||
[HtmlTextAst, 'before', 1],
|
||||
[HtmlElementAst, 'br', 1],
|
||||
[HtmlTextAst, 'after', 1],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should support optional end tags', () => {
|
||||
expect(humanizeDom(parser.parse('<div><p>1<p>2</div>', 'TestComp')))
|
||||
.toEqual([
|
||||
[HtmlElementAst, 'div', 0],
|
||||
[HtmlElementAst, 'p', 1],
|
||||
[HtmlTextAst, '1'],
|
||||
[HtmlTextAst, '1', 2],
|
||||
[HtmlElementAst, 'p', 1],
|
||||
[HtmlTextAst, '2'],
|
||||
[HtmlTextAst, '2', 2],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -187,7 +197,7 @@ export function main() {
|
|||
[HtmlAttrAst, '(e)', 'do()', '(e)="do()"'],
|
||||
[HtmlAttrAst, 'attr', 'v2', 'attr="v2"'],
|
||||
[HtmlAttrAst, 'noValue', '', 'noValue'],
|
||||
[HtmlTextAst, '\na\n', '\na\n'],
|
||||
[HtmlTextAst, '\na\n', 1, '\na\n'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -272,7 +282,7 @@ class Humanizer implements HtmlAstVisitor {
|
|||
}
|
||||
|
||||
visitText(ast: HtmlTextAst, context: any): any {
|
||||
var res = this._appendContext(ast, [HtmlTextAst, ast.value]);
|
||||
var res = this._appendContext(ast, [HtmlTextAst, ast.value, this.elDepth]);
|
||||
this.result.push(res);
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue