Implementation and some tests for inline footnotes. Also I noticed the list items had the wrong ids, that was silly of me.
moshee moshee@displaynone.us
Mon, 01 Jul 2013 01:37:52 +0000
4 files changed,
99 insertions(+),
23 deletions(-)
M
html.go
→
html.go
@@ -333,7 +333,7 @@ func (options *Html) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
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)
M
inline.go
→
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 @@ var t linkType
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 @@ link = lr.link
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 @@
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 + + 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 + } - // keep link and title from reference - link = lr.link - // if inline footnote, title == footnote contents - title = lr.title - noteId = lr.noteId + 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@@ -469,6 +505,15 @@ out.Truncate(outSize - 1)
} 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)
M
inline_test.go
→
inline_test.go
@@ -513,7 +513,7 @@
<hr /> <ol> -<li class="a">This is the note +<li id="fn:a">This is the note </li> </ol> </div>@@ -539,7 +539,7 @@
<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 @@
<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>
M
markdown.go
→
markdown.go
@@ -436,7 +436,9 @@ }
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 @@ raw []byte
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 @@ // reusing the link field for the id since footnotes don't have links
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]