mirror of
https://github.com/danog/blackfriday.git
synced 2025-01-23 05:41:27 +01:00
Clean up Renderer interface: remove all callbacks
We now expose the structure of the document in the form of AST, there's no longer need to have all those callbacks to represent structure.
This commit is contained in:
parent
c9ea588e6f
commit
c207eca993
592
html.go
592
html.go
@ -21,7 +21,6 @@ import (
|
||||
"html"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -202,597 +201,6 @@ func (r *HTML) entityEscapeWithSkip(src []byte, skipRanges [][]int) {
|
||||
r.attrEscape(src[end:])
|
||||
}
|
||||
|
||||
func (r *HTML) TitleBlock(text []byte) {
|
||||
text = bytes.TrimPrefix(text, []byte("% "))
|
||||
text = bytes.Replace(text, []byte("\n% "), []byte("\n"), -1)
|
||||
r.w.WriteString("<h1 class=\"title\">")
|
||||
r.w.Write(text)
|
||||
r.w.WriteString("\n</h1>")
|
||||
}
|
||||
|
||||
func (r *HTML) BeginHeader(level int, id string) {
|
||||
r.w.Newline()
|
||||
|
||||
if id == "" && r.Extensions&TOC != 0 {
|
||||
id = fmt.Sprintf("toc_%d", r.headerCount)
|
||||
}
|
||||
|
||||
if id != "" {
|
||||
id = r.ensureUniqueHeaderID(id)
|
||||
|
||||
if r.HeaderIDPrefix != "" {
|
||||
id = r.HeaderIDPrefix + id
|
||||
}
|
||||
|
||||
if r.HeaderIDSuffix != "" {
|
||||
id = id + r.HeaderIDSuffix
|
||||
}
|
||||
|
||||
r.w.WriteString(fmt.Sprintf("<h%d id=\"%s\">", level, id))
|
||||
} else {
|
||||
r.w.WriteString(fmt.Sprintf("<h%d>", level))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HTML) EndHeader(level int, id string, header []byte) {
|
||||
// are we building a table of contents?
|
||||
if r.Extensions&TOC != 0 {
|
||||
r.TocHeaderWithAnchor(header, level, id)
|
||||
}
|
||||
|
||||
r.w.WriteString(fmt.Sprintf("</h%d>\n", level))
|
||||
}
|
||||
|
||||
func (r *HTML) BlockHtml(text []byte) {
|
||||
if r.Flags&SkipHTML != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
r.w.Newline()
|
||||
r.w.Write(text)
|
||||
r.w.WriteByte('\n')
|
||||
}
|
||||
|
||||
func (r *HTML) HRule() {
|
||||
r.w.Newline()
|
||||
r.w.WriteString("<hr")
|
||||
r.w.WriteString(r.closeTag)
|
||||
r.w.WriteByte('\n')
|
||||
}
|
||||
|
||||
func (r *HTML) BlockCode(text []byte, lang string) {
|
||||
r.w.Newline()
|
||||
|
||||
// parse out the language names/classes
|
||||
count := 0
|
||||
for _, elt := range strings.Fields(lang) {
|
||||
if elt[0] == '.' {
|
||||
elt = elt[1:]
|
||||
}
|
||||
if len(elt) == 0 {
|
||||
continue
|
||||
}
|
||||
if count == 0 {
|
||||
r.w.WriteString("<pre><code class=\"language-")
|
||||
} else {
|
||||
r.w.WriteByte(' ')
|
||||
}
|
||||
r.attrEscape([]byte(elt))
|
||||
count++
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
r.w.WriteString("<pre><code>")
|
||||
} else {
|
||||
r.w.WriteString("\">")
|
||||
}
|
||||
|
||||
r.attrEscape(text)
|
||||
r.w.WriteString("</code></pre>\n")
|
||||
}
|
||||
|
||||
func (r *HTML) BlockQuote(text []byte) {
|
||||
r.w.Newline()
|
||||
r.w.WriteString("<blockquote>\n")
|
||||
r.w.Write(text)
|
||||
r.w.WriteString("</blockquote>\n")
|
||||
}
|
||||
|
||||
func (r *HTML) Table(header []byte, body []byte, columnData []CellAlignFlags) {
|
||||
r.w.Newline()
|
||||
r.w.WriteString("<table>\n<thead>\n")
|
||||
r.w.Write(header)
|
||||
r.w.WriteString("</thead>\n\n<tbody>\n")
|
||||
r.w.Write(body)
|
||||
r.w.WriteString("</tbody>\n</table>\n")
|
||||
}
|
||||
|
||||
func (r *HTML) TableRow(text []byte) {
|
||||
r.w.Newline()
|
||||
r.w.WriteString("<tr>\n")
|
||||
r.w.Write(text)
|
||||
r.w.WriteString("\n</tr>\n")
|
||||
}
|
||||
|
||||
func leadingNewline(out *bytes.Buffer) {
|
||||
if out.Len() > 0 {
|
||||
out.WriteByte('\n')
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HTML) TableHeaderCell(out *bytes.Buffer, text []byte, align CellAlignFlags) {
|
||||
leadingNewline(out)
|
||||
switch align {
|
||||
case TableAlignmentLeft:
|
||||
out.WriteString("<th align=\"left\">")
|
||||
case TableAlignmentRight:
|
||||
out.WriteString("<th align=\"right\">")
|
||||
case TableAlignmentCenter:
|
||||
out.WriteString("<th align=\"center\">")
|
||||
default:
|
||||
out.WriteString("<th>")
|
||||
}
|
||||
|
||||
out.Write(text)
|
||||
out.WriteString("</th>")
|
||||
}
|
||||
|
||||
func (r *HTML) TableCell(out *bytes.Buffer, text []byte, align CellAlignFlags) {
|
||||
leadingNewline(out)
|
||||
switch align {
|
||||
case TableAlignmentLeft:
|
||||
out.WriteString("<td align=\"left\">")
|
||||
case TableAlignmentRight:
|
||||
out.WriteString("<td align=\"right\">")
|
||||
case TableAlignmentCenter:
|
||||
out.WriteString("<td align=\"center\">")
|
||||
default:
|
||||
out.WriteString("<td>")
|
||||
}
|
||||
|
||||
out.Write(text)
|
||||
out.WriteString("</td>")
|
||||
}
|
||||
|
||||
func (r *HTML) BeginFootnotes() {
|
||||
r.w.WriteString("<div class=\"footnotes\">\n")
|
||||
r.HRule()
|
||||
r.BeginList(ListTypeOrdered)
|
||||
}
|
||||
|
||||
func (r *HTML) EndFootnotes() {
|
||||
r.EndList(ListTypeOrdered)
|
||||
r.w.WriteString("</div>\n")
|
||||
}
|
||||
|
||||
func (r *HTML) FootnoteItem(name, text []byte, flags ListType) {
|
||||
if flags&ListItemContainsBlock != 0 || flags&ListItemBeginningOfList != 0 {
|
||||
r.w.Newline()
|
||||
}
|
||||
slug := slugify(name)
|
||||
r.w.WriteString(`<li id="`)
|
||||
r.w.WriteString(`fn:`)
|
||||
r.w.WriteString(r.FootnoteAnchorPrefix)
|
||||
r.w.Write(slug)
|
||||
r.w.WriteString(`">`)
|
||||
r.w.Write(text)
|
||||
if r.Flags&FootnoteReturnLinks != 0 {
|
||||
r.w.WriteString(` <a class="footnote-return" href="#`)
|
||||
r.w.WriteString(`fnref:`)
|
||||
r.w.WriteString(r.FootnoteAnchorPrefix)
|
||||
r.w.Write(slug)
|
||||
r.w.WriteString(`">`)
|
||||
r.w.WriteString(r.FootnoteReturnLinkContents)
|
||||
r.w.WriteString(`</a>`)
|
||||
}
|
||||
r.w.WriteString("</li>\n")
|
||||
}
|
||||
|
||||
func (r *HTML) BeginList(flags ListType) {
|
||||
r.w.Newline()
|
||||
|
||||
if flags&ListTypeDefinition != 0 {
|
||||
r.w.WriteString("<dl>")
|
||||
} else if flags&ListTypeOrdered != 0 {
|
||||
r.w.WriteString("<ol>")
|
||||
} else {
|
||||
r.w.WriteString("<ul>")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HTML) EndList(flags ListType) {
|
||||
if flags&ListTypeDefinition != 0 {
|
||||
r.w.WriteString("</dl>\n")
|
||||
} else if flags&ListTypeOrdered != 0 {
|
||||
r.w.WriteString("</ol>\n")
|
||||
} else {
|
||||
r.w.WriteString("</ul>\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HTML) ListItem(text []byte, flags ListType) {
|
||||
if (flags&ListItemContainsBlock != 0 && flags&ListTypeDefinition == 0) ||
|
||||
flags&ListItemBeginningOfList != 0 {
|
||||
r.w.Newline()
|
||||
}
|
||||
if flags&ListTypeTerm != 0 {
|
||||
r.w.WriteString("<dt>")
|
||||
} else if flags&ListTypeDefinition != 0 {
|
||||
r.w.WriteString("<dd>")
|
||||
} else {
|
||||
r.w.WriteString("<li>")
|
||||
}
|
||||
r.w.Write(text)
|
||||
if flags&ListTypeTerm != 0 {
|
||||
r.w.WriteString("</dt>\n")
|
||||
} else if flags&ListTypeDefinition != 0 {
|
||||
r.w.WriteString("</dd>\n")
|
||||
} else {
|
||||
r.w.WriteString("</li>\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HTML) BeginParagraph() {
|
||||
r.w.Newline()
|
||||
r.w.WriteString("<p>")
|
||||
}
|
||||
|
||||
func (r *HTML) EndParagraph() {
|
||||
r.w.WriteString("</p>\n")
|
||||
}
|
||||
|
||||
func (r *HTML) AutoLink(link []byte, kind LinkType) {
|
||||
skipRanges := htmlEntity.FindAllIndex(link, -1)
|
||||
if r.Flags&Safelink != 0 && !isSafeLink(link) && kind != LinkTypeEmail {
|
||||
// mark it but don't link it if it is not a safe link: no smartypants
|
||||
r.w.WriteString("<tt>")
|
||||
r.entityEscapeWithSkip(link, skipRanges)
|
||||
r.w.WriteString("</tt>")
|
||||
return
|
||||
}
|
||||
|
||||
r.w.WriteString("<a href=\"")
|
||||
if kind == LinkTypeEmail {
|
||||
r.w.WriteString("mailto:")
|
||||
} else {
|
||||
r.maybeWriteAbsolutePrefix(link)
|
||||
}
|
||||
|
||||
r.entityEscapeWithSkip(link, skipRanges)
|
||||
|
||||
var relAttrs []string
|
||||
if r.Flags&NofollowLinks != 0 && !isRelativeLink(link) {
|
||||
relAttrs = append(relAttrs, "nofollow")
|
||||
}
|
||||
if r.Flags&NoreferrerLinks != 0 && !isRelativeLink(link) {
|
||||
relAttrs = append(relAttrs, "noreferrer")
|
||||
}
|
||||
if len(relAttrs) > 0 {
|
||||
r.w.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
|
||||
}
|
||||
|
||||
// blank target only add to external link
|
||||
if r.Flags&HrefTargetBlank != 0 && !isRelativeLink(link) {
|
||||
r.w.WriteString("\" target=\"_blank")
|
||||
}
|
||||
|
||||
r.w.WriteString("\">")
|
||||
|
||||
// Pretty print: if we get an email address as
|
||||
// an actual URI, e.g. `mailto:foo@bar.com`, we don't
|
||||
// want to print the `mailto:` prefix
|
||||
switch {
|
||||
case bytes.HasPrefix(link, []byte("mailto://")):
|
||||
r.attrEscape(link[len("mailto://"):])
|
||||
case bytes.HasPrefix(link, []byte("mailto:")):
|
||||
r.attrEscape(link[len("mailto:"):])
|
||||
default:
|
||||
r.entityEscapeWithSkip(link, skipRanges)
|
||||
}
|
||||
|
||||
r.w.WriteString("</a>")
|
||||
}
|
||||
|
||||
func (r *HTML) CodeSpan(text []byte) {
|
||||
r.w.WriteString("<code>")
|
||||
r.attrEscape(text)
|
||||
r.w.WriteString("</code>")
|
||||
}
|
||||
|
||||
func (r *HTML) DoubleEmphasis(text []byte) {
|
||||
r.w.WriteString("<strong>")
|
||||
r.w.Write(text)
|
||||
r.w.WriteString("</strong>")
|
||||
}
|
||||
|
||||
func (r *HTML) Emphasis(text []byte) {
|
||||
if len(text) == 0 {
|
||||
return
|
||||
}
|
||||
r.w.WriteString("<em>")
|
||||
r.w.Write(text)
|
||||
r.w.WriteString("</em>")
|
||||
}
|
||||
|
||||
func (r *HTML) maybeWriteAbsolutePrefix(link []byte) {
|
||||
if r.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
|
||||
r.w.WriteString(r.AbsolutePrefix)
|
||||
if link[0] != '/' {
|
||||
r.w.WriteByte('/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HTML) Image(link []byte, title []byte, alt []byte) {
|
||||
if r.Flags&SkipImages != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
r.w.WriteString("<img src=\"")
|
||||
r.maybeWriteAbsolutePrefix(link)
|
||||
r.attrEscape(link)
|
||||
r.w.WriteString("\" alt=\"")
|
||||
if len(alt) > 0 {
|
||||
r.attrEscape(alt)
|
||||
}
|
||||
if len(title) > 0 {
|
||||
r.w.WriteString("\" title=\"")
|
||||
r.attrEscape(title)
|
||||
}
|
||||
|
||||
r.w.WriteByte('"')
|
||||
r.w.WriteString(r.closeTag)
|
||||
}
|
||||
|
||||
func (r *HTML) LineBreak() {
|
||||
r.w.WriteString("<br")
|
||||
r.w.WriteString(r.closeTag)
|
||||
r.w.WriteByte('\n')
|
||||
}
|
||||
|
||||
func (r *HTML) Link(link []byte, title []byte, content []byte) {
|
||||
if r.Flags&SkipLinks != 0 {
|
||||
// write the link text out but don't link it, just mark it with typewriter font
|
||||
r.w.WriteString("<tt>")
|
||||
r.attrEscape(content)
|
||||
r.w.WriteString("</tt>")
|
||||
return
|
||||
}
|
||||
|
||||
if r.Flags&Safelink != 0 && !isSafeLink(link) {
|
||||
// write the link text out but don't link it, just mark it with typewriter font
|
||||
r.w.WriteString("<tt>")
|
||||
r.attrEscape(content)
|
||||
r.w.WriteString("</tt>")
|
||||
return
|
||||
}
|
||||
|
||||
r.w.WriteString("<a href=\"")
|
||||
r.maybeWriteAbsolutePrefix(link)
|
||||
r.attrEscape(link)
|
||||
if len(title) > 0 {
|
||||
r.w.WriteString("\" title=\"")
|
||||
r.attrEscape(title)
|
||||
}
|
||||
var relAttrs []string
|
||||
if r.Flags&NofollowLinks != 0 && !isRelativeLink(link) {
|
||||
relAttrs = append(relAttrs, "nofollow")
|
||||
}
|
||||
if r.Flags&NoreferrerLinks != 0 && !isRelativeLink(link) {
|
||||
relAttrs = append(relAttrs, "noreferrer")
|
||||
}
|
||||
if len(relAttrs) > 0 {
|
||||
r.w.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
|
||||
}
|
||||
|
||||
// blank target only add to external link
|
||||
if r.Flags&HrefTargetBlank != 0 && !isRelativeLink(link) {
|
||||
r.w.WriteString("\" target=\"_blank")
|
||||
}
|
||||
|
||||
r.w.WriteString("\">")
|
||||
r.w.Write(content)
|
||||
r.w.WriteString("</a>")
|
||||
return
|
||||
}
|
||||
|
||||
func (r *HTML) RawHtmlTag(text []byte) {
|
||||
if r.Flags&SkipHTML != 0 {
|
||||
return
|
||||
}
|
||||
if r.Flags&SkipStyle != 0 && isHtmlTag(text, "style") {
|
||||
return
|
||||
}
|
||||
if r.Flags&SkipLinks != 0 && isHtmlTag(text, "a") {
|
||||
return
|
||||
}
|
||||
if r.Flags&SkipImages != 0 && isHtmlTag(text, "img") {
|
||||
return
|
||||
}
|
||||
r.w.Write(text)
|
||||
}
|
||||
|
||||
func (r *HTML) TripleEmphasis(text []byte) {
|
||||
r.w.WriteString("<strong><em>")
|
||||
r.w.Write(text)
|
||||
r.w.WriteString("</em></strong>")
|
||||
}
|
||||
|
||||
func (r *HTML) StrikeThrough(text []byte) {
|
||||
r.w.WriteString("<del>")
|
||||
r.w.Write(text)
|
||||
r.w.WriteString("</del>")
|
||||
}
|
||||
|
||||
func (r *HTML) FootnoteRef(ref []byte, id int) {
|
||||
slug := slugify(ref)
|
||||
r.w.WriteString(`<sup class="footnote-ref" id="`)
|
||||
r.w.WriteString(`fnref:`)
|
||||
r.w.WriteString(r.FootnoteAnchorPrefix)
|
||||
r.w.Write(slug)
|
||||
r.w.WriteString(`"><a rel="footnote" href="#`)
|
||||
r.w.WriteString(`fn:`)
|
||||
r.w.WriteString(r.FootnoteAnchorPrefix)
|
||||
r.w.Write(slug)
|
||||
r.w.WriteString(`">`)
|
||||
r.w.WriteString(strconv.Itoa(id))
|
||||
r.w.WriteString(`</a></sup>`)
|
||||
}
|
||||
|
||||
func (r *HTML) Entity(entity []byte) {
|
||||
r.w.Write(entity)
|
||||
}
|
||||
|
||||
func (r *HTML) NormalText(text []byte) {
|
||||
if r.Extensions&Smartypants != 0 {
|
||||
r.Smartypants(text)
|
||||
} else {
|
||||
r.attrEscape(text)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HTML) Smartypants(text []byte) {
|
||||
r.w.Write(NewSmartypantsRenderer(r.Extensions).Process(text))
|
||||
}
|
||||
|
||||
func (r *HTML) DocumentHeader() {
|
||||
if r.Flags&CompletePage == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ending := ""
|
||||
if r.Flags&UseXHTML != 0 {
|
||||
r.w.WriteString("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ")
|
||||
r.w.WriteString("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n")
|
||||
r.w.WriteString("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n")
|
||||
ending = " /"
|
||||
} else {
|
||||
r.w.WriteString("<!DOCTYPE html>\n")
|
||||
r.w.WriteString("<html>\n")
|
||||
}
|
||||
r.w.WriteString("<head>\n")
|
||||
r.w.WriteString(" <title>")
|
||||
r.NormalText([]byte(r.Title))
|
||||
r.w.WriteString("</title>\n")
|
||||
r.w.WriteString(" <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v")
|
||||
r.w.WriteString(VERSION)
|
||||
r.w.WriteString("\"")
|
||||
r.w.WriteString(ending)
|
||||
r.w.WriteString(">\n")
|
||||
r.w.WriteString(" <meta charset=\"utf-8\"")
|
||||
r.w.WriteString(ending)
|
||||
r.w.WriteString(">\n")
|
||||
if r.CSS != "" {
|
||||
r.w.WriteString(" <link rel=\"stylesheet\" type=\"text/css\" href=\"")
|
||||
r.attrEscape([]byte(r.CSS))
|
||||
r.w.WriteString("\"")
|
||||
r.w.WriteString(ending)
|
||||
r.w.WriteString(">\n")
|
||||
}
|
||||
r.w.WriteString("</head>\n")
|
||||
r.w.WriteString("<body>\n")
|
||||
|
||||
r.tocMarker = r.w.Len() // XXX
|
||||
}
|
||||
|
||||
func (r *HTML) DocumentFooter() {
|
||||
// finalize and insert the table of contents
|
||||
if r.Extensions&TOC != 0 {
|
||||
r.TocFinalize()
|
||||
|
||||
// now we have to insert the table of contents into the document
|
||||
var temp bytes.Buffer
|
||||
|
||||
// start by making a copy of everything after the document header
|
||||
temp.Write(r.w.Bytes()[r.tocMarker:])
|
||||
|
||||
// now clear the copied material from the main output buffer
|
||||
r.w.Truncate(r.tocMarker)
|
||||
|
||||
// corner case spacing issue
|
||||
if r.Flags&CompletePage != 0 {
|
||||
r.w.WriteByte('\n')
|
||||
}
|
||||
|
||||
// insert the table of contents
|
||||
r.w.WriteString("<nav>\n")
|
||||
r.w.Write(r.toc.Bytes())
|
||||
r.w.WriteString("</nav>\n")
|
||||
|
||||
// corner case spacing issue
|
||||
if r.Flags&CompletePage == 0 && r.Extensions&OmitContents == 0 {
|
||||
r.w.WriteByte('\n')
|
||||
}
|
||||
|
||||
// write out everything that came after it
|
||||
if r.Extensions&OmitContents == 0 {
|
||||
r.w.Write(temp.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
if r.Flags&CompletePage != 0 {
|
||||
r.w.WriteString("\n</body>\n")
|
||||
r.w.WriteString("</html>\n")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (r *HTML) TocHeaderWithAnchor(text []byte, level int, anchor string) {
|
||||
for level > r.currentLevel {
|
||||
switch {
|
||||
case bytes.HasSuffix(r.toc.Bytes(), []byte("</li>\n")):
|
||||
// this sublist can nest underneath a header
|
||||
size := r.toc.Len()
|
||||
r.toc.Truncate(size - len("</li>\n"))
|
||||
|
||||
case r.currentLevel > 0:
|
||||
r.toc.WriteString("<li>")
|
||||
}
|
||||
if r.toc.Len() > 0 {
|
||||
r.toc.WriteByte('\n')
|
||||
}
|
||||
r.toc.WriteString("<ul>\n")
|
||||
r.currentLevel++
|
||||
}
|
||||
|
||||
for level < r.currentLevel {
|
||||
r.toc.WriteString("</ul>")
|
||||
if r.currentLevel > 1 {
|
||||
r.toc.WriteString("</li>\n")
|
||||
}
|
||||
r.currentLevel--
|
||||
}
|
||||
|
||||
r.toc.WriteString("<li><a href=\"#")
|
||||
if anchor != "" {
|
||||
r.toc.WriteString(anchor)
|
||||
} else {
|
||||
r.toc.WriteString("toc_")
|
||||
r.toc.WriteString(strconv.Itoa(r.headerCount))
|
||||
}
|
||||
r.toc.WriteString("\">")
|
||||
r.headerCount++
|
||||
|
||||
r.toc.Write(text)
|
||||
|
||||
r.toc.WriteString("</a></li>\n")
|
||||
}
|
||||
|
||||
func (r *HTML) TocHeader(text []byte, level int) {
|
||||
r.TocHeaderWithAnchor(text, level, "")
|
||||
}
|
||||
|
||||
func (r *HTML) TocFinalize() {
|
||||
for r.currentLevel > 1 {
|
||||
r.toc.WriteString("</ul></li>\n")
|
||||
r.currentLevel--
|
||||
}
|
||||
|
||||
if r.currentLevel > 0 {
|
||||
r.toc.WriteString("</ul>\n")
|
||||
}
|
||||
}
|
||||
|
||||
func isHtmlTag(tag []byte, tagname string) bool {
|
||||
found, _ := findHtmlTagPos(tag, tagname)
|
||||
return found
|
||||
|
42
markdown.go
42
markdown.go
@ -170,48 +170,6 @@ var blockTags = map[string]struct{}{
|
||||
//
|
||||
// Currently Html and Latex implementations are provided
|
||||
type Renderer interface {
|
||||
// block-level callbacks
|
||||
BlockCode(text []byte, lang string)
|
||||
BlockQuote(text []byte)
|
||||
BlockHtml(text []byte)
|
||||
BeginHeader(level int, id string)
|
||||
EndHeader(level int, id string, header []byte)
|
||||
HRule()
|
||||
BeginList(flags ListType)
|
||||
EndList(flags ListType)
|
||||
ListItem(text []byte, flags ListType)
|
||||
BeginParagraph()
|
||||
EndParagraph()
|
||||
Table(header []byte, body []byte, columnData []CellAlignFlags)
|
||||
TableRow(text []byte)
|
||||
TableHeaderCell(out *bytes.Buffer, text []byte, flags CellAlignFlags)
|
||||
TableCell(out *bytes.Buffer, text []byte, flags CellAlignFlags)
|
||||
BeginFootnotes()
|
||||
EndFootnotes()
|
||||
FootnoteItem(name, text []byte, flags ListType)
|
||||
TitleBlock(text []byte)
|
||||
|
||||
// Span-level callbacks
|
||||
AutoLink(link []byte, kind LinkType)
|
||||
CodeSpan(text []byte)
|
||||
DoubleEmphasis(text []byte)
|
||||
Emphasis(text []byte)
|
||||
Image(link []byte, title []byte, alt []byte)
|
||||
LineBreak()
|
||||
Link(link []byte, title []byte, content []byte)
|
||||
RawHtmlTag(tag []byte)
|
||||
TripleEmphasis(text []byte)
|
||||
StrikeThrough(text []byte)
|
||||
FootnoteRef(ref []byte, id int)
|
||||
|
||||
// Low-level callbacks
|
||||
Entity(entity []byte)
|
||||
NormalText(text []byte)
|
||||
|
||||
// Header and footer
|
||||
DocumentHeader()
|
||||
DocumentFooter()
|
||||
|
||||
Render(ast *Node) []byte
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user