|
|
|
package templates
|
|
|
|
|
|
|
|
import (
|
|
|
|
"html/template"
|
|
|
|
"io"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"git.phc.dm.unipi.it/phc/website/config"
|
|
|
|
"git.phc.dm.unipi.it/phc/website/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
type CachedTemplate struct {
|
|
|
|
LoadPatterns []string
|
|
|
|
cachedTmpl *template.Template
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewCacheTemplate(loadPatterns ...string) *CachedTemplate {
|
|
|
|
cachedTemplate := &CachedTemplate{
|
|
|
|
LoadPatterns: loadPatterns,
|
|
|
|
cachedTmpl: nil,
|
|
|
|
}
|
|
|
|
template.Must(cachedTemplate.Load(template.New("")))
|
|
|
|
return cachedTemplate
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ct *CachedTemplate) Load(t *template.Template) (*template.Template, error) {
|
|
|
|
if ct.cachedTmpl != nil {
|
|
|
|
return ct.cachedTmpl, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ct.cachedTmpl = t
|
|
|
|
|
|
|
|
for _, pattern := range ct.LoadPatterns {
|
|
|
|
var err error
|
|
|
|
ct.cachedTmpl, err = ct.cachedTmpl.ParseGlob(pattern)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ct.cachedTmpl, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ct *CachedTemplate) Reload() {
|
|
|
|
ct.cachedTmpl = nil
|
|
|
|
template.Must(ct.Load(nil))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ct *CachedTemplate) Template() *template.Template {
|
|
|
|
return ct.cachedTmpl
|
|
|
|
}
|
|
|
|
|
|
|
|
// Renderer holds cached templates for rendering
|
|
|
|
type Renderer struct {
|
|
|
|
rootPath string
|
|
|
|
loadPatterns []string
|
|
|
|
templateCache map[string]*CachedTemplate
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewRenderer constructs a template renderer with a base file
|
|
|
|
func NewRenderer(rootPath string, loadPatterns ...string) *Renderer {
|
|
|
|
return &Renderer{
|
|
|
|
rootPath,
|
|
|
|
loadPatterns,
|
|
|
|
map[string]*CachedTemplate{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Renderer) Load(name string) *CachedTemplate {
|
|
|
|
cachedTemplate, present := r.templateCache[name]
|
|
|
|
|
|
|
|
if !present {
|
|
|
|
loaders := []string{}
|
|
|
|
loaders = append(loaders, r.loadPatterns...)
|
|
|
|
loaders = append(loaders, path.Join(r.rootPath, name))
|
|
|
|
cachedTemplate = NewCacheTemplate(loaders...)
|
|
|
|
r.templateCache[name] = cachedTemplate
|
|
|
|
}
|
|
|
|
|
|
|
|
return cachedTemplate
|
|
|
|
}
|
|
|
|
|
|
|
|
// Render the template, also injects "Page" and "Config" values in the template
|
|
|
|
func (r *Renderer) Render(w io.Writer, name string, data util.H) error {
|
|
|
|
cachedTemplate := r.Load(name)
|
|
|
|
|
|
|
|
if config.Mode == "development" {
|
|
|
|
cachedTemplate.Reload()
|
|
|
|
}
|
|
|
|
|
|
|
|
newData := util.H{}
|
|
|
|
newData.Apply(data)
|
|
|
|
newData["Page"] = util.H{
|
|
|
|
// Used to inject a page specific class on <body>
|
|
|
|
"Name": strings.TrimSuffix(path.Base(name), ".html"),
|
|
|
|
}
|
|
|
|
newData["Config"] = config.Object()
|
|
|
|
|
|
|
|
return cachedTemplate.Template().ExecuteTemplate(w, "base", newData)
|
|
|
|
}
|