2016-05-30 16:08:09 +02:00
|
|
|
package template
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"github.com/klauspost/compress/gzip"
|
|
|
|
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/kataras/iris/config"
|
|
|
|
"github.com/kataras/iris/context"
|
|
|
|
"github.com/kataras/iris/render/template/engine/amber"
|
|
|
|
"github.com/kataras/iris/render/template/engine/html"
|
|
|
|
"github.com/kataras/iris/render/template/engine/jade"
|
|
|
|
"github.com/kataras/iris/render/template/engine/markdown"
|
|
|
|
"github.com/kataras/iris/render/template/engine/pongo"
|
|
|
|
"github.com/kataras/iris/utils"
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
2016-05-31 10:05:42 +02:00
|
|
|
// Engine the interface that all template engines must inheritance
|
2016-05-30 16:08:09 +02:00
|
|
|
Engine interface {
|
2016-05-31 10:05:42 +02:00
|
|
|
// BuildTemplates builds the templates for a directory
|
2016-05-30 16:08:09 +02:00
|
|
|
BuildTemplates() error
|
2016-05-31 10:05:42 +02:00
|
|
|
// ExecuteWriter finds and execute a template and write its result to the out writer
|
2016-05-30 16:08:09 +02:00
|
|
|
ExecuteWriter(out io.Writer, name string, binding interface{}, layout string) error
|
|
|
|
}
|
|
|
|
|
2016-05-31 10:05:42 +02:00
|
|
|
// Template the internal configs for the common configs for the template engines
|
2016-05-30 16:08:09 +02:00
|
|
|
Template struct {
|
2016-05-31 10:05:42 +02:00
|
|
|
// Engine the type of the Engine
|
|
|
|
Engine Engine
|
|
|
|
// Gzip enable gzip compression
|
|
|
|
// default is false
|
|
|
|
Gzip bool
|
|
|
|
// IsDevelopment re-builds the templates on each request
|
|
|
|
// default is false
|
|
|
|
IsDevelopment bool
|
|
|
|
// Directory the system path which the templates live
|
|
|
|
// default is ./templates
|
|
|
|
Directory string
|
|
|
|
// Extensions the allowed file extension
|
|
|
|
// default is []string{".html"}
|
|
|
|
Extensions []string
|
|
|
|
// ContentType is the Content-Type response header
|
|
|
|
// default is text/html but you can change if if needed
|
|
|
|
ContentType string
|
|
|
|
// Layout the template file ( with its extension) which is the mother of all
|
|
|
|
// use it to have it as a root file, and include others with {{ yield }}, refer the docs
|
|
|
|
Layout string
|
|
|
|
|
2016-05-30 16:08:09 +02:00
|
|
|
buffer *utils.BufferPool // this is used only for RenderString
|
|
|
|
gzipWriterPool sync.Pool
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// New creates and returns a Template instance which keeps the Template Engine and helps with render
|
|
|
|
func New(c config.Template) *Template {
|
|
|
|
|
|
|
|
var e Engine
|
|
|
|
// [ENGINE-2]
|
|
|
|
switch c.Engine {
|
|
|
|
case config.HTMLEngine:
|
|
|
|
e = html.New(c) // HTMLTemplate
|
|
|
|
case config.PongoEngine:
|
|
|
|
e = pongo.New(c) // Pongo2
|
|
|
|
case config.MarkdownEngine:
|
|
|
|
e = markdown.New(c) // Markdown
|
|
|
|
case config.JadeEngine:
|
|
|
|
e = jade.New(c) // Jade
|
|
|
|
case config.AmberEngine:
|
|
|
|
e = amber.New(c) // Amber
|
|
|
|
default: // config.NoEngine
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := e.BuildTemplates(); err != nil { // first build the templates, if error then panic because this is called before server's run
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
compiledContentType := c.ContentType + "; charset=" + c.Charset
|
|
|
|
|
|
|
|
t := &Template{
|
|
|
|
Engine: e,
|
|
|
|
IsDevelopment: c.IsDevelopment,
|
|
|
|
Gzip: c.Gzip,
|
|
|
|
ContentType: compiledContentType,
|
|
|
|
Layout: c.Layout,
|
|
|
|
buffer: utils.NewBufferPool(64),
|
|
|
|
gzipWriterPool: sync.Pool{New: func() interface{} {
|
|
|
|
return &gzip.Writer{}
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-05-31 10:05:42 +02:00
|
|
|
// Render renders a template using the context's writer
|
2016-05-30 16:08:09 +02:00
|
|
|
func (t *Template) Render(ctx context.IContext, name string, binding interface{}, layout ...string) (err error) {
|
|
|
|
|
|
|
|
if t == nil { // No engine was given but .Render was called
|
|
|
|
ctx.WriteHTML(403, "<b> Iris </b> <br/> Templates are disabled via config.NoEngine, check your iris' configuration please.")
|
|
|
|
return fmt.Errorf("[IRIS TEMPLATES] Templates are disabled via config.NoEngine, check your iris' configuration please.\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
// build templates again on each render if IsDevelopment.
|
|
|
|
if t.IsDevelopment {
|
|
|
|
if err = t.Engine.BuildTemplates(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// I don't like this, something feels wrong
|
|
|
|
_layout := ""
|
|
|
|
if len(layout) > 0 {
|
|
|
|
_layout = layout[0]
|
|
|
|
}
|
|
|
|
if _layout == "" {
|
|
|
|
_layout = t.Layout
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
ctx.GetRequestCtx().Response.Header.Set("Content-Type", t.ContentType)
|
|
|
|
|
|
|
|
var out io.Writer
|
|
|
|
if t.Gzip {
|
|
|
|
ctx.GetRequestCtx().Response.Header.Add("Content-Encoding", "gzip")
|
|
|
|
gzipWriter := t.gzipWriterPool.Get().(*gzip.Writer)
|
|
|
|
gzipWriter.Reset(ctx.GetRequestCtx().Response.BodyWriter())
|
|
|
|
defer gzipWriter.Close()
|
|
|
|
defer t.gzipWriterPool.Put(gzipWriter)
|
|
|
|
out = gzipWriter
|
|
|
|
} else {
|
|
|
|
out = ctx.GetRequestCtx().Response.BodyWriter()
|
|
|
|
}
|
|
|
|
|
|
|
|
err = t.Engine.ExecuteWriter(out, name, binding, _layout)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-05-31 10:05:42 +02:00
|
|
|
// RenderString executes a template and returns its contents result (string)
|
2016-05-30 16:08:09 +02:00
|
|
|
func (t *Template) RenderString(name string, binding interface{}, layout ...string) (result string, err error) {
|
|
|
|
|
|
|
|
if t == nil { // No engine was given but .Render was called
|
|
|
|
err = fmt.Errorf("[IRIS TEMPLATES] Templates are disabled via config.NoEngine, check your iris' configuration please.\n")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// build templates again on each render if IsDevelopment.
|
|
|
|
if t.IsDevelopment {
|
|
|
|
if err = t.Engine.BuildTemplates(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// I don't like this, something feels wrong
|
|
|
|
_layout := ""
|
|
|
|
if len(layout) > 0 {
|
|
|
|
_layout = layout[0]
|
|
|
|
}
|
|
|
|
if _layout == "" {
|
|
|
|
_layout = t.Layout
|
|
|
|
}
|
|
|
|
|
|
|
|
out := t.buffer.Get()
|
|
|
|
// if we have problems later consider that -> out.Reset()
|
|
|
|
defer t.buffer.Put(out)
|
|
|
|
err = t.Engine.ExecuteWriter(out, name, binding, _layout)
|
|
|
|
if err == nil {
|
|
|
|
result = out.String()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|