From 675af529c93ed4dd68a9132980fcdda0c8808b2f Mon Sep 17 00:00:00 2001 From: im7mortal Date: Sun, 3 Apr 2016 00:17:26 +0300 Subject: [PATCH 1/3] added a support of a "block" template feature from go1.6 fixed #567 --- examples/template-blocks/layouts/default.html | 10 ++++++ examples/template-blocks/main.go | 19 +++++++++++ examples/template-blocks/views/blocks1.html | 7 ++++ examples/template-blocks/views/blocks2.html | 7 ++++ gin.go | 16 +++++++++ render/template_storage.go | 33 +++++++++++++++++++ 6 files changed, 92 insertions(+) create mode 100644 examples/template-blocks/layouts/default.html create mode 100644 examples/template-blocks/main.go create mode 100644 examples/template-blocks/views/blocks1.html create mode 100644 examples/template-blocks/views/blocks2.html create mode 100644 render/template_storage.go diff --git a/examples/template-blocks/layouts/default.html b/examples/template-blocks/layouts/default.html new file mode 100644 index 00000000..71fc468a --- /dev/null +++ b/examples/template-blocks/layouts/default.html @@ -0,0 +1,10 @@ + + + + + {{block "head" .}} {{end}} + + +{{block "body" .}} {{end}} + + \ No newline at end of file diff --git a/examples/template-blocks/main.go b/examples/template-blocks/main.go new file mode 100644 index 00000000..e49003a6 --- /dev/null +++ b/examples/template-blocks/main.go @@ -0,0 +1,19 @@ +package main + +import "github.com/gin-gonic/gin" + +func main() { + router := gin.Default() + + router.AddHTMLTemplate("/", "layouts/default.html", "views/blocks1.html") + router.AddHTMLTemplate("/blocks2/", "layouts/default.html", "views/blocks2.html") + + router.GET("/", render) + router.GET("/blocks2/", render) + router.Run(":8080") + +} + +func render(c *gin.Context) { + c.HTML(200, c.Request.URL.Path, gin.H{}) +} \ No newline at end of file diff --git a/examples/template-blocks/views/blocks1.html b/examples/template-blocks/views/blocks1.html new file mode 100644 index 00000000..8b086c00 --- /dev/null +++ b/examples/template-blocks/views/blocks1.html @@ -0,0 +1,7 @@ +{{define "head"}} +Blocks 1 +{{end}} + +{{define "body"}} +Go to blocks 2 +{{end}} \ No newline at end of file diff --git a/examples/template-blocks/views/blocks2.html b/examples/template-blocks/views/blocks2.html new file mode 100644 index 00000000..8938eef7 --- /dev/null +++ b/examples/template-blocks/views/blocks2.html @@ -0,0 +1,7 @@ +{{define "head"}} +Blocks 2 +{{end}} + +{{define "body"}} +Go to blocks 1 +{{end}} \ No newline at end of file diff --git a/gin.go b/gin.go index fb1df9cd..19683914 100644 --- a/gin.go +++ b/gin.go @@ -147,6 +147,22 @@ func (engine *Engine) SetHTMLTemplate(templ *template.Template) { engine.HTMLRender = render.HTMLProduction{Template: templ} } +// AddHTMLTemplate allow to use "block" template feature from go1.6 +func (engine *Engine) AddHTMLTemplate(name string, paths... string) { + var templateStorage render.TemplateStorage + t, ok := engine.HTMLRender.(render.TemplateStorage) + if ok { + templateStorage = t + } else { + if len(engine.trees) > 0 { + debugPrintWARNINGSetHTMLTemplate() + } + templateStorage = render.TemplateStorage{make(map[string]*template.Template)} + } + templateStorage.Storage[name] = template.Must(template.ParseFiles(paths...)) + engine.HTMLRender = templateStorage +} + // Adds handlers for NoRoute. It return a 404 code by default. func (engine *Engine) NoRoute(handlers ...HandlerFunc) { engine.noRoute = handlers diff --git a/render/template_storage.go b/render/template_storage.go new file mode 100644 index 00000000..6afb4110 --- /dev/null +++ b/render/template_storage.go @@ -0,0 +1,33 @@ +// 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 TemplateStorage struct { + Storage map[string]*template.Template +} + +func (t TemplateStorage) Instance(name string, data interface{}) Render { + return HTMLwithBlock{ + Template: t.Storage[name], + Name: name, + Data: data, + } +} + +type HTMLwithBlock struct { + Template *template.Template + Name string + Data interface{} +} + +func (r HTMLwithBlock) Render(w http.ResponseWriter) error { + writeContentType(w, htmlContentType) + return r.Template.Execute(w, r.Data) +} \ No newline at end of file From bb0eff82a60288b205f1ef273f89e498b571c0de Mon Sep 17 00:00:00 2001 From: im7mortal Date: Thu, 14 Apr 2016 00:26:45 +0300 Subject: [PATCH 2/3] minor fixes for template_storage --- examples/template-blocks/layouts/default.html | 2 +- examples/template-blocks/main.go | 2 +- examples/template-blocks/views/blocks1.html | 2 +- examples/template-blocks/views/blocks2.html | 2 +- render/template_storage.go | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/template-blocks/layouts/default.html b/examples/template-blocks/layouts/default.html index 71fc468a..a519fce9 100644 --- a/examples/template-blocks/layouts/default.html +++ b/examples/template-blocks/layouts/default.html @@ -7,4 +7,4 @@ {{block "body" .}} {{end}} - \ No newline at end of file + diff --git a/examples/template-blocks/main.go b/examples/template-blocks/main.go index e49003a6..1d0fe2f1 100644 --- a/examples/template-blocks/main.go +++ b/examples/template-blocks/main.go @@ -16,4 +16,4 @@ func main() { func render(c *gin.Context) { c.HTML(200, c.Request.URL.Path, gin.H{}) -} \ No newline at end of file +} diff --git a/examples/template-blocks/views/blocks1.html b/examples/template-blocks/views/blocks1.html index 8b086c00..39c333b8 100644 --- a/examples/template-blocks/views/blocks1.html +++ b/examples/template-blocks/views/blocks1.html @@ -4,4 +4,4 @@ {{define "body"}} Go to blocks 2 -{{end}} \ No newline at end of file +{{end}} diff --git a/examples/template-blocks/views/blocks2.html b/examples/template-blocks/views/blocks2.html index 8938eef7..749d9b64 100644 --- a/examples/template-blocks/views/blocks2.html +++ b/examples/template-blocks/views/blocks2.html @@ -4,4 +4,4 @@ {{define "body"}} Go to blocks 1 -{{end}} \ No newline at end of file +{{end}} diff --git a/render/template_storage.go b/render/template_storage.go index 6afb4110..00e89b5e 100644 --- a/render/template_storage.go +++ b/render/template_storage.go @@ -14,20 +14,20 @@ type TemplateStorage struct { } func (t TemplateStorage) Instance(name string, data interface{}) Render { - return HTMLwithBlock{ + return HTMLWithBlock{ Template: t.Storage[name], Name: name, Data: data, } } -type HTMLwithBlock struct { +type HTMLWithBlock struct { Template *template.Template Name string Data interface{} } -func (r HTMLwithBlock) Render(w http.ResponseWriter) error { +func (r HTMLWithBlock) Render(w http.ResponseWriter) error { writeContentType(w, htmlContentType) return r.Template.Execute(w, r.Data) -} \ No newline at end of file +} From 2aea02ecb8735702d83406777d525dd7fe29146a Mon Sep 17 00:00:00 2001 From: im7mortal Date: Thu, 14 Apr 2016 00:41:32 +0300 Subject: [PATCH 3/3] added unit test for template_storage --- render/render_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/render/render_test.go b/render/render_test.go index 7a6ffb7d..0107709c 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -128,3 +128,41 @@ func TestRenderHTMLTemplate(t *testing.T) { assert.Equal(t, w.Body.String(), "Hello alexandernyquist") assert.Equal(t, w.Header().Get("Content-Type"), "text/html; charset=utf-8") } + +func TestRenderHTMLTemplateWithBlocks(t *testing.T) { + w := httptest.NewRecorder() + + var indexTemplate = template.Must(template.New("").Parse(`{{block "first" .}}{{end}}{{block "second" .}}{{end}}`)) + + first := `{{define "first"}}{{.first}}{{end}}{{define "second"}}_{{.second}}{{end}}` + var firstT = template.Must(template.Must(indexTemplate.Clone()).Parse(first)) + second := `{{define "first"}}{{.first}}{{end}}{{define "second"}}_{{.second}}{{end}}` + var secondT = template.Must(template.Must(indexTemplate.Clone()).Parse(second)) + + templateStorage := TemplateStorage{make(map[string]*template.Template)} + templateStorage.Storage["first"] = firstT + templateStorage.Storage["second"] = secondT + + testMap := map[string]interface{}{ + "second": "second", + "first": "first", + } + + instance := templateStorage.Instance("first", testMap) + + err := instance.Render(w) + + assert.NoError(t, err) + assert.Equal(t, w.Body.String(), "first_second") + assert.Equal(t, w.Header().Get("Content-Type"), "text/html; charset=utf-8") + + w = httptest.NewRecorder() + + instance = templateStorage.Instance("second", testMap) + + err = instance.Render(w) + + assert.NoError(t, err) + assert.Equal(t, w.Body.String(), "first_second") + assert.Equal(t, w.Header().Get("Content-Type"), "text/html; charset=utf-8") +}