97 lines
2.9 KiB
Go
97 lines
2.9 KiB
Go
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
pathLib "path"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/gomarkdown/markdown"
|
|
"github.com/gomarkdown/markdown/html"
|
|
"github.com/gomarkdown/markdown/parser"
|
|
)
|
|
|
|
// This implements very crude server-side rendered markdown using a Go markdown library
|
|
// Note: this not even nearly supports all SilverBullet markdown features. It's best effort.
|
|
// The ONLY use case of this is search engine indexing
|
|
// It is only activated when the space is both read-only and has no authentication, so basically the silverbullet.md scenario.
|
|
|
|
// Very crude markdown link replacement
|
|
func convertWikiLinksToMarkdown(input string) string {
|
|
// Regular expression to match [[text]] patterns
|
|
re := regexp.MustCompile(`\[\[([^\]]+)\]\]`)
|
|
|
|
// Replace all matches with [text](text) format
|
|
result := re.ReplaceAllStringFunc(input, func(match string) string {
|
|
// Extract the text between [[ and ]]
|
|
text := strings.TrimPrefix(match, "[[")
|
|
text = strings.TrimSuffix(text, "]]")
|
|
|
|
return fmt.Sprintf("[%s](%s)", text, text)
|
|
})
|
|
|
|
return result
|
|
}
|
|
|
|
func ServerSideRender(config *ServerConfig, spaceConfig *SpaceConfig, pageName string, w http.ResponseWriter, r *http.Request) {
|
|
// Let's fetch the index.html text
|
|
indexHtmlBuf, _, _ := config.ClientBundle.ReadFile(indexHtmlPath)
|
|
|
|
if pageName == "" {
|
|
pageName = spaceConfig.IndexPage
|
|
}
|
|
|
|
tpl := template.New("index_html")
|
|
tpl.Funcs(template.FuncMap{
|
|
"markdown": func(text string) template.HTML {
|
|
if text == "" {
|
|
// Let's not even bother doing anything
|
|
return ""
|
|
}
|
|
|
|
// Setup markdown renderer
|
|
var markdownParser = parser.NewWithExtensions(parser.CommonExtensions)
|
|
var markdownRenderer = html.NewRenderer(html.RendererOptions{})
|
|
text = convertWikiLinksToMarkdown(text)
|
|
doc := markdownParser.Parse([]byte(text))
|
|
return template.HTML(markdown.Render(doc, markdownRenderer))
|
|
},
|
|
})
|
|
tpl = template.Must(tpl.Parse(string(indexHtmlBuf)))
|
|
|
|
templateData := struct {
|
|
HostPrefix string
|
|
Title string
|
|
Description string
|
|
Content string
|
|
AdditionalHeadHTML template.HTML
|
|
}{
|
|
Title: "SilverBullet",
|
|
HostPrefix: config.HostURLPrefix,
|
|
AdditionalHeadHTML: spaceConfig.AdditionalHeadHTML,
|
|
}
|
|
|
|
if spaceConfig.ReadOnlyMode && spaceConfig.Auth == nil {
|
|
// Read only and without out, let's do some server side rendering
|
|
templateData.Title = pathLib.Base(pageName)
|
|
|
|
// Read page content
|
|
pageData, _, err := spaceConfig.SpacePrimitives.ReadFile(fmt.Sprintf("%s.md", pageName))
|
|
if err != nil {
|
|
log.Printf("Could not read content for page %s", pageName)
|
|
} else {
|
|
templateData.Content = string(pageData)
|
|
}
|
|
}
|
|
|
|
w.Header().Set("Content-type", "text/html")
|
|
w.WriteHeader(http.StatusOK)
|
|
if err := tpl.Execute(w, templateData); err != nil {
|
|
log.Printf("SSR error for %s: %v", pageName, err)
|
|
w.Write([]byte("Server error"))
|
|
}
|
|
}
|