add 'iris.Blocks' template engine

read more about its features at: https://github.com/kataras/blocks
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-08-05 06:46:45 +03:00
parent 6844be57ea
commit b363492cca
No known key found for this signature in database
GPG Key ID: 5DBE766BD26A54E7
24 changed files with 631 additions and 40 deletions

View File

@ -359,7 +359,9 @@ Response:
Other Improvements:
- Add [Ace](_examples/view/template_ace_0) template parser to the view engine and other minor improvements. <!-- a new html/template-based engine, with a different layout-page syntax but better performance, follows this week. -->
- Add [Blocks](_examples/view/template_blocks_0) template engine. <!-- Reminder for @kataras: follow https://github.com/flosch/pongo2/pull/236#issuecomment-668950566 discussion so we can get back on using the original pongo2 repository as they fixed the issue about an incompatible 3rd party package (although they need more fixes, that's why I commented there) -->
- Add [Ace](_examples/view/template_ace_0) template parser to the view engine and other minor improvements.
- Fix huge repo size of 55.7MB, which slows down the overall Iris installation experience. Now, go-get performs ~3 times faster. I 've managed it using the [bfg-repo-cleaner](https://github.com/rtyley/bfg-repo-cleaner) tool - an alternative to git-filter-branch command. Watch the small gif below to learn how:

21
NOTICE
View File

@ -6,7 +6,7 @@
The following 3rd-party software packages may be used by or distributed with iris. This document was automatically generated by FOSSA on 2020-5-8; any information relevant to third-party vendors listed below are collected using common, reasonable means.
Revision ID: d1c07411df0bb21f6b21f5b5d9325fac6f29c911
Revision ID: 6844be57ea3a098ef28fce3468959bf5bb6f735a
----------------- ----------------- ------------------------------------------
Package Version Website
@ -20,12 +20,15 @@ Revision ID: d1c07411df0bb21f6b21f5b5d9325fac6f29c911
bbolt a8af23b57f672fe https://github.com/etcd-io/bbolt
f05637de531bba5
aa00013364
blackfriday 48b3da6a6f3865c https://github.com/iris-contrib/
7eb1eba96d74cf0 blackfriday
a16f63faca
bluemonday 0a75d7616912ab9 https://github.com/microcosm-cc/
beb9cc6f7283ec1 bluemonday
blackfriday d3b5b032dc8e892 https://github.com/russross/blackfriday
7d31a5071b56e14
c89f045135
bluemonday 0a75d7616912ab9 https://github.com/microcosm-cc/bluemonday
beb9cc6f7283ec1
917c61b135
blocks 39dac49c58634f7 https://github.com/kataras/blocks
9bc54fcd5c299da
fe08dbd738
brotli c3da72aa01ed78f https://github.com/andybalholm/brotli
164593b9624fd91
d25082d2d2
@ -71,9 +74,9 @@ Revision ID: d1c07411df0bb21f6b21f5b5d9325fac6f29c911
pio 2e3d576cc65913a https://github.com/kataras/pio
dd6106f1ce02837
2c7e6d943c
pongo2 0738cc45f23da6a https://github.com/iris-contrib/pongo2
8c14959779a75d3
37b7944fb6
pongo2 5abacdfa4915f8a https://github.com/flosch/pongo2
fb6de6231455488
066273bea6
protobuf 6c66de79d66478d https://github.com/golang/protobuf
166c7ea05f5d2cc
af016fbd6b

View File

@ -103,6 +103,8 @@
* [Inject Data Between Handlers](view/context-view-data/main.go)
* [Embedding Templates Into App Executable File](view/embedding-templates-into-app/main.go)
* [Write to a custom `io.Writer`](view/write-to)
* [Blocks](view/template_blocks_0)
* [Blocks Embedded](view/template_blocks_1_embedded)
* [Pug: Greeting](view/template_pug_0)
* [Pug: `Actions`](view/template_pug_1)
* [Pug: `Includes`](view/template_pug_2)

View File

@ -15,8 +15,7 @@ func main() {
// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata
// $ go-bindata ./templates/...
// $ go build
// $ ./embedding-templates-into-app
// $ go run .
// html files are not used, you can delete the folder and run the example.
tmpl.Binary(Asset, AssetNames) // <-- IMPORTANT

View File

@ -0,0 +1,35 @@
package main
import "github.com/kataras/iris/v12"
func main() {
app := iris.New()
// Read about its syntax at: https://github.com/kataras/blocks
app.RegisterView(iris.Blocks("./views", ".html").Reload(true))
app.Get("/", index)
app.Get("/500", internalServerError)
app.Listen(":8080")
}
func index(ctx iris.Context) {
data := iris.Map{
"Title": "Page Title",
}
ctx.ViewLayout("main")
ctx.View("index", data)
}
func internalServerError(ctx iris.Context) {
ctx.StatusCode(iris.StatusInternalServerError)
data := iris.Map{
"Code": iris.StatusInternalServerError,
"Message": "Internal Server Error",
}
ctx.ViewLayout("error")
ctx.View("500", data)
}

View File

@ -0,0 +1,12 @@
<!-- You can define more than one block.
The default one is "content" which should be the main template's body.
So, even if it's missing (see index.html), it's added automatically by the view engine.
When you need to define more than one block, you have to be more specific:
-->
{{ define "content" }}
<h1>Internal Server Error</h1>
{{ end }}
{{ define "message" }}
<p style="color:red;">{{.Message}}</p>
{{ end }}

View File

@ -0,0 +1 @@
<h1>Index Body</h1>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Code}}</title>
</head>
<body>
{{ template "content" .}}
{{block "message" .}}{{end}}
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ if .Title }}{{ .Title }}{{ else }}Default Main Title{{ end }}</title>
</head>
<body>
{{ template "content" . }}
<footer>{{ partial "partials/footer" .}}</footer>
</body>
</html>

View File

@ -0,0 +1 @@
<h3>Footer Partial</h3>

View File

@ -0,0 +1,343 @@
// Code generated by go-bindata. (@generated) DO NOT EDIT.
//Package main generated by go-bindata.// sources:
// ../template_blocks_0/views/500.html
// ../template_blocks_0/views/index.html
// ../template_blocks_0/views/layouts/error.html
// ../template_blocks_0/views/layouts/main.html
// ../template_blocks_0/views/partials/footer.html
package main
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("read %q: %v", name, err)
}
if clErr != nil {
return nil, err
}
return buf.Bytes(), nil
}
type asset struct {
bytes []byte
info os.FileInfo
}
type bindataFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
// Name return file name
func (fi bindataFileInfo) Name() string {
return fi.name
}
// Size return file size
func (fi bindataFileInfo) Size() int64 {
return fi.size
}
// Mode return file mode
func (fi bindataFileInfo) Mode() os.FileMode {
return fi.mode
}
// ModTime return file modify time
func (fi bindataFileInfo) ModTime() time.Time {
return fi.modTime
}
// IsDir return file whether a directory
func (fi bindataFileInfo) IsDir() bool {
return fi.mode&os.ModeDir != 0
}
// Sys return file is sys mode
func (fi bindataFileInfo) Sys() interface{} {
return nil
}
var _views500Html = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x8f\xb1\x4e\xf3\x30\x14\x85\xf7\x48\x79\x87\xfb\x67\xe9\x8f\xd4\xa4\xea\x5a\x42\x37\x06\x06\xa6\x22\x21\x46\xc7\x3e\xad\x2d\x9c\x7b\x23\xdb\x49\x89\xa2\xbc\x3b\x6a\x5a\x04\x2c\xac\xf7\x7e\xe7\x3b\x3a\xf5\xbf\xb2\xa4\x37\xe9\x49\x2b\x26\x83\xa3\x63\x50\x2b\x01\x94\xac\x62\x12\x06\x35\x5e\xf4\x7b\x95\x67\x2f\x16\x17\x40\xf5\x3e\x2d\x77\x17\xa9\xd0\xc2\x09\x9c\x0a\x3a\x5b\xa7\x2d\x45\x2b\xbd\x37\xd4\x5c\xd2\xa0\x56\x39\xa6\x84\xb6\xf3\x2a\x61\x15\xa9\x11\x33\x56\x79\x76\x90\x35\x61\x00\x93\x3b\x92\x4b\xab\x48\xad\x8b\xd1\xf1\x89\xfe\x47\x80\x1c\x1b\x7c\x54\x36\xb5\xfe\x6e\x7d\x7d\x2b\x63\x60\x48\xf5\x49\x5a\x95\x9c\x56\xde\x8f\xd4\x8c\x4b\xc3\xe0\x70\x26\xf0\xc9\x31\xaa\x3c\x7b\xb5\x60\x1a\xa5\x27\x06\x0c\x25\xf9\x63\xce\x7a\xe1\xac\x1a\x70\xe1\x9a\x1b\x13\x3b\x68\x77\x74\x7a\x97\x67\x65\xb9\xcf\xb3\x69\xfa\x52\x7c\x0f\x9d\xe7\x3c\xab\xed\x76\xff\xc4\x09\x81\x95\xa7\x03\xc2\x80\x40\x8f\x21\x48\xa8\x37\x76\x7b\xcd\x81\xcd\x82\xfe\x92\xb4\x88\x51\x9d\x70\x93\x74\x14\xd3\xe8\xf1\x50\x68\xf1\x12\x76\x01\xe6\xbe\xd8\x4f\x53\xf5\x7c\xa5\xe6\xb9\xde\x74\x3f\x65\x9f\x01\x00\x00\xff\xff\xb3\xfa\x91\xbd\xaa\x01\x00\x00")
func views500HtmlBytes() ([]byte, error) {
return bindataRead(
_views500Html,
"views/500.html",
)
}
func views500Html() (*asset, error) {
bytes, err := views500HtmlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "views/500.html", size: 426, mode: os.FileMode(438), modTime: time.Unix(1596515591, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _viewsIndexHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb2\xc9\x30\xb4\xf3\xcc\x4b\x49\xad\x50\x70\xca\x4f\xa9\xb4\xd1\xcf\x30\xb4\x03\x04\x00\x00\xff\xff\xcc\x4b\x98\x69\x13\x00\x00\x00")
func viewsIndexHtmlBytes() ([]byte, error) {
return bindataRead(
_viewsIndexHtml,
"views/index.html",
)
}
func viewsIndexHtml() (*asset, error) {
bytes, err := viewsIndexHtmlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "views/index.html", size: 19, mode: os.FileMode(438), modTime: time.Unix(1596514225, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _viewsLayoutsErrorHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x90\xbf\x4e\xf3\x40\x10\xc4\x7b\x4b\x7e\x87\xfd\xb6\xfe\x6c\x43\x47\x71\xe7\x26\x40\x0b\x45\x28\x28\x37\x77\xa3\xf8\xc4\xfd\x89\xe2\x55\x22\x74\xf2\xbb\xa3\x18\x83\x44\xb5\xda\x99\x9f\x66\x57\x63\xfe\x3d\xbe\xec\xf6\xef\xaf\x4f\x34\x69\x8a\x63\xdb\x98\xdb\xa4\x28\xf9\x68\x19\x99\x57\x05\xe2\xc7\xb6\x21\x22\x32\x09\x2a\xe4\x26\x39\xcf\x50\xcb\x6f\xfb\xe7\xee\x81\xff\x78\x59\x12\x2c\x5f\x02\xae\xa7\x72\x56\x26\x57\xb2\x22\xab\xe5\x6b\xf0\x3a\x59\x8f\x4b\x70\xe8\xd6\xe5\x3f\x85\x1c\x34\x48\xec\x66\x27\x11\xf6\xbe\xbf\xfb\xcd\xd2\xa0\x11\x63\xad\xfd\xae\x78\x2c\x8b\x19\xbe\x85\xb6\x31\xc3\xf6\x8e\x39\x14\xff\xb9\xe1\xb5\x92\x22\x9d\xa2\x28\x88\xb7\x8b\x4c\xfd\xb2\xb4\xcd\x0f\x70\x88\xc5\x7d\x10\x27\xcc\xb3\x1c\xb1\x9a\xb5\x22\xfb\x1b\x63\x86\x2d\xcb\x0c\x6b\x0b\x5f\x01\x00\x00\xff\xff\xbe\xb7\x11\x67\x15\x01\x00\x00")
func viewsLayoutsErrorHtmlBytes() ([]byte, error) {
return bindataRead(
_viewsLayoutsErrorHtml,
"views/layouts/error.html",
)
}
func viewsLayoutsErrorHtml() (*asset, error) {
bytes, err := viewsLayoutsErrorHtmlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "views/layouts/error.html", size: 277, mode: os.FileMode(438), modTime: time.Unix(1596514340, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _viewsLayoutsMainHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x54\x90\xb1\x4e\xf4\x30\x10\x84\xfb\x48\x79\x87\xf9\x5d\xff\x49\xa0\xa3\xb0\xd3\x70\xd0\x21\x28\x42\x41\xb9\x24\x1b\x62\xc9\x71\xa2\x64\xb9\x13\xb2\xfc\xee\xc8\x39\x0b\xe9\x2a\xcf\xfa\xb3\x66\xc6\xab\xff\x9d\x5e\x1f\xbb\x8f\xb7\x27\x4c\x32\xbb\xb6\x2c\x74\x3a\xe1\xc8\x7f\x19\xc5\x5e\x1d\x37\x4c\x43\x5b\x16\x00\xa0\x67\x16\x42\x3f\xd1\xb6\xb3\x18\xf5\xde\x3d\x57\x0f\xea\x86\x79\x9a\xd9\xa8\xb3\xe5\xcb\xba\x6c\xa2\xd0\x2f\x5e\xd8\x8b\x51\x17\x3b\xc8\x64\x06\x3e\xdb\x9e\xab\x63\xf8\x0f\xeb\xad\x58\x72\xd5\xde\x93\x63\x73\x5f\xdf\xfd\x79\x89\x15\xc7\x6d\x08\xb0\x23\xea\x2e\x0d\x88\x31\x84\x1b\xcd\x6e\x4f\xea\xc4\x23\x7d\x3b\xc1\x0b\x59\x8f\x03\x27\xe6\x07\xc4\xa8\x9b\xab\x4f\x59\xe8\x26\xff\x42\x7f\x2e\xc3\x4f\x4e\x09\x01\xc2\xf3\xea\x48\x18\x2a\x17\x55\xa8\x11\x63\x59\x94\x85\x1e\x97\x45\x78\x4b\x25\x56\xda\x52\x4f\xa8\x2c\xf6\xe6\xca\x14\xea\x14\x92\x1f\xa6\x94\xec\xae\x9b\x63\x9d\xbf\x01\x00\x00\xff\xff\x44\x95\x63\x98\x5e\x01\x00\x00")
func viewsLayoutsMainHtmlBytes() ([]byte, error) {
return bindataRead(
_viewsLayoutsMainHtml,
"views/layouts/main.html",
)
}
func viewsLayoutsMainHtml() (*asset, error) {
bytes, err := viewsLayoutsMainHtmlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "views/layouts/main.html", size: 350, mode: os.FileMode(438), modTime: time.Unix(1596514155, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _viewsPartialsFooterHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb2\xc9\x30\xb6\x73\xcb\xcf\x2f\x49\x2d\x52\x08\x48\x2c\x2a\xc9\x4c\xcc\xb1\xd1\xcf\x30\xb6\x03\x04\x00\x00\xff\xff\x08\xe6\xe9\xf8\x17\x00\x00\x00")
func viewsPartialsFooterHtmlBytes() ([]byte, error) {
return bindataRead(
_viewsPartialsFooterHtml,
"views/partials/footer.html",
)
}
func viewsPartialsFooterHtml() (*asset, error) {
bytes, err := viewsPartialsFooterHtmlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "views/partials/footer.html", size: 23, mode: os.FileMode(438), modTime: time.Unix(1596514093, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
}
return a.bytes, nil
}
return nil, fmt.Errorf("Asset %s not found", name)
}
// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
a, err := Asset(name)
if err != nil {
panic("asset: Asset(" + name + "): " + err.Error())
}
return a
}
// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
}
return a.info, nil
}
return nil, fmt.Errorf("AssetInfo %s not found", name)
}
// AssetNames returns the names of the assets.
func AssetNames() []string {
names := make([]string, 0, len(_bindata))
for name := range _bindata {
names = append(names, name)
}
return names
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"views/500.html": views500Html,
"views/index.html": viewsIndexHtml,
"views/layouts/error.html": viewsLayoutsErrorHtml,
"views/layouts/main.html": viewsLayoutsMainHtml,
"views/partials/footer.html": viewsPartialsFooterHtml,
}
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
node := _bintree
if len(name) != 0 {
cannonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(cannonicalName, "/")
for _, p := range pathList {
node = node.Children[p]
if node == nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
}
}
if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
rv := make([]string, 0, len(node.Children))
for childName := range node.Children {
rv = append(rv, childName)
}
return rv, nil
}
type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"views": {nil, map[string]*bintree{
"500.html": {views500Html, map[string]*bintree{}},
"index.html": {viewsIndexHtml, map[string]*bintree{}},
"layouts": {nil, map[string]*bintree{
"error.html": {viewsLayoutsErrorHtml, map[string]*bintree{}},
"main.html": {viewsLayoutsMainHtml, map[string]*bintree{}},
}},
"partials": {nil, map[string]*bintree{
"footer.html": {viewsPartialsFooterHtml, map[string]*bintree{}},
}},
}},
}}
// RestoreAsset restores an asset under the given directory
func RestoreAsset(dir, name string) error {
data, err := Asset(name)
if err != nil {
return err
}
info, err := AssetInfo(name)
if err != nil {
return err
}
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
if err != nil {
return err
}
return nil
}
// RestoreAssets restores an asset under the given directory recursively
func RestoreAssets(dir, name string) error {
children, err := AssetDir(name)
// File
if err != nil {
return RestoreAsset(dir, name)
}
// Dir
for _, child := range children {
err = RestoreAssets(dir, filepath.Join(name, child))
if err != nil {
return err
}
}
return nil
}
func _filePath(dir, name string) string {
cannonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}

View File

@ -0,0 +1,40 @@
package main
import "github.com/kataras/iris/v12"
// $ go get -u github.com/go-bindata/go-bindata/v3/go-bindata
// $ go-bindata -prefix "../template_blocks_0" ../template_blocks_0/views/...
// $ go run .
// # OR go-bindata -prefix "../template_blocks_0/views" ../template_blocks_0/views/... with iris.Blocks("").Binary(...)
// System files are not used, you can optionally delete the folder and run the example now.
func main() {
app := iris.New()
app.RegisterView(iris.Blocks("./views", ".html").Binary(Asset, AssetNames))
app.Get("/", index)
app.Get("/500", internalServerError)
app.Listen(":8080")
}
func index(ctx iris.Context) {
data := iris.Map{
"Title": "Page Title",
}
ctx.ViewLayout("main")
ctx.View("index", data)
}
func internalServerError(ctx iris.Context) {
ctx.StatusCode(iris.StatusInternalServerError)
data := iris.Map{
"Code": iris.StatusInternalServerError,
"Message": "Internal Server Error",
}
ctx.ViewLayout("error")
ctx.View("500", data)
}

View File

@ -190,25 +190,29 @@ const NoLayout = view.NoLayout
var (
// HTML view engine.
// Shortcut of the kataras/iris/view.HTML.
// Shortcut of the view.HTML.
HTML = view.HTML
// Blocks view engine.
// Can be used as a faster alternative of the HTML engine.
// Shortcut of the view.Blocks.
Blocks = view.Blocks
// Django view engine.
// Shortcut of the kataras/iris/view.Django.
// Shortcut of the view.Django.
Django = view.Django
// Handlebars view engine.
// Shortcut of the kataras/iris/view.Handlebars.
// Shortcut of the view.Handlebars.
Handlebars = view.Handlebars
// Pug view engine.
// Shortcut of the kataras/iris/view.Pug.
// Shortcut of the view.Pug.
Pug = view.Pug
// Amber view engine.
// Shortcut of the kataras/iris/view.Amber.
// Shortcut of the view.Amber.
Amber = view.Amber
// Jet view engine.
// Shortcut of the kataras/iris/view.Jet.
// Shortcut of the view.Jet.
Jet = view.Jet
// Ace view engine.
// Shortcut of the kataras/iris/view.Ace.
// Shortcut of the view.Ace.
Ace = view.Ace
)

View File

@ -30,10 +30,10 @@ import (
"github.com/Shopify/goreferrer"
"github.com/fatih/structs"
"github.com/iris-contrib/blackfriday"
"github.com/iris-contrib/schema"
jsoniter "github.com/json-iterator/go"
"github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday/v2"
"github.com/vmihailenco/msgpack/v5"
"golang.org/x/net/publicsuffix"
"golang.org/x/time/rate"

3
go.mod
View File

@ -14,12 +14,12 @@ require (
github.com/gomodule/redigo v1.8.2
github.com/google/uuid v1.1.2-0.20200519141726-cb32006e483f
github.com/hashicorp/go-version v1.2.1
github.com/iris-contrib/blackfriday v2.0.0+incompatible
github.com/iris-contrib/httpexpect/v2 v2.0.5
github.com/iris-contrib/jade v1.1.4
github.com/iris-contrib/pongo2 v0.0.1
github.com/iris-contrib/schema v0.0.2
github.com/json-iterator/go v1.1.10
github.com/kataras/blocks v0.0.1
github.com/kataras/golog v0.0.18
github.com/kataras/neffos v0.0.16
github.com/kataras/pio v0.0.8
@ -28,6 +28,7 @@ require (
github.com/klauspost/compress v1.10.10
github.com/mediocregopher/radix/v3 v3.5.2
github.com/microcosm-cc/bluemonday v1.0.3
github.com/russross/blackfriday/v2 v2.0.1
github.com/ryanuber/columnize v2.1.0+incompatible
github.com/schollz/closestmatch v2.1.0+incompatible
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect

View File

@ -1,18 +1,21 @@
# View
Iris supports 7 template engines out-of-the-box, developers can still use any external golang template engine,
Iris supports 8 template engines out-of-the-box, developers can still use any external golang template engine,
as `Context.ResponseWriter()` is an `io.Writer`.
All of these six template engines have common features with common API,
like Layout, Template Funcs, Party-specific layout, partial rendering and more.
All template engines share a common API i.e.
Parse using embedded assets, Layouts and Party-specific layout, Template Funcs, Partial Render and more.
- The standard html, its template parser is the [golang.org/pkg/html/template/](https://golang.org/pkg/html/template/)
- Django, its template parser is the [github.com/iris-contrib/pongo2](https://github.com/iris-contrib/pongo2)
- Pug(Jade), its template parser is the [github.com/Joker/jade](https://github.com/Joker/jade)
- Handlebars, its template parser is the [github.com/aymerick/raymond](https://github.com/aymerick/raymond)
- Amber, its template parser is the [github.com/eknkc/amber](https://github.com/eknkc/amber)
- Jet, its template parser is the [github.com/CloudyKit/jet](https://github.com/CloudyKit/jet)
- Ace, its template parser is the [github.com/yosssi/ace](https://github.com/yosssi/ace)
| # | Name | Parser |
|:---|:-----------|----------|
| 1 | HTML | [html/template](https://pkg.go.dev/html/template) |
| 2 | Blocks | [kataras/blocks](https://github.com/kataras/blocks) |
| 3 | Django | [flosch/pongo2](https://github.com/flosch/pongo2) |
| 4 | Pug | [Joker/jade](https://github.com/Joker/jade) |
| 5 | Handlebars | [aymerick/raymond](https://github.com/aymerick/raymond) |
| 6 | Amber | [eknkc/amber](https://github.com/eknkc/amber) |
| 7 | Jet | [CloudyKit/jet](https://github.com/CloudyKit/jet) |
| 8 | Ace | [yosssi/ace](https://github.com/yosssi/ace) |
## Examples
@ -24,6 +27,8 @@ like Layout, Template Funcs, Party-specific layout, partial rendering and more.
- [The `url` tmpl func](https://github.com/kataras/iris/blob/master/_examples/view/template_html_4/main.go)
- [Inject Data Between Handlers](https://github.com/kataras/iris/blob/master/_examples/view/context-view-data/main.go)
- [Embedding Templates Into App Executable File](https://github.com/kataras/iris/blob/master/_examples/view/embedding-templates-into-app/main.go)
- [Blocks](https://github.com/kataras/iris/blob/master/_examples/view/template_blocks_0)
- [Blocks Embedded](https://github.com/kataras/iris/blob/master/_examples/view/template_blocks_1_embedded)
- [Greeting with Pug (Jade)`](view/template_pug_0)
- [Pug (Jade) Actions`](https://github.com/kataras/iris/blob/master/_examples/view/template_pug_1)
- [Pug (Jade) Includes`](https://github.com/kataras/iris/blob/master/_examples/view/template_pug_2)
@ -32,7 +37,7 @@ like Layout, Template Funcs, Party-specific layout, partial rendering and more.
- [Jet Embedded](https://github.com/kataras/iris/blob/master/_examples/view/template_jet_1_embedded)
- [Ace](https://github.com/kataras/iris/blob/master/_examples/view/template_ace_0)
You can serve [quicktemplate](https://github.com/valyala/quicktemplate) files too, simply by using the `context#ResponseWriter`, take a look at the [iris/_examples/view/quicktemplate](https://github.com/kataras/iris/tree/master/_examples/view/quicktemplate) example.
You can serve [quicktemplate](https://github.com/valyala/quicktemplate) files too, simply by using the `Context.ResponseWriter`, take a look at the [iris/_examples/view/quicktemplate](https://github.com/kataras/iris/tree/master/_examples/view/quicktemplate) example.
## Overview

View File

@ -10,6 +10,7 @@ import (
// Ace returns a new ace view engine.
// It shares the same exactly logic with the
// html view engine, it uses the same exactly configuration.
// The given "extension" MUST begin with a dot.
//
// Read more about the Ace Go Parser: https://github.com/yosssi/ace
func Ace(directory, extension string) *HTMLEngine {

View File

@ -29,6 +29,7 @@ type AmberEngine struct {
var _ Engine = (*AmberEngine)(nil)
// Amber creates and returns a new amber view engine.
// The given "extension" MUST begin with a dot.
func Amber(directory, extension string) *AmberEngine {
s := &AmberEngine{
directory: directory,

109
view/blocks.go Normal file
View File

@ -0,0 +1,109 @@
package view
import (
"html/template"
"io"
"github.com/kataras/blocks"
)
// BlocksEngine is an Iris view engine adapter for the blocks view engine.
// The blocks engine is based on the html/template standard Go package.
//
// To initialize a fresh one use the `Blocks` function.
// To wrap an existing one use the `WrapBlocks` function.
//
// It contains the following four default template functions:
// - url "routename" parameters...
// - urlpath "routename" parameters...
// - tr "language" "key" arguments...
// - partial "template_name" data
//
// Read more at: https://github.com/kataras/blocks.
type BlocksEngine struct {
Engine *blocks.Blocks
}
var _ Engine = (*BlocksEngine)(nil)
// WrapBlocks wraps an initialized blocks engine and returns its Iris adapter.
// See `Blocks` package-level function too.
func WrapBlocks(v *blocks.Blocks) *BlocksEngine {
return &BlocksEngine{Engine: v}
}
// Blocks returns a new blocks view engine.
// The given "extension" MUST begin with a dot.
//
// See `WrapBlocks` package-level function too.
func Blocks(directory, extension string) *BlocksEngine {
return WrapBlocks(blocks.New(directory).Extension(extension))
}
// Ext returns empty ext as this template engine
// supports template blocks without file suffix.
// Note that, if more than one view engine is registered to a single
// Iris application then, this Blocks engine should be the last entry one.
func (s *BlocksEngine) Ext() string {
return ""
}
// AddFunc implements the `EngineFuncer` which is being used
// by the framework to add template functions like:
// - url func(routeName string, args ...string) string
// - urlpath func(routeName string, args ...string) string
// - tr func(lang, key string, args ...interface{}) string
func (s *BlocksEngine) AddFunc(funcName string, funcBody interface{}) *BlocksEngine {
s.Engine.Funcs(template.FuncMap{funcName: funcBody})
return s
}
// AddLayoutFunc adds a template function for templates that are marked as layouts.
func (s *BlocksEngine) AddLayoutFunc(funcName string, funcBody interface{}) *BlocksEngine {
s.Engine.LayoutFuncs(template.FuncMap{funcName: funcBody})
return s
}
// Binary sets the function which reads contents based on a filename
// and a function that returns all the filenames.
// These functions are used to parse the corresponding files into templates.
// You do not need to set them when the given "rootDir" was a system directory.
// It's mostly useful when the application contains embedded template files,
// e.g. pass go-bindata's `Asset` and `AssetNames` functions
// to load templates from go-bindata generated content.
func (s *BlocksEngine) Binary(asset blocks.AssetFunc, assetNames blocks.AssetNamesFunc) *BlocksEngine {
s.Engine.Assets(asset, assetNames)
return s
}
// Layout sets the default layout which inside should use
// the {{ template "content" . }} to render the main template.
//
// Example for ./views/layouts/main.html:
// Blocks("./views", ".html").Layout("layouts/main")
func (s *BlocksEngine) Layout(layoutName string) *BlocksEngine {
s.Engine.DefaultLayout(layoutName)
return s
}
// Reload if called with a true parameter,
// each `ExecuteWriter` call will re-parse the templates.
// Useful when the application is at a development stage.
func (s *BlocksEngine) Reload(b bool) *BlocksEngine {
s.Engine.Reload(b)
return s
}
// Load parses the files into templates.
func (s *BlocksEngine) Load() error {
return s.Engine.Load()
}
// ExecuteWriter renders a template on "w".
func (s *BlocksEngine) ExecuteWriter(w io.Writer, tmplName, layoutName string, data interface{}) error {
if layoutName == NoLayout {
layoutName = ""
}
return s.Engine.ExecuteTemplate(w, tmplName, layoutName, data)
}

View File

@ -108,7 +108,8 @@ type DjangoEngine struct {
var _ Engine = (*DjangoEngine)(nil)
// Django creates and returns a new amber view engine.
// Django creates and returns a new django view engine.
// The given "extension" MUST begin with a dot.
func Django(directory, extension string) *DjangoEngine {
s := &DjangoEngine{
directory: directory,

View File

@ -30,6 +30,7 @@ type HandlebarsEngine struct {
var _ Engine = (*HandlebarsEngine)(nil)
// Handlebars creates and returns a new handlebars view engine.
// The given "extension" MUST begin with a dot.
func Handlebars(directory, extension string) *HandlebarsEngine {
s := &HandlebarsEngine{
directory: directory,

View File

@ -61,6 +61,7 @@ var emptyFuncs = template.FuncMap{
// HTML creates and returns a new html view engine.
// The html engine used like the "html/template" standard go package
// but with a lot of extra features.
// The given "extension" MUST begin with a dot.
func HTML(directory, extension string) *HTMLEngine {
s := &HTMLEngine{
directory: directory,
@ -173,6 +174,7 @@ func (s *HTMLEngine) AddLayoutFunc(funcName string, funcBody interface{}) *HTMLE
// - url func(routeName string, args ...string) string
// - urlpath func(routeName string, args ...string) string
// - render func(fullPartialName string) (template.HTML, error).
// - tr func(lang, key string, args ...interface{}) string
func (s *HTMLEngine) AddFunc(funcName string, funcBody interface{}) *HTMLEngine {
s.rmu.Lock()
s.funcs[funcName] = funcBody
@ -206,7 +208,7 @@ func (s *HTMLEngine) Funcs(funcMap template.FuncMap) *HTMLEngine {
// Load parses the templates to the engine.
// It's also responsible to add the necessary global functions.
//
// Returns an error if something bad happens, user is responsible to catch it.
// Returns an error if something bad happens, caller is responsible to handle that.
func (s *HTMLEngine) Load() error {
// No need to make this with a complicated and "pro" way, just add lockers to the `ExecuteWriter`.
// if `Reload(true)` and add a note for non conc access on dev mode.
@ -500,6 +502,12 @@ func (s *HTMLEngine) ExecuteWriter(w io.Writer, name string, layout string, bind
}
}
t := s.Templates.Lookup(name)
if t == nil {
return fmt.Errorf("template: %s does not exist in the dir: %s", name, s.directory)
}
s.runtimeFuncsFor(t, name, bindingData)
if layout = getLayout(layout, s.layout); layout != "" {
lt := s.Templates.Lookup(layout)
if lt == nil {
@ -510,11 +518,5 @@ func (s *HTMLEngine) ExecuteWriter(w io.Writer, name string, layout string, bind
return lt.Execute(w, bindingData)
}
t := s.Templates.Lookup(name)
if t == nil {
return fmt.Errorf("template: %s does not exist in the dir: %s", name, s.directory)
}
s.runtimeFuncsFor(t, name, bindingData)
return t.Execute(w, bindingData)
}

View File

@ -47,6 +47,7 @@ var jetExtensions = [...]string{
}
// Jet creates and returns a new jet view engine.
// The given "extension" MUST begin with a dot.
func Jet(directory, extension string) *JetEngine {
// if _, err := os.Stat(directory); os.IsNotExist(err) {
// panic(err)

View File

@ -12,6 +12,7 @@ import (
// Pug (or Jade) returns a new pug view engine.
// It shares the same exactly logic with the
// html view engine, it uses the same exactly configuration.
// The given "extension" MUST begin with a dot.
//
// Read more about the Jade Go Parser: https://github.com/Joker/jade
//