1
0
Fork 0
httpserver/templates/templates.go

118 Zeilen
2.7 KiB
Go

// Package templates helps sites to manage their templates
package templates
import (
"bytes"
"errors"
"io"
"io/fs"
"net/http"
"path/filepath"
"github.com/flosch/pongo2/v6"
"github.com/gin-gonic/gin/render"
"github.com/rs/zerolog/log"
)
var (
_ pongo2.TemplateLoader = &FSLoader{}
_ render.Render = &renderer{}
_ pongo2.TemplateLoader = &EmptyLoader{}
)
// TemplateSite is an interface that is for storing templates.
type TemplateSite interface {
Templates() pongo2.TemplateLoader
}
// FSLoader is an interim until pongo merges the pullrequest for fs.FS
type FSLoader struct {
fs.FS
}
// Abs return the join of base and name
func (e *FSLoader) Abs(base, name string) string {
return filepath.Join(filepath.Dir(base), name)
}
// Get returns an io.Reader where the template's content can be read from.
func (e *FSLoader) Get(path string) (reader io.Reader, err error) {
f, err := e.FS.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
bt, err := io.ReadAll(f)
if err != nil {
return nil, err
}
return bytes.NewBuffer(bt), nil
}
// Pongo2Renderer is an simple wrapper for gin to use pongo2 templates
type Pongo2Renderer struct {
ts *pongo2.TemplateSet
}
// NewPongo2Renderer creates an wrapper for gin
func NewPongo2Renderer(ts *pongo2.TemplateSet) render.HTMLRender {
return &Pongo2Renderer{ts: ts}
}
// Instance create an new instance of an REnder object
func (p2r *Pongo2Renderer) Instance(name string, data any) render.Render {
tmpl, err := p2r.ts.FromFile(name)
r := &renderer{
tmpl: tmpl,
err: err,
}
if data != nil {
switch data.(type) {
case pongo2.Context:
r.data = data.(pongo2.Context)
case map[string]any:
r.data = data.(map[string]any)
default:
r.err = errors.New("Failed to detect possible format for pongo2. It needs to be map[string]any or pongo2.Context")
}
}
log.Debug().Msg("Returning an instance")
return r
}
type renderer struct {
tmpl *pongo2.Template
err error
data pongo2.Context
}
// Render renders the template
func (r *renderer) Render(rw http.ResponseWriter) error {
if r.err != nil {
log.Debug().Msg("rendering failed")
return r.err
}
log.Debug().Msg("wirting template")
return r.tmpl.ExecuteWriter(r.data, rw)
}
// WriteContentType is an static function that always writes text/html as the Contenttype into the response
func (*renderer) WriteContentType(rw http.ResponseWriter) {
rw.Header().Set("Content-Type", "text/html")
}
// EmptyLoader is an Empty Loader
type EmptyLoader struct{}
// Abs return the join of base and name
func (*EmptyLoader) Abs(base, name string) string {
return filepath.Join(filepath.Dir(base), name)
}
// Get returns always errors
func (*EmptyLoader) Get(string) (io.Reader, error) {
return nil, errors.New("This Loader has no templates")
}