diff --git a/data/dk.db b/data/dk.db
index 3c31fb3..79b4a30 100644
Binary files a/data/dk.db and b/data/dk.db differ
diff --git a/internal/helpers/markdown/md.go b/internal/helpers/markdown/md.go
index 22c54a6..3459626 100644
--- a/internal/helpers/markdown/md.go
+++ b/internal/helpers/markdown/md.go
@@ -1,6 +1,7 @@
package markdown
import (
+ "fmt"
"html"
"strings"
)
@@ -40,6 +41,17 @@ func MarkdownToHTML(s string) string {
return `
` + s + "
"
}
+// MarkdownTemplateFunc is a TemplateFunc-compatible wrapper for MarkdownToHTML
+func MarkdownTemplateFunc(args ...any) any {
+ if len(args) == 0 {
+ return ""
+ }
+
+ // Convert first argument to string
+ input := fmt.Sprintf("%v", args[0])
+ return MarkdownToHTML(input)
+}
+
func replaceCodeSpans(s string) string {
for {
start := strings.Index(s, "`")
diff --git a/internal/routes/forum.go b/internal/routes/forum.go
index f744d48..7406c4e 100644
--- a/internal/routes/forum.go
+++ b/internal/routes/forum.go
@@ -17,16 +17,13 @@ import (
type ThreadInfo struct {
Thread *forum.Forum
Author *users.User
- AuthorClass string
LastReplyBy *users.User
}
// PostInfo combines a forum post/reply with its author
type PostInfo struct {
- Post *forum.Forum
- Author *users.User
- AuthorClass string
- Content string // Pre-processed markdown content
+ Post *forum.Forum
+ Author *users.User
}
func RegisterForumRoutes(app *sushi.App) {
@@ -68,8 +65,6 @@ func index(ctx sushi.Ctx) {
author = &users.User{Username: "[Deleted]", ClassID: 1}
}
- authorClass := author.Class().Name
-
// Get last reply author if there are replies
var lastReplyBy *users.User
if thread.Replies > 0 {
@@ -83,7 +78,6 @@ func index(ctx sushi.Ctx) {
threadInfos = append(threadInfos, ThreadInfo{
Thread: thread,
Author: author,
- AuthorClass: authorClass,
LastReplyBy: lastReplyBy,
})
}
@@ -161,8 +155,6 @@ func showThread(ctx sushi.Ctx) {
if threadAuthor == nil {
threadAuthor = &users.User{Username: "[Deleted]", Level: 1, ClassID: 1}
}
- threadAuthorClass := threadAuthor.Class().Name
- threadContent := markdown.MarkdownToHTML(thread.Content)
// Get replies with pagination
perPage := 30
@@ -174,21 +166,17 @@ func showThread(ctx sushi.Ctx) {
replies = make([]*forum.Forum, 0)
}
- // Build reply info with authors and processed content
+ // Build reply info with authors
var replyInfos []PostInfo
for _, reply := range replies {
author, _ := users.Find(reply.Author)
if author == nil {
author = &users.User{Username: "[Deleted]", Level: 1, ClassID: 1}
}
- authorClass := author.Class().Name
- content := markdown.MarkdownToHTML(reply.Content)
replyInfos = append(replyInfos, PostInfo{
- Post: reply,
- Author: author,
- AuthorClass: authorClass,
- Content: content,
+ Post: reply,
+ Author: author,
})
}
@@ -198,15 +186,14 @@ func showThread(ctx sushi.Ctx) {
}
components.RenderPage(ctx, thread.Title, "forum/thread.html", map[string]any{
- "thread": thread,
- "threadContent": threadContent,
- "threadAuthor": threadAuthor,
- "threadAuthorClass": threadAuthorClass,
- "replyInfos": replyInfos,
- "currentPage": page,
- "totalPages": totalPages,
- "hasNext": page < totalPages,
- "hasPrev": page > 1,
+ "thread": thread,
+ "threadAuthor": threadAuthor,
+ "replyInfos": replyInfos,
+ "currentPage": page,
+ "totalPages": totalPages,
+ "hasNext": page < totalPages,
+ "hasPrev": page > 1,
+ "markdown": markdown.MarkdownToHTML,
})
}
diff --git a/internal/template/template.go b/internal/template/template.go
index c5b5f10..3f42e63 100644
--- a/internal/template/template.go
+++ b/internal/template/template.go
@@ -25,8 +25,6 @@ type TemplateFunc func(args ...any) any
var (
funcRegistry = make(map[string]TemplateFunc)
funcMutex sync.RWMutex
- methodCache = make(map[string]reflect.Method)
- cacheMutex sync.RWMutex
)
func init() {
@@ -465,23 +463,9 @@ func (t *Template) callMethod(obj any, methodCall string, data map[string]any) a
argsStr := methodCall[parenIdx+1 : len(methodCall)-1]
rv := reflect.ValueOf(obj)
- objType := rv.Type()
-
- // Check method cache
- cacheKey := fmt.Sprintf("%s.%s", objType.String(), methodName)
- cacheMutex.RLock()
- method, cached := methodCache[cacheKey]
- cacheMutex.RUnlock()
-
- if !cached {
- method = rv.MethodByName(methodName)
- if !method.IsValid() {
- return nil
- }
-
- cacheMutex.Lock()
- methodCache[cacheKey] = method
- cacheMutex.Unlock()
+ method := rv.MethodByName(methodName)
+ if !method.IsValid() {
+ return nil
}
args := t.parseArgs(argsStr, data)
@@ -523,7 +507,7 @@ func (t *Template) parseArgs(argsStr string, data map[string]any) []any {
inQuotes := false
parenLevel := 0
- for i, r := range argsStr {
+ for _, r := range argsStr {
switch r {
case '"':
inQuotes = !inQuotes
@@ -682,12 +666,20 @@ func (t *Template) getNestedValue(data map[string]any, path string) any {
var current any = data
for i, key := range keys {
- // Check for method call
+ // Check for method call at any point in the chain
if strings.Contains(key, "(") && strings.HasSuffix(key, ")") {
- return t.callMethod(current, key, data)
+ result := t.callMethod(current, key, data)
+ if i == len(keys)-1 {
+ // This was the final key, return the method result
+ return result
+ }
+ // Continue with the method result for further chaining
+ current = t.convertToStringMap(result)
+ continue
}
if i == len(keys)-1 {
+ // Final key - get field/value
switch v := current.(type) {
case map[string]any:
return v[key]
@@ -696,6 +688,7 @@ func (t *Template) getNestedValue(data map[string]any, path string) any {
}
}
+ // Intermediate key - get next object in chain
var next any
switch v := current.(type) {
case map[string]any:
diff --git a/main.go b/main.go
index df24a8b..2e8785f 100644
--- a/main.go
+++ b/main.go
@@ -13,6 +13,7 @@ import (
"dk/internal/control"
"dk/internal/database"
+ "dk/internal/helpers/markdown"
"dk/internal/models/users"
"dk/internal/routes"
"dk/internal/template"
@@ -143,6 +144,7 @@ func start(port string) error {
defer control.Save()
template.InitializeCache(cwd)
+ template.RegisterFunc("md", markdown.MarkdownTemplateFunc)
authMW := auth.New(getUserByID)
diff --git a/templates/forum/index.html b/templates/forum/index.html
index 0c46194..42f36fb 100644
--- a/templates/forum/index.html
+++ b/templates/forum/index.html
@@ -9,32 +9,32 @@
{if #threadInfos > 0}
-
+
-
- Thread
- Replies
- Last Reply
+
+ Thread
+ Replies
+ Last Reply
{for threadInfo in threadInfos}
-
-
-
-
{threadInfo.Thread.Title}
+
+
+
-
- by {threadInfo.Author.Username} • {threadInfo.PostedTime}
+
+ by {threadInfo.Author.Username} • {threadInfo.Thread.PostedTime().Format("Jan 2, 2006 3:04 PM")}
-
+
{threadInfo.Thread.Replies}
-
+
{if threadInfo.LastReplyBy}
by {threadInfo.LastReplyBy.Username}
- {threadInfo.LastPostTime}
+ {threadInfo.Thread.LastPostTime().Format("Jan 2, 2006 3:04 PM")}
{else}
No replies
{/if}
@@ -45,13 +45,13 @@
{if totalPages > 1}
-
+
{if hasPrev}
Previous
{/if}
-
-
Page {currentPage} of {totalPages}
-
+
+
Page {currentPage} of {totalPages}
+
{if hasNext}
Next
{/if}
@@ -59,8 +59,8 @@
{/if}
{else}
-
+
{/if}
-{/block}
+{/block}
\ No newline at end of file
diff --git a/templates/forum/thread.html b/templates/forum/thread.html
index 63b48df..25ef39b 100644
--- a/templates/forum/thread.html
+++ b/templates/forum/thread.html
@@ -10,20 +10,20 @@
-
-
-
{threadAuthor.Username}
-
+
+
+
{threadAuthor.Username}
+
Level {threadAuthor.Level}
- {threadAuthorClass}
+ {threadAuthor.Class().Name}
-
-
- {threadContent}
+
+
+ {md(thread.Content)}
-
- Posted: {threadPostedTime}
+
+ Posted: {thread.PostedTime().Format("Jan 2, 2006 3:04 PM")}
@@ -31,20 +31,20 @@
{if #replyInfos > 0}
{for replyInfo in replyInfos}
-
-
-
{replyInfo.Author.Username}
-
+
+
+
{replyInfo.Author.Username}
+
Level {replyInfo.Author.Level}
- {replyInfo.AuthorClass}
+ {replyInfo.Author.Class().Name}
-
-
- {replyInfo.Content}
+
+
+ {markdown(replyInfo.Post.Content)}
-
- Posted: {replyInfo.PostedTime}
+
+ Posted: {replyInfo.Post.PostedTime().Format("Jan 2, 2006 3:04 PM")}
@@ -53,13 +53,13 @@
{if totalPages > 1}
-
+
{if hasPrev}
Previous
{/if}
-
-
Page {currentPage} of {totalPages}
-
+
+
Page {currentPage} of {totalPages}
+
{if hasNext}
Next
{/if}
@@ -67,7 +67,7 @@
{/if}
-
+
-{/block}
+{/block}
\ No newline at end of file