echojet/render.go
2020-01-13 22:30:41 +08:00

138 lines
3.5 KiB
Go

// library github.com/CloudyKit/jet
package echojet
import (
"io"
"net/http"
"reflect"
"sync"
"github.com/CloudyKit/jet/v3"
"github.com/labstack/echo/v4"
)
// RenderOptions is used to configure the renderer.
type RenderOptions struct {
TemplateDir string
ContentType string
VarMap *VarMapMx
}
// JetRender is a custom Gin template renderer using Pongo2.
type JetRender struct {
Options *RenderOptions
JetSet *jet.Set
}
// New creates a new JetRender instance with custom Options.
func New(options RenderOptions) *JetRender {
set := jet.NewHTMLSet(options.TemplateDir)
return &JetRender{
Options: &options,
JetSet: set,
}
}
// Default creates a JetRender instance with default options.
func Default() (jr *JetRender) {
jr = New(RenderOptions{
TemplateDir: "templates",
ContentType: "text/html; charset=utf-8",
// ContentType: "text/html",
VarMap: NewVarMapMx(),
})
jr.JetSet.SetDevelopmentMode(true)
return
}
// Render should render the template to the response.
func (p *JetRender) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
template, err := p.JetSet.GetTemplate(name)
if err != nil {
return err
}
// p.Options.VarMap["urlfor"] = reflect.ValueOf(jet.Func(func(a jet.Arguments) reflect.Value {
// a.RequireNumOfArguments("urlfor", 1, -1)
// args := make([]interface{}, a.NumOfArguments())
// for i := 0; i < a.NumOfArguments(); i++ {
// args[i] = a.Get(i).Interface()
// }
// return reflect.ValueOf(c.Echo().Reverse(args[0].(string), args[1:]...))
// }))
// p.WriteContentType(w)
return template.Execute(w, p.Options.VarMap.GetVarMap(), data)
}
// WriteContentType should add the Content-Type header to the response
// when not set yet.
func (p *JetRender) WriteContentType(w io.Writer) {
if rw, ok := w.(http.ResponseWriter); ok {
header := rw.Header()
if val := header["Content-Type"]; len(val) == 0 {
// header["Content-Type"] = []string{p.Options.ContentType}
header.Set("Content-Type", p.Options.ContentType)
}
}
}
// VarMapMx defines a mutex-protected jet.VarMap that's usable concurrently.
type VarMapMx struct {
mx sync.RWMutex
varMap jet.VarMap
}
// NewVarMapMx returns an initialized VarMapMx instance that is ready to be used.
func NewVarMapMx() *VarMapMx {
return &VarMapMx{varMap: jet.VarMap{}}
}
// Get returns the value for a key in the embedded jet.VarMap.
// The returned reflect.Value is not valid if the key does not exist.
func (scope *VarMapMx) Get(name string) reflect.Value {
v, _ := scope.Lookup(name)
return v
}
// Lookup returns the value for a key in the embedded jet.VarMap
// as well as whether the key was found or not.
func (scope *VarMapMx) Lookup(name string) (reflect.Value, bool) {
scope.mx.RLock()
defer scope.mx.RUnlock()
v, ok := scope.varMap[name]
return v, ok
}
// Set adds the key value pair in the embedded jet.VarMap.
func (scope *VarMapMx) Set(name string, v interface{}) *VarMapMx {
scope.mx.Lock()
defer scope.mx.Unlock()
scope.varMap.Set(name, v)
return scope
}
// SetFunc adds a jet.Func to the embedded jet.VarMap.
func (scope *VarMapMx) SetFunc(name string, v jet.Func) *VarMapMx {
scope.mx.Lock()
defer scope.mx.Unlock()
scope.varMap.Set(name, v)
return scope
}
// SetWriter adds a jet.SafeWriter to the embedded jet.VarMap.
func (scope *VarMapMx) SetWriter(name string, v jet.SafeWriter) *VarMapMx {
scope.mx.Lock()
defer scope.mx.Unlock()
scope.varMap.Set(name, v)
return scope
}
// GetVarMap returns the embedded jet.VarMap for use in template executions.
func (scope *VarMapMx) GetVarMap() jet.VarMap {
return scope.varMap
}