Skip to content

Commit

Permalink
markup/tableofcontents: Cast Fragments.ToHTML args to int
Browse files Browse the repository at this point in the history
Closes #13107
  • Loading branch information
jmooring authored and bep committed Dec 4, 2024
1 parent 487bb96 commit b529859
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 22 deletions.
13 changes: 6 additions & 7 deletions hugolib/page__content.go
Original file line number Diff line number Diff line change
Expand Up @@ -730,16 +730,15 @@ func (c *cachedContentScope) contentToC(ctx context.Context) (contentTableOfCont
isHTML := cp.po.p.m.pageConfig.ContentMediaType.IsHTML()

if !isHTML {
createAndSetToC := func(tocProvider converter.TableOfContentsProvider) {
createAndSetToC := func(tocProvider converter.TableOfContentsProvider) error {
cfg := p.s.ContentSpec.Converters.GetMarkupConfig()
ct.tableOfContents = tocProvider.TableOfContents()
ct.tableOfContentsHTML = template.HTML(
ct.tableOfContents.ToHTML(
cfg.TableOfContents.StartLevel,
cfg.TableOfContents.EndLevel,
cfg.TableOfContents.Ordered,
),
ct.tableOfContentsHTML, err = ct.tableOfContents.ToHTML(
cfg.TableOfContents.StartLevel,
cfg.TableOfContents.EndLevel,
cfg.TableOfContents.Ordered,
)
return err
}

// If the converter supports doing the parsing separately, we do that.
Expand Down
4 changes: 2 additions & 2 deletions markup/goldmark/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ unsafe = true

toc, ok := b.(converter.TableOfContentsProvider)
c.Assert(ok, qt.Equals, true)
tocString := string(toc.TableOfContents().ToHTML(1, 2, false))
c.Assert(tocString, qt.Contains, "TableOfContents")
tocHTML, _ := toc.TableOfContents().ToHTML(1, 2, false)
c.Assert(string(tocHTML), qt.Contains, "TableOfContents")
}

func TestConvertAutoIDAsciiOnly(t *testing.T) {
Expand Down
23 changes: 18 additions & 5 deletions markup/tableofcontents/tableofcontents.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
package tableofcontents

import (
"fmt"
"html/template"
"sort"
"strings"

"github.com/gohugoio/hugo/common/collections"
"github.com/spf13/cast"
)

// Empty is an empty ToC.
Expand Down Expand Up @@ -133,19 +135,30 @@ func (toc *Fragments) addAt(h *Heading, row, level int) {
}

// ToHTML renders the ToC as HTML.
func (toc *Fragments) ToHTML(startLevel, stopLevel int, ordered bool) template.HTML {
func (toc *Fragments) ToHTML(startLevel, stopLevel any, ordered bool) (template.HTML, error) {
if toc == nil {
return ""
return "", nil
}

iStartLevel, err := cast.ToIntE(startLevel)
if err != nil {
return "", fmt.Errorf("startLevel: %w", err)
}

iStopLevel, err := cast.ToIntE(stopLevel)
if err != nil {
return "", fmt.Errorf("stopLevel: %w", err)
}

b := &tocBuilder{
s: strings.Builder{},
h: toc.Headings,
startLevel: startLevel,
stopLevel: stopLevel,
startLevel: iStartLevel,
stopLevel: iStopLevel,
ordered: ordered,
}
b.Build()
return template.HTML(b.s.String())
return template.HTML(b.s.String()), nil
}

func (toc Fragments) walk(fn func(*Heading)) {
Expand Down
78 changes: 78 additions & 0 deletions markup/tableofcontents/tableofcontents_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package tableofcontents_test

import (
"strings"
"testing"

"github.com/gohugoio/hugo/hugolib"
Expand Down Expand Up @@ -43,3 +44,80 @@ disableKinds = ['page','rss','section','sitemap','taxonomy','term']
"heading-l5|5|Heading L5",
)
}

// Issue #13107
func TestToHTMLArgTypes(t *testing.T) {
t.Parallel()

files := `
-- hugo.toml --
disableKinds = ['home','section','rss','sitemap','taxonomy','term']
-- layouts/_default/single.html --
{{ .Fragments.ToHTML .Params.toc.startLevel .Params.toc.endLevel false }}
-- content/json.md --
{
"title": "json",
"params": {
"toc": {
"startLevel": 2,
"endLevel": 4
}
}
}
CONTENT
-- content/toml.md --
+++
title = 'toml'
[params.toc]
startLevel = 2
endLevel = 4
+++
CONTENT
-- content/yaml.md --
---
title: yaml
params:
toc:
startLevel: 2
endLevel: 4
---
CONTENT
`

content := `
# Level One
## Level Two
### Level Three
#### Level Four
##### Level Five
###### Level Six
`

want := `
<nav id="TableOfContents">
<ul>
<li><a href="#level-two">Level Two</a>
<ul>
<li><a href="#level-three">Level Three</a>
<ul>
<li><a href="#level-four">Level Four</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
`

files = strings.ReplaceAll(files, "CONTENT", content)

b := hugolib.Test(t, files)
b.AssertFileContentEquals("public/json/index.html", strings.TrimSpace(want))
b.AssertFileContentEquals("public/toml/index.html", strings.TrimSpace(want))
b.AssertFileContentEquals("public/yaml/index.html", strings.TrimSpace(want))

files = strings.ReplaceAll(files, `2`, `"x"`)

b, _ = hugolib.TestE(t, files)
b.AssertLogMatches(`error calling ToHTML: startLevel: unable to cast "x" of type string`)
}
24 changes: 16 additions & 8 deletions markup/tableofcontents/tableofcontents_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func TestToc(t *testing.T) {
toc.addAt(&Heading{Title: "1-H3-1", ID: "1-h2-2"}, 0, 2)
toc.addAt(&Heading{Title: "Heading 2", ID: "h1-2"}, 1, 0)

got := string(toc.ToHTML(1, -1, false))
tocHTML, _ := toc.ToHTML(1, -1, false)
got := string(tocHTML)
c.Assert(got, qt.Equals, `<nav id="TableOfContents">
<ul>
<li><a href="#h1-1">Heading 1</a>
Expand All @@ -62,15 +63,17 @@ func TestToc(t *testing.T) {
</ul>
</nav>`, qt.Commentf(got))

got = string(toc.ToHTML(1, 1, false))
tocHTML, _ = toc.ToHTML(1, 1, false)
got = string(tocHTML)
c.Assert(got, qt.Equals, `<nav id="TableOfContents">
<ul>
<li><a href="#h1-1">Heading 1</a></li>
<li><a href="#h1-2">Heading 2</a></li>
</ul>
</nav>`, qt.Commentf(got))

got = string(toc.ToHTML(1, 2, false))
tocHTML, _ = toc.ToHTML(1, 2, false)
got = string(tocHTML)
c.Assert(got, qt.Equals, `<nav id="TableOfContents">
<ul>
<li><a href="#h1-1">Heading 1</a>
Expand All @@ -83,15 +86,17 @@ func TestToc(t *testing.T) {
</ul>
</nav>`, qt.Commentf(got))

got = string(toc.ToHTML(2, 2, false))
tocHTML, _ = toc.ToHTML(2, 2, false)
got = string(tocHTML)
c.Assert(got, qt.Equals, `<nav id="TableOfContents">
<ul>
<li><a href="#1-h2-1">1-H2-1</a></li>
<li><a href="#1-h2-2">1-H2-2</a></li>
</ul>
</nav>`, qt.Commentf(got))

got = string(toc.ToHTML(1, -1, true))
tocHTML, _ = toc.ToHTML(1, -1, true)
got = string(tocHTML)
c.Assert(got, qt.Equals, `<nav id="TableOfContents">
<ol>
<li><a href="#h1-1">Heading 1</a>
Expand All @@ -118,7 +123,8 @@ func TestTocMissingParent(t *testing.T) {
toc.addAt(&Heading{Title: "H3", ID: "h3"}, 1, 2)
toc.addAt(&Heading{Title: "H3", ID: "h3"}, 1, 2)

got := string(toc.ToHTML(1, -1, false))
tocHTML, _ := toc.ToHTML(1, -1, false)
got := string(tocHTML)
c.Assert(got, qt.Equals, `<nav id="TableOfContents">
<ul>
<li>
Expand All @@ -139,15 +145,17 @@ func TestTocMissingParent(t *testing.T) {
</ul>
</nav>`, qt.Commentf(got))

got = string(toc.ToHTML(3, 3, false))
tocHTML, _ = toc.ToHTML(3, 3, false)
got = string(tocHTML)
c.Assert(got, qt.Equals, `<nav id="TableOfContents">
<ul>
<li><a href="#h3">H3</a></li>
<li><a href="#h3">H3</a></li>
</ul>
</nav>`, qt.Commentf(got))

got = string(toc.ToHTML(1, -1, true))
tocHTML, _ = toc.ToHTML(1, -1, true)
got = string(tocHTML)
c.Assert(got, qt.Equals, `<nav id="TableOfContents">
<ol>
<li>
Expand Down

0 comments on commit b529859

Please sign in to comment.
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy