package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/flosch/pongo2"
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
// Renderer manages a pongo2 TemplateSet
|
|
type Renderer struct {
|
|
Path string
|
|
TemplateSet *pongo2.TemplateSet
|
|
Debug bool
|
|
}
|
|
|
|
// NewRenderer creates a new instance of Renderer
|
|
func NewRenderer(root string) (*Renderer, error) {
|
|
// check if root exists
|
|
fInfo, err := os.Lstat(root)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if fInfo.IsDir() == false {
|
|
return nil, fmt.Errorf("%s is not a directory", root)
|
|
}
|
|
|
|
rdr := Renderer{}
|
|
loader, err := pongo2.NewLocalFileSystemLoader(root)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rdr.TemplateSet = pongo2.NewSet("TemplateSet-"+filepath.Base(root), loader)
|
|
|
|
return &rdr, nil
|
|
}
|
|
|
|
// Render implements echo.Render interface
|
|
func (r *Renderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
|
|
// get template, compile it anf store it in cache
|
|
//tpl, err := r.TemplateSet.FromCache(name)
|
|
tpl, err := r.TemplateSet.FromFile(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// convert supplied data to pongo2.Context
|
|
val, err := toPongoCtx(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// generate render the template
|
|
err = tpl.ExecuteWriter(val, w)
|
|
return err
|
|
}
|
|
|
|
// toPongoCtx converts a pongo2.Context, struct, map[string] to
|
|
// pongo2.Context
|
|
func toPongoCtx(data interface{}) (pongo2.Context, error) {
|
|
if c, ok := data.(pongo2.Context); ok {
|
|
return c, nil
|
|
}
|
|
|
|
var (
|
|
ctx = pongo2.Context{}
|
|
val = reflect.ValueOf(data)
|
|
)
|
|
if val.Kind().String() == "struct" {
|
|
for i := 0; i < val.NumField(); i++ {
|
|
ctx[val.Type().Field(i).Name] = val.Field(i).Interface()
|
|
}
|
|
} else if strings.HasPrefix(val.Type().String(), "map[string]") {
|
|
for _, k := range val.MapKeys() {
|
|
ctx[k.String()] = val.MapIndex(k).Interface()
|
|
}
|
|
} else {
|
|
return nil, fmt.Errorf("cant convert %T to pongo2.Context", data)
|
|
}
|
|
|
|
return ctx, nil
|
|
}
|