package iris import ( "github.com/kataras/go-fs" "github.com/kataras/go-template" "io" ) var ( builtinFuncs = [...]string{"url", "urlpath"} ) const ( // NoLayout to disable layout for a particular template file NoLayout = template.NoLayout // TemplateLayoutContextKey is the name of the user values which can be used to set a template layout from a middleware and override the parent's TemplateLayoutContextKey = "templateLayout" ) type ( // RenderOptions is a helper type for the optional runtime options can be passed by user when Render // an example of this is the "layout" or "gzip" option // same as Map but more specific name RenderOptions map[string]interface{} ) // templateEngines just a wrapper of template.Mux in order to use it's execute without break the whole of the API type templateEngines struct { *template.Mux } func newTemplateEngines(sharedFuncs map[string]interface{}) *templateEngines { return &templateEngines{Mux: template.NewMux(sharedFuncs)} } // getGzipOption receives a default value and the render options map and returns if gzip is enabled for this render action func getGzipOption(defaultValue bool, options map[string]interface{}) bool { gzipOpt := options["gzip"] // we only need that, so don't create new map to keep the options. if b, isBool := gzipOpt.(bool); isBool { return b } return defaultValue } // gtCharsetOption receives a default value and the render options map and returns the correct charset for this render action func getCharsetOption(defaultValue string, options map[string]interface{}) string { charsetOpt := options["charset"] if s, isString := charsetOpt.(string); isString { return s } return defaultValue } // render executes a template and write its result to the context's body // options are the optional runtime options can be passed by user and catched by the template engine when render // an example of this is the "layout" // note that gzip option is an iris dynamic option which exists for all template engines // the gzip and charset options are built'n with iris func (t *templateEngines) render(ctx *Context, filename string, binding interface{}, options ...map[string]interface{}) (err error) { // we do all these because we don't want to initialize a new map for each execution... gzipEnabled := ctx.framework.Config.Gzip charset := ctx.framework.Config.Charset if len(options) > 0 { gzipEnabled = getGzipOption(gzipEnabled, options[0]) charset = getCharsetOption(charset, options[0]) } ctxLayout := ctx.GetString(TemplateLayoutContextKey) if ctxLayout != "" { if len(options) > 0 { options[0]["layout"] = ctxLayout } else { options = []map[string]interface{}{map[string]interface{}{"layout": ctxLayout}} } } ctx.SetContentType(contentHTML + "; charset=" + charset) var out io.Writer if gzipEnabled && ctx.clientAllowsGzip() { ctx.RequestCtx.Response.Header.Add(varyHeader, acceptEncodingHeader) ctx.SetHeader(contentEncodingHeader, "gzip") gzipWriter := fs.AcquireGzipWriter(ctx.Response.BodyWriter()) defer fs.ReleaseGzipWriter(gzipWriter) out = gzipWriter } else { out = ctx.Response.BodyWriter() } err = t.ExecuteWriter(out, filename, binding, options...) return err } // renderSource executes a template source raw contents (string) and write its result to the context's body // note that gzip option is an iris dynamic option which exists for all template engines // the gzip and charset options are built'n with iris func (t *templateEngines) renderSource(ctx *Context, src string, binding interface{}, options ...map[string]interface{}) (err error) { // we do all these because we don't want to initialize a new map for each execution... gzipEnabled := ctx.framework.Config.Gzip charset := ctx.framework.Config.Charset if len(options) > 0 { gzipEnabled = template.GetGzipOption(gzipEnabled, options[0]) charset = template.GetCharsetOption(charset, options[0]) } ctx.SetContentType(contentHTML + "; charset=" + charset) var out io.Writer if gzipEnabled && ctx.clientAllowsGzip() { ctx.RequestCtx.Response.Header.Add(varyHeader, acceptEncodingHeader) ctx.SetHeader(contentEncodingHeader, "gzip") gzipWriter := fs.AcquireGzipWriter(ctx.Response.BodyWriter()) defer fs.ReleaseGzipWriter(gzipWriter) out = gzipWriter } else { out = ctx.Response.BodyWriter() } return t.ExecuteRaw(src, out, binding) }