diff --git a/sui/api/process.go b/sui/api/process.go
index a751c85c05..0f0a0dee90 100644
--- a/sui/api/process.go
+++ b/sui/api/process.go
@@ -655,16 +655,7 @@ func EditorRender(process *process.Process) interface{} {
exception.New(err.Error(), 500).Throw()
}
- // Request data
- urlQuery := url.Values{}
- if process.NumOfArgs() > 3 {
- if v, ok := process.Args[3].(url.Values); ok {
- urlQuery = v
- }
- }
-
- req := &core.Request{Method: "GET", Query: urlQuery}
- res, err := page.EditorRender(req)
+ res, err := page.EditorRender()
if err != nil {
exception.New(err.Error(), 500).Throw()
}
diff --git a/sui/api/request.go b/sui/api/request.go
index bc38f90537..69f16b29f6 100644
--- a/sui/api/request.go
+++ b/sui/api/request.go
@@ -69,13 +69,20 @@ func (r *Request) Render() (string, int, error) {
dataSel.Remove()
}
+ globalDataText := ""
+ globalDataSel := doc.Find("script[name=global]")
+ if globalDataSel != nil && globalDataSel.Length() > 0 {
+ globalDataText = globalDataSel.Text()
+ globalDataSel.Remove()
+ }
+
html, err := doc.Html()
if err != nil {
return "", 500, fmt.Errorf("parse error, please re-complie the page %s", err.Error())
}
// Save to The Cache
- c = core.SetCache(r.File, html, dataText)
+ c = core.SetCache(r.File, html, dataText, globalDataText)
log.Trace("The page %s is cached", r.File)
}
@@ -88,6 +95,14 @@ func (r *Request) Render() (string, int, 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
+ }
+
parser := core.NewTemplateParser(data, nil)
html, err := parser.Render(c.HTML)
if err != nil {
diff --git a/sui/core/build.go b/sui/core/build.go
index f1dd058250..f9dbfdf265 100644
--- a/sui/core/build.go
+++ b/sui/core/build.go
@@ -11,7 +11,7 @@ import (
func (page *Page) Build(option *BuildOption) (*goquery.Document, []string, error) {
warnings := []string{}
- html, err := page.BuildHTML(option.AssetRoot)
+ html, err := page.BuildHTML(option)
if err != nil {
warnings = append(warnings, err.Error())
}
@@ -23,14 +23,14 @@ func (page *Page) Build(option *BuildOption) (*goquery.Document, []string, error
}
// Add Style
- style, err := page.BuildStyle(option.AssetRoot)
+ style, err := page.BuildStyle(option)
if err != nil {
warnings = append(warnings, err.Error())
}
doc.Selection.Find("head").AppendHtml(style)
// Add Script
- script, err := page.BuildScript(option.AssetRoot)
+ script, err := page.BuildScript(option)
if err != nil {
warnings = append(warnings, err.Error())
}
@@ -39,15 +39,18 @@ func (page *Page) Build(option *BuildOption) (*goquery.Document, []string, error
}
// BuildHTML build the html
-func (page *Page) BuildHTML(assetRoot string) (string, error) {
+func (page *Page) BuildHTML(option *BuildOption) (string, error) {
html := string(page.Document)
if page.Codes.HTML.Code != "" {
html = strings.Replace(html, "{{ __page }}", page.Codes.HTML.Code, 1)
}
- code := strings.ReplaceAll(html, "@assets", assetRoot)
- res, err := page.CompileHTML([]byte(code), false)
+ if !option.IgnoreAssetRoot {
+ html = strings.ReplaceAll(html, "@assets", option.AssetRoot)
+ }
+
+ res, err := page.CompileHTML([]byte(html), false)
if err != nil {
return "", err
}
@@ -56,12 +59,16 @@ func (page *Page) BuildHTML(assetRoot string) (string, error) {
}
// BuildStyle build the style
-func (page *Page) BuildStyle(assetRoot string) (string, error) {
+func (page *Page) BuildStyle(option *BuildOption) (string, error) {
if page.Codes.CSS.Code == "" {
return "", nil
}
- code := strings.ReplaceAll(page.Codes.CSS.Code, "@assets", assetRoot)
+ code := page.Codes.CSS.Code
+ if !option.IgnoreAssetRoot {
+ code = strings.ReplaceAll(page.Codes.CSS.Code, "@assets", option.AssetRoot)
+ }
+
res, err := page.CompileCSS([]byte(code), false)
if err != nil {
return "", err
@@ -71,7 +78,7 @@ func (page *Page) BuildStyle(assetRoot string) (string, error) {
}
// BuildScript build the script
-func (page *Page) BuildScript(assetRoot string) (string, error) {
+func (page *Page) BuildScript(option *BuildOption) (string, error) {
if page.Codes.JS.Code == "" && page.Codes.TS.Code == "" {
return "", nil
@@ -86,7 +93,11 @@ func (page *Page) BuildScript(assetRoot string) (string, error) {
return fmt.Sprintf("\n", res), nil
}
- code := strings.ReplaceAll(page.Codes.JS.Code, "@assets", assetRoot)
+ code := page.Codes.JS.Code
+ if !option.IgnoreAssetRoot {
+ code = strings.ReplaceAll(page.Codes.JS.Code, "@assets", option.AssetRoot)
+ }
+
res, err := page.CompileJS([]byte(code), false)
if err != nil {
return "", err
diff --git a/sui/core/compile.go b/sui/core/compile.go
index c3fc0955f9..d5dd7718e0 100644
--- a/sui/core/compile.go
+++ b/sui/core/compile.go
@@ -22,6 +22,7 @@ func (page *Page) Compile(option *BuildOption) (string, error) {
}
}
+ // Page Data
if page.Codes.DATA.Code != "" {
doc.Find("body").AppendHtml("\n\n" + `\n")
+ // Page Global Data
+ if page.GlobalData != nil && len(page.GlobalData) > 0 {
+ doc.Find("body").AppendHtml("\n\n" + `\n\n",
+ )
+ }
+
+ // Replace the document
+ page.Config = page.GetConfig()
+ page.ReplaceDocument(doc)
html, err := doc.Html()
if err != nil {
diff --git a/sui/core/data.go b/sui/core/data.go
index 888765462a..b94136948f 100644
--- a/sui/core/data.go
+++ b/sui/core/data.go
@@ -9,6 +9,7 @@ import (
"github.com/antonmedv/expr/ast"
"github.com/antonmedv/expr/vm"
"github.com/yaoapp/gou/process"
+ "github.com/yaoapp/kun/log"
)
var stmtRe = regexp.MustCompile(`\{\{([^}]+)\}\}`)
@@ -56,6 +57,20 @@ func (data Data) ExecString(stmt string) (string, error) {
return fmt.Sprintf("%v", res), nil
}
+// Replace replace the statement
+func (data Data) Replace(value string) (string, bool) {
+ hasStmt := false
+ res := stmtRe.ReplaceAllStringFunc(value, func(stmt string) string {
+ hasStmt = true
+ res, err := data.ExecString(stmt)
+ if err != nil {
+ log.Warn("Replace %s: %s", stmt, err)
+ }
+ return res
+ })
+ return res, hasStmt
+}
+
func _process(args ...any) (interface{}, error) {
if len(args) < 1 {
diff --git a/sui/core/editor.go b/sui/core/editor.go
index b905642bf6..baf1737d9e 100644
--- a/sui/core/editor.go
+++ b/sui/core/editor.go
@@ -5,7 +5,7 @@ import (
)
// EditorRender render HTML for the editor
-func (page *Page) EditorRender(request *Request) (*ResponseEditorRender, error) {
+func (page *Page) EditorRender() (*ResponseEditorRender, error) {
res := &ResponseEditorRender{
HTML: "",
@@ -32,27 +32,16 @@ func (page *Page) EditorRender(request *Request) (*ResponseEditorRender, error)
}
res.Styles = append(res.Styles, styles...)
- // // Page Styles
- // if page.Codes.CSS.Code != "" {
- // res.Styles = append(res.Styles, filepath.Join("@pages", page.Route, page.Name+".css"))
- // }
-
- // // Render the HTML with the data
- // // Page Scripts
- // if page.Codes.JS.Code != "" {
- // res.Scripts = append(res.Scripts, filepath.Join("@pages", page.Route, page.Name+".js"))
- // }
- // if page.Codes.TS.Code != "" {
- // res.Scripts = append(res.Scripts, filepath.Join("@pages", page.Route, page.Name+".ts"))
- // }
+ // Render the page
+ request := NewRequestMock(page.Config.Mock)
// Render tools
// res.Scripts = append(res.Scripts, filepath.Join("@assets", "__render.js"))
// res.Styles = append(res.Styles, filepath.Join("@assets", "__render.css"))
doc, warnings, err := page.Build(&BuildOption{
- SSR: true,
- AssetRoot: request.AssetRoot,
+ SSR: true,
+ IgnoreAssetRoot: true,
})
if err != nil {
@@ -77,6 +66,13 @@ func (page *Page) EditorRender(request *Request) (*ResponseEditorRender, error)
}
res.Render(data)
+
+ // Set the title
+ res.Config.Rendered = &PageConfigRendered{
+ Title: page.RenderTitle(data),
+ Link: page.Link(request),
+ }
+
return res, nil
}
@@ -91,7 +87,8 @@ func (res *ResponseEditorRender) Render(data map[string]interface{}) error {
}
var err error
- parser := NewTemplateParser(data, nil)
+ parser := NewTemplateParser(data, &ParserOption{Editor: true})
+
res.HTML, err = parser.Render(res.HTML)
if err != nil {
return err
@@ -102,6 +99,7 @@ func (res *ResponseEditorRender) Render(data map[string]interface{}) error {
res.Warnings = append(res.Warnings, err.Error())
}
}
+
return nil
}
diff --git a/sui/core/interfaces.go b/sui/core/interfaces.go
index 2a03f8f60b..2e11dfa146 100644
--- a/sui/core/interfaces.go
+++ b/sui/core/interfaces.go
@@ -27,6 +27,7 @@ type SUI interface {
WithSid(sid string)
PublicRootMatcher() *Matcher
GetPublic() *Public
+ PublicRootWithSid(sid string) (string, error)
}
// ITemplate is the interface for the ITemplate
@@ -70,7 +71,7 @@ type IPage interface {
SaveTemp(request *RequestSource) error
Remove() error
- EditorRender(request *Request) (*ResponseEditorRender, error)
+ EditorRender() (*ResponseEditorRender, error)
EditorPageSource() SourceData
EditorScriptSource() SourceData
EditorStyleSource() SourceData
diff --git a/sui/core/page.go b/sui/core/page.go
index 04c9b76fc4..942ee13348 100644
--- a/sui/core/page.go
+++ b/sui/core/page.go
@@ -1,9 +1,12 @@
package core
import (
+ "path/filepath"
"strings"
+ "github.com/PuerkitoBio/goquery"
jsoniter "github.com/json-iterator/go"
+ "github.com/yaoapp/kun/log"
)
// Get get the base info
@@ -13,17 +16,29 @@ func (page *Page) Get() *Page {
// GetConfig get the config
func (page *Page) GetConfig() *PageConfig {
- if page.Config == nil && page.Codes.CONF.Code != "" {
+
+ if page.Codes.CONF.Code != "" {
var config PageConfig
err := jsoniter.Unmarshal([]byte(page.Codes.CONF.Code), &config)
if err == nil {
page.Config = &config
}
}
+
+ if page.Config == nil {
+ page.Config = &PageConfig{
+ Mock: &PageMock{Method: "GET"},
+ }
+ }
+
+ if page.Config.Mock == nil {
+ page.Config.Mock = &PageMock{Method: "GET"}
+ }
+
return page.Config
}
-// Data get the data
+// Data get the data (deprecated)
func (page *Page) Data(request *Request) (Data, map[string]interface{}, error) {
setting := map[string]interface{}{
@@ -51,5 +66,140 @@ func (page *Page) Exec(request *Request) (Data, error) {
return nil, err
}
+ // Global data
+ if page.GlobalData != nil {
+ global, err := request.ExecString(string(page.GlobalData))
+ if err != nil {
+ return nil, err
+ }
+ data["$global"] = global
+ }
+
return data, nil
}
+
+// RenderTitle render the title
+func (page *Page) RenderTitle(data Data) string {
+
+ if page.Config == nil {
+ return "Untitled"
+ }
+
+ if page.Config.Title != "" {
+ title, _ := data.Replace(page.Config.Title)
+ return title
+ }
+
+ return "Untitled"
+}
+
+// Link get the link
+func (page *Page) Link(r *Request) string {
+ sui, has := SUIs[page.SuiID]
+ if !has {
+ log.Error("[sui] get page link %s not found", page.SuiID)
+ return ""
+ }
+
+ root, err := sui.PublicRootWithSid(r.Sid)
+ if err != nil {
+ log.Error("[sui] get page link %s root error %s", page.SuiID, err.Error())
+ return ""
+ }
+
+ parts := strings.Split(page.Route, "/")
+ if len(parts) == 0 {
+ log.Error("[sui] get page link %s path not found", page.SuiID)
+ return ""
+ }
+
+ // Get the route
+ paths := []string{root, "/"}
+ for _, part := range parts {
+ if part == "" {
+ continue
+ }
+ if strings.HasPrefix(part, "[") && strings.HasSuffix(part, "]") {
+ name := strings.TrimSuffix(strings.TrimPrefix(part, "["), "]")
+ if name == "" {
+ continue
+ }
+
+ if r == nil {
+ continue
+ }
+
+ value, has := r.Params[name]
+ if !has {
+ paths = append(paths, name)
+ continue
+ }
+
+ paths = append(paths, value)
+ continue
+ }
+ paths = append(paths, part)
+ }
+
+ url := filepath.Join(paths...)
+ if r.Query != nil {
+ query := r.Query.Encode()
+ if query != "" {
+ url = url + "?" + query
+ }
+ }
+
+ return url
+}
+
+// ReplaceDocument replace the document
+func (page *Page) ReplaceDocument(doc *goquery.Document) {
+
+ if page.Config == nil {
+ return
+ }
+
+ if doc == nil {
+ return
+ }
+
+ if page.Config.Title != "" {
+ if doc.Find("title") != nil {
+ doc.Find("title").SetText(page.Config.Title)
+ }
+ }
+
+ if page.Config.Description != "" {
+ if doc.Find("meta[name=description]") != nil {
+ doc.Find("meta[name=description]").SetAttr("content", page.Config.Description)
+ }
+ }
+
+ if page.Config.SEO != nil {
+
+ if page.Config.SEO.Title != "" {
+ if doc.Find("meta[property=og:title]") != nil {
+ doc.Find("meta[property=og:title]").SetAttr("content", page.Config.SEO.Title)
+ }
+ }
+
+ if page.Config.SEO.Description != "" {
+ if doc.Find("meta[name=description]") != nil {
+ doc.Find("meta[name=description]").SetAttr("content", page.Config.SEO.Description)
+ }
+ }
+
+ if page.Config.SEO.Image != "" {
+ if doc.Find("meta[property=og:image]") != nil {
+ doc.Find("meta[property=og:image]").SetAttr("content", page.Config.SEO.Image)
+ }
+ }
+
+ if page.Config.SEO.URL != "" {
+ if doc.Find("meta[property=og:url]") != nil {
+ doc.Find("meta[property=og:url]").SetAttr("content", page.Config.SEO.URL)
+ }
+ }
+ }
+
+}
diff --git a/sui/core/parser.go b/sui/core/parser.go
index be38d2a0f1..84738df8df 100644
--- a/sui/core/parser.go
+++ b/sui/core/parser.go
@@ -16,6 +16,7 @@ type TemplateParser struct {
sequence int // sequence for the rendering
errors []error // errors
replace map[*goquery.Selection][]*html.Node // replace nodes
+ option *ParserOption // parser option
}
// Mapping mapping for the template
@@ -26,16 +27,24 @@ type Mapping struct {
}
// ParserOption parser option
-type ParserOption struct{}
+type ParserOption struct {
+ Editor bool `json:"editor,omitempty"`
+ Preview bool `json:"preview,omitempty"`
+}
// NewTemplateParser create a new template parser
func NewTemplateParser(data Data, option *ParserOption) *TemplateParser {
+ if option == nil {
+ option = &ParserOption{}
+ }
+
return &TemplateParser{
data: data,
mapping: map[string]Mapping{},
sequence: 0,
errors: []error{},
replace: map[*goquery.Selection][]*html.Node{},
+ option: option,
}
}
@@ -103,17 +112,7 @@ func (parser *TemplateParser) parseElementNode(sel *goquery.Selection) {
func (parser *TemplateParser) parseTextNode(node *html.Node) {
parser.sequence = parser.sequence + 1
- hasStmt := false
- res := stmtRe.ReplaceAllFunc([]byte(node.Data), func(stmt []byte) []byte {
- hasStmt = true
- res, err := parser.data.ExecString(string(stmt))
- if err != nil {
- parser.errors = append(parser.errors, err)
- return []byte(``)
- }
- return []byte(res)
- })
-
+ res, hasStmt := parser.data.Replace(node.Data)
// Bind the variable to the parent node
if node.Parent != nil && hasStmt {
bindings := strings.TrimSpace(node.Data)
@@ -125,8 +124,7 @@ func (parser *TemplateParser) parseTextNode(node *html.Node) {
}...)
}
}
-
- node.Data = string(res)
+ node.Data = res
}
func (parser *TemplateParser) forStatementNode(sel *goquery.Selection) {
@@ -153,6 +151,12 @@ func (parser *TemplateParser) forStatementNode(sel *goquery.Selection) {
indexVarName := sel.AttrOr("s:for-index", "index")
itemNodes := []*html.Node{}
+ // Keep the node if the editor is enabled
+ if parser.option.Editor {
+ clone := sel.Clone()
+ itemNodes = append(itemNodes, clone.Nodes...)
+ }
+
for idx, item := range items {
// Create a new node
@@ -168,6 +172,10 @@ func (parser *TemplateParser) forStatementNode(sel *goquery.Selection) {
parser.data[itemVarName] = item
parser.data[indexVarName] = idx
+ if parser.option.Editor {
+ parser.setSuiAttr(new, "generate", "true")
+ }
+
// Process the new node
for i := range new.Nodes {
parser.parseNode(new.Nodes[i])
@@ -259,7 +267,23 @@ func (parser *TemplateParser) elseStatementNode(sel *goquery.Selection) ([]*goqu
return elifNodes, elseNode
}
+func (parser *TemplateParser) setSuiAttr(sel *goquery.Selection, key, value string) *goquery.Selection {
+ key = fmt.Sprintf("data-sui-%s", key)
+ return sel.SetAttr(key, value)
+}
+
+func (parser *TemplateParser) removeSuiAttr(sel *goquery.Selection, key string) *goquery.Selection {
+ key = fmt.Sprintf("data-sui-%s", key)
+ return sel.RemoveAttr(key)
+}
+
func (parser *TemplateParser) hide(sel *goquery.Selection) {
+
+ if parser.option.Editor {
+ parser.setSuiAttr(sel, "hide", "true")
+ return
+ }
+
style := sel.AttrOr("style", "")
if strings.Contains(style, "display: none") {
return
@@ -274,6 +298,12 @@ func (parser *TemplateParser) hide(sel *goquery.Selection) {
}
func (parser *TemplateParser) show(sel *goquery.Selection) {
+
+ if parser.option.Editor {
+ parser.removeSuiAttr(sel, "hide")
+ return
+ }
+
style := sel.AttrOr("style", "")
if !strings.Contains(style, "display: none") {
return
diff --git a/sui/core/request.go b/sui/core/request.go
index 1f18416624..5de6585020 100644
--- a/sui/core/request.go
+++ b/sui/core/request.go
@@ -11,13 +11,30 @@ import (
// Cache the cache
type Cache struct {
- Data string
- HTML string
+ Data string
+ Global string
+ HTML string
}
// Caches the caches
var Caches = map[string]*Cache{}
+// NewRequestMock is the constructor for Request.
+func NewRequestMock(mock *PageMock) *Request {
+ if mock == nil {
+ mock = &PageMock{Method: "GET"}
+ }
+ return &Request{
+ Method: mock.Method,
+ Query: mock.Query,
+ Body: mock.Body,
+ Payload: mock.Payload,
+ Referer: mock.Referer,
+ Headers: mock.Headers,
+ Params: mock.Params,
+ }
+}
+
// ExecString get the data
func (r *Request) ExecString(data string) (Data, error) {
var res Data
@@ -231,10 +248,11 @@ func (r *Request) parseArgs(args []interface{}) ([]interface{}, error) {
}
// SetCache set the cache
-func SetCache(file string, html string, data string) *Cache {
+func SetCache(file string, html string, data string, global string) *Cache {
Caches[file] = &Cache{
- Data: data,
- HTML: html,
+ Data: data,
+ HTML: html,
+ Global: global,
}
return Caches[file]
}
diff --git a/sui/core/sui.go b/sui/core/sui.go
index 7845e4c455..5632740b4d 100644
--- a/sui/core/sui.go
+++ b/sui/core/sui.go
@@ -45,6 +45,28 @@ func (sui *DSL) PublicRootMatcher() *Matcher {
return &Matcher{Exact: pub.Root}
}
+// PublicRootWithSid returns the public root path with sid
+func (sui *DSL) PublicRootWithSid(sid string) (string, error) {
+ ss := session.Global().ID(sid)
+ data, err := ss.Dump()
+ if err != nil {
+ return "", err
+ }
+
+ vars := map[string]interface{}{"$session": data}
+ var root = sui.Public.Root
+ dot := maps.Of(vars).Dot()
+ output := varRe.ReplaceAllStringFunc(root, func(matched string) string {
+ varName := strings.TrimSpace(matched[2 : len(matched)-2])
+ if value, ok := dot[varName]; ok {
+ return fmt.Sprint(value)
+ }
+ return "__undefined"
+ })
+
+ return output, nil
+}
+
// PublicRoot returns the public root path
func (sui *DSL) PublicRoot() (string, error) {
// Cache the public root
diff --git a/sui/core/types.go b/sui/core/types.go
index 04a8db22d8..c5ffa74275 100644
--- a/sui/core/types.go
+++ b/sui/core/types.go
@@ -33,6 +33,7 @@ type Page struct {
Path string `json:"-"`
Codes SourceCodes `json:"-"`
Document []byte `json:"-"`
+ GlobalData []byte `json:"-"`
}
// PageTreeNode is the struct for the page tree node
@@ -86,6 +87,7 @@ type Template struct {
Screenshots []string `json:"screenshots"`
Themes []SelectOption `json:"themes"`
Document []byte `json:"-"`
+ GlobalData []byte `json:"-"`
}
// Theme is the struct for the theme
@@ -133,10 +135,11 @@ type MediaSearchResult struct {
// BuildOption is the struct for the option option
type BuildOption struct {
- SSR bool `json:"ssr"`
- CDN bool `json:"cdn"`
- UpdateAll bool `json:"update_all"`
- AssetRoot string `json:"asset_root,omitempty"`
+ SSR bool `json:"ssr"`
+ CDN bool `json:"cdn"`
+ UpdateAll bool `json:"update_all"`
+ AssetRoot string `json:"asset_root,omitempty"`
+ IgnoreAssetRoot bool `json:"ignore_asset_root,omitempty"`
}
// Request is the struct for the request
@@ -202,17 +205,21 @@ type BoardSourceData struct {
// PageMock is the struct for the request
type PageMock struct {
- Method string `json:"method,omitempty"`
- Params map[string]string `json:"params,omitempty"`
- Query map[string][]string `json:"query,omitempty"`
- Headers map[string][]string `json:"headers,omitempty"`
- Body interface{} `json:"body,omitempty"`
+ Method string `json:"method,omitempty"`
+ Referer string `json:"referer,omitempty"`
+ Payload map[string]interface{} `json:"payload,omitempty"`
+ Query url.Values `json:"query,omitempty"`
+ Params map[string]string `json:"params,omitempty"`
+ Headers url.Values `json:"headers,omitempty"`
+ Body interface{} `json:"body,omitempty"`
+ Sid string `json:"sid,omitempty"`
}
// PageConfig is the struct for the page config
type PageConfig struct {
PageSetting `json:",omitempty"`
- Mock *PageMock `json:"mock,omitempty"`
+ Mock *PageMock `json:"mock,omitempty"`
+ Rendered *PageConfigRendered `json:"rendered,omitempty"`
}
// PageSetting is the struct for the page setting
@@ -222,6 +229,12 @@ type PageSetting struct {
SEO *PageSEO `json:"seo,omitempty"`
}
+// PageConfigRendered is the struct for the page config rendered
+type PageConfigRendered struct {
+ Title string `json:"title,omitempty"`
+ Link string `json:"link,omitempty"`
+}
+
// PageSEO is the struct for the page seo
type PageSEO struct {
Title string `json:"title,omitempty"`
diff --git a/sui/storages/local/local.go b/sui/storages/local/local.go
index 3e7c64f5eb..99cb89636b 100644
--- a/sui/storages/local/local.go
+++ b/sui/storages/local/local.go
@@ -146,6 +146,16 @@ func (local *Local) getTemplate(id string, path string) (*Template, error) {
tmpl.Document = documentBytes
}
+ // load the __data.json
+ dataFile := filepath.Join(path, "__data.json")
+ if local.fs.IsFile(dataFile) {
+ dataBytes, err := local.fs.ReadFile(dataFile)
+ if err != nil {
+ return nil, err
+ }
+ tmpl.GlobalData = dataBytes
+ }
+
return &tmpl, nil
}
diff --git a/sui/storages/local/page.go b/sui/storages/local/page.go
index 0047bb7127..11b02b68e9 100644
--- a/sui/storages/local/page.go
+++ b/sui/storages/local/page.go
@@ -374,6 +374,9 @@ func (page *Page) Load() error {
// Set the page document
page.Document = page.tmpl.Document
+
+ // Set the page global data
+ page.GlobalData = page.tmpl.GlobalData
return nil
}
diff --git a/sui/storages/local/page_render_test.go b/sui/storages/local/page_render_test.go
index 8ba566af74..8e4092eb0d 100644
--- a/sui/storages/local/page_render_test.go
+++ b/sui/storages/local/page_render_test.go
@@ -23,8 +23,7 @@ func TestPageEditorRender(t *testing.T) {
t.Fatalf("Page error: %v", err)
}
- r := &core.Request{Method: "GET"}
- res, err := page.EditorRender(r)
+ res, err := page.EditorRender()
if err != nil {
t.Fatalf("EditorRender error: %v", err)
}