package echo
import (
"html/template"
"io"
"io/fs"
"net/http"
"path/filepath"
"github.com/labstack/echo/v4"
)
type TemplateChecker interface {
HaveTemplate(string) bool
}
type TemplateRenderer struct {
templates fs.FS
glob string
funcs template.FuncMap
cache *template.Template
debug bool
}
func NewTemplateRenderer(templates fs.FS, glob string, funcs template.FuncMap, debug bool) (*TemplateRenderer, error) {
var err error
r := &TemplateRenderer{
templates: templates,
glob: glob,
funcs: funcs,
debug: debug,
}
r.cache, err = r.loadTemplates()
if err != nil {
return nil, err
}
return r, nil
}
func (r *TemplateRenderer) loadTemplates() (*template.Template, error) {
t := template.New("").Funcs(r.funcs)
err := fs.WalkDir(r.templates, ".", func(path string, info fs.DirEntry, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
_, fn := filepath.Split(path)
if ok, _ := filepath.Match(r.glob, fn); ok {
fc, err := fs.ReadFile(r.templates, path)
if err != nil {
return err
}
_, err = t.New(path).Parse(string(fc))
if err != nil {
return err
}
}
}
return nil
})
if err != nil {
return nil, err
}
return t, nil
}
func (r *TemplateRenderer) getTemplateCache() (*template.Template, error) {
if !r.debug {
return r.cache, nil
}
tc, err := r.loadTemplates()
if err != nil {
return nil, err
}
return tc, nil
}
func (r *TemplateRenderer) Render(w io.Writer, name string, data interface{}, ctx echo.Context) error {
tc, err := r.getTemplateCache()
if err != nil {
return err
}
if tc.Lookup(name) == nil {
return echo.NewHTTPError(http.StatusNotFound, "Page not found")
}
if err := tc.ExecuteTemplate(w, name, data); err != nil {
return err
}
return nil
}
func (r *TemplateRenderer) HaveTemplate(name string) bool {
tc, err := r.getTemplateCache()
if err != nil {
return false
}
return tc.Lookup(name) != nil
}
var _ echo.Renderer = (*TemplateRenderer)(nil)
var _ TemplateChecker = (*TemplateRenderer)(nil)