vinegar/servlet/templates.go
2023-08-01 13:34:08 -04:00

195 lines
4.6 KiB
Go

package servlet
import (
"errors"
util "geniuscartel.xyz/vinegar/vinegarUtil"
"html/template"
"io/ioutil"
"net/http"
"os"
"path"
"strings"
)
type (
//TemplateManager handles loading and rendering templates.
//It contains the following fields:
//
//templatePath - The base path to load template files from.
//
//componentPath - The base path to load template components from.
//
//templates - A map of template name to parsed *template.Template.
//
//components - A map of component name to template.HTML content.
//
//mixins - A map of mixin name to content string.
//
//Templates - A slice of all template names that were loaded.
//
//The main methods are:
//
//NewTemplateManager - Constructor to create a new instance.
//
//RenderTemplate - Renders a template by name and returns the output.
//
//GetComponent - Fetches a component by name.
//
//AddMixin - Adds a new mixin value by name.
//
//AddMixinFromFile - Loads a mixin from a file.
//
//RenderAllToFile - Renders all templates to files in a directory.
//
//Typical usage:
//
// tm := NewTemplateManager("templates", "components")
// output := tm.RenderTemplate("index.tmpl")
// tm.AddMixin("title", "My Page")
TemplateManager struct {
templatePath string
componentPath string
templates map[string]*template.Template
components map[string]template.HTML
mixins map[string]string
Templates []string
}
)
func NewTemplateManager(templatePath string, componentPath string) *TemplateManager {
templates := make(map[string]*template.Template)
components := make(map[string]template.HTML)
mixins := make(map[string]string)
tm := TemplateManager{templatePath: templatePath, componentPath: componentPath, templates: templates, components: components, mixins: mixins}
tm.loadAssets()
return &tm
}
func (tm *TemplateManager) loadAssets() error {
templateFiles, err := os.ReadDir(tm.templatePath)
if err != nil {
return err
}
for _, templateFile := range templateFiles {
if !templateFile.IsDir() {
filePath := path.Join(tm.templatePath, templateFile.Name())
dataContent, err := util.GetDiskContent(filePath)
if err != nil {
return err
}
tmpl := template.New(templateFile.Name())
tmpl.Parse(string(*dataContent))
tm.templates[templateFile.Name()] = tmpl
tm.Templates = append(tm.Templates, templateFile.Name())
}
}
componentFiles, err := os.ReadDir(tm.componentPath)
if err != nil {
return err
}
for _, componentFile := range componentFiles {
if !componentFile.IsDir() {
filePath := path.Join(tm.componentPath, componentFile.Name())
contentBytes, err := util.GetDiskContent(filePath)
if err != nil {
return err
}
content := string(*contentBytes)
tm.components[componentFile.Name()] = template.HTML(content)
}
}
return nil
}
func (tm *TemplateManager) RenderTemplate(key string) (string, error) {
tmpl, exists := tm.templates[key]
if !exists {
return "", errors.New("Could not load template for key: " + key)
}
buff := strings.Builder{}
err := tmpl.Execute(&buff, tm)
if err != nil {
return "", err
}
return buff.String(), nil
}
func (tm *TemplateManager) GetComponent(key string) (template.HTML, error) {
content, exists := tm.components[key]
if !exists {
return "", errors.New("Could not load data for key: " + key)
}
return content, nil
}
func (tm *TemplateManager) GetMixin(key string) template.HTML {
content, exists := tm.mixins[key]
if exists {
return template.HTML(content)
} else {
return ""
}
}
func (tm *TemplateManager) AddMixin(key string, value string) error {
tm.mixins[key] = value
return nil
}
func (tm *TemplateManager) AddMixinFromFile(key string, pathlike string) error {
content, err := util.GetDiskContent(pathlike)
if err != nil {
return err
} else {
err2 := tm.AddMixin(key, string(*content))
if err2 != nil {
return err2
}
return nil
}
}
func (tm *TemplateManager) RenderAllToFile(pathlike string) error {
for _, v := range tm.Templates {
p := path.Join(pathlike, v)
tmpl := tm.templates[v]
buff := strings.Builder{}
err := tmpl.Execute(&buff, tm)
if err != nil {
return err
}
err = ioutil.WriteFile(p, []byte(buff.String()), 0755)
if err != nil {
return err
}
}
return nil
}
func RenderTemplate(w http.ResponseWriter, pathlike string, data any) error {
templateHelper := template.New(pathlike)
f, err := os.OpenFile(pathlike, os.O_RDONLY, 0777)
if err != nil {
return err
}
defer f.Close()
content, err := ioutil.ReadAll(f)
if err != nil {
return err
}
templ, err := templateHelper.Parse(string(content))
err = templ.Execute(w, data)
if err != nil {
return err
}
return nil
}