128 lines
2.9 KiB
Go
128 lines
2.9 KiB
Go
// Copyright (C) 2019 Marius Schellenberger
|
|
|
|
package render
|
|
|
|
import (
|
|
"git.giftfish.de/ston1th/gowiki/pkg/core"
|
|
"github.com/blevesearch/bleve/analysis"
|
|
"github.com/blevesearch/bleve/analysis/char/html"
|
|
"github.com/russross/blackfriday"
|
|
"html/template"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var filter = makeFilter()
|
|
|
|
func makeFilter() analysis.CharFilter {
|
|
f, _ := html.CharFilterConstructor(nil, nil)
|
|
return f
|
|
}
|
|
|
|
var (
|
|
reHeader = regexp.MustCompile("(<h[1-6]>)(.+)(</h[1-6]>)")
|
|
reLink = regexp.MustCompile(`id="(.+?)"`)
|
|
whiteSpace = regexp.MustCompile(`\s+`)
|
|
reIndex = regexp.MustCompile("<h([1-6])>(.+)</h[1-6]>")
|
|
titleRe = regexp.MustCompile("[^a-zA-Z0-9 -]+")
|
|
)
|
|
|
|
func Render(p *core.Page) string {
|
|
rend := blackfriday.MarkdownCommon([]byte(p.Markdown))
|
|
toc, html := buildTOC(string(rend))
|
|
html = strings.Replace(html, "<table>", `<table class="table">`, -1)
|
|
html = strings.Replace(html, "</h1>", `</h1><hr>`, -1)
|
|
html = strings.Replace(html, "<a", `<a target="_blank" rel="noopener noreferrer"`, -1)
|
|
p.TOC = template.HTML(toc)
|
|
p.HTML = template.HTML(html)
|
|
return whiteSpace.ReplaceAllString(string(filter.Filter(rend)), " ")
|
|
}
|
|
|
|
func Title(title string) string {
|
|
return whiteSpace.ReplaceAllString(titleRe.ReplaceAllString(title, ""), "+")
|
|
}
|
|
|
|
func StoreTitle(section, title string) string {
|
|
return section + "/" + title
|
|
}
|
|
|
|
func SplitStoreTitle(st string) (section, title string) {
|
|
a := strings.Split(st, "/")
|
|
switch len(a) {
|
|
case 1:
|
|
return a[0], ""
|
|
case 2:
|
|
return a[0], a[1]
|
|
}
|
|
return
|
|
}
|
|
|
|
func buildTOC(html string) (string, string) {
|
|
var toc string
|
|
m := make(map[string]int)
|
|
hn := reIndex.FindAllStringSubmatch(html, -1)
|
|
html = reHeader.ReplaceAllString(html, `<a id="${2}" class="anchor"></a>${1}${2}${3}`)
|
|
html = reLink.ReplaceAllStringFunc(html, func(s string) string {
|
|
if len(s) >= 3 {
|
|
return `id="` + Title(s[2:]) + `"`
|
|
}
|
|
return s
|
|
})
|
|
for k, v := range hn {
|
|
link := Title(v[2])
|
|
i := m[link]
|
|
m[link] = i + 1
|
|
newLink := link + strconv.Itoa(i)
|
|
html = strings.Replace(html, link+`"`, newLink+`"`, 1)
|
|
toc += before(hn, k)
|
|
toc += `<li><a href="#` + newLink + `">` + v[2] + "</a>"
|
|
toc += after(hn, k)
|
|
}
|
|
return toc, html
|
|
}
|
|
|
|
func before(arr [][]string, i int) string {
|
|
c, _ := strconv.Atoi(arr[i][1])
|
|
if c == 1 {
|
|
return `<ul class="toc">`
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func after(arr [][]string, i int) string {
|
|
c, _ := strconv.Atoi(arr[i][1])
|
|
if len(arr) <= i+1 {
|
|
return closeTag(c-1) + "</ul>"
|
|
}
|
|
n, _ := strconv.Atoi(arr[i+1][1])
|
|
switch {
|
|
case n == 1:
|
|
return closeTag(c-n) + "</ul>"
|
|
case n < c:
|
|
return closeTag(c - n)
|
|
case n > c:
|
|
return openTag(n - c)
|
|
case n == c:
|
|
return "</li>"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func openTag(j int) (ret string) {
|
|
for i := 0; i < j; i++ {
|
|
ret += `<ul class="toc"><li>`
|
|
}
|
|
ret = ret[0 : len(ret)-4]
|
|
return
|
|
}
|
|
|
|
func closeTag(j int) (ret string) {
|
|
for i := 0; i < j; i++ {
|
|
ret += "</li></ul></li>"
|
|
}
|
|
if j > 1 {
|
|
ret = strings.Replace(ret, "</li></li>", "</li>", -1)
|
|
}
|
|
return
|
|
}
|