mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-29 22:29:56 +02:00
tpl: Allow the partial template func to return any type
This commit adds support for return values in partials. This means that you can now do this and similar: {{ $v := add . 42 }} {{ return $v }} Partials without a `return` statement will be rendered as before. This works for both `partial` and `partialCached`. Fixes #5783
This commit is contained in:
committed by
GitHub
parent
9225db636e
commit
a55640de8e
@@ -18,10 +18,14 @@ package partials
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"sync"
|
||||
texttemplate "text/template"
|
||||
|
||||
"github.com/gohugoio/hugo/tpl"
|
||||
|
||||
bp "github.com/gohugoio/hugo/bufferpool"
|
||||
"github.com/gohugoio/hugo/deps"
|
||||
)
|
||||
@@ -62,8 +66,22 @@ type Namespace struct {
|
||||
cachedPartials *partialCache
|
||||
}
|
||||
|
||||
// Include executes the named partial and returns either a string,
|
||||
// when the partial is a text/template, or template.HTML when html/template.
|
||||
// contextWrapper makes room for a return value in a partial invocation.
|
||||
type contextWrapper struct {
|
||||
Arg interface{}
|
||||
Result interface{}
|
||||
}
|
||||
|
||||
// Set sets the return value and returns an empty string.
|
||||
func (c *contextWrapper) Set(in interface{}) string {
|
||||
c.Result = in
|
||||
return ""
|
||||
}
|
||||
|
||||
// Include executes the named partial.
|
||||
// If the partial contains a return statement, that value will be returned.
|
||||
// Else, the rendered output will be returned:
|
||||
// A string if the partial is a text/template, or template.HTML when html/template.
|
||||
func (ns *Namespace) Include(name string, contextList ...interface{}) (interface{}, error) {
|
||||
if strings.HasPrefix(name, "partials/") {
|
||||
name = name[8:]
|
||||
@@ -83,31 +101,54 @@ func (ns *Namespace) Include(name string, contextList ...interface{}) (interface
|
||||
// For legacy reasons.
|
||||
templ, found = ns.deps.Tmpl.Lookup(n + ".html")
|
||||
}
|
||||
if found {
|
||||
b := bp.GetBuffer()
|
||||
defer bp.PutBuffer(b)
|
||||
|
||||
if err := templ.Execute(b, context); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, ok := templ.(*texttemplate.Template); ok {
|
||||
s := b.String()
|
||||
if ns.deps.Metrics != nil {
|
||||
ns.deps.Metrics.TrackValue(n, s)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
s := b.String()
|
||||
if ns.deps.Metrics != nil {
|
||||
ns.deps.Metrics.TrackValue(n, s)
|
||||
}
|
||||
return template.HTML(s), nil
|
||||
|
||||
if !found {
|
||||
return "", fmt.Errorf("partial %q not found", name)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("partial %q not found", name)
|
||||
var info tpl.Info
|
||||
if ip, ok := templ.(tpl.TemplateInfoProvider); ok {
|
||||
info = ip.TemplateInfo()
|
||||
}
|
||||
|
||||
var w io.Writer
|
||||
|
||||
if info.HasReturn {
|
||||
// Wrap the context sent to the template to capture the return value.
|
||||
// Note that the template is rewritten to make sure that the dot (".")
|
||||
// and the $ variable points to Arg.
|
||||
context = &contextWrapper{
|
||||
Arg: context,
|
||||
}
|
||||
|
||||
// We don't care about any template output.
|
||||
w = ioutil.Discard
|
||||
} else {
|
||||
b := bp.GetBuffer()
|
||||
defer bp.PutBuffer(b)
|
||||
w = b
|
||||
}
|
||||
|
||||
if err := templ.Execute(w, context); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
|
||||
if ctx, ok := context.(*contextWrapper); ok {
|
||||
result = ctx.Result
|
||||
} else if _, ok := templ.(*texttemplate.Template); ok {
|
||||
result = w.(fmt.Stringer).String()
|
||||
} else {
|
||||
result = template.HTML(w.(fmt.Stringer).String())
|
||||
}
|
||||
|
||||
if ns.deps.Metrics != nil {
|
||||
ns.deps.Metrics.TrackValue(n, result)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
// IncludeCached executes and caches partial templates. An optional variant
|
||||
|
Reference in New Issue
Block a user