mirror of
https://github.com/foolin/goview.git
synced 2025-09-26 19:01:15 +08:00
Initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.idea
|
||||
go.sum
|
6
.travis.yml
Normal file
6
.travis.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Foolin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
753
README.md
Normal file
753
README.md
Normal file
@@ -0,0 +1,753 @@
|
||||
# goview
|
||||
|
||||
[![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis]
|
||||
|
||||
Goview is a lightweight, simple and easy template library based on golang html/template for building Go web application.
|
||||
|
||||
## Contents
|
||||
|
||||
- [Install](#install)
|
||||
- [Features](#features)
|
||||
- [Docs](#docs)
|
||||
- [Usage](#usage)
|
||||
- [Overview](#overview)
|
||||
- [Config](#config)
|
||||
- [Include syntax](#include-syntax)
|
||||
- [Render name](#render-name)
|
||||
- [Examples](#examples)
|
||||
- [Basic example](#basic-example)
|
||||
- [Gin example](#gin-example)
|
||||
- [Echo example](#echo-example)
|
||||
- [Go-chi example](#go-chi-example)
|
||||
- [Advance example](#advance-example)
|
||||
- [Multiple example](#multiple-example)
|
||||
- [go.rice example](#gorice-example)
|
||||
- [Supports](#supports)
|
||||
|
||||
|
||||
## Install
|
||||
```bash
|
||||
go get -u github.com/foolin/goview
|
||||
```
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
* **Lightweight** - use golang html/template syntax.
|
||||
* **Easy** - easy use for your web application.
|
||||
* **Fast** - Support configure cache template.
|
||||
* **Include syntax** - Support include file.
|
||||
* **Master layout** - Support configure master layout file.
|
||||
* **Extension** - Support configure template file extension.
|
||||
* **Easy** - Support configure templates directory.
|
||||
* **Auto reload** - Support dynamic reload template(disable cache mode).
|
||||
* **Multiple Engine** - Support multiple templates for frontend and backend.
|
||||
* **No external dependencies** - plain ol' Go html/template.
|
||||
* **Gorice** - Support gorice for package resources.
|
||||
* **Gin/Echo/Chi** - Support gin framework,echo framework, go-chi framework.
|
||||
|
||||
|
||||
## Docs
|
||||
See https://www.godoc.org/github.com/foolin/goview
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### Overview
|
||||
|
||||
Project structure:
|
||||
|
||||
```go
|
||||
|-- app/views/
|
||||
|--- index.html
|
||||
|--- page.html
|
||||
|-- layouts/
|
||||
|--- footer.html
|
||||
|--- master.html
|
||||
|
||||
```
|
||||
|
||||
Use default instance:
|
||||
|
||||
```go
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
Use new instance with config:
|
||||
|
||||
```go
|
||||
|
||||
gv := goview.New(goview.Config{
|
||||
Root: "views",
|
||||
Extension: ".tpl",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"sub": func(a, b int) int {
|
||||
return a - b
|
||||
},
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
//Set new instance
|
||||
goview.Use(gv)
|
||||
|
||||
//render index use `index` without `.tpl` extension, that will render with master layout.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
|
||||
Use multiple instance with config:
|
||||
|
||||
```go
|
||||
|
||||
gvFrontend := goview.New(goview.Config{
|
||||
Root: "views/frontend",
|
||||
Extension: ".tpl",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"sub": func(a, b int) int {
|
||||
return a - b
|
||||
},
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
//render index use `index` without `.tpl` extension, that will render with master layout.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := gvFrontend.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//Backend
|
||||
|
||||
gvBackend := goview.New(goview.Config{
|
||||
Root: "views/backend",
|
||||
Extension: ".tpl",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"sub": func(a, b int) int {
|
||||
return a - b
|
||||
},
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
//render index use `index` without `.tpl` extension, that will render with master layout.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := gvBackend.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### Config
|
||||
|
||||
```go
|
||||
goview.Config{
|
||||
Root: "views", //template root path
|
||||
Extension: ".tpl", //file extension
|
||||
Master: "layouts/master", //master layout file
|
||||
Partials: []string{"partials/head"}, //partial files
|
||||
Funcs: template.FuncMap{
|
||||
"sub": func(a, b int) int {
|
||||
return a - b
|
||||
},
|
||||
// more funcs
|
||||
},
|
||||
DisableCache: false, //if disable cache, auto reload template file for debug.
|
||||
}
|
||||
```
|
||||
|
||||
### Include syntax
|
||||
|
||||
```go
|
||||
//template file
|
||||
{{include "layouts/footer"}}
|
||||
```
|
||||
|
||||
### Render name:
|
||||
|
||||
Render name use `index` without `.html` extension, that will render with master layout.
|
||||
|
||||
- **"index"** - Render with master layout.
|
||||
- **"index.html"** - Not render with master layout.
|
||||
|
||||
```
|
||||
Notice: `.html` is default template extension, you can change with config
|
||||
```
|
||||
|
||||
|
||||
Render with master
|
||||
|
||||
```go
|
||||
//use name without extension `.html`
|
||||
goview.Render(w, http.StatusOK, "index", gin.H{})
|
||||
```
|
||||
|
||||
The `w` is instance of `http.ResponseWriter`
|
||||
|
||||
Render only file(not use master layout)
|
||||
```go
|
||||
//use full name with extension `.html`
|
||||
goview.Render(w, http.StatusOK, "page.html", gin.H{})
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
See [_examples/](https://github.com/foolin/goview/blob/master/_examples/) for a variety of examples.
|
||||
|
||||
|
||||
### Basic example
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/foolin/goview"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
//render index use `index` without `.tpl` extension, that will render with master layout.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//render page use `page.tpl` with '.tpl' will only file template without master layout.
|
||||
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render page.html error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :9090")
|
||||
http.ListenAndServe(":9090", nil)
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Project structure:
|
||||
```go
|
||||
|-- app/views/
|
||||
|--- index.html
|
||||
|--- page.html
|
||||
|-- layouts/
|
||||
|--- footer.html
|
||||
|--- master.html
|
||||
|
||||
|
||||
See in "examples/basic" folder
|
||||
```
|
||||
|
||||
[Basic example](https://github.com/foolin/goview/tree/master/_examples/basic)
|
||||
|
||||
|
||||
### Gin example
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/foolin/goview/supports/ginview"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
|
||||
//new template engine
|
||||
router.HTMLRender = ginview.Default()
|
||||
|
||||
router.GET("/", func(ctx *gin.Context) {
|
||||
//render with master
|
||||
ctx.HTML(http.StatusOK, "index", gin.H{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/page", func(ctx *gin.Context) {
|
||||
//render only file, must full name with extension
|
||||
ctx.HTML(http.StatusOK, "page.html", gin.H{"title": "Page file title!!"})
|
||||
})
|
||||
|
||||
router.Run(":9090")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Project structure:
|
||||
```go
|
||||
|-- app/views/
|
||||
|--- index.html
|
||||
|--- page.html
|
||||
|-- layouts/
|
||||
|--- footer.html
|
||||
|--- master.html
|
||||
|
||||
|
||||
See in "examples/basic" folder
|
||||
```
|
||||
|
||||
[Gin example](https://github.com/foolin/goview/tree/master/_examples/gin)
|
||||
|
||||
|
||||
|
||||
### Echo example
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/foolin/goview/supports/echoview"
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Echo instance
|
||||
e := echo.New()
|
||||
|
||||
// Middleware
|
||||
e.Use(middleware.Logger())
|
||||
e.Use(middleware.Recover())
|
||||
|
||||
//Set Renderer
|
||||
e.Renderer = echoview.Default()
|
||||
|
||||
// Routes
|
||||
e.GET("/", func(c echo.Context) error {
|
||||
//render with master
|
||||
return c.Render(http.StatusOK, "index", echo.Map{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
e.GET("/page", func(c echo.Context) error {
|
||||
//render only file, must full name with extension
|
||||
return c.Render(http.StatusOK, "page.html", echo.Map{"title": "Page file title!!"})
|
||||
})
|
||||
|
||||
// Start server
|
||||
e.Logger.Fatal(e.Start(":9090"))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Project structure:
|
||||
```go
|
||||
|-- app/views/
|
||||
|--- index.html
|
||||
|--- page.html
|
||||
|-- layouts/
|
||||
|--- footer.html
|
||||
|--- master.html
|
||||
|
||||
|
||||
See in "examples/basic" folder
|
||||
```
|
||||
|
||||
[Echo example](https://github.com/foolin/goview/tree/master/_examples/echo)
|
||||
|
||||
|
||||
|
||||
### Go-chi example
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/foolin/goview"
|
||||
"github.com/go-chi/chi"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
//render index use `index` without `.tpl` extension, that will render with master layout.
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
//render page use `page.tpl` with '.tpl' will only file template without master layout.
|
||||
r.Get("/page", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render page.html error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :9090")
|
||||
http.ListenAndServe(":9090", r)
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Project structure:
|
||||
```go
|
||||
|-- app/views/
|
||||
|--- index.html
|
||||
|--- page.html
|
||||
|-- layouts/
|
||||
|--- footer.html
|
||||
|--- master.html
|
||||
|
||||
|
||||
See in "examples/basic" folder
|
||||
```
|
||||
|
||||
[Chi example](https://github.com/foolin/goview/tree/master/_examples/go-chi)
|
||||
|
||||
|
||||
|
||||
### Advance example
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/foolin/goview"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
gv := goview.New(goview.Config{
|
||||
Root: "views",
|
||||
Extension: ".tpl",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"sub": func(a, b int) int {
|
||||
return a - b
|
||||
},
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
//Set new instance
|
||||
goview.Use(gv)
|
||||
|
||||
//render index use `index` without `.tpl` extension, that will render with master layout.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//render page use `page.tpl` with '.tpl' will only file template without master layout.
|
||||
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "page.tpl", goview.M{"title": "Page file title!!"})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render page.html error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :9090")
|
||||
http.ListenAndServe(":9090", nil)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Project structure:
|
||||
```go
|
||||
|-- app/views/
|
||||
|--- index.tpl
|
||||
|--- page.tpl
|
||||
|-- layouts/
|
||||
|--- footer.tpl
|
||||
|--- head.tpl
|
||||
|--- master.tpl
|
||||
|-- partials/
|
||||
|--- ad.tpl
|
||||
|
||||
|
||||
See in "examples/advance" folder
|
||||
```
|
||||
|
||||
[Advance example](https://github.com/foolin/goview/tree/master/_examples/advance)
|
||||
|
||||
### Multiple example
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/foolin/goview"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
|
||||
//new template engine
|
||||
router.HTMLRender = gintemplate.New(gintemplate.TemplateConfig{
|
||||
Root: "views/fontend",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
router.GET("/", func(ctx *gin.Context) {
|
||||
// `HTML()` is a helper func to deal with multiple TemplateEngine's.
|
||||
// It detects the suitable TemplateEngine for each path automatically.
|
||||
gintemplate.HTML(ctx, http.StatusOK, "index", gin.H{
|
||||
"title": "Fontend title!",
|
||||
})
|
||||
})
|
||||
|
||||
//=========== Backend ===========//
|
||||
|
||||
//new middleware
|
||||
mw := gintemplate.NewMiddleware(gintemplate.TemplateConfig{
|
||||
Root: "views/backend",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{},
|
||||
Funcs: template.FuncMap{
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
// You should use helper func `Middleware()` to set the supplied
|
||||
// TemplateEngine and make `HTML()` work validly.
|
||||
backendGroup := router.Group("/admin", mw)
|
||||
|
||||
backendGroup.GET("/", func(ctx *gin.Context) {
|
||||
// With the middleware, `HTML()` can detect the valid TemplateEngine.
|
||||
gintemplate.HTML(ctx, http.StatusOK, "index", gin.H{
|
||||
"title": "Backend title!",
|
||||
})
|
||||
})
|
||||
|
||||
router.Run(":9090")
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Project structure:
|
||||
```go
|
||||
|-- app/views/
|
||||
|-- fontend/
|
||||
|--- index.html
|
||||
|-- layouts/
|
||||
|--- footer.html
|
||||
|--- head.html
|
||||
|--- master.html
|
||||
|-- partials/
|
||||
|--- ad.html
|
||||
|-- backend/
|
||||
|--- index.html
|
||||
|-- layouts/
|
||||
|--- footer.html
|
||||
|--- head.html
|
||||
|--- master.html
|
||||
|
||||
See in "examples/multiple" folder
|
||||
```
|
||||
|
||||
[Multiple example](https://github.com/foolin/goview/tree/master/_examples/multiple)
|
||||
|
||||
|
||||
### go.rice example
|
||||
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/foolin/goview"
|
||||
"github.com/foolin/goview/supports/gorice"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
//static
|
||||
staticBox := rice.MustFindBox("static")
|
||||
staticFileServer := http.StripPrefix("/static/", http.FileServer(staticBox.HTTPBox()))
|
||||
http.Handle("/static/", staticFileServer)
|
||||
|
||||
//new view engine
|
||||
gv := gorice.New(rice.MustFindBox("views"))
|
||||
//set engine for default instance
|
||||
goview.Use(gv)
|
||||
|
||||
//render index use `index` without `.tpl` extension, that will render with master layout.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//render page use `page.tpl` with '.tpl' will only file template without master layout.
|
||||
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render page.html error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :9090")
|
||||
http.ListenAndServe(":9090", nil)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Project structure:
|
||||
```go
|
||||
|-- app/views/
|
||||
|--- index.html
|
||||
|--- page.html
|
||||
|-- layouts/
|
||||
|--- footer.html
|
||||
|--- master.html
|
||||
|-- app/static/
|
||||
|-- css/
|
||||
|--- bootstrap.css
|
||||
|-- img/
|
||||
|--- gopher.png
|
||||
|
||||
See in "examples/gorice" folder
|
||||
```
|
||||
|
||||
[gorice example](https://github.com/foolin/goview/tree/master/_examples/gorice)
|
||||
|
||||
## Supports
|
||||
- go-chi The same as golang http
|
||||
- [ginview](https://github.com/foolin/goview/tree/master/supports/ginview) goview for gin framework
|
||||
- [echoview](https://github.com/foolin/goview/tree/master/supports/echoview) goview for echo framework
|
||||
- [go.rice](https://github.com/foolin/goview/tree/master/supports/gorice) goview for go.rice
|
||||
|
||||
|
||||
[GoDoc]: https://godoc.org/github.com/foolin/goview
|
||||
[GoDoc Widget]: https://godoc.org/github.com/foolin/goview?status.svg
|
||||
[Travis]: https://travis-ci.org/foolin/goview
|
||||
[Travis Widget]: https://travis-ci.org/foolin/goview.svg?branch=master
|
202
_examples/.idea/workspace.xml
generated
Normal file
202
_examples/.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,202 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="ce420b0a-6004-4397-9780-497f5816a9ad" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/advance/README.md" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/advance/main.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/advance/views/index.tpl" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/advance/views/layouts/footer.tpl" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/advance/views/layouts/head.tpl" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/advance/views/layouts/master.tpl" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/advance/views/page.tpl" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/advance/views/partials/ad.tpl" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/basic/README.md" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/basic/main.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/basic/views/index.html" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/basic/views/layouts/footer.html" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/basic/views/layouts/master.html" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/basic/views/page.html" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/../supports/ginview/ginview.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/../supports/gorice/gorice.go" afterDir="false" />
|
||||
</list>
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf>
|
||||
<file pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/basic/main.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="272">
|
||||
<caret line="16" column="13" selection-start-line="16" selection-start-column="13" selection-end-line="16" selection-end-column="13" />
|
||||
<folding>
|
||||
<element signature="e#180#271#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/advance/main.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="237">
|
||||
<caret line="30" selection-start-line="30" selection-end-line="33" selection-end-column="37" />
|
||||
<folding>
|
||||
<element signature="e#180#209#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/go.mod">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="204">
|
||||
<caret line="12" selection-start-line="12" selection-end-line="12" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="GOROOT" path="C:\Go" />
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||
</component>
|
||||
<component name="GoLibraries">
|
||||
<option name="indexEntireGoPath" value="false" />
|
||||
</component>
|
||||
<component name="IdeDocumentHistory">
|
||||
<option name="CHANGED_PATHS">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/basic/main.go" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectConfigurationFiles">
|
||||
<option name="files">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/.idea/_examples.iml" />
|
||||
<option value="$PROJECT_DIR$/.idea/misc.xml" />
|
||||
<option value="$PROJECT_DIR$/.idea/vcs.xml" />
|
||||
<option value="$PROJECT_DIR$/.idea/modules.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds" extendedState="6">
|
||||
<option name="x" value="-10" />
|
||||
<option name="width" value="1940" />
|
||||
<option name="height" value="1040" />
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectView">
|
||||
<navigator proportions="" version="1">
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="_examples" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="_examples" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="_examples" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="_examples" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="basic" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="Scope" />
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="go.gopath.indexing.explicitly.defined" value="true" />
|
||||
<property name="go.import.settings.migrated" value="true" />
|
||||
<property name="go.sdk.automatically.set" value="true" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||
<property name="settings.editor.selected.configurable" value="configurable.group.appearance" />
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="-7" y="-7" width="1550" height="838" extended-state="6" />
|
||||
<layout>
|
||||
<window_info id="Favorites" side_tool="true" />
|
||||
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.25" />
|
||||
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Docker" show_stripe_button="false" />
|
||||
<window_info anchor="bottom" id="Database Changes" />
|
||||
<window_info anchor="bottom" id="Version Control" />
|
||||
<window_info active="true" anchor="bottom" id="Terminal" visible="true" weight="0.3286119" />
|
||||
<window_info anchor="bottom" id="Event Log" side_tool="true" />
|
||||
<window_info anchor="bottom" id="Message" order="0" />
|
||||
<window_info anchor="bottom" id="Find" order="1" />
|
||||
<window_info anchor="bottom" id="Run" order="2" />
|
||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
||||
<window_info anchor="bottom" id="TODO" order="6" />
|
||||
<window_info anchor="right" id="Database" />
|
||||
<window_info anchor="right" id="Commander" order="0" weight="0.4" />
|
||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="1" />
|
||||
</component>
|
||||
<component name="VgoProject">
|
||||
<integration-enabled>true</integration-enabled>
|
||||
<proxy>https://goproxy.io</proxy>
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/advance/main.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="237">
|
||||
<caret line="30" selection-start-line="30" selection-end-line="33" selection-end-column="37" />
|
||||
<folding>
|
||||
<element signature="e#180#209#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/go.mod">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="204">
|
||||
<caret line="12" selection-start-line="12" selection-end-line="12" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/basic/main.go">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="272">
|
||||
<caret line="16" column="13" selection-start-line="16" selection-start-column="13" selection-end-line="16" selection-end-column="13" />
|
||||
<folding>
|
||||
<element signature="e#180#271#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
</project>
|
14
_examples/advance/README.md
Normal file
14
_examples/advance/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Advance
|
||||
Exmaple for gin template
|
||||
|
||||
# Run
|
||||
```go
|
||||
go run main.go
|
||||
```
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
64
_examples/advance/main.go
Normal file
64
_examples/advance/main.go
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/foolin/goview"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
gv := goview.New(goview.Config{
|
||||
Root: "views",
|
||||
Extension: ".tpl",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"sub": func(a, b int) int {
|
||||
return a - b
|
||||
},
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
//Set new instance
|
||||
goview.Use(gv)
|
||||
|
||||
//render index use `index` without `.tpl` extension, that will render with master layout.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//render page use `page.tpl` with '.tpl' will only file template without master layout.
|
||||
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "page.tpl", goview.M{"title": "Page file title!!"})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render page.html error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :9090")
|
||||
http.ListenAndServe(":9090", nil)
|
||||
}
|
7
_examples/advance/views/index.tpl
Normal file
7
_examples/advance/views/index.tpl
Normal file
@@ -0,0 +1,7 @@
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is content!!!!</h1>
|
||||
<p>123 + 333 = {{call $.add 123 333}}</p>
|
||||
<p>123 - 100= {{sub 123 100}}</p>
|
||||
<hr>
|
||||
<p><a href="/page">Page render</a></p>
|
||||
{{end}}
|
1
_examples/advance/views/layouts/footer.tpl
Normal file
1
_examples/advance/views/layouts/footer.tpl
Normal file
@@ -0,0 +1 @@
|
||||
Copyright © {{copy}} <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
4
_examples/advance/views/layouts/head.tpl
Normal file
4
_examples/advance/views/layouts/head.tpl
Normal file
@@ -0,0 +1,4 @@
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
17
_examples/advance/views/layouts/master.tpl
Normal file
17
_examples/advance/views/layouts/master.tpl
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{include "layouts/head"}}
|
||||
</head>
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{template "ad" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
16
_examples/advance/views/page.tpl
Normal file
16
_examples/advance/views/page.tpl
Normal file
@@ -0,0 +1,16 @@
|
||||
<!-- /views/page.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{include "layouts/head"}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a href="/"><- Back home!</a>
|
||||
{{template "ad" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
3
_examples/advance/views/partials/ad.tpl
Normal file
3
_examples/advance/views/partials/ad.tpl
Normal file
@@ -0,0 +1,3 @@
|
||||
{{define "ad"}}
|
||||
<p>[AD: <a href="https://github.com/foolin" target="_blank">Wellcome to github!</a>]</p>
|
||||
{{end}}
|
14
_examples/basic/README.md
Normal file
14
_examples/basic/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Basic
|
||||
Exmaple for gin template
|
||||
|
||||
# Run
|
||||
```go
|
||||
go run main.go
|
||||
```
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
44
_examples/basic/main.go
Normal file
44
_examples/basic/main.go
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/foolin/goview"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
//render index use `index` without `.html` extension, that will render with master layout.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//render page use `page.html` with '.html' will only file template without master layout.
|
||||
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render page.html error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :9090")
|
||||
http.ListenAndServe(":9090", nil)
|
||||
|
||||
}
|
14
_examples/basic/views/index.html
Normal file
14
_examples/basic/views/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{{define "head"}}
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is content!!!!</h1>
|
||||
<p>123 + 333 = {{call $.add 123 333}}</p>
|
||||
<hr>
|
||||
<p><a href="/page">Page render</a></p>
|
||||
{{end}}
|
1
_examples/basic/views/layouts/footer.html
Normal file
1
_examples/basic/views/layouts/footer.html
Normal file
@@ -0,0 +1 @@
|
||||
Copyright ©2018 <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
15
_examples/basic/views/layouts/master.html
Normal file
15
_examples/basic/views/layouts/master.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
19
_examples/basic/views/page.html
Normal file
19
_examples/basic/views/page.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- /views/page.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a href="/"><- Back home!</a>
|
||||
<hr>
|
||||
This page not use master, Render code:
|
||||
<pre>goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})</pre>
|
||||
<br>
|
||||
"page.html" - add extension ".html" will render without master.
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
14
_examples/echo-multiple/README.md
Normal file
14
_examples/echo-multiple/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Multiple
|
||||
Exmaple for gin template, font end and back end.
|
||||
|
||||
# Run
|
||||
```go
|
||||
go run main.go
|
||||
```
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
82
_examples/echo-multiple/main.go
Normal file
82
_examples/echo-multiple/main.go
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/foolin/goview"
|
||||
"github.com/foolin/goview/supports/echoview"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Echo instance
|
||||
e := echo.New()
|
||||
|
||||
// Middleware
|
||||
e.Use(middleware.Logger())
|
||||
e.Use(middleware.Recover())
|
||||
|
||||
//new template engine
|
||||
e.Renderer = echoview.New(goview.Config{
|
||||
Root: "views/frontend",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
e.GET("/", func(ctx echo.Context) error {
|
||||
// `HTML()` is a helper func to deal with multiple TemplateEngine's.
|
||||
// It detects the suitable TemplateEngine for each path automatically.
|
||||
return echoview.Render(ctx, http.StatusOK, "index", echo.Map{
|
||||
"title": "Frontend title!",
|
||||
})
|
||||
})
|
||||
|
||||
//=========== Backend ===========//
|
||||
|
||||
//new middleware
|
||||
mw := echoview.NewMiddleware(goview.Config{
|
||||
Root: "views/backend",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{},
|
||||
Funcs: template.FuncMap{
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
// You should use helper func `Middleware()` to set the supplied
|
||||
// TemplateEngine and make `HTML()` work validly.
|
||||
backendGroup := e.Group("/admin", mw)
|
||||
|
||||
backendGroup.GET("/", func(ctx echo.Context) error {
|
||||
// With the middleware, `HTML()` can detect the valid TemplateEngine.
|
||||
return echoview.Render(ctx, http.StatusOK, "index", echo.Map{
|
||||
"title": "Backend title!",
|
||||
})
|
||||
})
|
||||
|
||||
// Start server
|
||||
e.Logger.Fatal(e.Start(":9090"))
|
||||
}
|
5
_examples/echo-multiple/views/backend/index.html
Normal file
5
_examples/echo-multiple/views/backend/index.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is backend!!!!</h1>
|
||||
<hr>
|
||||
<p><a href="/">Go to frontend</a></p>
|
||||
{{end}}
|
@@ -0,0 +1 @@
|
||||
Copyright © {{copy}} <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
4
_examples/echo-multiple/views/backend/layouts/head.html
Normal file
4
_examples/echo-multiple/views/backend/layouts/head.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
15
_examples/echo-multiple/views/backend/layouts/master.html
Normal file
15
_examples/echo-multiple/views/backend/layouts/master.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{include "layouts/head"}}
|
||||
</head>
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
5
_examples/echo-multiple/views/frontend/index.html
Normal file
5
_examples/echo-multiple/views/frontend/index.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is frontend!!!!</h1>
|
||||
<hr>
|
||||
<p><a href="/admin/">Go to backend</a></p>
|
||||
{{end}}
|
@@ -0,0 +1 @@
|
||||
Copyright © {{copy}} <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
4
_examples/echo-multiple/views/frontend/layouts/head.html
Normal file
4
_examples/echo-multiple/views/frontend/layouts/head.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
17
_examples/echo-multiple/views/frontend/layouts/master.html
Normal file
17
_examples/echo-multiple/views/frontend/layouts/master.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{include "layouts/head"}}
|
||||
</head>
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{template "ad" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
3
_examples/echo-multiple/views/frontend/partials/ad.html
Normal file
3
_examples/echo-multiple/views/frontend/partials/ad.html
Normal file
@@ -0,0 +1,3 @@
|
||||
{{define "ad"}}
|
||||
<p>[AD: <a href="https://github.com/foolin" target="_blank">Wellcome to fontend!</a>]</p>
|
||||
{{end}}
|
14
_examples/echo/README.md
Normal file
14
_examples/echo/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Basic
|
||||
Exmaple for gin template
|
||||
|
||||
# Run
|
||||
```go
|
||||
go run main.go
|
||||
```
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
48
_examples/echo/main.go
Normal file
48
_examples/echo/main.go
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/foolin/goview/supports/echoview"
|
||||
"github.com/labstack/echo"
|
||||
"github.com/labstack/echo/middleware"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Echo instance
|
||||
e := echo.New()
|
||||
|
||||
// Middleware
|
||||
e.Use(middleware.Logger())
|
||||
e.Use(middleware.Recover())
|
||||
|
||||
//Set Renderer
|
||||
e.Renderer = echoview.Default()
|
||||
|
||||
// Routes
|
||||
e.GET("/", func(c echo.Context) error {
|
||||
//render with master
|
||||
return c.Render(http.StatusOK, "index", echo.Map{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
e.GET("/page", func(c echo.Context) error {
|
||||
//render only file, must full name with extension
|
||||
return c.Render(http.StatusOK, "page.html", echo.Map{"title": "Page file title!!"})
|
||||
})
|
||||
|
||||
// Start server
|
||||
e.Logger.Fatal(e.Start(":9090"))
|
||||
}
|
14
_examples/echo/views/index.html
Normal file
14
_examples/echo/views/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{{define "head"}}
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is content!!!!</h1>
|
||||
<p>123 + 333 = {{call $.add 123 333}}</p>
|
||||
<hr>
|
||||
<p><a href="/page">Page render</a></p>
|
||||
{{end}}
|
1
_examples/echo/views/layouts/footer.html
Normal file
1
_examples/echo/views/layouts/footer.html
Normal file
@@ -0,0 +1 @@
|
||||
Copyright ©2018 <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
15
_examples/echo/views/layouts/master.html
Normal file
15
_examples/echo/views/layouts/master.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
19
_examples/echo/views/page.html
Normal file
19
_examples/echo/views/page.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- /views/page.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a href="/"><- Back home!</a>
|
||||
<hr>
|
||||
This page not use master, Render code:
|
||||
<pre>goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})</pre>
|
||||
<br>
|
||||
"page.html" - add extension ".html" will render without master.
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
14
_examples/gin-multiple/README.md
Normal file
14
_examples/gin-multiple/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Multiple
|
||||
Exmaple for gin template, font end and back end.
|
||||
|
||||
# Run
|
||||
```go
|
||||
go run main.go
|
||||
```
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
73
_examples/gin-multiple/main.go
Normal file
73
_examples/gin-multiple/main.go
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/foolin/goview"
|
||||
"github.com/foolin/goview/supports/ginview"
|
||||
"github.com/gin-gonic/gin"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
|
||||
//new template engine
|
||||
router.HTMLRender = ginview.New(goview.Config{
|
||||
Root: "views/frontend",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
router.GET("/", func(ctx *gin.Context) {
|
||||
// `HTML()` is a helper func to deal with multiple TemplateEngine's.
|
||||
// It detects the suitable TemplateEngine for each path automatically.
|
||||
ginview.HTML(ctx, http.StatusOK, "index", gin.H{
|
||||
"title": "Frontend title!",
|
||||
})
|
||||
})
|
||||
|
||||
//=========== Backend ===========//
|
||||
|
||||
//new middleware
|
||||
mw := ginview.NewMiddleware(goview.Config{
|
||||
Root: "views/backend",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{},
|
||||
Funcs: template.FuncMap{
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
// You should use helper func `Middleware()` to set the supplied
|
||||
// TemplateEngine and make `HTML()` work validly.
|
||||
backendGroup := router.Group("/admin", mw)
|
||||
|
||||
backendGroup.GET("/", func(ctx *gin.Context) {
|
||||
// With the middleware, `HTML()` can detect the valid TemplateEngine.
|
||||
ginview.HTML(ctx, http.StatusOK, "index", gin.H{
|
||||
"title": "Backend title!",
|
||||
})
|
||||
})
|
||||
|
||||
router.Run(":9090")
|
||||
}
|
5
_examples/gin-multiple/views/backend/index.html
Normal file
5
_examples/gin-multiple/views/backend/index.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is backend!!!!</h1>
|
||||
<hr>
|
||||
<p><a href="/">Go to frontend</a></p>
|
||||
{{end}}
|
1
_examples/gin-multiple/views/backend/layouts/footer.html
Normal file
1
_examples/gin-multiple/views/backend/layouts/footer.html
Normal file
@@ -0,0 +1 @@
|
||||
Copyright © {{copy}} <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
4
_examples/gin-multiple/views/backend/layouts/head.html
Normal file
4
_examples/gin-multiple/views/backend/layouts/head.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
15
_examples/gin-multiple/views/backend/layouts/master.html
Normal file
15
_examples/gin-multiple/views/backend/layouts/master.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{include "layouts/head"}}
|
||||
</head>
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
5
_examples/gin-multiple/views/frontend/index.html
Normal file
5
_examples/gin-multiple/views/frontend/index.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is frontend!!!!</h1>
|
||||
<hr>
|
||||
<p><a href="/admin/">Go to backend</a></p>
|
||||
{{end}}
|
@@ -0,0 +1 @@
|
||||
Copyright © {{copy}} <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
4
_examples/gin-multiple/views/frontend/layouts/head.html
Normal file
4
_examples/gin-multiple/views/frontend/layouts/head.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
17
_examples/gin-multiple/views/frontend/layouts/master.html
Normal file
17
_examples/gin-multiple/views/frontend/layouts/master.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{include "layouts/head"}}
|
||||
</head>
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{template "ad" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
3
_examples/gin-multiple/views/frontend/partials/ad.html
Normal file
3
_examples/gin-multiple/views/frontend/partials/ad.html
Normal file
@@ -0,0 +1,3 @@
|
||||
{{define "ad"}}
|
||||
<p>[AD: <a href="https://github.com/foolin" target="_blank">Wellcome to fontend!</a>]</p>
|
||||
{{end}}
|
14
_examples/gin/README.md
Normal file
14
_examples/gin/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Basic
|
||||
Exmaple for gin template
|
||||
|
||||
# Run
|
||||
```go
|
||||
go run main.go
|
||||
```
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
39
_examples/gin/main.go
Normal file
39
_examples/gin/main.go
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/foolin/goview/supports/ginview"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
|
||||
//new template engine
|
||||
router.HTMLRender = ginview.Default()
|
||||
|
||||
router.GET("/", func(ctx *gin.Context) {
|
||||
//render with master
|
||||
ctx.HTML(http.StatusOK, "index", gin.H{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
router.GET("/page", func(ctx *gin.Context) {
|
||||
//render only file, must full name with extension
|
||||
ctx.HTML(http.StatusOK, "page.html", gin.H{"title": "Page file title!!"})
|
||||
})
|
||||
|
||||
router.Run(":9090")
|
||||
}
|
14
_examples/gin/views/index.html
Normal file
14
_examples/gin/views/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{{define "head"}}
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is content!!!!</h1>
|
||||
<p>123 + 333 = {{call $.add 123 333}}</p>
|
||||
<hr>
|
||||
<p><a href="/page">Page render</a></p>
|
||||
{{end}}
|
1
_examples/gin/views/layouts/footer.html
Normal file
1
_examples/gin/views/layouts/footer.html
Normal file
@@ -0,0 +1 @@
|
||||
Copyright ©2018 <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
15
_examples/gin/views/layouts/master.html
Normal file
15
_examples/gin/views/layouts/master.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
19
_examples/gin/views/page.html
Normal file
19
_examples/gin/views/page.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- /views/page.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a href="/"><- Back home!</a>
|
||||
<hr>
|
||||
This page not use master, Render code:
|
||||
<pre>goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})</pre>
|
||||
<br>
|
||||
"page.html" - add extension ".html" will render without master.
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
14
_examples/go-chi/README.md
Normal file
14
_examples/go-chi/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Basic
|
||||
Exmaple for gin template
|
||||
|
||||
# Run
|
||||
```go
|
||||
go run main.go
|
||||
```
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
44
_examples/go-chi/main.go
Normal file
44
_examples/go-chi/main.go
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/foolin/goview"
|
||||
"github.com/go-chi/chi"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
r.Get("/page", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render page.html error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :9090")
|
||||
http.ListenAndServe(":9090", r)
|
||||
|
||||
}
|
14
_examples/go-chi/views/index.html
Normal file
14
_examples/go-chi/views/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{{define "head"}}
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is content!!!!</h1>
|
||||
<p>123 + 333 = {{call $.add 123 333}}</p>
|
||||
<hr>
|
||||
<p><a href="/page">Page render</a></p>
|
||||
{{end}}
|
1
_examples/go-chi/views/layouts/footer.html
Normal file
1
_examples/go-chi/views/layouts/footer.html
Normal file
@@ -0,0 +1 @@
|
||||
Copyright ©2018 <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
15
_examples/go-chi/views/layouts/master.html
Normal file
15
_examples/go-chi/views/layouts/master.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
19
_examples/go-chi/views/page.html
Normal file
19
_examples/go-chi/views/page.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- /views/page.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a href="/"><- Back home!</a>
|
||||
<hr>
|
||||
This page not use master, Render code:
|
||||
<pre>ctx.HTML(200, "page.html", gin.H{})</pre>
|
||||
<br>
|
||||
"page.html" - add extension ".html" will render without master.
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
41
_examples/gorice/README.md
Normal file
41
_examples/gorice/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Basic
|
||||
Exmaple for gin template
|
||||
|
||||
|
||||
# Install
|
||||
```go
|
||||
go get github.com/GeertJohan/go.rice
|
||||
```
|
||||
|
||||
# Build & Run
|
||||
|
||||
```bash
|
||||
|
||||
#build
|
||||
go build -o bin/gorice
|
||||
|
||||
#run
|
||||
./bin/gorice
|
||||
|
||||
```
|
||||
|
||||
# Script
|
||||
```bash
|
||||
|
||||
./run.sh
|
||||
|
||||
```
|
||||
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
||||
# Links
|
||||
|
||||
- [gin template](https://github.com/foolin/gin-template)
|
||||
- [gin-template support go.rice](https://github.com/foolin/gin-template/tree/master/supports/gorice)
|
||||
- [gin framework](https://github.com/gin-gonic/gin)
|
||||
- [go.rice](https://github.com/GeertJohan/go.rice)
|
BIN
_examples/gorice/bin/gorice
Normal file
BIN
_examples/gorice/bin/gorice
Normal file
Binary file not shown.
53
_examples/gorice/main.go
Normal file
53
_examples/gorice/main.go
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/foolin/goview"
|
||||
"github.com/foolin/goview/supports/gorice"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
//static
|
||||
staticBox := rice.MustFindBox("static")
|
||||
staticFileServer := http.StripPrefix("/static/", http.FileServer(staticBox.HTTPBox()))
|
||||
http.Handle("/static/", staticFileServer)
|
||||
|
||||
//new view engine
|
||||
gv := gorice.New(rice.MustFindBox("views"))
|
||||
//set engine for default instance
|
||||
goview.Use(gv)
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Index title!",
|
||||
"add": func(a int, b int) int {
|
||||
return a + b
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
http.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := goview.Render(w, http.StatusOK, "page.html", goview.M{"title": "Page file title!!"})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render page.html error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :9090")
|
||||
http.ListenAndServe(":9090", nil)
|
||||
}
|
10
_examples/gorice/run.sh
Normal file
10
_examples/gorice/run.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#rice embed-go
|
||||
#echo " => rice embed-go"
|
||||
|
||||
go build -o bin/gorice
|
||||
echo " => go build -o bin/gorice"
|
||||
|
||||
echo " => ./bin/gorice"
|
||||
./bin/gorice
|
8950
_examples/gorice/static/css/bootstrap.css
vendored
Normal file
8950
_examples/gorice/static/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
_examples/gorice/static/css/bootstrap.css.map
Normal file
1
_examples/gorice/static/css/bootstrap.css.map
Normal file
File diff suppressed because one or more lines are too long
7
_examples/gorice/static/css/bootstrap.min.css
vendored
Normal file
7
_examples/gorice/static/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
_examples/gorice/static/css/bootstrap.min.css.map
Normal file
1
_examples/gorice/static/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
BIN
_examples/gorice/static/img/gopher.png
Normal file
BIN
_examples/gorice/static/img/gopher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
13
_examples/gorice/views/index.html
Normal file
13
_examples/gorice/views/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{{define "head"}}
|
||||
{{end}}
|
||||
|
||||
|
||||
{{define "content"}}
|
||||
<div class="shadow-lg p-3 mb-5 bg-white rounded">
|
||||
<h1 class="display-4">Hello template!</h1>
|
||||
<img src="/static/img/gopher.png" alt="Gopher">
|
||||
<p class="py-3">This is example for template support go.rice.</p>
|
||||
<hr class="my-4">
|
||||
<a class="btn btn-primary btn-lg" href="/page" role="button">Enter Page</a>
|
||||
</div>
|
||||
{{end}}
|
1
_examples/gorice/views/layouts/footer.html
Normal file
1
_examples/gorice/views/layouts/footer.html
Normal file
@@ -0,0 +1 @@
|
||||
Copyright ©2018 <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
26
_examples/gorice/views/layouts/master.html
Normal file
26
_examples/gorice/views/layouts/master.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
|
||||
|
||||
<title>{{.title}}</title>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container py-5">
|
||||
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
35
_examples/gorice/views/page.html
Normal file
35
_examples/gorice/views/page.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!-- /views/page.html -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
|
||||
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container py-5">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">Home</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Page</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<hr>
|
||||
<p class="text-justify">
|
||||
This page not use master, Render code:
|
||||
<pre><code>goview.Render(200, "page.html", goview.M{})</code></pre>
|
||||
<br>
|
||||
"page.html" - add extension ".html" will render without master.
|
||||
</p>
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
_examples/multiple/README.md
Normal file
14
_examples/multiple/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Multiple
|
||||
Exmaple for gin template, font end and back end.
|
||||
|
||||
# Run
|
||||
```go
|
||||
go run main.go
|
||||
```
|
||||
|
||||
# View
|
||||
Use the browser to visit the following url:
|
||||
```
|
||||
http://127.0.0.1:9090
|
||||
```
|
||||
|
69
_examples/multiple/main.go
Normal file
69
_examples/multiple/main.go
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/foolin/goview"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
gvFront := goview.New(goview.Config{
|
||||
Root: "views/frontend",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{"partials/ad"},
|
||||
Funcs: template.FuncMap{
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := gvFront.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Frontend title!",
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
//=========== Backend ===========//
|
||||
|
||||
gvBackend := goview.New(goview.Config{
|
||||
Root: "views/backend",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{},
|
||||
Funcs: template.FuncMap{
|
||||
"copy": func() string {
|
||||
return time.Now().Format("2006")
|
||||
},
|
||||
},
|
||||
DisableCache: true,
|
||||
})
|
||||
|
||||
http.HandleFunc("/admin/", func(w http.ResponseWriter, r *http.Request) {
|
||||
err := gvBackend.Render(w, http.StatusOK, "index", goview.M{
|
||||
"title": "Backend title!",
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Render index error: %v!", err)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Printf("Server start on :9090")
|
||||
http.ListenAndServe(":9090", nil)
|
||||
}
|
5
_examples/multiple/views/backend/index.html
Normal file
5
_examples/multiple/views/backend/index.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is backend!!!!</h1>
|
||||
<hr>
|
||||
<p><a href="/">Go to frontend</a></p>
|
||||
{{end}}
|
1
_examples/multiple/views/backend/layouts/footer.html
Normal file
1
_examples/multiple/views/backend/layouts/footer.html
Normal file
@@ -0,0 +1 @@
|
||||
Copyright © {{copy}} <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
4
_examples/multiple/views/backend/layouts/head.html
Normal file
4
_examples/multiple/views/backend/layouts/head.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
15
_examples/multiple/views/backend/layouts/master.html
Normal file
15
_examples/multiple/views/backend/layouts/master.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{include "layouts/head"}}
|
||||
</head>
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
5
_examples/multiple/views/frontend/index.html
Normal file
5
_examples/multiple/views/frontend/index.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{{define "content"}}
|
||||
<h1 class="hello">This is frontend!!!!</h1>
|
||||
<hr>
|
||||
<p><a href="/admin/">Go to backend</a></p>
|
||||
{{end}}
|
1
_examples/multiple/views/frontend/layouts/footer.html
Normal file
1
_examples/multiple/views/frontend/layouts/footer.html
Normal file
@@ -0,0 +1 @@
|
||||
Copyright © {{copy}} <a href="https://github.com/foolin" target="_blank">Foolin</a>
|
4
_examples/multiple/views/frontend/layouts/head.html
Normal file
4
_examples/multiple/views/frontend/layouts/head.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<style>
|
||||
.hello{ color: red;}
|
||||
hr{ border: 1px #ccc dashed;}
|
||||
</style>
|
17
_examples/multiple/views/frontend/layouts/master.html
Normal file
17
_examples/multiple/views/frontend/layouts/master.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- /views/admin/master.html -->
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
{{include "layouts/head"}}
|
||||
</head>
|
||||
<body>
|
||||
{{template "content" .}}
|
||||
<hr>
|
||||
{{template "ad" .}}
|
||||
<hr>
|
||||
{{include "layouts/footer"}}
|
||||
</body>
|
||||
</html>
|
3
_examples/multiple/views/frontend/partials/ad.html
Normal file
3
_examples/multiple/views/frontend/partials/ad.html
Normal file
@@ -0,0 +1,3 @@
|
||||
{{define "ad"}}
|
||||
<p>[AD: <a href="https://github.com/foolin" target="_blank">Wellcome to fontend!</a>]</p>
|
||||
{{end}}
|
20
go.mod
Normal file
20
go.mod
Normal file
@@ -0,0 +1,20 @@
|
||||
module github.com/foolin/goview
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/GeertJohan/go.rice v1.0.0
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
|
||||
github.com/gin-gonic/gin v1.3.0
|
||||
github.com/go-chi/chi v4.0.2+incompatible // indirect
|
||||
github.com/golang/protobuf v1.3.1 // indirect
|
||||
github.com/labstack/echo v3.3.10+incompatible
|
||||
github.com/labstack/gommon v0.2.8 // indirect
|
||||
github.com/mattn/go-colorable v0.1.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.7 // indirect
|
||||
github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a // indirect
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.2 // indirect
|
||||
)
|
21
instance.go
Normal file
21
instance.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package goview
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var instance *ViewEngine
|
||||
|
||||
// Use setting default instance engine
|
||||
func Use(engine *ViewEngine) {
|
||||
instance = engine
|
||||
}
|
||||
|
||||
// Render render view template with default instance
|
||||
func Render(w http.ResponseWriter, status int, name string, data interface{}) error {
|
||||
if instance == nil {
|
||||
instance = Default()
|
||||
//return fmt.Errorf("instance not yet initialized, please call Init() first before Render()")
|
||||
}
|
||||
return instance.Render(w, status, name, data)
|
||||
}
|
52
supports/echoview/echoview.go
Normal file
52
supports/echoview/echoview.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package echoview
|
||||
|
||||
import (
|
||||
"github.com/foolin/goview"
|
||||
"github.com/labstack/echo"
|
||||
"io"
|
||||
)
|
||||
|
||||
const templateEngineKey = "foolin-goview-echoview"
|
||||
|
||||
type ViewEngine struct {
|
||||
*goview.ViewEngine
|
||||
}
|
||||
|
||||
func New(config goview.Config) *ViewEngine {
|
||||
return &ViewEngine{
|
||||
ViewEngine: goview.New(config),
|
||||
}
|
||||
}
|
||||
|
||||
func Default() *ViewEngine {
|
||||
return New(goview.DefaultConfig)
|
||||
}
|
||||
|
||||
func (e *ViewEngine) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
|
||||
return e.RenderWriter(w, name, data)
|
||||
}
|
||||
|
||||
// You should use helper func `Middleware()` to set the supplied
|
||||
// TemplateEngine and make `Render()` work validly.
|
||||
func Render(ctx echo.Context, code int, name string, data interface{}) error {
|
||||
if val := ctx.Get(templateEngineKey); val != nil {
|
||||
if e, ok := val.(*ViewEngine); ok {
|
||||
return e.Render(ctx.Response().Writer, name, data, ctx)
|
||||
}
|
||||
}
|
||||
return ctx.Render(code, name, data)
|
||||
}
|
||||
|
||||
//New gin middleware for func `goview.Render()`
|
||||
func NewMiddleware(config goview.Config) echo.MiddlewareFunc {
|
||||
return Middleware(New(config))
|
||||
}
|
||||
|
||||
func Middleware(e *ViewEngine) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
c.Set(templateEngineKey, e)
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
78
supports/ginview/ginview.go
Normal file
78
supports/ginview/ginview.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package ginview
|
||||
|
||||
import (
|
||||
"github.com/foolin/goview"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/render"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const templateEngineKey = "foolin-goview-ginview"
|
||||
|
||||
type ViewEngine struct {
|
||||
*goview.ViewEngine
|
||||
}
|
||||
|
||||
type ViewRender struct {
|
||||
Engine *ViewEngine
|
||||
Name string
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func New(config goview.Config) *ViewEngine {
|
||||
return &ViewEngine{
|
||||
ViewEngine: goview.New(config),
|
||||
}
|
||||
}
|
||||
|
||||
func Default() *ViewEngine {
|
||||
return New(goview.DefaultConfig)
|
||||
}
|
||||
|
||||
func (e *ViewEngine) Instance(name string, data interface{}) render.Render {
|
||||
return ViewRender{
|
||||
Engine: e,
|
||||
Name: name,
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ViewEngine) HTML(ctx *gin.Context, code int, name string, data interface{}) {
|
||||
instance := e.Instance(name, data)
|
||||
ctx.Render(code, instance)
|
||||
}
|
||||
|
||||
// Render (YAML) marshals the given interface object and writes data with custom ContentType.
|
||||
func (v ViewRender) Render(w http.ResponseWriter) error {
|
||||
return v.Engine.RenderWriter(w, v.Name, v.Data)
|
||||
}
|
||||
|
||||
func (v ViewRender) WriteContentType(w http.ResponseWriter) {
|
||||
header := w.Header()
|
||||
if val := header["Content-Type"]; len(val) == 0 {
|
||||
header["Content-Type"] = goview.HtmlContentType
|
||||
}
|
||||
}
|
||||
|
||||
//New gin middleware for func `gintemplate.HTML()`
|
||||
func NewMiddleware(config goview.Config) gin.HandlerFunc {
|
||||
return Middleware(New(config))
|
||||
}
|
||||
|
||||
func Middleware(e *ViewEngine) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Set(templateEngineKey, e)
|
||||
}
|
||||
}
|
||||
|
||||
// You should use helper func `Middleware()` to set the supplied
|
||||
// TemplateEngine and make `HTML()` work validly.
|
||||
func HTML(ctx *gin.Context, code int, name string, data interface{}) {
|
||||
if val, ok := ctx.Get(templateEngineKey); ok {
|
||||
if e, ok := val.(*ViewEngine); ok {
|
||||
e.HTML(ctx, code, name, data)
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.HTML(code, name, data)
|
||||
}
|
34
supports/gorice/gorice.go
Normal file
34
supports/gorice/gorice.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package gorice
|
||||
|
||||
import (
|
||||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/foolin/goview"
|
||||
)
|
||||
|
||||
/**
|
||||
New gin template engine, default views root.
|
||||
*/
|
||||
func New(viewsRootBox *rice.Box) *goview.ViewEngine {
|
||||
return NewWithConfig(viewsRootBox, goview.DefaultConfig)
|
||||
}
|
||||
|
||||
/**
|
||||
New gin template engine
|
||||
Important!!! The viewsRootBox's name and config.Root must be consistent.
|
||||
*/
|
||||
func NewWithConfig(viewsRootBox *rice.Box, config goview.Config) *goview.ViewEngine {
|
||||
config.Root = viewsRootBox.Name()
|
||||
engine := goview.New(config)
|
||||
engine.SetFileHandler(FileHandler(viewsRootBox))
|
||||
return engine
|
||||
}
|
||||
|
||||
/**
|
||||
Support go.rice file handler
|
||||
*/
|
||||
func FileHandler(viewsRootBox *rice.Box) goview.FileHandler {
|
||||
return func(config goview.Config, tplFile string) (content string, err error) {
|
||||
// get file contents as string
|
||||
return viewsRootBox.String(tplFile + config.Extension)
|
||||
}
|
||||
}
|
193
view.go
Normal file
193
view.go
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2018 Foolin. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a MIT style
|
||||
* license that can be found in the LICENSE file.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Goview is a lightweight, simple and easy view based on golang html/template for building Go web application.
|
||||
See https://github.com/foolin/goview for more information.
|
||||
*/
|
||||
package goview
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//const templateEngineKey = "httpx_templateEngine"
|
||||
var HtmlContentType = []string{"text/html; charset=utf-8"}
|
||||
|
||||
var DefaultConfig = Config{
|
||||
Root: "views",
|
||||
Extension: ".html",
|
||||
Master: "layouts/master",
|
||||
Partials: []string{},
|
||||
Funcs: make(template.FuncMap),
|
||||
DisableCache: false,
|
||||
Delims: Delims{Left: "{{", Right: "}}"},
|
||||
}
|
||||
|
||||
type ViewEngine struct {
|
||||
config Config
|
||||
tplMap map[string]*template.Template
|
||||
tplMutex sync.RWMutex
|
||||
fileHandler FileHandler
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Root string //view root
|
||||
Extension string //template extension
|
||||
Master string //template master
|
||||
Partials []string //template partial, such as head, foot
|
||||
Funcs template.FuncMap //template functions
|
||||
DisableCache bool //disable cache, debug mode
|
||||
Delims Delims //delimeters
|
||||
}
|
||||
|
||||
type M map[string]interface{}
|
||||
|
||||
type Delims struct {
|
||||
Left string
|
||||
Right string
|
||||
}
|
||||
|
||||
type FileHandler func(config Config, tplFile string) (content string, err error)
|
||||
|
||||
func New(config Config) *ViewEngine {
|
||||
return &ViewEngine{
|
||||
config: config,
|
||||
tplMap: make(map[string]*template.Template),
|
||||
tplMutex: sync.RWMutex{},
|
||||
fileHandler: DefaultFileHandler(),
|
||||
}
|
||||
}
|
||||
|
||||
func Default() *ViewEngine {
|
||||
return New(DefaultConfig)
|
||||
}
|
||||
|
||||
func (e *ViewEngine) Render(w http.ResponseWriter, statusCode int, name string, data interface{}) error {
|
||||
header := w.Header()
|
||||
if val := header["Content-Type"]; len(val) == 0 {
|
||||
header["Content-Type"] = HtmlContentType
|
||||
}
|
||||
w.WriteHeader(statusCode)
|
||||
return e.executeRender(w, name, data)
|
||||
}
|
||||
|
||||
func (e *ViewEngine) RenderWriter(w io.Writer, name string, data interface{}) error {
|
||||
return e.executeRender(w, name, data)
|
||||
}
|
||||
|
||||
func (e *ViewEngine) executeRender(out io.Writer, name string, data interface{}) error {
|
||||
useMaster := true
|
||||
if filepath.Ext(name) == e.config.Extension {
|
||||
useMaster = false
|
||||
name = strings.TrimSuffix(name, e.config.Extension)
|
||||
|
||||
}
|
||||
return e.executeTemplate(out, name, data, useMaster)
|
||||
}
|
||||
|
||||
func (e *ViewEngine) executeTemplate(out io.Writer, name string, data interface{}, useMaster bool) error {
|
||||
var tpl *template.Template
|
||||
var err error
|
||||
var ok bool
|
||||
|
||||
allFuncs := make(template.FuncMap, 0)
|
||||
allFuncs["include"] = func(layout string) (template.HTML, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
err := e.executeTemplate(buf, layout, data, false)
|
||||
return template.HTML(buf.String()), err
|
||||
}
|
||||
|
||||
// Get the plugin collection
|
||||
for k, v := range e.config.Funcs {
|
||||
allFuncs[k] = v
|
||||
}
|
||||
|
||||
e.tplMutex.RLock()
|
||||
tpl, ok = e.tplMap[name]
|
||||
e.tplMutex.RUnlock()
|
||||
|
||||
exeName := name
|
||||
if useMaster && e.config.Master != "" {
|
||||
exeName = e.config.Master
|
||||
}
|
||||
|
||||
if !ok || e.config.DisableCache {
|
||||
tplList := make([]string, 0)
|
||||
if useMaster {
|
||||
//render()
|
||||
if e.config.Master != "" {
|
||||
tplList = append(tplList, e.config.Master)
|
||||
}
|
||||
}
|
||||
tplList = append(tplList, name)
|
||||
tplList = append(tplList, e.config.Partials...)
|
||||
|
||||
// Loop through each template and test the full path
|
||||
tpl = template.New(name).Funcs(allFuncs).Delims(e.config.Delims.Left, e.config.Delims.Right)
|
||||
for _, v := range tplList {
|
||||
var data string
|
||||
data, err = e.fileHandler(e.config, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var tmpl *template.Template
|
||||
if v == name {
|
||||
tmpl = tpl
|
||||
} else {
|
||||
tmpl = tpl.New(v)
|
||||
}
|
||||
_, err = tmpl.Parse(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ViewEngine render parser name:%v, error: %v", v, err)
|
||||
}
|
||||
}
|
||||
e.tplMutex.Lock()
|
||||
e.tplMap[name] = tpl
|
||||
e.tplMutex.Unlock()
|
||||
}
|
||||
|
||||
// Display the content to the screen
|
||||
err = tpl.Funcs(allFuncs).ExecuteTemplate(out, exeName, data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ViewEngine execute template error: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *ViewEngine) SetFileHandler(handle FileHandler) {
|
||||
if handle == nil {
|
||||
panic("FileHandler can't set nil!")
|
||||
}
|
||||
e.fileHandler = handle
|
||||
}
|
||||
|
||||
func DefaultFileHandler() FileHandler {
|
||||
return func(config Config, tplFile string) (content string, err error) {
|
||||
// Get the absolute path of the root template
|
||||
path, err := filepath.Abs(config.Root + string(os.PathSeparator) + tplFile + config.Extension)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ViewEngine path:%v error: %v", path, err)
|
||||
}
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ViewEngine render read name:%v, path:%v, error: %v", tplFile, path, err)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user