Fixes debug HTML rendering:

- Stateless algorithm
This commit is contained in:
Manu Mtz-Almeida 2015-03-31 17:36:13 +02:00
parent 59d949d350
commit df3ed787e1
3 changed files with 94 additions and 62 deletions

8
gin.go
View File

@ -76,8 +76,8 @@ func (engine *Engine) allocateContext() (c *Context) {
func (engine *Engine) LoadHTMLGlob(pattern string) { func (engine *Engine) LoadHTMLGlob(pattern string) {
if IsDebugging() { if IsDebugging() {
render.HTMLDebug.AddGlob(pattern) r := &render.HTMLDebugRender{Glob: pattern}
engine.HTMLRender = render.HTMLDebug engine.HTMLRender = r
} else { } else {
templ := template.Must(template.ParseGlob(pattern)) templ := template.Must(template.ParseGlob(pattern))
engine.SetHTMLTemplate(templ) engine.SetHTMLTemplate(templ)
@ -86,8 +86,8 @@ func (engine *Engine) LoadHTMLGlob(pattern string) {
func (engine *Engine) LoadHTMLFiles(files ...string) { func (engine *Engine) LoadHTMLFiles(files ...string) {
if IsDebugging() { if IsDebugging() {
render.HTMLDebug.AddFiles(files...) r := &render.HTMLDebugRender{Files: files}
engine.HTMLRender = render.HTMLDebug engine.HTMLRender = r
} else { } else {
templ := template.Must(template.ParseFiles(files...)) templ := template.Must(template.ParseFiles(files...))
engine.SetHTMLTemplate(templ) engine.SetHTMLTemplate(templ)

50
render/html_debug.go Normal file
View File

@ -0,0 +1,50 @@
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package render
import (
"html/template"
"net/http"
)
type HTMLDebugRender struct {
files []string
globs []string
}
func (r *HTMLDebugRender) AddGlob(pattern string) {
r.globs = append(r.globs, pattern)
}
func (r *HTMLDebugRender) AddFiles(files ...string) {
r.files = append(r.files, files...)
}
func (r *HTMLDebugRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
WriteHeader(w, code, "text/html")
file := data[0].(string)
obj := data[1]
if t, err := r.newTemplate(); err == nil {
return t.ExecuteTemplate(w, file, obj)
} else {
return err
}
}
func (r *HTMLDebugRender) newTemplate() (*template.Template, error) {
t := template.New("")
if len(r.files) > 0 {
if _, err := t.ParseFiles(r.files...); err != nil {
return nil, err
}
}
for _, glob := range r.globs {
if _, err := t.ParseGlob(glob); err != nil {
return nil, err
}
}
return t, nil
}

View File

@ -27,11 +27,6 @@ type (
redirectRender struct{} redirectRender struct{}
htmlDebugRender struct {
files []string
globs []string
}
HTMLRender struct { HTMLRender struct {
Template *template.Template Template *template.Template
} }
@ -43,34 +38,26 @@ var (
HTMLPlain = htmlPlainRender{} HTMLPlain = htmlPlainRender{}
Plain = plainTextRender{} Plain = plainTextRender{}
Redirect = redirectRender{} Redirect = redirectRender{}
HTMLDebug = &htmlDebugRender{}
) )
func writeHeader(w http.ResponseWriter, code int, contentType string) {
w.Header().Set("Content-Type", contentType+"; charset=utf-8")
w.WriteHeader(code)
}
func (_ jsonRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "application/json")
encoder := json.NewEncoder(w)
return encoder.Encode(data[0])
}
func (_ redirectRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { func (_ redirectRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
w.Header().Set("Location", data[0].(string)) w.Header().Set("Location", data[0].(string))
w.WriteHeader(code) w.WriteHeader(code)
return nil return nil
} }
func (_ jsonRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
WriteHeader(w, code, "application/json")
return json.NewEncoder(w).Encode(data[0])
}
func (_ xmlRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { func (_ xmlRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "application/xml") WriteHeader(w, code, "application/xml")
encoder := xml.NewEncoder(w) return xml.NewEncoder(w).Encode(data[0])
return encoder.Encode(data[0])
} }
func (_ plainTextRender) Render(w http.ResponseWriter, code int, data ...interface{}) (err error) { func (_ plainTextRender) Render(w http.ResponseWriter, code int, data ...interface{}) (err error) {
writeHeader(w, code, "text/plain") WriteHeader(w, code, "text/plain")
format := data[0].(string) format := data[0].(string)
args := data[1].([]interface{}) args := data[1].([]interface{})
if len(args) > 0 { if len(args) > 0 {
@ -81,52 +68,47 @@ func (_ plainTextRender) Render(w http.ResponseWriter, code int, data ...interfa
return return
} }
func (_ htmlPlainRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { func (_ htmlPlainRender) Render(w http.ResponseWriter, code int, data ...interface{}) (err error) {
writeHeader(w, code, "text/html") WriteHeader(w, code, "text/html")
format := data[0].(string) format := data[0].(string)
args := data[1].([]interface{}) args := data[1].([]interface{})
var err error
if len(args) > 0 { if len(args) > 0 {
_, err = w.Write([]byte(fmt.Sprintf(format, args...))) _, err = w.Write([]byte(fmt.Sprintf(format, args...)))
} else { } else {
_, err = w.Write([]byte(format)) _, err = w.Write([]byte(format))
} }
return err return
}
func (r *htmlDebugRender) AddGlob(pattern string) {
r.globs = append(r.globs, pattern)
}
func (r *htmlDebugRender) AddFiles(files ...string) {
r.files = append(r.files, files...)
}
func (r *htmlDebugRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "text/html")
file := data[0].(string)
obj := data[1]
t := template.New("")
if len(r.files) > 0 {
if _, err := t.ParseFiles(r.files...); err != nil {
return err
}
}
for _, glob := range r.globs {
if _, err := t.ParseGlob(glob); err != nil {
return err
}
}
return t.ExecuteTemplate(w, file, obj)
} }
func (html HTMLRender) Render(w http.ResponseWriter, code int, data ...interface{}) error { func (html HTMLRender) Render(w http.ResponseWriter, code int, data ...interface{}) error {
writeHeader(w, code, "text/html") WriteHeader(w, code, "text/html")
file := data[0].(string) file := data[0].(string)
obj := data[1] args := data[1]
return html.Template.ExecuteTemplate(w, file, obj) return html.Template.ExecuteTemplate(w, file, args)
}
func WriteHeader(w http.ResponseWriter, code int, contentType string) {
contentType = joinStrings(contentType, "; charset=utf-8")
w.Header().Set("Content-Type", contentType)
w.WriteHeader(code)
}
func joinStrings(a ...string) string {
if len(a) == 0 {
return ""
}
if len(a) == 1 {
return a[0]
}
n := 0
for i := 0; i < len(a); i++ {
n += len(a[i])
}
b := make([]byte, n)
n = 0
for _, s := range a {
n += copy(b[n:], s)
}
return string(b)
} }