fix(compiler-dom): should ignore leading newline in <textarea> per spec
This commit is contained in:
parent
10a2c6053b
commit
3c4bf76276
|
@ -2369,6 +2369,7 @@ describe('compiler: parse', () => {
|
||||||
test('should remove leading newline character immediately following the pre element start tag', () => {
|
test('should remove leading newline character immediately following the pre element start tag', () => {
|
||||||
const ast = parse(`<pre>\n foo bar </pre>`, {
|
const ast = parse(`<pre>\n foo bar </pre>`, {
|
||||||
isPreTag: tag => tag === 'pre',
|
isPreTag: tag => tag === 'pre',
|
||||||
|
isIgnoreNewlineTag: tag => tag === 'pre',
|
||||||
})
|
})
|
||||||
expect(ast.children).toHaveLength(1)
|
expect(ast.children).toHaveLength(1)
|
||||||
const preElement = ast.children[0] as ElementNode
|
const preElement = ast.children[0] as ElementNode
|
||||||
|
|
|
@ -52,6 +52,11 @@ export interface ParserOptions
|
||||||
* e.g. elements that should preserve whitespace inside, e.g. `<pre>`
|
* e.g. elements that should preserve whitespace inside, e.g. `<pre>`
|
||||||
*/
|
*/
|
||||||
isPreTag?: (tag: string) => boolean
|
isPreTag?: (tag: string) => boolean
|
||||||
|
/**
|
||||||
|
* Elements that should ignore the first newline token per parinsg spec
|
||||||
|
* e.g. `<textarea>` and `<pre>`
|
||||||
|
*/
|
||||||
|
isIgnoreNewlineTag?: (tag: string) => boolean
|
||||||
/**
|
/**
|
||||||
* Platform-specific built-in components e.g. `<Transition>`
|
* Platform-specific built-in components e.g. `<Transition>`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -72,6 +72,7 @@ export const defaultParserOptions: MergedParserOptions = {
|
||||||
getNamespace: () => Namespaces.HTML,
|
getNamespace: () => Namespaces.HTML,
|
||||||
isVoidTag: NO,
|
isVoidTag: NO,
|
||||||
isPreTag: NO,
|
isPreTag: NO,
|
||||||
|
isIgnoreNewlineTag: NO,
|
||||||
isCustomElement: NO,
|
isCustomElement: NO,
|
||||||
onError: defaultOnError,
|
onError: defaultOnError,
|
||||||
onWarn: defaultOnWarn,
|
onWarn: defaultOnWarn,
|
||||||
|
@ -633,7 +634,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// refine element type
|
// refine element type
|
||||||
const { tag, ns } = el
|
const { tag, ns, children } = el
|
||||||
if (!inVPre) {
|
if (!inVPre) {
|
||||||
if (tag === 'slot') {
|
if (tag === 'slot') {
|
||||||
el.tagType = ElementTypes.SLOT
|
el.tagType = ElementTypes.SLOT
|
||||||
|
@ -646,8 +647,18 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
|
||||||
|
|
||||||
// whitespace management
|
// whitespace management
|
||||||
if (!tokenizer.inRCDATA) {
|
if (!tokenizer.inRCDATA) {
|
||||||
el.children = condenseWhitespace(el.children, el.tag)
|
el.children = condenseWhitespace(children, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ns === Namespaces.HTML && currentOptions.isIgnoreNewlineTag(tag)) {
|
||||||
|
// remove leading newline for <textarea> and <pre> per html spec
|
||||||
|
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody
|
||||||
|
const first = children[0]
|
||||||
|
if (first && first.type === NodeTypes.TEXT) {
|
||||||
|
first.content = first.content.replace(/^\r?\n/, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ns === Namespaces.HTML && currentOptions.isPreTag(tag)) {
|
if (ns === Namespaces.HTML && currentOptions.isPreTag(tag)) {
|
||||||
inPre--
|
inPre--
|
||||||
}
|
}
|
||||||
|
@ -869,14 +880,6 @@ function condenseWhitespace(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inPre && tag && currentOptions.isPreTag(tag)) {
|
|
||||||
// remove leading newline per html spec
|
|
||||||
// https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element
|
|
||||||
const first = nodes[0]
|
|
||||||
if (first && first.type === NodeTypes.TEXT) {
|
|
||||||
first.content = first.content.replace(/^\r?\n/, '')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return removedWhitespace ? nodes.filter(Boolean) : nodes
|
return removedWhitespace ? nodes.filter(Boolean) : nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,22 @@ describe('DOM parser', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('<textarea> should remove leading newline', () => {
|
||||||
|
const ast = parse('<textarea>\nhello</textarea>', parserOptions)
|
||||||
|
const element = ast.children[0] as ElementNode
|
||||||
|
const text = element.children[0] as TextNode
|
||||||
|
expect(element.children.length).toBe(1)
|
||||||
|
expect(text).toStrictEqual({
|
||||||
|
type: NodeTypes.TEXT,
|
||||||
|
content: 'hello',
|
||||||
|
loc: {
|
||||||
|
start: { offset: 10, line: 1, column: 11 },
|
||||||
|
end: { offset: 16, line: 2, column: 6 },
|
||||||
|
source: '\nhello',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('should not treat Uppercase component as special tag', () => {
|
test('should not treat Uppercase component as special tag', () => {
|
||||||
const ast = parse(
|
const ast = parse(
|
||||||
'<TextArea>some<div>text</div>and<!--comment--></TextArea>',
|
'<TextArea>some<div>text</div>and<!--comment--></TextArea>',
|
||||||
|
|
|
@ -8,6 +8,7 @@ export const parserOptions: ParserOptions = {
|
||||||
isVoidTag,
|
isVoidTag,
|
||||||
isNativeTag: tag => isHTMLTag(tag) || isSVGTag(tag) || isMathMLTag(tag),
|
isNativeTag: tag => isHTMLTag(tag) || isSVGTag(tag) || isMathMLTag(tag),
|
||||||
isPreTag: tag => tag === 'pre',
|
isPreTag: tag => tag === 'pre',
|
||||||
|
isIgnoreNewlineTag: tag => tag === 'pre' || tag === 'textarea',
|
||||||
decodeEntities: __BROWSER__ ? decodeHtmlBrowser : undefined,
|
decodeEntities: __BROWSER__ ? decodeHtmlBrowser : undefined,
|
||||||
|
|
||||||
isBuiltInComponent: tag => {
|
isBuiltInComponent: tag => {
|
||||||
|
|
Loading…
Reference in New Issue