diff options
-rw-r--r-- | docs/content/en/getting-started/configuration-markup.md | 3 | ||||
-rw-r--r-- | hugolib/content_render_hooks_test.go | 18 | ||||
-rw-r--r-- | markup/converter/hooks/hooks.go | 7 | ||||
-rw-r--r-- | markup/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 index 4c4d270a6..ca88d5557 100644 --- 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 index 197581bb6..218ad918b 100644 --- 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 index 622d503ef..6f08a2161 100644 --- 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 index f17e4e139..6bedc897e 100644 --- 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()}, }, ) |