package tmpls import ( "errors" "html/template" "io/fs" "net/http" "os" "path/filepath" "strings" "github.com/gin-gonic/gin/render" ) var ErrNoTmpl = errors.New("no such template in map") // TmplMap is a map of templates that implements // the render.HTMLRender interface type Map map[string]*template.Template // Instance returns a Tmpl instance for the given template func (m Map) Instance(name string, data interface{}) render.Render { tmpl, ok := m[name] if !ok { return nil } return Tmpl{ Template: tmpl, data: data, } } // Tmpl implements the render.Render interface type Tmpl struct { *template.Template data interface{} } // Render renders the template to response writer func (t Tmpl) Render(res http.ResponseWriter) error { if t.Template == nil { return ErrNoTmpl } return t.Execute(res, t.data) } // WriteContentType sets content type to HTML func (t Tmpl) WriteContentType(res http.ResponseWriter) { res.Header().Set("Content-Type", "text/html; charset=utf-8") } func FromFS(f fs.FS, root, ext string, fm template.FuncMap) (Map, error) { tmpls := Map{} err := fs.WalkDir(f, root, func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if d.IsDir() || path == filepath.Join(root, "base"+ext) { return nil } tmplName := strings.TrimPrefix(path, root+"/") tmplName = strings.TrimSuffix(tmplName, ext) tmpl := template.New(filepath.Base(path)) if fm != nil { tmpl = tmpl.Funcs(fm) } tmpl, err = tmpl.ParseFS(f, path, filepath.Join(root, "base"+ext)) if err != nil { return err } tmpls[tmplName] = tmpl return nil }) return tmpls, err } func FromDir(baseDir, ext string, fm template.FuncMap) (Map, error) { dir := filepath.Dir(baseDir) root := filepath.Base(baseDir) return FromFS(os.DirFS(dir), root, ext, fm) }