mirror of
https://github.com/pocketbase/pocketbase.git
synced 2025-01-10 00:43:36 +02:00
102 lines
2.8 KiB
Go
102 lines
2.8 KiB
Go
// Package template is a thin wrapper around the standard html/template
|
|
// and text/template packages that implements a convenient registry to
|
|
// load and cache templates on the fly concurrently.
|
|
//
|
|
// It was created to assist the JSVM plugin HTML rendering, but could be used in other Go code.
|
|
//
|
|
// Example:
|
|
//
|
|
// registry := template.NewRegistry()
|
|
//
|
|
// html1, err := registry.LoadFiles(
|
|
// // the files set wil be parsed only once and then cached
|
|
// "layout.html",
|
|
// "content.html",
|
|
// ).Render(map[string]any{"name": "John"})
|
|
//
|
|
// html2, err := registry.LoadFiles(
|
|
// // reuse the already parsed and cached files set
|
|
// "layout.html",
|
|
// "content.html",
|
|
// ).Render(map[string]any{"name": "Jane"})
|
|
package template
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"io/fs"
|
|
"strings"
|
|
|
|
"github.com/pocketbase/pocketbase/tools/store"
|
|
)
|
|
|
|
// NewRegistry creates and initializes a new blank templates registry.
|
|
//
|
|
// Use the Registry.Load* methods to load templates into the registry.
|
|
func NewRegistry() *Registry {
|
|
return &Registry{
|
|
cache: store.New[*Renderer](nil),
|
|
}
|
|
}
|
|
|
|
// Registry defines a templates registry that is safe to be used by multiple goroutines.
|
|
//
|
|
// Use the Registry.Load* methods to load templates into the registry.
|
|
type Registry struct {
|
|
cache *store.Store[*Renderer]
|
|
}
|
|
|
|
// LoadFiles caches (if not already) the specified filenames set as a
|
|
// single template and returns a ready to use Renderer instance.
|
|
//
|
|
// There must be at least 1 filename specified.
|
|
func (r *Registry) LoadFiles(filenames ...string) *Renderer {
|
|
key := strings.Join(filenames, ",")
|
|
|
|
found := r.cache.Get(key)
|
|
|
|
if found == nil {
|
|
// parse and cache
|
|
tpl, err := template.ParseFiles(filenames...)
|
|
found = &Renderer{template: tpl, parseError: err}
|
|
r.cache.Set(key, found)
|
|
}
|
|
|
|
return found
|
|
}
|
|
|
|
// LoadString caches (if not already) the specified inline string as a
|
|
// single template and returns a ready to use Renderer instance.
|
|
func (r *Registry) LoadString(text string) *Renderer {
|
|
found := r.cache.Get(text)
|
|
|
|
if found == nil {
|
|
// parse and cache (using the text as key)
|
|
tpl, err := template.New("").Parse(text)
|
|
found = &Renderer{template: tpl, parseError: err}
|
|
r.cache.Set(text, found)
|
|
}
|
|
|
|
return found
|
|
}
|
|
|
|
// LoadString caches (if not already) the specified fs and globPatterns
|
|
// pair as single template and returns a ready to use Renderer instance.
|
|
//
|
|
// There must be at least 1 file matching the provided globPattern(s)
|
|
// (note that most file names serves as glob patterns matching themselves).
|
|
func (r *Registry) LoadFS(fs fs.FS, globPatterns ...string) *Renderer {
|
|
key := fmt.Sprintf("%v%v", fs, globPatterns)
|
|
|
|
found := r.cache.Get(key)
|
|
|
|
if found == nil {
|
|
// parse and cache
|
|
tpl, err := template.ParseFS(fs, globPatterns...)
|
|
found = &Renderer{template: tpl, parseError: err}
|
|
r.cache.Set(key, found)
|
|
}
|
|
|
|
return found
|
|
}
|