+
+
+
diff --git a/view.go b/view.go
index 48c00b3..ad8b728 100644
--- a/view.go
+++ b/view.go
@@ -1,5 +1,5 @@
// Copyright (c) Jeevanandam M. (https://github.com/jeevatkm)
-// go-aah/view source code and usage is governed by a MIT style
+// aahframework.org/view source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
// Package view is implementation of aah framework view engine using Go
@@ -8,11 +8,13 @@
package view
import (
+ "bytes"
"errors"
"fmt"
"html/template"
"path"
"path/filepath"
+ "regexp"
"strings"
"aahframework.org/config.v0"
@@ -124,7 +126,7 @@ func (t *Templates) Keys() []string {
}
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
-// type EngineBase, methods
+// type EngineBase, its methods
//______________________________________________________________________________
// EngineBase struct is to create common and repurpose the implementation.
@@ -139,8 +141,9 @@ type EngineBase struct {
RightDelim string
AppConfig *config.Config
Templates map[string]*Templates
- AntiCSRFField *AntiCSRFField
VFS *vfs.VFS
+
+ loginFormRegex *regexp.Regexp
}
// Init method is to initialize the base fields values.
@@ -170,11 +173,66 @@ func (eb *EngineBase) Init(fs *vfs.VFS, appCfg *config.Config, baseDir, defaultE
}
eb.LeftDelim, eb.RightDelim = delimiter[0], delimiter[1]
- // Anti CSRF
- eb.AntiCSRFField = NewAntiCSRFFieldWithVFS(eb.VFS, "go", eb.LeftDelim, eb.RightDelim)
+ eb.loginFormRegex = regexp.MustCompile(`(")) {
+ fc = strings.Replace(string(b), "", fmt.Sprintf(`
+ `, eb.LeftDelim, eb.RightDelim), -1)
+ }
+
+ // _rt field
+ if matches := eb.loginFormRegex.FindAllStringIndex(fc, -1); len(matches) > 0 {
+ for _, m := range matches {
+ ts := fc[m[0]:m[1]]
+ fc = strings.Replace(fc, ts, fmt.Sprintf(`%s
+ `, ts), 1)
+ }
+ }
+
+ return fc, nil
+}
+
+// ParseFiles method parses given files with given template instance.
+func (eb *EngineBase) ParseFiles(t *template.Template, filenames ...string) (*template.Template, error) {
+ for _, filename := range filenames {
+ s, err := eb.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ name := filepath.Base(filename)
+ var tmpl *template.Template
+ if t == nil {
+ t = eb.NewTemplate(name)
+ }
+ if name == t.Name() {
+ tmpl = t
+ } else {
+ tmpl = t.New(name)
+ }
+ if _, err = tmpl.Parse(s); err != nil {
+ return nil, err
+ }
+ }
+
+ return t, nil
+}
+
// Get method returns the template based given name if found, otherwise nil.
func (eb *EngineBase) Get(layout, path, tmplName string) (*template.Template, error) {
if ess.IsStrEmpty(layout) {
From ed332a505632e5f0e0ec9c9c876582588ed4ff10 Mon Sep 17 00:00:00 2001
From: Jeevanandam M
Date: Wed, 13 Jun 2018 03:31:06 -0700
Subject: [PATCH 4/8] adding trace log for auto insertion field and build
config update
---
.travis.yml | 2 +-
go_engine_test.go | 15 +++++++++++----
view.go | 2 ++
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index b70c781..b15be07 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,7 +11,7 @@ branches:
go:
- 1.9
- - "1.10"
+ - 1.x
- tip
go_import_path: aahframework.org/view.v0
diff --git a/go_engine_test.go b/go_engine_test.go
index 01c384c..12e7dd5 100644
--- a/go_engine_test.go
+++ b/go_engine_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"errors"
"html/template"
+ "io/ioutil"
"strings"
"testing"
@@ -17,7 +18,8 @@ import (
)
func TestViewAppPages(t *testing.T) {
- _ = log.SetLevel("trace")
+ // _ = log.SetLevel("trace")
+ log.SetWriter(ioutil.Discard)
cfg, _ := config.ParseString(`view { }`)
ge := loadGoViewEngine(t, cfg, "views")
@@ -45,7 +47,8 @@ func TestViewAppPages(t *testing.T) {
}
func TestViewUserPages(t *testing.T) {
- _ = log.SetLevel("trace")
+ // _ = log.SetLevel("trace")
+ log.SetWriter(ioutil.Discard)
cfg, _ := config.ParseString(`view {
delimiters = "{{.}}"
}`)
@@ -78,7 +81,8 @@ func TestViewUserPages(t *testing.T) {
}
func TestViewUserPagesNoLayout(t *testing.T) {
- _ = log.SetLevel("trace")
+ // _ = log.SetLevel("trace")
+ log.SetWriter(ioutil.Discard)
cfg, _ := config.ParseString(`view {
delimiters = "{{.}}"
default_layout = false
@@ -126,7 +130,8 @@ func TestViewDelimitersError(t *testing.T) {
}
func TestViewErrors(t *testing.T) {
- _ = log.SetLevel("trace")
+ // _ = log.SetLevel("trace")
+ log.SetWriter(ioutil.Discard)
cfg, _ := config.ParseString(`view {
default_layout = false
}`)
@@ -186,5 +191,7 @@ func loadGoViewEngine(t *testing.T, cfg *config.Config, dir string) *GoViewEngin
assert.NotNil(t, (&EngineBase{}).Init(nil, nil, "", "", ""))
+ log.SetWriter(ioutil.Discard)
+
return ge
}
diff --git a/view.go b/view.go
index ad8b728..866c35f 100644
--- a/view.go
+++ b/view.go
@@ -191,12 +191,14 @@ func (eb *EngineBase) Open(filename string) (string, error) {
// process auto field insertion, if form tag exists
// anti_csrf_token field
if bytes.Contains(b, []byte("")) {
+ log.Tracef("Adding field 'anti_csrf_token' into all forms: %s", filename)
fc = strings.Replace(string(b), "", fmt.Sprintf(`
`, eb.LeftDelim, eb.RightDelim), -1)
}
// _rt field
if matches := eb.loginFormRegex.FindAllStringIndex(fc, -1); len(matches) > 0 {
+ log.Tracef("Adding field '_rt' into login form: %s", filename)
for _, m := range matches {
ts := fc[m[0]:m[1]]
fc = strings.Replace(fc, ts, fmt.Sprintf(`%s
From 53b8da6ec05bd6adc14f8b22a094614d3c9fe190 Mon Sep 17 00:00:00 2001
From: Jeevanandam M
Date: Thu, 14 Jun 2018 00:41:13 -0700
Subject: [PATCH 5/8] go-aah/aah#189 view file hotreload without watcher
---
funcs.go | 26 ++++++++++++++++++--------
go_engine.go | 20 +++++---------------
go_engine_test.go | 9 +++++----
view.go | 39 ++++++++++++++++++++++++++++++++++++---
4 files changed, 64 insertions(+), 30 deletions(-)
diff --git a/funcs.go b/funcs.go
index 5fa22fa..33b69dd 100644
--- a/funcs.go
+++ b/funcs.go
@@ -13,30 +13,40 @@ import (
)
// tmplSafeHTML method outputs given HTML as-is, use it with care.
-func tmplSafeHTML(str string) template.HTML {
+func (e *GoViewEngine) tmplSafeHTML(str string) template.HTML {
return template.HTML(str)
}
// tmplInclude method renders given template with View Args and imports into
// current template.
-func tmplInclude(name string, viewArgs map[string]interface{}) template.HTML {
+func (e *GoViewEngine) tmplInclude(name string, viewArgs map[string]interface{}) template.HTML {
if !strings.HasPrefix(name, "common") {
name = "common/" + name
}
+
name = filepath.ToSlash(name)
+ var err error
+ var tmpl *template.Template
+ if e.hotReload {
+ if tmpl, err = e.ParseFile(name); err != nil {
+ log.Errorf("goviewengine: %s", err)
+ return e.tmplSafeHTML("")
+ }
+ } else {
+ tmpl = commonTemplates.Lookup(name)
+ }
- tmpl := commonTemplates.Lookup(name)
if tmpl == nil {
log.Warnf("goviewengine: common template not found: %s", name)
- return tmplSafeHTML("")
+ return e.tmplSafeHTML("")
}
buf := acquireBuffer()
defer releaseBuffer(buf)
- if err := tmpl.Execute(buf, viewArgs); err != nil {
- log.Error(err)
- return template.HTML("")
+ if err = tmpl.Execute(buf, viewArgs); err != nil {
+ log.Errorf("goviewengine: %s", err)
+ return e.tmplSafeHTML("")
}
- return tmplSafeHTML(buf.String())
+ return e.tmplSafeHTML(buf.String())
}
diff --git a/go_engine.go b/go_engine.go
index 16fcf71..c6ed1cc 100644
--- a/go_engine.go
+++ b/go_engine.go
@@ -46,8 +46,9 @@ func (e *GoViewEngine) Init(fs *vfs.VFS, appCfg *config.Config, baseDir string)
// Add template func
AddTemplateFunc(template.FuncMap{
- "import": tmplInclude,
- "include": tmplInclude, // alias for import
+ "safeHTML": e.tmplSafeHTML,
+ "import": e.tmplInclude,
+ "include": e.tmplInclude, // alias for import
})
// load common templates
@@ -99,18 +100,12 @@ func (e *GoViewEngine) loadCommonTemplates() error {
continue
}
- tmplKey := StripPathPrefixAt(filepath.ToSlash(file), "views/")
- tmpl := e.NewTemplate(tmplKey)
-
log.Tracef("Parsing file: %s", TrimPathPrefix(prefix, file))
- tstr, err := e.Open(file)
+ tmpl, err := e.ParseFile(file)
if err != nil {
return err
}
- if _, err = tmpl.Parse(tstr); err != nil {
- return err
- }
- if err = commonTemplates.Add(tmplKey, tmpl); err != nil {
+ if err = commonTemplates.Add(tmpl.Name(), tmpl); err != nil {
return err
}
}
@@ -198,9 +193,4 @@ func (e *GoViewEngine) loadNonLayoutTemplates(scope string) error {
func init() {
_ = AddEngine("go", &GoViewEngine{})
-
- // Add template func
- AddTemplateFunc(template.FuncMap{
- "safeHTML": tmplSafeHTML,
- })
}
diff --git a/go_engine_test.go b/go_engine_test.go
index 12e7dd5..8b5c7b1 100644
--- a/go_engine_test.go
+++ b/go_engine_test.go
@@ -21,7 +21,7 @@ func TestViewAppPages(t *testing.T) {
// _ = log.SetLevel("trace")
log.SetWriter(ioutil.Discard)
cfg, _ := config.ParseString(`view { }`)
- ge := loadGoViewEngine(t, cfg, "views")
+ ge := loadGoViewEngine(t, cfg, "views", false)
data := map[string]interface{}{
"GreetName": "aah framework",
@@ -52,7 +52,7 @@ func TestViewUserPages(t *testing.T) {
cfg, _ := config.ParseString(`view {
delimiters = "{{.}}"
}`)
- ge := loadGoViewEngine(t, cfg, "views")
+ ge := loadGoViewEngine(t, cfg, "views", true)
data := map[string]interface{}{
"GreetName": "aah framework",
@@ -87,7 +87,7 @@ func TestViewUserPagesNoLayout(t *testing.T) {
delimiters = "{{.}}"
default_layout = false
}`)
- ge := loadGoViewEngine(t, cfg, "views")
+ ge := loadGoViewEngine(t, cfg, "views", false)
data := map[string]interface{}{
"GreetName": "aah framework",
@@ -165,7 +165,7 @@ func TestViewErrors(t *testing.T) {
assert.Equal(t, "goviewengine: error processing templates, please check the log", err.Error())
}
-func loadGoViewEngine(t *testing.T, cfg *config.Config, dir string) *GoViewEngine {
+func loadGoViewEngine(t *testing.T, cfg *config.Config, dir string, hotreload bool) *GoViewEngine {
// dummy func for test
AddTemplateFunc(template.FuncMap{
"anticsrftoken": func(arg interface{}) string {
@@ -184,6 +184,7 @@ func loadGoViewEngine(t *testing.T, cfg *config.Config, dir string) *GoViewEngin
err := ge.Init(newVFS(), cfg, viewsDir)
assert.FailNowOnError(t, err, "")
+ ge.hotReload = hotreload
assert.Equal(t, viewsDir, ge.BaseDir)
assert.NotNil(t, ge.AppConfig)
diff --git a/view.go b/view.go
index 866c35f..6627390 100644
--- a/view.go
+++ b/view.go
@@ -143,6 +143,7 @@ type EngineBase struct {
Templates map[string]*Templates
VFS *vfs.VFS
+ hotReload bool
loginFormRegex *regexp.Regexp
}
@@ -192,7 +193,7 @@ func (eb *EngineBase) Open(filename string) (string, error) {
// anti_csrf_token field
if bytes.Contains(b, []byte("")) {
log.Tracef("Adding field 'anti_csrf_token' into all forms: %s", filename)
- fc = strings.Replace(string(b), "", fmt.Sprintf(`
+ fc = strings.Replace(fc, "", fmt.Sprintf(`
`, eb.LeftDelim, eb.RightDelim), -1)
}
@@ -209,6 +210,19 @@ func (eb *EngineBase) Open(filename string) (string, error) {
return fc, nil
}
+// ParseFile method parses given single file.
+func (eb *EngineBase) ParseFile(filename string) (*template.Template, error) {
+ if !strings.HasPrefix(filename, eb.BaseDir) {
+ filename = path.Join(eb.BaseDir, filename)
+ }
+ tmpl := eb.NewTemplate(StripPathPrefixAt(filepath.ToSlash(filename), "views/"))
+ tstr, err := eb.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ return tmpl.Parse(tstr)
+}
+
// ParseFiles method parses given files with given template instance.
func (eb *EngineBase) ParseFiles(t *template.Template, filenames ...string) (*template.Template, error) {
for _, filename := range filenames {
@@ -236,13 +250,27 @@ func (eb *EngineBase) ParseFiles(t *template.Template, filenames ...string) (*te
}
// Get method returns the template based given name if found, otherwise nil.
-func (eb *EngineBase) Get(layout, path, tmplName string) (*template.Template, error) {
+func (eb *EngineBase) Get(layout, tpath, tmplName string) (*template.Template, error) {
+ if eb.hotReload {
+ key := path.Join(tpath, tmplName)
+ if !eb.CaseSensitive {
+ key = strings.ToLower(key)
+ }
+
+ if ess.IsStrEmpty(layout) {
+ return eb.ParseFile(path.Join(eb.BaseDir, key))
+ }
+ return eb.ParseFiles(eb.NewTemplate(key),
+ path.Join(eb.BaseDir, "layouts", layout),
+ path.Join(eb.BaseDir, key))
+ }
+
if ess.IsStrEmpty(layout) {
layout = noLayout
}
if tmpls, found := eb.Templates[layout]; found {
- key := filepath.Join(path, tmplName)
+ key := path.Join(tpath, tmplName)
if layout == noLayout {
key = noLayout + "-" + key
}
@@ -259,6 +287,11 @@ func (eb *EngineBase) Get(layout, path, tmplName string) (*template.Template, er
return nil, ErrTemplateNotFound
}
+// SetHotReload method set teh view engine mode into hot reload without watcher.
+func (eb *EngineBase) SetHotReload(r bool) {
+ eb.hotReload = r
+}
+
// AddTemplate method adds the given template for layout and key.
func (eb *EngineBase) AddTemplate(layout, key string, tmpl *template.Template) error {
if eb.Templates[layout] == nil {
From 9e7ae25f2d59790271e7223055834b8efb818ad8 Mon Sep 17 00:00:00 2001
From: Jeevanandam M
Date: Fri, 15 Jun 2018 10:17:35 -0700
Subject: [PATCH 6/8] anti-csrf form field name red from app config
---
funcs.go | 2 +-
view.go | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/funcs.go b/funcs.go
index 33b69dd..b372173 100644
--- a/funcs.go
+++ b/funcs.go
@@ -1,5 +1,5 @@
// Copyright (c) Jeevanandam M. (https://github.com/jeevatkm)
-// go-aah/view source code and usage is governed by a MIT style
+// aahframework.org/view source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package view
diff --git a/view.go b/view.go
index 6627390..9dacb54 100644
--- a/view.go
+++ b/view.go
@@ -193,8 +193,9 @@ func (eb *EngineBase) Open(filename string) (string, error) {
// anti_csrf_token field
if bytes.Contains(b, []byte("")) {
log.Tracef("Adding field 'anti_csrf_token' into all forms: %s", filename)
- fc = strings.Replace(fc, "", fmt.Sprintf(`
- `, eb.LeftDelim, eb.RightDelim), -1)
+ fieldName := eb.AppConfig.StringDefault("security.anti_csrf.form_field_name", "anti_csrf_token")
+ fc = strings.Replace(fc, "", fmt.Sprintf(`
+ `, fieldName, eb.LeftDelim, eb.RightDelim), -1)
}
// _rt field
From 3c684a2995a90bf9ec15e5e52c49d5ff469c1cf8 Mon Sep 17 00:00:00 2001
From: Jeevanandam M
Date: Thu, 21 Jun 2018 20:37:25 -0700
Subject: [PATCH 7/8] extracted auto field insertion as a method in base engine
---
view.go | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/view.go b/view.go
index 9dacb54..70ae7d1 100644
--- a/view.go
+++ b/view.go
@@ -8,7 +8,6 @@
package view
import (
- "bytes"
"errors"
"fmt"
"html/template"
@@ -89,7 +88,7 @@ type Templates struct {
set map[string]*template.Template
}
-// Get method return the template for given key.
+// Lookup method return the template for given key.
func (t *Templates) Lookup(key string) *template.Template {
return t.set[filepath.ToSlash(key)]
}
@@ -134,6 +133,7 @@ func (t *Templates) Keys() []string {
type EngineBase struct {
CaseSensitive bool
IsLayoutEnabled bool
+ hotReload bool
Name string
BaseDir string
FileExt string
@@ -142,9 +142,7 @@ type EngineBase struct {
AppConfig *config.Config
Templates map[string]*Templates
VFS *vfs.VFS
-
- hotReload bool
- loginFormRegex *regexp.Regexp
+ loginFormRegex *regexp.Regexp
}
// Init method is to initialize the base fields values.
@@ -187,28 +185,31 @@ func (eb *EngineBase) Open(filename string) (string, error) {
if err != nil {
return "", err
}
+ return eb.AutoFieldInsertion(filename, string(b)), nil
+}
- fc := string(b)
+// AutoFieldInsertion method processes the aah view's to auto insert the field.
+func (eb *EngineBase) AutoFieldInsertion(name, v string) string {
// process auto field insertion, if form tag exists
// anti_csrf_token field
- if bytes.Contains(b, []byte("")) {
- log.Tracef("Adding field 'anti_csrf_token' into all forms: %s", filename)
+ if strings.Contains(v, "") {
+ log.Tracef("Adding field 'anti_csrf_token' into all forms: %s", name)
fieldName := eb.AppConfig.StringDefault("security.anti_csrf.form_field_name", "anti_csrf_token")
- fc = strings.Replace(fc, "", fmt.Sprintf(`
+ v = strings.Replace(v, "", fmt.Sprintf(`
`, fieldName, eb.LeftDelim, eb.RightDelim), -1)
}
// _rt field
- if matches := eb.loginFormRegex.FindAllStringIndex(fc, -1); len(matches) > 0 {
- log.Tracef("Adding field '_rt' into login form: %s", filename)
+ if matches := eb.loginFormRegex.FindAllStringIndex(v, -1); len(matches) > 0 {
+ log.Tracef("Adding field '_rt' into login form: %s", name)
for _, m := range matches {
- ts := fc[m[0]:m[1]]
- fc = strings.Replace(fc, ts, fmt.Sprintf(`%s
+ ts := v[m[0]:m[1]]
+ v = strings.Replace(v, ts, fmt.Sprintf(`%s
`, ts), 1)
}
}
- return fc, nil
+ return v
}
// ParseFile method parses given single file.
@@ -252,7 +253,7 @@ func (eb *EngineBase) ParseFiles(t *template.Template, filenames ...string) (*te
// Get method returns the template based given name if found, otherwise nil.
func (eb *EngineBase) Get(layout, tpath, tmplName string) (*template.Template, error) {
- if eb.hotReload {
+ if eb.hotReload && eb.Name == "go" {
key := path.Join(tpath, tmplName)
if !eb.CaseSensitive {
key = strings.ToLower(key)
From 64b129486c68af0a05aab9e86a32be4d3cc2f984 Mon Sep 17 00:00:00 2001
From: Jeevanandam M
Date: Fri, 6 Jul 2018 22:19:18 -0700
Subject: [PATCH 8/8] readme update and version bump for v0.9.0 release
---
README.md | 22 +++++++++++++---------
version.go | 4 ++--
2 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index c8dd29b..b74f283 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,21 @@
-# view - aah framework
-[![Build Status](https://travis-ci.org/go-aah/view.svg?branch=master)](https://travis-ci.org/go-aah/view) [![codecov](https://codecov.io/gh/go-aah/view/branch/master/graph/badge.svg)](https://codecov.io/gh/go-aah/view/branch/master) [![Go Report Card](https://goreportcard.com/badge/aahframework.org/view.v0)](https://goreportcard.com/report/aahframework.org/view.v0) [![Version](https://img.shields.io/badge/version-0.8.2-blue.svg)](https://github.com/go-aah/view/releases/latest) [![GoDoc](https://godoc.org/aahframework.org/view.v0?status.svg)](https://godoc.org/aahframework.org/view.v0) [![License](https://img.shields.io/github/license/go-aah/view.svg)](LICENSE) [![Twitter](https://img.shields.io/badge/twitter-@aahframework-55acee.svg)](https://twitter.com/aahframework)
+
+
+
View Engine library by aah framework
+
+
+
+
-***v0.8.2 [released](https://github.com/go-aah/view/releases/latest) and tagged on Apr 25, 2018***
+View Engine library provides enhanced Go template engine which supports partial template inheritance, imports, etc.
-Go HTML template library which supports partial template inheritance, imports, etc.
+### News
-*`view` developed for aah framework. However, it's an independent library, can be used separately with any `Go` language project. Feel free to use it.*
+ * `v0.9.0` [released](https://github.com/go-aah/view/releases/latest) and tagged on Jul 06, 2018.
+
+## Installation
-# Installation
-#### Stable Version - Production Ready
```bash
-# install the library
go get -u aahframework.org/view.v0
```
-Visit official website https://aahframework.org to learn more.
+Visit official website https://aahframework.org to learn more about `aah` framework.
diff --git a/version.go b/version.go
index fbffb41..cacaec6 100644
--- a/version.go
+++ b/version.go
@@ -1,8 +1,8 @@
// Copyright (c) Jeevanandam M. (https://github.com/jeevatkm)
-// go-aah/view source code and usage is governed by a MIT style
+// aahframework.org/view source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package view
// Version no. of aah framework view library
-const Version = "0.9.0-edge"
+const Version = "0.9.0"