hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit cd0c5d7ef32cbd570af00c50ce760452381df64e
parent e7e194435b4c566f47d644f2e60c096ea1866254
Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Date:   Mon, 22 Feb 2021 11:27:14 +0100

Allow markdown attribute lists to be used in title render hooks

Fixes #8270

Diffstat:
Mdocs/content/en/getting-started/configuration-markup.md | 3+++
Mhugolib/content_render_hooks_test.go | 18++++++++++++++++--
Mmarkup/converter/hooks/hooks.go | 7+++++++
Mmarkup/goldmark/render_hooks.go | 33++++++++++++++++++++++++++++-----
4 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/docs/content/en/getting-started/configuration-markup.md b/docs/content/en/getting-started/configuration-markup.md
@@ -179,6 +179,9 @@ Text
 PlainText
 : The plain variant of the above.
 
+Attributes (map) {{< new-in "0.82.0" >}}
+: A map of attributes (e.g. `id`, `class`)
+
 #### Link with title Markdown example:
 
 ```md
diff --git a/hugolib/content_render_hooks_test.go b/hugolib/content_render_hooks_test.go
@@ -60,6 +60,16 @@ func TestRenderHooks(t *testing.T) {
 	config := `
 baseURL="https://example.org"
 workingDir="/mywork"
+
+[markup]
+[markup.goldmark]
+[markup.goldmark.parser]
+autoHeadingID = true
+autoHeadingIDType = "github"
+[markup.goldmark.parser.attribute]
+block = true
+title = true
+
 `
 	b := newTestSitesBuilder(t).WithWorkingDir("/mywork").WithConfigFile("toml", config).Running()
 	b.WithTemplatesAdded("_default/single.html", `{{ .Content }}`)
@@ -85,7 +95,7 @@ Inner Block: {{ .Inner | .Page.RenderString (dict "display" "block" ) }}
 	b.WithTemplatesAdded("_default/_markup/render-link.html", `{{ with .Page }}{{ .Title }}{{ end }}|{{ .Destination | safeURL }}|Title: {{ .Title | safeHTML }}|Text: {{ .Text | safeHTML }}|END`)
 	b.WithTemplatesAdded("docs/_markup/render-link.html", `Link docs section: {{ .Text | safeHTML }}|END`)
 	b.WithTemplatesAdded("_default/_markup/render-image.html", `IMAGE: {{ .Page.Title }}||{{ .Destination | safeURL }}|Title: {{ .Title | safeHTML }}|Text: {{ .Text | safeHTML }}|END`)
-	b.WithTemplatesAdded("_default/_markup/render-heading.html", `HEADING: {{ .Page.Title }}||Level: {{ .Level }}|Anchor: {{ .Anchor | safeURL }}|Text: {{ .Text | safeHTML }}|END`)
+	b.WithTemplatesAdded("_default/_markup/render-heading.html", `HEADING: {{ .Page.Title }}||Level: {{ .Level }}|Anchor: {{ .Anchor | safeURL }}|Text: {{ .Text | safeHTML }}|Attributes: {{ .Attributes }}|END`)
 	b.WithTemplatesAdded("docs/_markup/render-heading.html", `Docs Level: {{ .Level }}|END`)
 
 	b.WithContent("customview/p1.md", `---
@@ -108,6 +118,10 @@ Image:
 
 ![Drag Racing](/images/Dragster.jpg "image title")
 
+Attributes:
+
+## Some Heading {.text-serif #a-heading title="Hovered"} 
+
 
 `, "blog/p2.md", `---
 title: Cool Page2
@@ -238,7 +252,7 @@ SHORT3|
 	// We may add type template support later, keep this for then. b.AssertFileContent("public/docs/docs1/index.html", `DOCS EDITED: https://www.google.com|</p>`)
 	b.AssertFileContent("public/blog/p4/index.html", `IMAGE EDITED: /images/Dragster.jpg|`)
 	b.AssertFileContent("public/blog/p6/index.html", "<p>Inner Link: EDITED: https://www.gohugo.io|</p>")
-	b.AssertFileContent("public/blog/p7/index.html", "HEADING: With Headings||Level: 1|Anchor: heading-level-1|Text: Heading Level 1|END<p>some text</p>\nHEADING: With Headings||Level: 2|Anchor: heading-level-2|Text: Heading Level 2|ENDHEADING: With Headings||Level: 3|Anchor: heading-level-3|Text: Heading Level 3|END")
+	b.AssertFileContent("public/blog/p7/index.html", "HEADING: With Headings||Level: 1|Anchor: heading-level-1|Text: Heading Level 1|Attributes: map[id:heading-level-1]|END<p>some text</p>\nHEADING: With Headings||Level: 2|Anchor: heading-level-2|Text: Heading Level 2|Attributes: map[id:heading-level-2]|ENDHEADING: With Headings||Level: 3|Anchor: heading-level-3|Text: Heading Level 3|Attributes: map[id:heading-level-3]|END")
 
 	// https://github.com/gohugoio/hugo/issues/7349
 	b.AssertFileContent("public/docs/p8/index.html", "Docs Level: 1")
diff --git a/markup/converter/hooks/hooks.go b/markup/converter/hooks/hooks.go
@@ -19,6 +19,10 @@ import (
 	"github.com/gohugoio/hugo/identity"
 )
 
+type AttributesProvider interface {
+	Attributes() map[string]string
+}
+
 type LinkContext interface {
 	Page() interface{}
 	Destination() string
@@ -45,6 +49,9 @@ type HeadingContext interface {
 	Text() string
 	// PlainText is the unrendered version of Text.
 	PlainText() string
+
+	// Attributes (e.g. CSS classes)
+	AttributesProvider
 }
 
 // HeadingRenderer describes a uniquely identifiable rendering hook.
diff --git a/markup/goldmark/render_hooks.go b/markup/goldmark/render_hooks.go
@@ -14,6 +14,8 @@
 package goldmark
 
 import (
+	"sync"
+
 	"github.com/gohugoio/hugo/markup/converter/hooks"
 
 	"github.com/yuin/goldmark"
@@ -38,6 +40,25 @@ func newLinks() goldmark.Extender {
 	return &links{}
 }
 
+type attributesHolder struct {
+	// What we get from Goldmark.
+	astAttributes []ast.Attribute
+
+	// What we send to the the render hooks.
+	attributesInit sync.Once
+	attributes     map[string]string
+}
+
+func (a *attributesHolder) Attributes() map[string]string {
+	a.attributesInit.Do(func() {
+		a.attributes = make(map[string]string)
+		for _, attr := range a.astAttributes {
+			a.attributes[string(attr.Name)] = string(util.EscapeHTML(attr.Value.([]byte)))
+		}
+	})
+	return a.attributes
+}
+
 type linkContext struct {
 	page        interface{}
 	destination string
@@ -76,6 +97,7 @@ type headingContext struct {
 	anchor    string
 	text      string
 	plainText string
+	*attributesHolder
 }
 
 func (ctx headingContext) Page() interface{} {
@@ -301,11 +323,12 @@ func (r *hookedRenderer) renderHeading(w util.BufWriter, source []byte, node ast
 	err := h.HeadingRenderer.RenderHeading(
 		w,
 		headingContext{
-			page:      ctx.DocumentContext().Document,
-			level:     n.Level,
-			anchor:    string(anchor),
-			text:      string(text),
-			plainText: string(n.Text(source)),
+			page:             ctx.DocumentContext().Document,
+			level:            n.Level,
+			anchor:           string(anchor),
+			text:             string(text),
+			plainText:        string(n.Text(source)),
+			attributesHolder: &attributesHolder{astAttributes: n.Attributes()},
 		},
 	)