mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-15 20:44:01 +02:00
markup/goldmark: Fix blockquote render hook text parsing
Fixes #12913 Fixes #13119
This commit is contained in:
committed by
Bjørn Erik Pedersen
parent
3afe91d4b1
commit
34373407b7
@@ -74,7 +74,7 @@ func (r *htmlRenderer) renderBlockquote(w util.BufWriter, src []byte, node ast.N
|
|||||||
ordinal := ctx.GetAndIncrementOrdinal(ast.KindBlockquote)
|
ordinal := ctx.GetAndIncrementOrdinal(ast.KindBlockquote)
|
||||||
|
|
||||||
typ := typeRegular
|
typ := typeRegular
|
||||||
alert := resolveBlockQuoteAlert(string(text))
|
alert := resolveBlockQuoteAlert(text)
|
||||||
if alert.typ != "" {
|
if alert.typ != "" {
|
||||||
typ = typeAlert
|
typ = typeAlert
|
||||||
}
|
}
|
||||||
@@ -85,10 +85,21 @@ func (r *htmlRenderer) renderBlockquote(w util.BufWriter, src []byte, node ast.N
|
|||||||
}
|
}
|
||||||
|
|
||||||
if typ == typeAlert {
|
if typ == typeAlert {
|
||||||
// Trim preamble: <p>[!NOTE]<br>\n but preserve leading paragraph.
|
// Parse the blockquote content to determine the alert text. The alert
|
||||||
// We could possibly complicate this by moving this to the parser, but
|
// text begins after the first newline, but we need to add an opening p
|
||||||
// keep it simple for now.
|
// tag if the first line of the blockquote content does not have a
|
||||||
text = "<p>" + text[strings.Index(text, "\n")+1:]
|
// closing p tag. At some point we might want to move this to the
|
||||||
|
// parser.
|
||||||
|
before, after, found := strings.Cut(strings.TrimSpace(text), "\n")
|
||||||
|
if found {
|
||||||
|
if strings.HasSuffix(before, "</p>") {
|
||||||
|
text = after
|
||||||
|
} else {
|
||||||
|
text = "<p>" + after
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bqctx := &blockquoteContext{
|
bqctx := &blockquoteContext{
|
||||||
@@ -165,7 +176,7 @@ func resolveBlockQuoteAlert(s string) blockQuoteAlert {
|
|||||||
m := blockQuoteAlertRe.FindStringSubmatch(s)
|
m := blockQuoteAlertRe.FindStringSubmatch(s)
|
||||||
if len(m) == 4 {
|
if len(m) == 4 {
|
||||||
title := strings.TrimSpace(m[3])
|
title := strings.TrimSpace(m[3])
|
||||||
title = strings.TrimRight(title, "</p>")
|
title = strings.TrimSuffix(title, "</p>")
|
||||||
return blockQuoteAlert{
|
return blockQuoteAlert{
|
||||||
typ: strings.ToLower(m[1]),
|
typ: strings.ToLower(m[1]),
|
||||||
sign: m[2],
|
sign: m[2],
|
||||||
|
@@ -48,10 +48,9 @@ Content: {{ .Content }}
|
|||||||
title: "p1"
|
title: "p1"
|
||||||
---
|
---
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> This is a note with some whitespace after the alert type.
|
> This is a note with some whitespace after the alert type.
|
||||||
|
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> This is a tip.
|
> This is a tip.
|
||||||
|
|
||||||
@@ -64,29 +63,26 @@ title: "p1"
|
|||||||
> This is a tip with attributes.
|
> This is a tip with attributes.
|
||||||
{class="foo bar" id="baz"}
|
{class="foo bar" id="baz"}
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Note triggering showing the position.
|
> Note triggering showing the position.
|
||||||
{showpos="true"}
|
{showpos="true"}
|
||||||
|
|
||||||
|
> [!nOtE]
|
||||||
> [!nOtE]
|
|
||||||
> Mixed case alert type.
|
> Mixed case alert type.
|
||||||
|
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
b := hugolib.Test(t, files)
|
b := hugolib.Test(t, files)
|
||||||
b.AssertFileContentExact("public/p1/index.html",
|
b.AssertFileContentExact("public/p1/index.html",
|
||||||
"Blockquote Alert: |<p>This is a note with some whitespace after the alert type.</p>\n|alert|",
|
"Blockquote Alert: |<p>This is a note with some whitespace after the alert type.</p>|alert|",
|
||||||
"Blockquote Alert: |<p>This is a tip.</p>",
|
"Blockquote Alert: |<p>This is a tip.</p>",
|
||||||
"Blockquote Alert: |<p>This is a caution with some whitespace before the alert type.</p>\n|alert|",
|
"Blockquote Alert: |<p>This is a caution with some whitespace before the alert type.</p>|alert|",
|
||||||
"Blockquote: |<p>A regular blockquote.</p>\n|regular|",
|
"Blockquote: |<p>A regular blockquote.</p>\n|regular|",
|
||||||
"Blockquote Alert Attributes: |<p>This is a tip with attributes.</p>\n|map[class:foo bar id:baz]|",
|
"Blockquote Alert Attributes: |<p>This is a tip with attributes.</p>|map[class:foo bar id:baz]|",
|
||||||
filepath.FromSlash("/content/p1.md:20:3"),
|
filepath.FromSlash("/content/p1.md:19:3"),
|
||||||
"Blockquote Alert Page: |<p>This is a tip with attributes.</p>\n|p1|p1|",
|
"Blockquote Alert Page: |<p>This is a tip with attributes.</p>|p1|p1|",
|
||||||
|
|
||||||
// Issue 12767.
|
// Issue 12767.
|
||||||
"Blockquote Alert: |<p>Mixed case alert type.</p>\n|alert",
|
"Blockquote Alert: |<p>Mixed case alert type.</p>|alert",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,17 +138,113 @@ title: "Home"
|
|||||||
{{ .Content }}
|
{{ .Content }}
|
||||||
-- layouts/_default/_markup/render-blockquote.html --
|
-- layouts/_default/_markup/render-blockquote.html --
|
||||||
AlertType: {{ .AlertType }}|AlertTitle: {{ .AlertTitle }}|AlertSign: {{ .AlertSign | safeHTML }}|Text: {{ .Text }}|
|
AlertType: {{ .AlertType }}|AlertTitle: {{ .AlertTitle }}|AlertSign: {{ .AlertSign | safeHTML }}|Text: {{ .Text }}|
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
b := hugolib.Test(t, files)
|
b := hugolib.Test(t, files)
|
||||||
b.AssertFileContentExact("public/index.html",
|
b.AssertFileContentExact("public/index.html",
|
||||||
"AlertType: tip|AlertTitle: Callouts can have custom titles|AlertSign: |",
|
"AlertType: tip|AlertTitle: Callouts can have custom titles|AlertSign: |",
|
||||||
"AlertType: tip|AlertTitle: Title-only callout|AlertSign: |",
|
"AlertType: tip|AlertTitle: Title-only callout|AlertSign: |",
|
||||||
"AlertType: faq|AlertTitle: Foldable negated callout|AlertSign: -|Text: <p>Yes! In a foldable callout, the contents are hidden when the callout is collapsed</p>\n|",
|
"AlertType: faq|AlertTitle: Foldable negated callout|AlertSign: -|Text: <p>Yes! In a foldable callout, the contents are hidden when the callout is collapsed</p>|",
|
||||||
"AlertType: faq|AlertTitle: Foldable callout|AlertSign: +|Text: <p>Yes! In a foldable callout, the contents are hidden when the callout is collapsed</p>\n|",
|
"AlertType: faq|AlertTitle: Foldable callout|AlertSign: +|Text: <p>Yes! In a foldable callout, the contents are hidden when the callout is collapsed</p>|",
|
||||||
"AlertType: danger|AlertTitle: |AlertSign: |Text: <p>Do not approach or handle without protective gear.</p>\n|",
|
"AlertType: danger|AlertTitle: |AlertSign: |Text: <p>Do not approach or handle without protective gear.</p>|",
|
||||||
"AlertTitle: Can callouts be nested?|",
|
"AlertTitle: Can callouts be nested?|",
|
||||||
"AlertTitle: You can even use multiple layers of nesting.|",
|
"AlertTitle: You can even use multiple layers of nesting.|",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue 12913
|
||||||
|
// Issue 13119
|
||||||
|
func TestBlockquoteRenderHookTextParsing(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- hugo.toml --
|
||||||
|
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
|
||||||
|
-- layouts/index.html --
|
||||||
|
{{ .Content }}
|
||||||
|
-- layouts/_default/_markup/render-blockquote.html --
|
||||||
|
AlertType: {{ .AlertType }}|AlertTitle: {{ .AlertTitle }}|Text: {{ .Text }}|
|
||||||
|
-- content/_index.md --
|
||||||
|
---
|
||||||
|
title: home
|
||||||
|
---
|
||||||
|
|
||||||
|
> [!one]
|
||||||
|
|
||||||
|
> [!two] title
|
||||||
|
|
||||||
|
> [!three]
|
||||||
|
> line 1
|
||||||
|
|
||||||
|
> [!four] title
|
||||||
|
> line 1
|
||||||
|
|
||||||
|
> [!five]
|
||||||
|
> line 1
|
||||||
|
> line 2
|
||||||
|
|
||||||
|
> [!six] title
|
||||||
|
> line 1
|
||||||
|
> line 2
|
||||||
|
|
||||||
|
> [!seven]
|
||||||
|
> - list item
|
||||||
|
|
||||||
|
> [!eight] title
|
||||||
|
> - list item
|
||||||
|
|
||||||
|
> [!nine]
|
||||||
|
> line 1
|
||||||
|
> - list item
|
||||||
|
|
||||||
|
> [!ten] title
|
||||||
|
> line 1
|
||||||
|
> - list item
|
||||||
|
|
||||||
|
> [!eleven]
|
||||||
|
> line 1
|
||||||
|
> - list item
|
||||||
|
>
|
||||||
|
> line 2
|
||||||
|
|
||||||
|
> [!twelve] title
|
||||||
|
> line 1
|
||||||
|
> - list item
|
||||||
|
>
|
||||||
|
> line 2
|
||||||
|
|
||||||
|
> [!thirteen]
|
||||||
|
> 
|
||||||
|
|
||||||
|
> [!fourteen] title
|
||||||
|
> 
|
||||||
|
|
||||||
|
> [!fifteen] _title_
|
||||||
|
|
||||||
|
> [!sixteen] _title_
|
||||||
|
> line one
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
b := hugolib.Test(t, files)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/index.html",
|
||||||
|
"AlertType: one|AlertTitle: |Text: |",
|
||||||
|
"AlertType: two|AlertTitle: title|Text: |",
|
||||||
|
"AlertType: three|AlertTitle: |Text: <p>line 1</p>|",
|
||||||
|
"AlertType: four|AlertTitle: title|Text: <p>line 1</p>|",
|
||||||
|
"AlertType: five|AlertTitle: |Text: <p>line 1\nline 2</p>|",
|
||||||
|
"AlertType: six|AlertTitle: title|Text: <p>line 1\nline 2</p>|",
|
||||||
|
"AlertType: seven|AlertTitle: |Text: <ul>\n<li>list item</li>\n</ul>|",
|
||||||
|
"AlertType: eight|AlertTitle: title|Text: <ul>\n<li>list item</li>\n</ul>|",
|
||||||
|
"AlertType: nine|AlertTitle: |Text: <p>line 1</p>\n<ul>\n<li>list item</li>\n</ul>|",
|
||||||
|
"AlertType: ten|AlertTitle: title|Text: <p>line 1</p>\n<ul>\n<li>list item</li>\n</ul>|",
|
||||||
|
"AlertType: eleven|AlertTitle: |Text: <p>line 1</p>\n<ul>\n<li>list item</li>\n</ul>\n<p>line 2</p>|",
|
||||||
|
"AlertType: twelve|AlertTitle: title|Text: <p>line 1</p>\n<ul>\n<li>list item</li>\n</ul>\n<p>line 2</p>|",
|
||||||
|
"AlertType: thirteen|AlertTitle: |Text: <p><img src=\"a.jpg\" alt=\"alt\"></p>|",
|
||||||
|
"AlertType: fourteen|AlertTitle: title|Text: <p><img src=\"a.jpg\" alt=\"alt\"></p>|",
|
||||||
|
"AlertType: fifteen|AlertTitle: <em>title</em>|Text: |",
|
||||||
|
"AlertType: sixteen|AlertTitle: <em>title</em>|Text: <p>line one</p>|",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user