Skip to content

Commit

Permalink
Adding ability to set html/template options
Browse files Browse the repository at this point in the history
  • Loading branch information
unrolled committed Feb 26, 2023
1 parent b037de6 commit 369f257
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -101,6 +101,7 @@ r := render.New(render.Options{
UseMutexLock: true, // Overrides the default no lock implementation and uses the standard `sync.RWMutex` lock.
UnEscapeHTML: true, // Replace ensure '&<>' are output correctly (JSON only).
StreamingJSON: true, // Streams the JSON response via json.Encoder.
HTMLTemplateOption: "missingkey=error", // Sets the option value for HTML templates. See https://pkg.go.dev/html/template#Template.Option for a list of known options.
RequirePartials: true, // Return an error if a template is missing a partial used in a layout.
DisableHTTPErrorRendering: true, // Disables automatic rendering of http.StatusInternalServerError when an error occurs.
})
Expand Down Expand Up @@ -139,6 +140,7 @@ r := render.New(render.Options{
IsDevelopment: false,
UseMutexLock: false,
UnEscapeHTML: false,
HTMLTemplateOption: "",
StreamingJSON: false,
RequirePartials: false,
DisableHTTPErrorRendering: false,
Expand Down
12 changes: 12 additions & 0 deletions render.go
Expand Up @@ -97,6 +97,8 @@ type Options struct {
UseMutexLock bool
// Unescape HTML characters "&<>" to their original values. Default is false.
UnEscapeHTML bool
// Sets the `Option` value for HTML templates. Defaults to blank ("").
HTMLTemplateOption string
// Streams JSON responses instead of marshalling prior to sending. Default is false.
StreamingJSON bool
// Require that all partials executed in the layout are implemented in all templates using the layout. Default is false.
Expand Down Expand Up @@ -217,6 +219,11 @@ func (r *Render) CompileTemplates() {
func (r *Render) compileTemplatesFromDir() {
dir := r.opt.Directory
tmpTemplates := template.New(dir)

if len(r.opt.HTMLTemplateOption) > 0 {
tmpTemplates.Option(r.opt.HTMLTemplateOption)
}

tmpTemplates.Delims(r.opt.Delims.Left, r.opt.Delims.Right)

var watcher *fsnotify.Watcher
Expand Down Expand Up @@ -301,6 +308,11 @@ func (r *Render) compileTemplatesFromDir() {
func (r *Render) compileTemplatesFromAsset() {
dir := r.opt.Directory
tmpTemplates := template.New(dir)

if len(r.opt.HTMLTemplateOption) > 0 {
tmpTemplates.Option(r.opt.HTMLTemplateOption)
}

tmpTemplates.Delims(r.opt.Delims.Left, r.opt.Delims.Right)

for _, path := range r.opt.AssetNames() {
Expand Down
73 changes: 73 additions & 0 deletions render_html_test.go
Expand Up @@ -6,6 +6,7 @@ import (
"html/template"
"net/http"
"net/http/httptest"
"strings"
"testing"
)

Expand Down Expand Up @@ -428,3 +429,75 @@ func TestHTMLDisabledCharset(t *testing.T) {
expect(t, res.Header().Get(ContentType), ContentHTML)
expect(t, res.Body.String(), "<h1>Hello gophers</h1>\n")
}

func TestHTMLTemplateOptionDefault(t *testing.T) {
render := New(Options{
Directory: "testdata/basic",
})

var err error

// Template expects "world" key.
templateData := map[string]int{"missing-key-here": 100}

h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err = render.HTML(w, http.StatusOK, "map", templateData)
})

res := httptest.NewRecorder()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "/foo", nil)
h.ServeHTTP(res, req)

expectNil(t, err)
expect(t, res.Code, 200)
expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8")
expect(t, res.Body.String(), "<h1>Hello </h1>\n")
}

func TestHTMLTemplateOptionZero(t *testing.T) {
render := New(Options{
Directory: "testdata/basic",
HTMLTemplateOption: "missingkey=zero",
})

var err error

// Template expects "world" key.
templateData := map[string]int{"missing-key-here": 100}

h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err = render.HTML(w, http.StatusOK, "map", templateData)
})

res := httptest.NewRecorder()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "/foo", nil)
h.ServeHTTP(res, req)

expectNil(t, err)
expect(t, res.Code, 200)
expect(t, res.Header().Get(ContentType), ContentHTML+"; charset=UTF-8")
expect(t, res.Body.String(), "<h1>Hello 0</h1>\n")
}

func TestHTMLTemplateOptionError(t *testing.T) {
render := New(Options{
Directory: "testdata/basic",
HTMLTemplateOption: "missingkey=error",
})

var err error

// Template expects "world" key.
templateData := map[string]string{"missing-key-here": "gophers"}

h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err = render.HTML(w, http.StatusOK, "map", templateData)
})

res := httptest.NewRecorder()
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "/foo", nil)
h.ServeHTTP(res, req)

expectNotNil(t, err)
expect(t, strings.Contains(err.Error(), "map has no entry for key"), true)
}
1 change: 1 addition & 0 deletions testdata/basic/map.tmpl
@@ -0,0 +1 @@
<h1>Hello {{.world}}</h1>

0 comments on commit 369f257

Please sign in to comment.