Merge v1.2.1-master

Signed-off-by: Emile Vauge <emile@vauge.com>
This commit is contained in:
Emile Vauge 2017-04-11 17:10:46 +02:00
parent a590155b0b
commit aeb17182b4
No known key found for this signature in database
GPG key ID: D808B4C167352E59
396 changed files with 27271 additions and 9969 deletions

View file

@ -39,3 +39,8 @@ func (bp *BufferPool) Put(b *bytes.Buffer) {
default: // Discard the buffer if the pool is full.
}
}
// Initialize buffer pool for writing templates into.
func init() {
bufPool = NewBufferPool(64)
}

View file

@ -5,12 +5,13 @@ import (
"encoding/json"
"encoding/xml"
"html/template"
"io"
"net/http"
)
// Engine is the generic interface for all responses.
type Engine interface {
Render(http.ResponseWriter, interface{}) error
Render(io.Writer, interface{}) error
}
// Head defines the basic ContentType and Status fields.
@ -66,19 +67,21 @@ func (h Head) Write(w http.ResponseWriter) {
}
// Render a data response.
func (d Data) Render(w http.ResponseWriter, v interface{}) error {
c := w.Header().Get(ContentType)
if c != "" {
d.Head.ContentType = c
func (d Data) Render(w io.Writer, v interface{}) error {
if hw, ok := w.(http.ResponseWriter); ok {
c := hw.Header().Get(ContentType)
if c != "" {
d.Head.ContentType = c
}
d.Head.Write(hw)
}
d.Head.Write(w)
w.Write(v.([]byte))
return nil
}
// Render a HTML response.
func (h HTML) Render(w http.ResponseWriter, binding interface{}) error {
func (h HTML) Render(w io.Writer, binding interface{}) error {
// Retrieve a buffer from the pool to write to.
out := bufPool.Get()
err := h.Templates.ExecuteTemplate(out, h.Name, binding)
@ -86,7 +89,9 @@ func (h HTML) Render(w http.ResponseWriter, binding interface{}) error {
return err
}
h.Head.Write(w)
if hw, ok := w.(http.ResponseWriter); ok {
h.Head.Write(hw)
}
out.WriteTo(w)
// Return the buffer to the pool.
@ -95,7 +100,7 @@ func (h HTML) Render(w http.ResponseWriter, binding interface{}) error {
}
// Render a JSON response.
func (j JSON) Render(w http.ResponseWriter, v interface{}) error {
func (j JSON) Render(w io.Writer, v interface{}) error {
if j.StreamingJSON {
return j.renderStreamingJSON(w, v)
}
@ -121,7 +126,9 @@ func (j JSON) Render(w http.ResponseWriter, v interface{}) error {
}
// JSON marshaled fine, write out the result.
j.Head.Write(w)
if hw, ok := w.(http.ResponseWriter); ok {
j.Head.Write(hw)
}
if len(j.Prefix) > 0 {
w.Write(j.Prefix)
}
@ -129,8 +136,10 @@ func (j JSON) Render(w http.ResponseWriter, v interface{}) error {
return nil
}
func (j JSON) renderStreamingJSON(w http.ResponseWriter, v interface{}) error {
j.Head.Write(w)
func (j JSON) renderStreamingJSON(w io.Writer, v interface{}) error {
if hw, ok := w.(http.ResponseWriter); ok {
j.Head.Write(hw)
}
if len(j.Prefix) > 0 {
w.Write(j.Prefix)
}
@ -139,7 +148,7 @@ func (j JSON) renderStreamingJSON(w http.ResponseWriter, v interface{}) error {
}
// Render a JSONP response.
func (j JSONP) Render(w http.ResponseWriter, v interface{}) error {
func (j JSONP) Render(w io.Writer, v interface{}) error {
var result []byte
var err error
@ -153,7 +162,9 @@ func (j JSONP) Render(w http.ResponseWriter, v interface{}) error {
}
// JSON marshaled fine, write out the result.
j.Head.Write(w)
if hw, ok := w.(http.ResponseWriter); ok {
j.Head.Write(hw)
}
w.Write([]byte(j.Callback + "("))
w.Write(result)
w.Write([]byte(");"))
@ -166,19 +177,21 @@ func (j JSONP) Render(w http.ResponseWriter, v interface{}) error {
}
// Render a text response.
func (t Text) Render(w http.ResponseWriter, v interface{}) error {
c := w.Header().Get(ContentType)
if c != "" {
t.Head.ContentType = c
func (t Text) Render(w io.Writer, v interface{}) error {
if hw, ok := w.(http.ResponseWriter); ok {
c := hw.Header().Get(ContentType)
if c != "" {
t.Head.ContentType = c
}
t.Head.Write(hw)
}
t.Head.Write(w)
w.Write([]byte(v.(string)))
return nil
}
// Render an XML response.
func (x XML) Render(w http.ResponseWriter, v interface{}) error {
func (x XML) Render(w io.Writer, v interface{}) error {
var result []byte
var err error
@ -193,7 +206,9 @@ func (x XML) Render(w http.ResponseWriter, v interface{}) error {
}
// XML marshaled fine, write out the result.
x.Head.Write(w)
if hw, ok := w.(http.ResponseWriter); ok {
x.Head.Write(hw)
}
if len(x.Prefix) > 0 {
w.Write(x.Prefix)
}

View file

@ -4,12 +4,14 @@ import (
"bytes"
"fmt"
"html/template"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
)
const (
@ -85,6 +87,8 @@ type Options struct {
RequireBlocks bool
// Disables automatic rendering of http.StatusInternalServerError when an error occurs. Default is false.
DisableHTTPErrorRendering bool
// Enables using partials without the current filename suffix which allows use of the same template in multiple files. e.g {{ partial "carosuel" }} inside the home template will match carosel-home or carosel.
RenderPartialsWithoutPrefix bool
}
// HTMLOptions is a struct for overriding some rendering Options for specific HTML call.
@ -99,6 +103,7 @@ type Render struct {
// Customize Secure with an Options struct.
opt Options
templates *template.Template
templatesLk sync.Mutex
compiledCharset string
}
@ -118,11 +123,6 @@ func New(options ...Options) *Render {
r.prepareOptions()
r.compileTemplates()
// Create a new buffer pool for writing templates into.
if bufPool == nil {
bufPool = NewBufferPool(64)
}
return &r
}
@ -270,6 +270,9 @@ func (r *Render) addLayoutFuncs(name string, binding interface{}) {
"block": func(partialName string) (template.HTML, error) {
log.Print("Render's `block` implementation is now depericated. Use `partial` as a drop in replacement.")
fullPartialName := fmt.Sprintf("%s-%s", partialName, name)
if r.TemplateLookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix {
fullPartialName = partialName
}
if r.opt.RequireBlocks || r.TemplateLookup(fullPartialName) != nil {
buf, err := r.execute(fullPartialName, binding)
// Return safe HTML here since we are rendering our own template.
@ -279,6 +282,9 @@ func (r *Render) addLayoutFuncs(name string, binding interface{}) {
},
"partial": func(partialName string) (template.HTML, error) {
fullPartialName := fmt.Sprintf("%s-%s", partialName, name)
if r.TemplateLookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix {
fullPartialName = partialName
}
if r.opt.RequirePartials || r.TemplateLookup(fullPartialName) != nil {
buf, err := r.execute(fullPartialName, binding)
// Return safe HTML here since we are rendering our own template.
@ -303,16 +309,16 @@ func (r *Render) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions {
}
// Render is the generic function called by XML, JSON, Data, HTML, and can be called by custom implementations.
func (r *Render) Render(w http.ResponseWriter, e Engine, data interface{}) error {
func (r *Render) Render(w io.Writer, e Engine, data interface{}) error {
err := e.Render(w, data)
if err != nil && !r.opt.DisableHTTPErrorRendering {
http.Error(w, err.Error(), http.StatusInternalServerError)
if hw, ok := w.(http.ResponseWriter); err != nil && !r.opt.DisableHTTPErrorRendering && ok {
http.Error(hw, err.Error(), http.StatusInternalServerError)
}
return err
}
// Data writes out the raw bytes as binary data.
func (r *Render) Data(w http.ResponseWriter, status int, v []byte) error {
func (r *Render) Data(w io.Writer, status int, v []byte) error {
head := Head{
ContentType: ContentBinary,
Status: status,
@ -326,7 +332,10 @@ func (r *Render) Data(w http.ResponseWriter, status int, v []byte) error {
}
// HTML builds up the response from the specified template and bindings.
func (r *Render) HTML(w http.ResponseWriter, status int, name string, binding interface{}, htmlOpt ...HTMLOptions) error {
func (r *Render) HTML(w io.Writer, status int, name string, binding interface{}, htmlOpt ...HTMLOptions) error {
r.templatesLk.Lock()
defer r.templatesLk.Unlock()
// If we are in development mode, recompile the templates on every HTML request.
if r.opt.IsDevelopment {
r.compileTemplates()
@ -354,7 +363,7 @@ func (r *Render) HTML(w http.ResponseWriter, status int, name string, binding in
}
// JSON marshals the given interface object and writes the JSON response.
func (r *Render) JSON(w http.ResponseWriter, status int, v interface{}) error {
func (r *Render) JSON(w io.Writer, status int, v interface{}) error {
head := Head{
ContentType: ContentJSON + r.compiledCharset,
Status: status,
@ -372,7 +381,7 @@ func (r *Render) JSON(w http.ResponseWriter, status int, v interface{}) error {
}
// JSONP marshals the given interface object and writes the JSON response.
func (r *Render) JSONP(w http.ResponseWriter, status int, callback string, v interface{}) error {
func (r *Render) JSONP(w io.Writer, status int, callback string, v interface{}) error {
head := Head{
ContentType: ContentJSONP + r.compiledCharset,
Status: status,
@ -388,7 +397,7 @@ func (r *Render) JSONP(w http.ResponseWriter, status int, callback string, v int
}
// Text writes out a string as plain text.
func (r *Render) Text(w http.ResponseWriter, status int, v string) error {
func (r *Render) Text(w io.Writer, status int, v string) error {
head := Head{
ContentType: ContentText + r.compiledCharset,
Status: status,
@ -402,7 +411,7 @@ func (r *Render) Text(w http.ResponseWriter, status int, v string) error {
}
// XML marshals the given interface object and writes the XML response.
func (r *Render) XML(w http.ResponseWriter, status int, v interface{}) error {
func (r *Render) XML(w io.Writer, status int, v interface{}) error {
head := Head{
ContentType: ContentXML + r.compiledCharset,
Status: status,