Merge pull request #626 from trheyi/main
refactor: Update TemplateParser to support debug mode and DisableCache
This commit is contained in:
commit
1fc9f9aab5
4 changed files with 138 additions and 141 deletions
|
|
@ -8,6 +8,7 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/gin-gonic/gin"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou/application"
|
||||
|
|
@ -76,10 +77,19 @@ func NewRequestContext(c *gin.Context) (*Request, int, error) {
|
|||
// Render is the response for the page API.
|
||||
func (r *Request) Render() (string, int, error) {
|
||||
|
||||
c := core.GetCache(r.File)
|
||||
c = nil // disable cache @todo disable cache on development
|
||||
// if c == nil {
|
||||
if true {
|
||||
// Read content from cache
|
||||
var c *core.Cache = nil
|
||||
if !r.Request.DisableCache() {
|
||||
c = core.GetCache(r.File)
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
|
||||
// The page is not cached
|
||||
message := fmt.Sprintf("[SUI] The page %s is not cached. file=%s DisableCache=%v", r.Request.URL.Path, r.File, r.Request.DisableCache())
|
||||
fmt.Println(color.YellowString(message))
|
||||
log.Warn(message)
|
||||
|
||||
// Read the file
|
||||
content, err := application.App.Read(r.File)
|
||||
if err != nil {
|
||||
|
|
@ -136,7 +146,6 @@ func (r *Request) Render() (string, int, error) {
|
|||
}
|
||||
|
||||
// Save to The Cache
|
||||
// c = core.SetCache(r.File, html, dataText, globalDataText)
|
||||
c = &core.Cache{
|
||||
Data: dataText,
|
||||
Global: globalDataText,
|
||||
|
|
@ -145,54 +154,16 @@ func (r *Request) Render() (string, int, error) {
|
|||
GuardRedirect: guardRedirect,
|
||||
Config: configText,
|
||||
}
|
||||
log.Trace("The page %s is cached", r.File)
|
||||
core.SetCache(r.File, c)
|
||||
log.Trace("[SUI] The page %s is cached file=%s", r.Request.URL.Path, r.File)
|
||||
}
|
||||
|
||||
// Guard the page
|
||||
if c.Guard != "" && r.context != nil {
|
||||
|
||||
if guard, has := Guards[c.Guard]; has {
|
||||
err := guard(r)
|
||||
if err != nil {
|
||||
|
||||
// Redirect the page (should refector before release)
|
||||
if c.GuardRedirect != "" {
|
||||
redirect := c.GuardRedirect
|
||||
data := core.Data{}
|
||||
if c.Data != "" {
|
||||
data, err = r.Request.ExecString(c.Data)
|
||||
if err != nil {
|
||||
return "", 500, fmt.Errorf("data error, please re-complie the page %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if c.Global != "" {
|
||||
global, err := r.Request.ExecString(c.Global)
|
||||
if err != nil {
|
||||
return "", 500, fmt.Errorf("global data error, please re-complie the page %s", err.Error())
|
||||
}
|
||||
data["$global"] = global
|
||||
}
|
||||
|
||||
redirect, _ = data.Replace(redirect)
|
||||
return "", 302, fmt.Errorf("%s", redirect)
|
||||
}
|
||||
|
||||
// Return the error
|
||||
ex := exception.Err(err, 403)
|
||||
return "", ex.Code, fmt.Errorf("%s", ex.Message)
|
||||
}
|
||||
} else {
|
||||
// Process the guard
|
||||
err := r.processGuard(c.Guard)
|
||||
if err != nil {
|
||||
ex := exception.Err(err, 403)
|
||||
return "", ex.Code, fmt.Errorf("%s", ex.Message)
|
||||
}
|
||||
}
|
||||
code, err := r.Guard(c)
|
||||
if err != nil {
|
||||
return "", code, err
|
||||
}
|
||||
|
||||
var err error
|
||||
data := core.Data{}
|
||||
if c.Data != "" {
|
||||
data, err = r.Request.ExecString(c.Data)
|
||||
|
|
@ -210,18 +181,16 @@ func (r *Request) Render() (string, int, error) {
|
|||
}
|
||||
|
||||
// Set the page request data
|
||||
data["$payload"] = r.Request.Payload
|
||||
data["$query"] = r.Request.Query
|
||||
data["$param"] = r.Request.Params
|
||||
data["$cookie"] = r.Request.Cookies()
|
||||
data["$url"] = r.Request.URL
|
||||
|
||||
printData := false
|
||||
if r.Query != nil && r.Query.Has("__sui_print_data") {
|
||||
printData = true
|
||||
r.Request.WithData(data)
|
||||
option := core.ParserOption{
|
||||
Theme: data["$theme"].(string),
|
||||
Lang: data["$lang"].(string),
|
||||
Debug: r.Request.DebugMode(),
|
||||
Request: true,
|
||||
}
|
||||
|
||||
parser := core.NewTemplateParser(data, &core.ParserOption{PrintData: printData, Request: true})
|
||||
// Parse the template
|
||||
parser := core.NewTemplateParser(data, &option)
|
||||
html, err := parser.Render(c.HTML)
|
||||
if err != nil {
|
||||
return "", 500, fmt.Errorf("render error, please re-complie the page %s", err.Error())
|
||||
|
|
@ -230,6 +199,58 @@ func (r *Request) Render() (string, int, error) {
|
|||
return html, 200, nil
|
||||
}
|
||||
|
||||
// Guard the page
|
||||
func (r *Request) Guard(c *core.Cache) (int, error) {
|
||||
|
||||
// Guard not set
|
||||
if c.Guard == "" || r.context == nil {
|
||||
return 200, nil
|
||||
}
|
||||
|
||||
// Built-in guard
|
||||
if guard, has := Guards[c.Guard]; has {
|
||||
err := guard(r)
|
||||
if err != nil {
|
||||
// Redirect the page (should refector before release)
|
||||
if c.GuardRedirect != "" {
|
||||
redirect := c.GuardRedirect
|
||||
data := core.Data{}
|
||||
if c.Data != "" {
|
||||
data, err = r.Request.ExecString(c.Data)
|
||||
if err != nil {
|
||||
return 500, fmt.Errorf("data error, please re-complie the page %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if c.Global != "" {
|
||||
global, err := r.Request.ExecString(c.Global)
|
||||
if err != nil {
|
||||
return 500, fmt.Errorf("global data error, please re-complie the page %s", err.Error())
|
||||
}
|
||||
data["$global"] = global
|
||||
}
|
||||
|
||||
redirect, _ = data.Replace(redirect)
|
||||
return 302, fmt.Errorf("%s", redirect)
|
||||
}
|
||||
|
||||
// Return the error
|
||||
ex := exception.Err(err, 403)
|
||||
return ex.Code, fmt.Errorf("%s", ex.Message)
|
||||
}
|
||||
return 200, nil
|
||||
}
|
||||
|
||||
// Developer custom guard
|
||||
err := r.processGuard(c.Guard)
|
||||
if err != nil {
|
||||
ex := exception.Err(err, 403)
|
||||
return ex.Code, fmt.Errorf("%s", ex.Message)
|
||||
}
|
||||
|
||||
return 200, nil
|
||||
}
|
||||
|
||||
func parserPath(c *gin.Context) (string, map[string]string, error) {
|
||||
|
||||
params := map[string]string{}
|
||||
|
|
@ -265,74 +286,6 @@ func parserPath(c *gin.Context) (string, map[string]string, error) {
|
|||
}
|
||||
}
|
||||
return filename, params, nil
|
||||
|
||||
// // Match the sui
|
||||
// matchers := core.RouteExactMatchers[parts[0]]
|
||||
// if matchers == nil {
|
||||
// for matcher, reMatchers := range core.RouteMatchers {
|
||||
// matched := matcher.FindStringSubmatch(parts[0])
|
||||
// if len(matched) > 0 {
|
||||
// matchers = reMatchers
|
||||
// fileParts = append(fileParts, matched[0])
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // No matchers
|
||||
// if matchers == nil {
|
||||
// if len(parts) < 1 {
|
||||
// return "", nil, fmt.Errorf("path parts error: %s", strings.Join(parts, "/"))
|
||||
// }
|
||||
|
||||
// fileParts = append(fileParts, parts...)
|
||||
// return filepath.Join(fileParts...) + ".sui", params, nil
|
||||
// }
|
||||
|
||||
// // Match the page parts
|
||||
// for i, part := range parts[1:] {
|
||||
// if len(matchers) < i+1 {
|
||||
// return "", nil, fmt.Errorf("matchers length error %d < %d", len(matchers), i+1)
|
||||
// }
|
||||
|
||||
// parent := ""
|
||||
// if i > 0 {
|
||||
// parent = parts[i]
|
||||
// }
|
||||
// matched := false
|
||||
// for _, matcher := range matchers[i] {
|
||||
|
||||
// // Filter the parent
|
||||
// if matcher.Parent != "" && matcher.Parent != parent {
|
||||
// continue
|
||||
// }
|
||||
|
||||
// if matcher.Exact == part {
|
||||
// fileParts = append(fileParts, matcher.Exact)
|
||||
// matched = true
|
||||
// break
|
||||
|
||||
// } else if matcher.Regex != nil {
|
||||
// if matcher.Regex.MatchString(part) {
|
||||
// file := matcher.Ref
|
||||
// key := strings.TrimRight(strings.TrimLeft(file, "["), "]")
|
||||
// params[key] = part
|
||||
// fileParts = append(fileParts, file)
|
||||
// matched = true
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if !matched {
|
||||
// return "", nil, fmt.Errorf("route does not match")
|
||||
// }
|
||||
// }
|
||||
// return filepath.Join(fileParts...) + ".sui", params, nil
|
||||
}
|
||||
|
||||
func params(c *gin.Context) map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func payload(c *gin.Context) (map[string]interface{}, interface{}, error) {
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ func (res *ResponseEditorRender) Render(data map[string]interface{}) error {
|
|||
}
|
||||
|
||||
var err error
|
||||
parser := NewTemplateParser(data, &ParserOption{Editor: true, PrintData: true})
|
||||
parser := NewTemplateParser(data, &ParserOption{Editor: true, Debug: true})
|
||||
|
||||
res.HTML, err = parser.Render(res.HTML)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -29,10 +29,12 @@ type Mapping struct {
|
|||
|
||||
// ParserOption parser option
|
||||
type ParserOption struct {
|
||||
Editor bool `json:"editor,omitempty"`
|
||||
Preview bool `json:"preview,omitempty"`
|
||||
PrintData bool `json:"print_data,omitempty"`
|
||||
Request bool `json:"request,omitempty"`
|
||||
Editor bool `json:"editor,omitempty"`
|
||||
Preview bool `json:"preview,omitempty"`
|
||||
Debug bool `json:"debug,omitempty"`
|
||||
Request bool `json:"request,omitempty"`
|
||||
Theme string `json:"theme,omitempty"`
|
||||
Lang string `json:"lang,omitempty"`
|
||||
}
|
||||
|
||||
var keepWords = map[string]bool{
|
||||
|
|
@ -66,7 +68,7 @@ func NewTemplateParser(data Data, option *ParserOption) *TemplateParser {
|
|||
func (parser *TemplateParser) Render(html string) (string, error) {
|
||||
|
||||
if !strings.Contains(html, "<html") {
|
||||
html = fmt.Sprintf(`<!DOCTYPE html><html lang="en">%s</html>`, html)
|
||||
html = fmt.Sprintf(`<!DOCTYPE html><html lang="en-us">%s</html>`, html)
|
||||
}
|
||||
|
||||
doc, err := NewDocumentString(html)
|
||||
|
|
@ -85,7 +87,7 @@ func (parser *TemplateParser) Render(html string) (string, error) {
|
|||
|
||||
// Print the data
|
||||
jsPrintData := ""
|
||||
if parser.option != nil && parser.option.PrintData {
|
||||
if parser.option != nil && parser.option.Debug {
|
||||
jsPrintData = "console.log(__sui_data);\n"
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +123,7 @@ func (parser *TemplateParser) Render(html string) (string, error) {
|
|||
// Remove the sui-hide attribute
|
||||
doc.Find("[sui-hide]").Remove()
|
||||
|
||||
// Remove All comments
|
||||
// Remove All comments and unsed nodes
|
||||
parser.tidy(doc.Selection)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,53 @@ func (r *Request) Cookies() map[string]string {
|
|||
return cookies
|
||||
}
|
||||
|
||||
// DebugMode get the debug mode
|
||||
func (r *Request) DebugMode() bool {
|
||||
debug := false
|
||||
if r.Query != nil && (r.Query.Has("__sui_print_data") || r.Query.Has("__debug")) {
|
||||
debug = true
|
||||
}
|
||||
return debug
|
||||
}
|
||||
|
||||
// DisableCache get the disable cache
|
||||
func (r *Request) DisableCache() bool {
|
||||
disable := false
|
||||
if (r.Query != nil && r.Query.Has("__debug") || r.Query.Has("__sui_disable_cache")) || (r.Headers != nil && r.Headers.Get("Cache-Control") == "no-cache") {
|
||||
disable = true
|
||||
}
|
||||
return disable
|
||||
}
|
||||
|
||||
// WithData set the data
|
||||
func (r *Request) WithData(data Data) *Request {
|
||||
cookies := r.Cookies()
|
||||
data["$payload"] = r.Payload
|
||||
data["$query"] = r.Query
|
||||
data["$param"] = r.Params
|
||||
data["$cookie"] = cookies
|
||||
data["$url"] = r.URL
|
||||
data["$theme"] = GetTheme(cookies)
|
||||
data["$lang"] = GetLang(cookies)
|
||||
return r
|
||||
}
|
||||
|
||||
// GetLang get the lang
|
||||
func GetLang(cookies map[string]string) string {
|
||||
if lang, has := cookies["lang"]; has {
|
||||
return lang
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetTheme get the theme
|
||||
func GetTheme(cookies map[string]string) string {
|
||||
if theme, has := cookies["color-theme"]; has {
|
||||
return theme
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ExecString get the data
|
||||
func (r *Request) ExecString(data string) (Data, error) {
|
||||
var res Data
|
||||
|
|
@ -314,13 +361,8 @@ func (url ReqeustURL) Map() Data {
|
|||
}
|
||||
|
||||
// SetCache set the cache
|
||||
func SetCache(file string, html string, data string, global string) *Cache {
|
||||
Caches[file] = &Cache{
|
||||
Data: data,
|
||||
HTML: html,
|
||||
Global: global,
|
||||
}
|
||||
return Caches[file]
|
||||
func SetCache(file string, cache *Cache) {
|
||||
Caches[file] = cache
|
||||
}
|
||||
|
||||
// GetCache get the cache
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue