Skip to content

Commit

Permalink
Merge pull request #316 from denovodavid/master
Browse files Browse the repository at this point in the history
Add support for nested layouts to HTML template engine
  • Loading branch information
ReneWerner87 authored Jan 8, 2024
2 parents 9dd46c8 + 4cbd251 commit fd5a1ab
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 12 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/gosec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
json: true
escape_json: false
dir_names: true
dir_names_max_depth: '1'
dir_names_exclude_current_dir: true

gosec-scan:
Expand All @@ -61,4 +62,4 @@ jobs:
run: go install github.com/securego/gosec/v2/cmd/gosec@latest
- name: Run gosec
working-directory: ${{ matrix.modules }}
run: gosec ./...
run: gosec ./...
7 changes: 7 additions & 0 deletions html/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ func main() {
}, "layouts/main")
})

app.Get("/layouts-nested", func(c *fiber.Ctx) error {
// Render index within layouts/nested/main within layouts/nested/base
return c.Render("index", fiber.Map{
"Title": "Hello, World!",
}, "layouts/nested/main", "layouts/nested/base")
})

log.Fatal(app.Listen(":3000"))
}

Expand Down
32 changes: 21 additions & 11 deletions html/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,24 +133,34 @@ func (e *Engine) Render(out io.Writer, name string, binding interface{}, layout
return err
}
}

tmpl := e.Templates.Lookup(name)
if tmpl == nil {
return fmt.Errorf("render: template %s does not exist", name)
}
render := renderFuncCreate(e, out, binding, *tmpl, nil)
if len(layout) > 0 && layout[0] != "" {
lay := e.Templates.Lookup(layout[0])
if lay == nil {
return fmt.Errorf("render: LayoutName %s does not exist", layout[0])
}
e.Mutex.Lock()
defer e.Mutex.Unlock()
lay.Funcs(map[string]interface{}{
e.LayoutName: func() error {
return tmpl.Execute(out, binding)
},
}
// construct a nested render function to embed templates in layouts
for _, layName := range layout {
if layName == "" {
break
}
lay := e.Templates.Lookup(layName)
if lay == nil {
return fmt.Errorf("render: LayoutName %s does not exist", layName)
}
render = renderFuncCreate(e, out, binding, *lay, render)
}
return render()
}

func renderFuncCreate(e *Engine, out io.Writer, binding interface{}, tmpl template.Template, childRenderFunc func() error) func() error {
return func() error {
tmpl.Funcs(map[string]interface{}{
e.LayoutName: childRenderFunc,
})
return lay.Execute(out, binding)
return tmpl.Execute(out, binding)
}
return tmpl.Execute(out, binding)
}
19 changes: 19 additions & 0 deletions html/html_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,25 @@ func Test_Layout_Multi(t *testing.T) {
}
}

func Test_Layout_Nested(t *testing.T) {
t.Parallel()
engine := New("./views", ".html")

engine.AddFunc("isAdmin", func(user string) bool {
return user == admin
})
require.NoError(t, engine.Load())

var buf bytes.Buffer
err := engine.Render(&buf, "index", map[string]interface{}{
"Title": "Hello, World!",
}, "layouts/nested/main", "layouts/nested/base")
require.NoError(t, err)

result := trim(buf.String())
require.Equal(t, complexexpect, result)
}

func Test_FileSystem(t *testing.T) {
t.Parallel()
engine := NewFileSystem(http.Dir("./views"), ".html")
Expand Down
6 changes: 6 additions & 0 deletions html/views/layouts/nested/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>

{{embed}}

</html>
7 changes: 7 additions & 0 deletions html/views/layouts/nested/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<head>
<title>Main</title>
</head>

<body>
{{embed}}
</body>

0 comments on commit fd5a1ab

Please sign in to comment.