mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
add resource feature support for gview
This commit is contained in:
@ -1,18 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/.example/net/ghttp/server/resource/testdata"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gres"
|
||||
_ "github.com/gogf/gf/os/gres/testdata"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gres.Dump()
|
||||
|
||||
v := g.View()
|
||||
v.SetResource(gres.Default())
|
||||
v.SetPath("/template/layout1")
|
||||
|
||||
s := g.Server()
|
||||
s.SetIndexFolder(true)
|
||||
s.SetResource(gres.Default())
|
||||
s.SetServerRoot("/root")
|
||||
s.BindHandler("/template", func(r *ghttp.Request) {
|
||||
r.Response.WriteTpl("layout.html")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
9
.example/os/gres/testdata/testdata.go
vendored
9
.example/os/gres/testdata/testdata.go
vendored
File diff suppressed because one or more lines are too long
20
.example/os/gview/resource/main1.go
Normal file
20
.example/os/gview/resource/main1.go
Normal file
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gres"
|
||||
_ "github.com/gogf/gf/os/gres/testdata"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gres.Dump()
|
||||
|
||||
v := g.View()
|
||||
v.SetResource(gres.Default())
|
||||
v.SetPath("/template/layout1")
|
||||
s, err := v.Parse("layout.html")
|
||||
fmt.Println(err)
|
||||
fmt.Println(s)
|
||||
}
|
||||
22
.example/os/gview/resource/main2.go
Normal file
22
.example/os/gview/resource/main2.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gres"
|
||||
_ "github.com/gogf/gf/os/gres/testdata"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gres.Dump()
|
||||
|
||||
v := g.View()
|
||||
v.SetResource(gres.Default())
|
||||
v.SetPath("/template/layout2")
|
||||
s, err := v.Parse("layout.html", g.Map{
|
||||
"mainTpl": "main/main1.html",
|
||||
})
|
||||
fmt.Println(err)
|
||||
fmt.Println(s)
|
||||
}
|
||||
@ -36,12 +36,12 @@ func (r *Response) WriteTplContent(content string, params ...gview.Params) error
|
||||
|
||||
// 解析模板文件,并返回模板内容
|
||||
func (r *Response) ParseTpl(tpl string, params ...gview.Params) (string, error) {
|
||||
return gins.View().Parse(tpl, r.buildInVars(params...))
|
||||
return r.Server.config.View.Parse(tpl, r.buildInVars(params...))
|
||||
}
|
||||
|
||||
// 解析并返回模板内容
|
||||
func (r *Response) ParseTplContent(content string, params ...gview.Params) (string, error) {
|
||||
return gins.View().ParseContent(content, r.buildInVars(params...))
|
||||
return r.Server.config.View.ParseContent(content, r.buildInVars(params...))
|
||||
}
|
||||
|
||||
// 内置变量/对象
|
||||
|
||||
@ -13,6 +13,8 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/gview"
|
||||
|
||||
"github.com/gogf/gf/os/gres"
|
||||
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
@ -50,6 +52,7 @@ type ServerConfig struct {
|
||||
TLSConfig tls.Config // HTTPS证书配置
|
||||
KeepAlive bool // 是否开启长连接
|
||||
ServerAgent string // Server Agent
|
||||
View *gview.View // 模板引擎对象
|
||||
Resource *gres.Resource // 资源文件对象
|
||||
Rewrites map[string]string // URI Rewrite重写配置
|
||||
IndexFiles []string // Static: 默认访问的文件列表
|
||||
@ -87,6 +90,7 @@ var defaultServerConfig = ServerConfig{
|
||||
IdleTimeout: 60 * time.Second,
|
||||
MaxHeaderBytes: 1024,
|
||||
KeepAlive: true,
|
||||
View: gview.Instance(),
|
||||
IndexFiles: []string{"index.html", "index.htm"},
|
||||
IndexFolder: false,
|
||||
ServerAgent: "gf http server",
|
||||
@ -311,6 +315,15 @@ func (s *Server) SetKeepAlive(enabled bool) {
|
||||
s.config.KeepAlive = enabled
|
||||
}
|
||||
|
||||
// 设置模板引擎对象
|
||||
func (s *Server) SetView(view *gview.View) {
|
||||
if s.Status() == SERVER_STATUS_RUNNING {
|
||||
glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR)
|
||||
return
|
||||
}
|
||||
s.config.View = view
|
||||
}
|
||||
|
||||
// 获取WebServer名称
|
||||
func (s *Server) GetName() string {
|
||||
return s.name
|
||||
|
||||
@ -57,6 +57,11 @@ func GetWithIndex(path string, indexFiles []string) *File {
|
||||
return defaultResource.GetWithIndex(path, indexFiles)
|
||||
}
|
||||
|
||||
// GetContent directly returns the content of <path> in default resource object.
|
||||
func GetContent(path string) []byte {
|
||||
return defaultResource.GetContent(path)
|
||||
}
|
||||
|
||||
// Contains checks whether the <path> exists in the default resource object.
|
||||
func Contains(path string) bool {
|
||||
return defaultResource.Contains(path)
|
||||
|
||||
@ -32,17 +32,17 @@ func (f *File) Open() (io.ReadCloser, error) {
|
||||
}
|
||||
|
||||
// Content returns the content of the file.
|
||||
func (f *File) Content() ([]byte, error) {
|
||||
func (f *File) Content() []byte {
|
||||
reader, err := f.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil
|
||||
}
|
||||
defer reader.Close()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if _, err := io.Copy(buffer, reader); err != nil {
|
||||
return nil, err
|
||||
return nil
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
return buffer.Bytes()
|
||||
}
|
||||
|
||||
// FileInfo returns an os.FileInfo for the FileHeader.
|
||||
|
||||
@ -57,11 +57,7 @@ func (f *File) Seek(offset int64, whence int) (int64, error) {
|
||||
|
||||
func (f *File) getReader() (*bytes.Reader, error) {
|
||||
if f.reader == nil {
|
||||
content, err := f.Content()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.reader = bytes.NewReader(content)
|
||||
f.reader = bytes.NewReader(f.Content())
|
||||
}
|
||||
return f.reader, nil
|
||||
}
|
||||
|
||||
@ -76,11 +76,6 @@ func (r *Resource) Get(path string) *File {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Contains checks whether the <path> exists in current resource object.
|
||||
func (r *Resource) Contains(path string) bool {
|
||||
return r.Get(path) != nil
|
||||
}
|
||||
|
||||
// GetWithIndex searches file with <path>, if the file is directory
|
||||
// it then does index files searching under this directory.
|
||||
//
|
||||
@ -105,6 +100,20 @@ func (r *Resource) GetWithIndex(path string, indexFiles []string) *File {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetContent directly returns the content of <path>.
|
||||
func (r *Resource) GetContent(path string) []byte {
|
||||
file := r.Get(path)
|
||||
if file != nil {
|
||||
return file.Content()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Contains checks whether the <path> exists in current resource object.
|
||||
func (r *Resource) Contains(path string) bool {
|
||||
return r.Get(path) != nil
|
||||
}
|
||||
|
||||
// Scan returns the files under the given path, the parameter <path> should be a folder type.
|
||||
//
|
||||
// The pattern parameter <pattern> supports multiple file name patterns,
|
||||
|
||||
3
os/gres/testdata/files/template/layout1/container.html
vendored
Normal file
3
os/gres/testdata/files/template/layout1/container.html
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{{define "container"}}
|
||||
<h1>CONTAINER</h1>
|
||||
{{end}}
|
||||
3
os/gres/testdata/files/template/layout1/footer.html
vendored
Normal file
3
os/gres/testdata/files/template/layout1/footer.html
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{{define "footer"}}
|
||||
<h1>FOOTER</h1>
|
||||
{{end}}
|
||||
3
os/gres/testdata/files/template/layout1/header.html
vendored
Normal file
3
os/gres/testdata/files/template/layout1/header.html
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{{define "header"}}
|
||||
<h1>HEADER</h1>
|
||||
{{end}}
|
||||
15
os/gres/testdata/files/template/layout1/layout.html
vendored
Normal file
15
os/gres/testdata/files/template/layout1/layout.html
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>GoFrame Layout</title>
|
||||
{{template "header"}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{{template "container"}}
|
||||
</div>
|
||||
<div class="footer">
|
||||
{{template "footer"}}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
1
os/gres/testdata/files/template/layout2/footer.html
vendored
Normal file
1
os/gres/testdata/files/template/layout2/footer.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
<h1>FOOTER</h1>
|
||||
1
os/gres/testdata/files/template/layout2/header.html
vendored
Normal file
1
os/gres/testdata/files/template/layout2/header.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
<h1>HEADER</h1>
|
||||
3
os/gres/testdata/files/template/layout2/layout.html
vendored
Normal file
3
os/gres/testdata/files/template/layout2/layout.html
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{{include "header.html" .}}
|
||||
{{include .mainTpl .}}
|
||||
{{include "footer.html" .}}
|
||||
1
os/gres/testdata/files/template/layout2/main/main1.html
vendored
Normal file
1
os/gres/testdata/files/template/layout2/main/main1.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
<h1>MAIN1</h1>
|
||||
1
os/gres/testdata/files/template/layout2/main/main2.html
vendored
Normal file
1
os/gres/testdata/files/template/layout2/main/main2.html
vendored
Normal file
@ -0,0 +1 @@
|
||||
<h1>MAIN2</h1>
|
||||
2
os/gres/testdata/testdata.go
vendored
2
os/gres/testdata/testdata.go
vendored
File diff suppressed because one or more lines are too long
@ -60,6 +60,9 @@ func New(path string, cache bool) *SPath {
|
||||
|
||||
// 创建/获取一个单例的搜索对象, root必须为目录的绝对路径
|
||||
func Get(root string, cache bool) *SPath {
|
||||
if root == "" {
|
||||
root = "/"
|
||||
}
|
||||
return pathsMap.GetOrSetFuncLock(root, func() interface{} {
|
||||
return New(root, cache)
|
||||
}).(*SPath)
|
||||
|
||||
@ -8,11 +8,12 @@
|
||||
package gview
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/gogf/gf/os/gres"
|
||||
|
||||
"github.com/gogf/gf"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/internal/cmdenv"
|
||||
@ -27,6 +28,7 @@ type View struct {
|
||||
paths *garray.StringArray // Searching path array.
|
||||
data map[string]interface{} // Global template variables.
|
||||
funcMap map[string]interface{} // Global template function map.
|
||||
resource *gres.Resource // Resource management object.
|
||||
delimiters []string // Customized template delimiters.
|
||||
}
|
||||
|
||||
@ -120,43 +122,51 @@ func New(path ...string) *View {
|
||||
return view
|
||||
}
|
||||
|
||||
// SetResource sets the resource management object for current view.
|
||||
func (view *View) SetResource(resource *gres.Resource) {
|
||||
view.resource = resource
|
||||
view.paths.Clear()
|
||||
view.paths.Append("/")
|
||||
}
|
||||
|
||||
// SetPath sets the template directory path for template file search.
|
||||
// The parameter <path> can be absolute or relative path, but absolute path is suggested.
|
||||
func (view *View) SetPath(path string) error {
|
||||
// Absolute path.
|
||||
realPath := gfile.RealPath(path)
|
||||
if realPath == "" {
|
||||
// Relative path.
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
for _, v := range array {
|
||||
if path, _ := gspath.Search(v, path); path != "" {
|
||||
realPath = path
|
||||
break
|
||||
isDir := false
|
||||
realPath := ""
|
||||
if view.resource != nil {
|
||||
if file := view.resource.Get(path); file != nil {
|
||||
realPath = path
|
||||
isDir = file.FileInfo().IsDir()
|
||||
}
|
||||
} else {
|
||||
// Absolute path.
|
||||
realPath = gfile.RealPath(path)
|
||||
if realPath == "" {
|
||||
// Relative path.
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
for _, v := range array {
|
||||
if path, _ := gspath.Search(v, path); path != "" {
|
||||
realPath = path
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if realPath != "" {
|
||||
isDir = gfile.IsDir(realPath)
|
||||
}
|
||||
}
|
||||
// Path not exist.
|
||||
if realPath == "" {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if view.paths.Len() > 0 {
|
||||
buffer.WriteString(fmt.Sprintf("[gview] SetPath failed: cannot find directory \"%s\" in following paths:", path))
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
for k, v := range array {
|
||||
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
buffer.WriteString(fmt.Sprintf(`[gview] SetPath failed: path "%s" does not exist`, path))
|
||||
}
|
||||
err := errors.New(buffer.String())
|
||||
err := errors.New(fmt.Sprintf(`[gview] SetPath failed: path "%s" does not exist`, path))
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// Should be a directory.
|
||||
if !gfile.IsDir(realPath) {
|
||||
if !isDir {
|
||||
err := errors.New(fmt.Sprintf(`[gview] SetPath failed: path "%s" should be directory type`, path))
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
@ -175,40 +185,41 @@ func (view *View) SetPath(path string) error {
|
||||
|
||||
// AddPath adds a absolute or relative path to the search paths.
|
||||
func (view *View) AddPath(path string) error {
|
||||
// Absolute path.
|
||||
realPath := gfile.RealPath(path)
|
||||
if realPath == "" {
|
||||
// Relative path.
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
for _, v := range array {
|
||||
if path, _ := gspath.Search(v, path); path != "" {
|
||||
realPath = path
|
||||
break
|
||||
isDir := false
|
||||
realPath := ""
|
||||
if view.resource != nil {
|
||||
if file := view.resource.Get(path); file != nil {
|
||||
realPath = path
|
||||
isDir = file.FileInfo().IsDir()
|
||||
}
|
||||
} else {
|
||||
// Absolute path.
|
||||
realPath = gfile.RealPath(path)
|
||||
if realPath == "" {
|
||||
// Relative path.
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
for _, v := range array {
|
||||
if path, _ := gspath.Search(v, path); path != "" {
|
||||
realPath = path
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if realPath != "" {
|
||||
isDir = gfile.IsDir(realPath)
|
||||
}
|
||||
}
|
||||
// Path not exist.
|
||||
if realPath == "" {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if view.paths.Len() > 0 {
|
||||
buffer.WriteString(fmt.Sprintf("[gview] AddPath failed: cannot find directory \"%s\" in following paths:", path))
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
for k, v := range array {
|
||||
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
buffer.WriteString(fmt.Sprintf(`[gview] AddPath failed: path "%s" does not exist`, path))
|
||||
}
|
||||
err := errors.New(buffer.String())
|
||||
err := errors.New(fmt.Sprintf(`[gview] AddPath failed: path "%s" does not exist`, path))
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// realPath should be type of folder.
|
||||
if !gfile.IsDir(realPath) {
|
||||
if !isDir {
|
||||
err := errors.New(fmt.Sprintf(`[gview] AddPath failed: path "%s" should be directory type`, path))
|
||||
if errorPrint() {
|
||||
glog.Error(err)
|
||||
|
||||
@ -79,6 +79,7 @@ func (view *View) funcInclude(file string, data ...map[string]interface{}) strin
|
||||
if len(data) > 0 {
|
||||
m = data[0]
|
||||
}
|
||||
// It will search the file internally.
|
||||
content, err := view.Parse(file, m)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
|
||||
@ -10,11 +10,15 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/gogf/gf/os/gfcache"
|
||||
|
||||
"github.com/gogf/gf/os/gres"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/encoding/ghash"
|
||||
"github.com/gogf/gf/os/gfcache"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gfsnotify"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
@ -41,12 +45,27 @@ var (
|
||||
// if the template files under <path> changes (recursively).
|
||||
func (view *View) getTemplate(path string, pattern string) (tpl *template.Template, err error) {
|
||||
r := templates.GetOrSetFuncLock(path, func() interface{} {
|
||||
files := ([]string)(nil)
|
||||
files, err = gfile.ScanDir(path, pattern, true)
|
||||
tpl = template.New(path).Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
|
||||
if view.resource != nil {
|
||||
tempFiles := view.resource.Scan(path, pattern, true)
|
||||
if len(tempFiles) > 0 {
|
||||
var err error
|
||||
for _, v := range tempFiles {
|
||||
if v.FileInfo().IsDir() {
|
||||
continue
|
||||
}
|
||||
_, err = tpl.New(v.FileInfo().Name()).Parse(string(v.Content()))
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
}
|
||||
return tpl
|
||||
}
|
||||
}
|
||||
files, err := gfile.ScanDir(path, pattern, true)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
tpl = template.New(path).Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
|
||||
if tpl, err = tpl.ParseFiles(files...); err != nil {
|
||||
return nil
|
||||
}
|
||||
@ -64,18 +83,40 @@ func (view *View) getTemplate(path string, pattern string) (tpl *template.Templa
|
||||
|
||||
// searchFile returns the found absolute path for <file>, and its template folder path.
|
||||
func (view *View) searchFile(file string) (path string, folder string, err error) {
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
for _, v := range array {
|
||||
if path, _ = gspath.Search(v, file); path != "" {
|
||||
folder = v
|
||||
break
|
||||
separator := gfile.Separator
|
||||
if view.resource != nil {
|
||||
separator = "/"
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
f := (*gres.File)(nil)
|
||||
for _, v := range array {
|
||||
v = strings.TrimRight(v, separator)
|
||||
if f = view.resource.Get(v + separator + file); f != nil {
|
||||
path = f.Name()
|
||||
folder = gfile.Dir(path)
|
||||
break
|
||||
}
|
||||
if f = view.resource.Get(v + separator + "template" + separator + file); f != nil {
|
||||
path = f.Name()
|
||||
folder = gfile.Dir(path)
|
||||
break
|
||||
}
|
||||
}
|
||||
if path, _ = gspath.Search(v+gfile.Separator+"template", file); path != "" {
|
||||
folder = v + gfile.Separator + "template"
|
||||
break
|
||||
})
|
||||
} else {
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
for _, v := range array {
|
||||
v = strings.TrimRight(v, separator)
|
||||
if path, _ = gspath.Search(v, file); path != "" {
|
||||
folder = v
|
||||
break
|
||||
}
|
||||
if path, _ = gspath.Search(v+separator+"template", file); path != "" {
|
||||
folder = v + separator + "template"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if path == "" {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
if view.paths.Len() > 0 {
|
||||
@ -83,9 +124,13 @@ func (view *View) searchFile(file string) (path string, folder string, err error
|
||||
view.paths.RLockFunc(func(array []string) {
|
||||
index := 1
|
||||
for _, v := range array {
|
||||
v = strings.TrimRight(v, "/")
|
||||
if v == "" {
|
||||
v = "/"
|
||||
}
|
||||
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v))
|
||||
index++
|
||||
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v+gfile.Separator+"template"))
|
||||
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, strings.TrimRight(v, "/")+separator+"template"))
|
||||
index++
|
||||
}
|
||||
})
|
||||
@ -116,7 +161,12 @@ func (view *View) Parse(file string, params ...Params) (parsed string, err error
|
||||
}
|
||||
// Using memory lock to ensure concurrent safety for template parsing.
|
||||
gmlock.LockFunc("gview-parsing:"+folder, func() {
|
||||
tpl, err = tpl.Parse(gfcache.GetContents(path))
|
||||
if view.resource != nil {
|
||||
tpl, err = tpl.Parse(string(view.resource.GetContent(path)))
|
||||
} else {
|
||||
tpl, err = tpl.Parse(gfcache.GetContents(path))
|
||||
}
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
Reference in New Issue
Block a user