generated from ElnuDev/go-project
Better template loading, word page
See https://stackoverflow.com/a/11468132
This commit is contained in:
parent
f558d7f0c1
commit
e70916c6c1
11 changed files with 236 additions and 87 deletions
|
@ -1,25 +1,21 @@
|
|||
package httputils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Handler = func(http.ResponseWriter, *http.Request)
|
||||
|
||||
const templateFolder = "templates"
|
||||
|
||||
var templatePaths, templateModTimes, _ = getTemplates()
|
||||
var templates *template.Template = template.Must(template.ParseFiles(templatePaths...))
|
||||
|
||||
func getTemplates() ([]string, map[string]time.Time, error) {
|
||||
func getPartials() ([]string, map[string]time.Time, error) {
|
||||
var modTimes map[string]time.Time = make(map[string]time.Time)
|
||||
err := filepath.Walk(templateFolder, func(path string, info os.FileInfo, err error) error {
|
||||
err := filepath.Walk(partialsFolder, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -37,35 +33,15 @@ func getTemplates() ([]string, map[string]time.Time, error) {
|
|||
return paths, modTimes, err
|
||||
}
|
||||
|
||||
func reloadTemplateIfModified(path string) {
|
||||
fileInfo, _ := os.Stat(path)
|
||||
modTime := fileInfo.ModTime()
|
||||
if modTime.After(templateModTimes[path]) {
|
||||
fmt.Printf("Reloading template %s...\n", path)
|
||||
templates.ParseFiles(path)
|
||||
templateModTimes[path] = modTime
|
||||
}
|
||||
}
|
||||
|
||||
func reloadTemplatesIfModified() {
|
||||
for _, path := range templatePaths {
|
||||
reloadTemplateIfModified(path)
|
||||
}
|
||||
}
|
||||
|
||||
const reloadTemplates = true
|
||||
|
||||
func GenerateHandler(
|
||||
file interface{}, // either string or func() string
|
||||
handler func(http.ResponseWriter, *http.Request) bool,
|
||||
data func(http.ResponseWriter, *http.Request) any,
|
||||
templateSet TemplateSet,
|
||||
template func(http.ResponseWriter, *http.Request) (template string, data any),
|
||||
methods []string,
|
||||
) Handler {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// All templates must be reloaded in case of dependencies
|
||||
if reloadTemplates {
|
||||
reloadTemplatesIfModified()
|
||||
}
|
||||
for _, method := range methods {
|
||||
if method == r.Method {
|
||||
goto ok
|
||||
|
@ -75,16 +51,18 @@ func GenerateHandler(
|
|||
return
|
||||
ok:
|
||||
renderTemplate := handler(w, r)
|
||||
if renderTemplate && file != "" {
|
||||
var file_path string
|
||||
switch file.(type) {
|
||||
case string:
|
||||
file_path = file.(string)
|
||||
case func(http.ResponseWriter, *http.Request) string:
|
||||
file_path = file.(func(http.ResponseWriter, *http.Request) string)(w, r)
|
||||
if renderTemplate {
|
||||
file_path, data := template(w, r)
|
||||
buf := &bytes.Buffer{}
|
||||
err := templateSet.ExecuteTemplate(buf, file_path, reflect.ValueOf(data))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
fmt.Fprint(w, "500 Internal Server Error")
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
templates.ExecuteTemplate(w, file_path, data(w, r))
|
||||
fmt.Fprint(w, buf.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
86
httputils/templates.go
Normal file
86
httputils/templates.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
package httputils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TemplateSet struct {
|
||||
templates *template.Template
|
||||
paths []string
|
||||
modTimes map[string]time.Time
|
||||
}
|
||||
|
||||
func newTemplateSet(partials *TemplateSet, paths ...string) TemplateSet {
|
||||
var partialPaths []string
|
||||
if partials == nil {
|
||||
partialPaths = make([]string, 0)
|
||||
} else {
|
||||
partialPaths = partials.paths
|
||||
}
|
||||
allPaths := append(partialPaths, paths...)
|
||||
modTimes := make(map[string]time.Time)
|
||||
for _, path := range allPaths {
|
||||
fileInfo, _ := os.Stat(path)
|
||||
modTimes[path] = fileInfo.ModTime()
|
||||
}
|
||||
templates := template.Must(template.ParseFiles(allPaths...))
|
||||
return TemplateSet{
|
||||
templates: templates,
|
||||
paths: allPaths,
|
||||
modTimes: modTimes,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTemplateSet(paths ...string) TemplateSet {
|
||||
for i, path := range paths {
|
||||
paths[i] = fmt.Sprintf("%s/%s", templateFolder, path)
|
||||
}
|
||||
return newTemplateSet(&partials, paths...)
|
||||
}
|
||||
|
||||
func (templateSet *TemplateSet) ExecuteTemplate(wr io.Writer, name string, data any) error {
|
||||
templateSet.reloadTemplatesIfModified()
|
||||
return templateSet.templates.ExecuteTemplate(wr, name, data)
|
||||
}
|
||||
|
||||
func (templateSet *TemplateSet) reloadTemplateIfModified(path string) {
|
||||
fileInfo, _ := os.Stat(path)
|
||||
modTime := fileInfo.ModTime()
|
||||
if modTime.After(templateSet.modTimes[path]) {
|
||||
fmt.Printf("Reloading template %s...\n", path)
|
||||
templateSet.templates.ParseFiles(path)
|
||||
templateSet.modTimes[path] = modTime
|
||||
}
|
||||
}
|
||||
|
||||
func (templateSet *TemplateSet) reloadTemplatesIfModified() {
|
||||
for _, path := range templateSet.paths {
|
||||
templateSet.reloadTemplateIfModified(path)
|
||||
}
|
||||
}
|
||||
|
||||
func getTemplatePathsInDirectory(directory string) (paths []string, err error) {
|
||||
paths = make([]string, 0)
|
||||
err = filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() && strings.HasSuffix(path, ".html") {
|
||||
paths = append(paths, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const templateFolder = "templates"
|
||||
const partialsFolder = templateFolder + "/partials"
|
||||
|
||||
var paths, _ = getTemplatePathsInDirectory(partialsFolder)
|
||||
var partials = newTemplateSet(nil, paths...)
|
Reference in a new issue