diff --git a/block.go b/block.go
index b7d870c..23a693c 100644
--- a/block.go
+++ b/block.go
@@ -15,7 +15,7 @@ package blackfriday
import (
"bytes"
- "unicode"
+ "github.com/shurcooL/go/github_flavored_markdown/sanitized_anchor_name"
)
// Parse block-level data.
@@ -227,7 +227,7 @@ func (p *parser) prefixHeader(out *bytes.Buffer, data []byte) int {
}
if end > i {
if id == "" && p.flags&EXTENSION_AUTO_HEADER_IDS != 0 {
- id = createSanitizedAnchorName(string(data[i:end]))
+ id = sanitized_anchor_name.Create(string(data[i:end]))
}
work := func() bool {
p.inline(out, data[i:end])
@@ -1276,7 +1276,7 @@ func (p *parser) paragraph(out *bytes.Buffer, data []byte) int {
id := ""
if p.flags&EXTENSION_AUTO_HEADER_IDS != 0 {
- id = createSanitizedAnchorName(string(data[prev:eol]))
+ id = sanitized_anchor_name.Create(string(data[prev:eol]))
}
p.r.Header(out, work, level, id)
@@ -1325,16 +1325,3 @@ func (p *parser) paragraph(out *bytes.Buffer, data []byte) int {
p.renderParagraph(out, data[:i])
return i
}
-
-func createSanitizedAnchorName(text string) string {
- var anchorName []rune
- for _, r := range []rune(text) {
- switch {
- case r == ' ':
- anchorName = append(anchorName, '-')
- case unicode.IsLetter(r) || unicode.IsNumber(r):
- anchorName = append(anchorName, unicode.ToLower(r))
- }
- }
- return string(anchorName)
-}
diff --git a/block_test.go b/block_test.go
index de77aa9..1c4f50a 100644
--- a/block_test.go
+++ b/block_test.go
@@ -275,10 +275,27 @@ func TestPrefixAutoHeaderIdExtension(t *testing.T) {
"* List\n * Nested list\n # Nested header\n",
"
\n",
+
+ "# Header\n\n# Header\n",
+ "\n\n\n",
+
+ "# Header 1\n\n# Header 1",
+ "\n\n\n",
+
+ "# Header\n\n# Header 1\n\n# Header\n\n# Header",
+ "\n\n\n\n\n\n\n",
}
doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS)
}
+func TestPrefixMultipleHeaderExtensions(t *testing.T) {
+ var tests = []string{
+ "# Header\n\n# Header {#header}\n\n# Header 1",
+ "\n\n\n\n\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS|EXTENSION_HEADER_IDS)
+}
+
func TestUnderlineHeaders(t *testing.T) {
var tests = []string{
"Header 1\n========\n",
@@ -369,6 +386,12 @@ func TestUnderlineHeadersAutoIDs(t *testing.T) {
"Double underline\n=====\n=====\n",
"Double underline
\n\n=====
\n",
+
+ "Header\n======\n\nHeader\n======\n",
+ "\n\n\n",
+
+ "Header 1\n========\n\nHeader 1\n========\n",
+ "\n\n\n",
}
doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS)
}
diff --git a/html.go b/html.go
index a85f918..a552508 100644
--- a/html.go
+++ b/html.go
@@ -81,6 +81,9 @@ type Html struct {
currentLevel int
toc *bytes.Buffer
+ // Track header IDs to prevent ID collision in a single generation.
+ headerIDs map[string]int
+
smartypants *smartypantsRenderer
}
@@ -123,6 +126,8 @@ func HtmlRendererWithParameters(flags int, title string,
currentLevel: 0,
toc: new(bytes.Buffer),
+ headerIDs: make(map[string]int),
+
smartypants: smartypants(flags),
}
}
@@ -190,11 +195,12 @@ func (options *Html) Header(out *bytes.Buffer, text func() bool, level int, id s
marker := out.Len()
doubleSpace(out)
+ if id == "" && options.flags&HTML_TOC != 0 {
+ id = fmt.Sprintf("toc_%d", options.headerCount)
+ }
+
if id != "" {
- out.WriteString(fmt.Sprintf("", level, id))
- } else if options.flags&HTML_TOC != 0 {
- // headerCount is incremented in htmlTocHeader
- out.WriteString(fmt.Sprintf("", level, options.headerCount))
+ out.WriteString(fmt.Sprintf("", level, options.ensureUniqueHeaderID(id)))
} else {
out.WriteString(fmt.Sprintf("", level))
}
@@ -853,3 +859,22 @@ func isRelativeLink(link []byte) (yes bool) {
}
return
}
+
+func (options *Html) ensureUniqueHeaderID(id string) string {
+ for count, found := options.headerIDs[id]; found; count, found = options.headerIDs[id] {
+ tmp := fmt.Sprintf("%s-%d", id, count+1)
+
+ if _, tmpFound := options.headerIDs[tmp]; !tmpFound {
+ options.headerIDs[id] = count + 1
+ id = tmp
+ } else {
+ id = id + "-1"
+ }
+ }
+
+ if _, found := options.headerIDs[id]; !found {
+ options.headerIDs[id] = 0
+ }
+
+ return id
+}