mirror of
https://github.com/russross/blackfriday.git
synced 2024-03-22 13:40:34 +08:00
Implementation and some tests for inline footnotes. Also I noticed the list items had the wrong ids, that was silly of me.
This commit is contained in:
parent
8346559a1a
commit
c23099e5ee
2
html.go
2
html.go
|
@ -333,7 +333,7 @@ func (options *Html) FootnoteItem(out *bytes.Buffer, name, text []byte, flags in
|
|||
if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
|
||||
doubleSpace(out)
|
||||
}
|
||||
out.WriteString(`<li class="`)
|
||||
out.WriteString(`<li id="fn:`)
|
||||
out.Write(slugify(name))
|
||||
out.WriteString(`">`)
|
||||
out.Write(text)
|
||||
|
|
75
inline.go
75
inline.go
|
@ -15,6 +15,7 @@ package blackfriday
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Functions to parse text within a block
|
||||
|
@ -174,8 +175,7 @@ const (
|
|||
linkNormal linkType = iota
|
||||
linkImg
|
||||
linkDeferredFootnote
|
||||
|
||||
// linkInlineFootnote
|
||||
linkInlineFootnote
|
||||
)
|
||||
|
||||
// '[': parse a link or an image or a footnote
|
||||
|
@ -193,7 +193,9 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
|
|||
if offset > 0 && data[offset-1] == '!' {
|
||||
t = linkImg
|
||||
} else if p.flags&EXTENSION_FOOTNOTES != 0 {
|
||||
if len(data)-1 > offset && data[offset+1] == '^' {
|
||||
if offset > 0 && data[offset-1] == '^' {
|
||||
t = linkInlineFootnote
|
||||
} else if len(data)-1 > offset && data[offset+1] == '^' {
|
||||
t = linkDeferredFootnote
|
||||
}
|
||||
}
|
||||
|
@ -387,7 +389,7 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
|
|||
title = lr.title
|
||||
i++
|
||||
|
||||
// shortcut reference style link or footnote
|
||||
// shortcut reference style link or reference or inline footnote
|
||||
default:
|
||||
var id []byte
|
||||
|
||||
|
@ -407,24 +409,58 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
|
|||
id = b.Bytes()
|
||||
} else {
|
||||
if t == linkDeferredFootnote {
|
||||
id = data[2:txtE]
|
||||
id = data[2:txtE] // get rid of the ^
|
||||
} else {
|
||||
id = data[1:txtE]
|
||||
}
|
||||
}
|
||||
|
||||
// find the reference with matching id
|
||||
key := string(bytes.ToLower(id))
|
||||
lr, ok := p.refs[key]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
if t == linkInlineFootnote {
|
||||
// create a new reference
|
||||
noteId = len(p.notes) + 1
|
||||
|
||||
// keep link and title from reference
|
||||
link = lr.link
|
||||
// if inline footnote, title == footnote contents
|
||||
title = lr.title
|
||||
noteId = lr.noteId
|
||||
var fragment []byte
|
||||
if len(id) > 0 {
|
||||
if len(id) < 16 {
|
||||
fragment = make([]byte, len(id))
|
||||
} else {
|
||||
fragment = make([]byte, 16)
|
||||
}
|
||||
copy(fragment, slugify(id))
|
||||
} else {
|
||||
fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteId))...)
|
||||
}
|
||||
|
||||
ref := &reference{
|
||||
noteId: noteId,
|
||||
hasBlock: false,
|
||||
link: fragment,
|
||||
title: id,
|
||||
}
|
||||
|
||||
p.notes = append(p.notes, ref)
|
||||
|
||||
link = ref.link
|
||||
title = ref.title
|
||||
} else {
|
||||
// find the reference with matching id
|
||||
lr, ok := p.refs[key]
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
if t == linkDeferredFootnote {
|
||||
lr.noteId = len(p.notes) + 1
|
||||
p.notes = append(p.notes, lr)
|
||||
}
|
||||
|
||||
// keep link and title from reference
|
||||
link = lr.link
|
||||
// if inline footnote, title == footnote contents
|
||||
title = lr.title
|
||||
noteId = lr.noteId
|
||||
}
|
||||
|
||||
// rewind the whitespace
|
||||
i = txtE + 1
|
||||
|
@ -470,6 +506,15 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
|
|||
|
||||
p.r.Image(out, uLink, title, content.Bytes())
|
||||
|
||||
case linkInlineFootnote:
|
||||
outSize := out.Len()
|
||||
outBytes := out.Bytes()
|
||||
if outSize > 0 && outBytes[outSize-1] == '^' {
|
||||
out.Truncate(outSize - 1)
|
||||
}
|
||||
|
||||
p.r.FootnoteRef(out, link, noteId)
|
||||
|
||||
case linkDeferredFootnote:
|
||||
p.r.FootnoteRef(out, link, noteId)
|
||||
|
||||
|
|
|
@ -513,7 +513,7 @@ func TestFootnotes(t *testing.T) {
|
|||
<hr />
|
||||
|
||||
<ol>
|
||||
<li class="a">This is the note
|
||||
<li id="fn:a">This is the note
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
@ -539,7 +539,7 @@ No longer in the footnote
|
|||
<hr />
|
||||
|
||||
<ol>
|
||||
<li class="b"><p>Paragraph 1</p>
|
||||
<li id="fn:b"><p>Paragraph 1</p>
|
||||
|
||||
<p>Paragraph 2</p>
|
||||
|
||||
|
@ -577,9 +577,39 @@ what happens here
|
|||
<hr />
|
||||
|
||||
<ol>
|
||||
<li class="c">this is <a href="/link/c">note</a> c
|
||||
<li id="fn:c">this is <a href="/link/c">note</a> c
|
||||
</li>
|
||||
<li class="d">this is note d
|
||||
<li id="fn:d">this is note d
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
`,
|
||||
|
||||
"testing inline^[this is the note] notes.\n",
|
||||
`<p>testing inline<sup class="footnote-ref" id="fnref:this-is-the-note"><a rel="footnote" href="#fn:this-is-the-note">1</a></sup> notes.</p>
|
||||
<div class="footnotes">
|
||||
|
||||
<hr />
|
||||
|
||||
<ol>
|
||||
<li id="fn:this-is-the-note">this is the note</li>
|
||||
</ol>
|
||||
</div>
|
||||
`,
|
||||
|
||||
"testing multiple[^1] types^[inline note] of notes[^2]\n\n[^2]: the second deferred note\n[^1]: the first deferred note\n\n\twhich happens to be a block\n",
|
||||
`<p>testing multiple<sup class="footnote-ref" id="fnref:1"><a rel="footnote" href="#fn:1">1</a></sup> types<sup class="footnote-ref" id="fnref:inline-note"><a rel="footnote" href="#fn:inline-note">2</a></sup> of notes<sup class="footnote-ref" id="fnref:2"><a rel="footnote" href="#fn:2">3</a></sup></p>
|
||||
<div class="footnotes">
|
||||
|
||||
<hr />
|
||||
|
||||
<ol>
|
||||
<li id="fn:1"><p>the first deferred note</p>
|
||||
|
||||
<p>which happens to be a block</p>
|
||||
</li>
|
||||
<li id="fn:inline-note">inline note</li>
|
||||
<li id="fn:2">the second deferred note
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
|
|
@ -436,7 +436,9 @@ func isReference(p *parser, data []byte, tabSize int) int {
|
|||
i++
|
||||
if p.flags&EXTENSION_FOOTNOTES != 0 {
|
||||
if data[i] == '^' {
|
||||
noteId = len(p.notes) + 1
|
||||
// we can set it to anything here because the proper noteIds will
|
||||
// be assigned later during the second pass. It just has to be != 0
|
||||
noteId = 1
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
@ -479,7 +481,7 @@ func isReference(p *parser, data []byte, tabSize int) int {
|
|||
hasBlock bool
|
||||
)
|
||||
|
||||
if p.flags&EXTENSION_FOOTNOTES != 0 && noteId > 0 {
|
||||
if p.flags&EXTENSION_FOOTNOTES != 0 && noteId != 0 {
|
||||
linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
|
||||
lineEnd = linkEnd
|
||||
} else {
|
||||
|
@ -501,7 +503,6 @@ func isReference(p *parser, data []byte, tabSize int) int {
|
|||
ref.link = data[idOffset:idEnd]
|
||||
// if footnote, it's not really a title, it's the contained text
|
||||
ref.title = raw
|
||||
p.notes = append(p.notes, ref)
|
||||
} else {
|
||||
ref.link = data[linkOffset:linkEnd]
|
||||
ref.title = data[titleOffset:titleEnd]
|
||||
|
|
Loading…
Reference in New Issue
Block a user