2021-12-03 03:11:01 -08:00
|
|
|
package funcmap
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"html/template"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/Masterminds/sprig"
|
2024-06-14 09:35:35 -07:00
|
|
|
"github.com/labstack/echo/v4"
|
2021-12-03 03:11:01 -08:00
|
|
|
"github.com/labstack/gommon/random"
|
|
|
|
|
2024-07-09 17:57:05 -07:00
|
|
|
"git.grosinger.net/tgrosinger/saasitone/config"
|
2021-12-19 13:08:09 -08:00
|
|
|
)
|
2021-12-03 03:11:01 -08:00
|
|
|
|
2024-07-09 17:57:05 -07:00
|
|
|
// CacheBuster stores a random string used as a cache buster for static files.
|
|
|
|
var CacheBuster = random.String(10)
|
|
|
|
|
2024-06-14 09:35:35 -07:00
|
|
|
type funcMap struct {
|
|
|
|
web *echo.Echo
|
|
|
|
}
|
2021-12-03 03:11:01 -08:00
|
|
|
|
2024-06-14 09:35:35 -07:00
|
|
|
// NewFuncMap provides a template function map
|
|
|
|
func NewFuncMap(web *echo.Echo) template.FuncMap {
|
|
|
|
fm := &funcMap{web: web}
|
2021-12-03 03:11:01 -08:00
|
|
|
|
2024-06-14 09:35:35 -07:00
|
|
|
// See http://masterminds.github.io/sprig/ for all provided funcs
|
|
|
|
funcs := sprig.FuncMap()
|
|
|
|
|
|
|
|
// Include all the custom functions
|
|
|
|
funcs["hasField"] = fm.hasField
|
|
|
|
funcs["file"] = fm.file
|
|
|
|
funcs["link"] = fm.link
|
|
|
|
funcs["url"] = fm.url
|
2021-12-03 03:11:01 -08:00
|
|
|
|
2024-06-14 09:35:35 -07:00
|
|
|
return funcs
|
2021-12-03 03:11:01 -08:00
|
|
|
}
|
|
|
|
|
2024-06-14 09:35:35 -07:00
|
|
|
// hasField checks if an interface contains a given field
|
|
|
|
func (fm *funcMap) hasField(v any, name string) bool {
|
2021-12-03 03:11:01 -08:00
|
|
|
rv := reflect.ValueOf(v)
|
|
|
|
if rv.Kind() == reflect.Ptr {
|
|
|
|
rv = rv.Elem()
|
|
|
|
}
|
|
|
|
if rv.Kind() != reflect.Struct {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return rv.FieldByName(name).IsValid()
|
|
|
|
}
|
|
|
|
|
2024-06-14 09:35:35 -07:00
|
|
|
// file appends a cache buster to a given filepath so it can remain cached until the app is restarted
|
|
|
|
func (fm *funcMap) file(filepath string) string {
|
2021-12-19 13:08:09 -08:00
|
|
|
return fmt.Sprintf("/%s/%s?v=%s", config.StaticPrefix, filepath, CacheBuster)
|
2021-12-03 03:11:01 -08:00
|
|
|
}
|
|
|
|
|
2024-07-13 21:20:37 -07:00
|
|
|
func File(filepath string) string {
|
|
|
|
return fmt.Sprintf("/%s/%s?v=%s", config.StaticPrefix, filepath, CacheBuster)
|
|
|
|
}
|
|
|
|
|
2024-06-14 09:35:35 -07:00
|
|
|
// link outputs HTML for a link element, providing the ability to dynamically set the active class
|
|
|
|
func (fm *funcMap) link(url, text, currentPath string, classes ...string) template.HTML {
|
2021-12-03 03:11:01 -08:00
|
|
|
if currentPath == url {
|
2021-12-03 05:49:07 -08:00
|
|
|
classes = append(classes, "is-active")
|
2021-12-03 03:11:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
html := fmt.Sprintf(`<a class="%s" href="%s">%s</a>`, strings.Join(classes, " "), url, text)
|
|
|
|
return template.HTML(html)
|
|
|
|
}
|
2024-06-14 09:35:35 -07:00
|
|
|
|
|
|
|
// url generates a URL from a given route name and optional parameters
|
|
|
|
func (fm *funcMap) url(routeName string, params ...any) string {
|
|
|
|
return fm.web.Reverse(routeName, params...)
|
|
|
|
}
|