templates: Fix base template block customization

Previously, kiln would error out if any blocks defined in the base
template were not defined in page or index templates. Instead, make
customizing base template blocks optional. This also allows base
template blocks to have a default value.
This commit is contained in:
Adnan Maolood 2022-09-27 08:13:11 -04:00
parent 3a3ec83e0f
commit 299cb5e1d1

View file

@ -9,50 +9,69 @@ import (
pathpkg "path" pathpkg "path"
"strings" "strings"
"text/template" "text/template"
"text/template/parse"
) )
// Template represents a template. // Template represents a template.
type Template interface { type Template interface {
AddParseTree(*parse.Tree) error Clone() (Template, error)
AddTemplates(Template) error
Execute(io.Writer, interface{}) error Execute(io.Writer, interface{}) error
Tree() *parse.Tree
} }
type textTemplate struct { type textTemplate struct {
tmpl *template.Template tmpl *template.Template
} }
func (t textTemplate) AddParseTree(tree *parse.Tree) error { func (t textTemplate) Clone() (Template, error) {
_, err := t.tmpl.AddParseTree(t.tmpl.Name(), tree) clone, err := t.tmpl.Clone()
return err return textTemplate{clone}, err
}
func (t textTemplate) AddTemplates(other Template) error {
otherTmpl := other.(textTemplate).tmpl
for _, def := range otherTmpl.Templates() {
if def.Name() == otherTmpl.Name() {
continue
}
_, err := t.tmpl.AddParseTree(def.Name(), def.Tree)
if err != nil {
return err
}
}
return nil
} }
func (t textTemplate) Execute(w io.Writer, data interface{}) error { func (t textTemplate) Execute(w io.Writer, data interface{}) error {
return t.tmpl.Execute(w, data) return t.tmpl.Execute(w, data)
} }
func (t textTemplate) Tree() *parse.Tree {
return t.tmpl.Tree
}
type htmlTemplate struct { type htmlTemplate struct {
tmpl *htemplate.Template tmpl *htemplate.Template
} }
func (t htmlTemplate) AddParseTree(tree *parse.Tree) error { func (t htmlTemplate) Clone() (Template, error) {
_, err := t.tmpl.AddParseTree(t.tmpl.Name(), tree) clone, err := t.tmpl.Clone()
return err return htmlTemplate{clone}, err
}
func (t htmlTemplate) AddTemplates(other Template) error {
otherTmpl := other.(htmlTemplate).tmpl
for _, def := range otherTmpl.Templates() {
if def.Name() == otherTmpl.Name() {
continue
}
_, err := t.tmpl.AddParseTree(def.Name(), def.Tree)
if err != nil {
return err
}
}
return nil
} }
func (t htmlTemplate) Execute(w io.Writer, data interface{}) error { func (t htmlTemplate) Execute(w io.Writer, data interface{}) error {
return t.tmpl.Execute(w, data) return t.tmpl.Execute(w, data)
} }
func (t htmlTemplate) Tree() *parse.Tree {
return t.tmpl.Tree
}
// Templates contains site templates. // Templates contains site templates.
type Templates struct { type Templates struct {
tmpls map[string]Template tmpls map[string]Template
@ -129,12 +148,20 @@ func (t *Templates) Load(dir string, exts []string) error {
if _, ok := extsMap[ext]; !ok { if _, ok := extsMap[ext]; !ok {
continue continue
} }
base := pathpkg.Join(pathpkg.Dir(path), "base"+ext) basePath := pathpkg.Join(pathpkg.Dir(path), "base"+ext)
if tmpl, ok := t.tmpls[base]; ok { if path == basePath {
err := t.tmpls[path].AddParseTree(tmpl.Tree()) continue
}
if base, ok := t.tmpls[basePath]; ok {
tmpl, err := base.Clone()
if err != nil { if err != nil {
return err return err
} }
// Load customized template definitions
if err := tmpl.AddTemplates(t.tmpls[path]); err != nil {
return err
}
t.tmpls[path] = tmpl
} }
} }
return nil return nil