bloat/renderer/renderer.go

161 lines
3.7 KiB
Go
Raw Normal View History

2019-12-13 20:08:26 +02:00
package renderer
import (
2020-01-28 19:51:00 +02:00
"fmt"
2019-12-13 20:08:26 +02:00
"io"
"strconv"
"strings"
"text/template"
"time"
2020-02-01 13:31:44 +02:00
"bloat/mastodon"
2019-12-13 20:08:26 +02:00
)
2020-02-23 21:51:42 +02:00
type Page string
const (
SigninPage = "signin.tmpl"
ErrorPage = "error.tmpl"
NavPage = "nav.tmpl"
RootPage = "root.tmpl"
TimelinePage = "timeline.tmpl"
ThreadPage = "thread.tmpl"
NotificationPage = "notification.tmpl"
UserPage = "user.tmpl"
UserSearchPage = "usersearch.tmpl"
AboutPage = "about.tmpl"
EmojiPage = "emoji.tmpl"
LikedByPage = "likedby.tmpl"
RetweetedByPage = "retweetedby.tmpl"
SearchPage = "search.tmpl"
SettingsPage = "settings.tmpl"
)
2020-01-14 18:57:16 +02:00
type TemplateData struct {
Data interface{}
Ctx *Context
}
2020-02-23 21:51:42 +02:00
func emojiFilter(content string, emojis []mastodon.Emoji) string {
2019-12-21 07:48:06 +02:00
var replacements []string
2020-01-28 19:51:00 +02:00
var r string
2019-12-21 07:48:06 +02:00
for _, e := range emojis {
r = fmt.Sprintf("<img class=\"emoji\" src=\"%s\" alt=\":%s:\" title=\":%s:\" height=\"24\" />",
2020-01-28 19:51:00 +02:00
e.URL, e.ShortCode, e.ShortCode)
replacements = append(replacements, ":"+e.ShortCode+":", r)
2019-12-21 07:48:06 +02:00
}
return strings.NewReplacer(replacements...).Replace(content)
}
2020-02-23 21:51:42 +02:00
func statusContentFilter(spoiler string, content string,
2020-01-28 19:51:00 +02:00
emojis []mastodon.Emoji, mentions []mastodon.Mention) string {
var replacements []string
var r string
2019-12-21 09:22:21 +02:00
if len(spoiler) > 0 {
content = spoiler + "<br />" + content
}
2019-12-13 20:08:26 +02:00
for _, e := range emojis {
r = fmt.Sprintf("<img class=\"emoji\" src=\"%s\" alt=\":%s:\" title=\":%s:\" height=\"32\" />",
2020-01-28 19:51:00 +02:00
e.URL, e.ShortCode, e.ShortCode)
replacements = append(replacements, ":"+e.ShortCode+":", r)
2019-12-21 07:48:06 +02:00
}
for _, m := range mentions {
2020-10-30 18:07:11 +02:00
replacements = append(replacements, `"`+m.URL+`"`, `"/user/`+m.ID+`" title="@`+m.Acct+`"`)
2019-12-13 20:08:26 +02:00
}
2019-12-21 07:48:06 +02:00
return strings.NewReplacer(replacements...).Replace(content)
2019-12-13 20:08:26 +02:00
}
2020-02-23 21:51:42 +02:00
func displayInteractionCount(c int64) string {
2019-12-13 20:08:26 +02:00
if c > 0 {
return strconv.Itoa(int(c))
}
return ""
}
func DurToStr(dur time.Duration) string {
2019-12-13 20:08:26 +02:00
s := dur.Seconds()
if s < 60 {
return strconv.Itoa(int(s)) + "s"
}
m := dur.Minutes()
2020-09-22 07:43:07 +03:00
if m < 60*2 {
2019-12-13 20:08:26 +02:00
return strconv.Itoa(int(m)) + "m"
}
h := dur.Hours()
2020-09-22 07:43:07 +03:00
if h < 24*2 {
2019-12-13 20:08:26 +02:00
return strconv.Itoa(int(h)) + "h"
}
d := h / 24
2020-09-22 07:43:07 +03:00
if d < 30*2 {
2019-12-13 20:08:26 +02:00
return strconv.Itoa(int(d)) + "d"
}
mo := d / 30
2020-09-22 07:43:07 +03:00
if mo < 12*2 {
2019-12-13 20:08:26 +02:00
return strconv.Itoa(int(mo)) + "mo"
}
2019-12-20 20:31:55 +02:00
y := mo / 12
2019-12-13 20:08:26 +02:00
return strconv.Itoa(int(y)) + "y"
}
2020-02-23 21:51:42 +02:00
func timeSince(t time.Time) string {
d := time.Since(t)
if d < 0 {
d = 0
}
return DurToStr(d)
}
2020-02-23 21:51:42 +02:00
func timeUntil(t time.Time) string {
d := time.Until(t)
if d < 0 {
d = 0
}
return DurToStr(d)
}
2020-02-23 21:51:42 +02:00
func formatTimeRFC3339(t time.Time) string {
2019-12-13 20:08:26 +02:00
return t.Format(time.RFC3339)
}
2020-01-10 06:05:01 +02:00
2020-02-23 21:51:42 +02:00
func formatTimeRFC822(t time.Time) string {
2020-01-10 06:05:01 +02:00
return t.Format(time.RFC822)
}
2020-01-12 19:16:57 +02:00
2020-02-23 21:51:42 +02:00
func withContext(data interface{}, ctx *Context) TemplateData {
2020-01-14 18:57:16 +02:00
return TemplateData{data, ctx}
}
2020-02-23 21:51:42 +02:00
type Renderer interface {
Render(ctx *Context, writer io.Writer, page string, data interface{}) (err error)
}
type renderer struct {
template *template.Template
}
func NewRenderer(templateGlobPattern string) (r *renderer, err error) {
t := template.New("default")
t, err = t.Funcs(template.FuncMap{
"EmojiFilter": emojiFilter,
"StatusContentFilter": statusContentFilter,
"DisplayInteractionCount": displayInteractionCount,
"TimeSince": timeSince,
"TimeUntil": timeUntil,
"FormatTimeRFC3339": formatTimeRFC3339,
"FormatTimeRFC822": formatTimeRFC822,
"WithContext": withContext,
}).ParseGlob(templateGlobPattern)
if err != nil {
return
}
return &renderer{
template: t,
}, nil
}
func (r *renderer) Render(ctx *Context, writer io.Writer,
page string, data interface{}) (err error) {
return r.template.ExecuteTemplate(writer, page, withContext(data, ctx))
}