Migliorato il sistema dei template, ora è presente la cartella "views/partials/"
In particolare è stato generalizzato leggermente il sistema di loading dei template (ok forse un po' più del necessario) però ora è possibile aggiungere facilmente più cartelle di parziali e creare gerarchie di template più complicate.main-old
parent
847f588e87
commit
1a2e2341d3
@ -1,52 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/phc-dm/phc-server/config"
|
|
||||||
"github.com/phc-dm/phc-server/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TemplateRenderer holds cached templates for rendering
|
|
||||||
type TemplateRenderer struct {
|
|
||||||
baseFile string
|
|
||||||
baseTemplate *template.Template
|
|
||||||
templateMap map[string]*template.Template
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTemplateRenderer constructs a template renderer with a base file
|
|
||||||
func NewTemplateRenderer(baseFile string) *TemplateRenderer {
|
|
||||||
return &TemplateRenderer{
|
|
||||||
baseFile: baseFile,
|
|
||||||
baseTemplate: template.Must(template.ParseFiles("./views/" + baseFile)),
|
|
||||||
templateMap: make(map[string]*template.Template),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the template
|
|
||||||
func (t *TemplateRenderer) Render(w io.Writer, name string, data util.H) error {
|
|
||||||
tmpl := t.templateMap[name]
|
|
||||||
|
|
||||||
if config.Mode == "development" || tmpl == nil {
|
|
||||||
if config.Mode == "development" {
|
|
||||||
tmpl = template.Must(template.ParseFiles("./views/" + t.baseFile))
|
|
||||||
} else {
|
|
||||||
tmpl = template.Must(t.baseTemplate.Clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl.ParseFiles("./views/" + name)
|
|
||||||
t.templateMap[name] = tmpl
|
|
||||||
}
|
|
||||||
|
|
||||||
newData := util.H{}
|
|
||||||
newData.Apply(data)
|
|
||||||
newData["Page"] = util.H{
|
|
||||||
// Used to inject a page specific class on <body>
|
|
||||||
"Name": strings.TrimSuffix(name, ".html"),
|
|
||||||
}
|
|
||||||
newData["Config"] = config.Object()
|
|
||||||
|
|
||||||
return tmpl.ExecuteTemplate(w, "base", newData)
|
|
||||||
}
|
|
@ -0,0 +1,117 @@
|
|||||||
|
package templates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/phc-dm/phc-server/config"
|
||||||
|
"github.com/phc-dm/phc-server/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoadTemplate interface {
|
||||||
|
Load(t *template.Template) (*template.Template, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type File string
|
||||||
|
|
||||||
|
func (file File) Load(t *template.Template) (*template.Template, error) {
|
||||||
|
return t.ParseFiles(string(file))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pattern string
|
||||||
|
|
||||||
|
func (pattern Pattern) Load(t *template.Template) (*template.Template, error) {
|
||||||
|
return t.ParseGlob(string(pattern))
|
||||||
|
}
|
||||||
|
|
||||||
|
type CachedTemplate struct {
|
||||||
|
Loaders []LoadTemplate
|
||||||
|
template *template.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCacheTemplate(loaders ...LoadTemplate) *CachedTemplate {
|
||||||
|
cachedTemplate := &CachedTemplate{
|
||||||
|
Loaders: loaders,
|
||||||
|
template: nil,
|
||||||
|
}
|
||||||
|
template.Must(cachedTemplate.Load(template.New("")))
|
||||||
|
return cachedTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *CachedTemplate) Load(t *template.Template) (*template.Template, error) {
|
||||||
|
if ct.template != nil {
|
||||||
|
return ct.template, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ct.template = t
|
||||||
|
|
||||||
|
for _, loader := range ct.Loaders {
|
||||||
|
var err error
|
||||||
|
ct.template, err = loader.Load(ct.template)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ct.template, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *CachedTemplate) Reload() {
|
||||||
|
ct.template = nil
|
||||||
|
template.Must(ct.Load(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ct *CachedTemplate) Template() *template.Template {
|
||||||
|
return ct.template
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renderer holds cached templates for rendering
|
||||||
|
type Renderer struct {
|
||||||
|
rootPath string
|
||||||
|
baseLoaders []LoadTemplate
|
||||||
|
routes map[string]*CachedTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRenderer constructs a template renderer with a base file
|
||||||
|
func NewRenderer(rootPath string, loaders ...LoadTemplate) *Renderer {
|
||||||
|
return &Renderer{
|
||||||
|
rootPath,
|
||||||
|
loaders,
|
||||||
|
map[string]*CachedTemplate{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Renderer) Load(name string) *CachedTemplate {
|
||||||
|
cachedTemplate, present := r.routes[name]
|
||||||
|
|
||||||
|
if !present {
|
||||||
|
loaders := []LoadTemplate{}
|
||||||
|
loaders = append(loaders, r.baseLoaders...)
|
||||||
|
loaders = append(loaders, File(path.Join(r.rootPath, name)))
|
||||||
|
cachedTemplate = NewCacheTemplate(loaders...)
|
||||||
|
r.routes[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)
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
{{ define "navbar" }}
|
||||||
|
<nav>
|
||||||
|
<!-- Site -->
|
||||||
|
<div class="nav-logo">
|
||||||
|
<a class="nav-element" href="/">
|
||||||
|
<img src="/public/images/logo-circuit-board.svg" alt="phc-logo">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-main">
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/utenti">Utenti</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item dropdown">
|
||||||
|
<div class="name">
|
||||||
|
<a class="nav-element" href="/progetti">
|
||||||
|
<div class="icon">
|
||||||
|
<i class="fas fa-chevron-down"></i>
|
||||||
|
</div>
|
||||||
|
<div class="label">
|
||||||
|
Progetti
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-items">
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="{{ .Config.GitUrl }}">Gitea</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="{{ .Config.ForumUrl }}">Zulip</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/seminari">Seminari</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item dropdown">
|
||||||
|
<div class="name">
|
||||||
|
<a class="nav-element" href="/risorse">
|
||||||
|
<div class="icon">
|
||||||
|
<i class="fas fa-chevron-down"></i>
|
||||||
|
</div>
|
||||||
|
<div class="label">
|
||||||
|
Risorse
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-items">
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/news">News</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/guide">Guide</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/link">Link Utili</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/storia">Storia</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/about">About</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-item filler"></div>
|
||||||
|
|
||||||
|
<!-- User Related -->
|
||||||
|
<div class="nav-item">
|
||||||
|
<div id="toggle-dark-mode" class="nav-button">
|
||||||
|
<i class="fas fa-moon"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{if .User}}
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/profile">@{{ .User }}</a>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="nav-item">
|
||||||
|
<a class="nav-element" href="/login">Accedi</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{{ end }}
|
Loading…
Reference in New Issue