yao/sui/api/render.go
2024-08-10 17:18:35 +08:00

181 lines
4.1 KiB
Go

package api
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/yaoapp/gou/process"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/yao/sui/core"
)
// Render the frontend page
func Render(process *process.Process) interface{} {
process.ValidateArgNums(3)
ctx, ok := process.Args[0].(*gin.Context)
if !ok {
return "The context is required"
}
ctx.Header("Content-Type", "text/html; charset=utf-8")
route := process.ArgsString(1)
payload := process.ArgsMap(2)
if route == "" {
return "The route is required"
}
if payload["name"] == nil {
return "The render name is required"
}
ctx.Request.URL.Path = route
r, _, err := NewRequestContext(ctx)
if err != nil {
return fmt.Sprintf("<span class='sui-render-error'> %s </span>", err.Error())
}
var c *core.Cache = nil
if !r.Request.DisableCache() {
c = core.GetCache(r.File)
}
if c == nil {
c, _, err = r.MakeCache()
if err != nil {
return fmt.Sprintf("<span class='sui-render-error'> %s </span>", err.Error())
}
}
if c == nil {
return fmt.Sprintf("<span class='sui-render-error'> Cache not found </span>")
}
// Guard the page
code, err := r.Guard(c)
if err != nil {
return fmt.Sprintf("<span class='sui-render-error'> %v %s </span>", code, err.Error())
}
data, ok := payload["data"].(map[string]interface{})
if !ok {
return fmt.Sprintf("<span class='sui-render-error'> Data not found </span>")
}
name, ok := payload["name"].(string)
if !ok {
return fmt.Sprintf("<span class='sui-render-error'> Name not found </span>")
}
html, err := r.renderHTML(c, name, c.HTML, core.Data(data))
if err != nil {
return fmt.Sprintf("<span class='sui-render-error'> %s </span>", err.Error())
}
return html
}
func (r *Request) renderHTML(c *core.Cache, name string, html string, data core.Data) (string, error) {
doc, err := core.NewDocument([]byte(html))
if err != nil {
return "", fmt.Errorf("Document error: %w", err)
}
sel := doc.Find(fmt.Sprintf("[s\\:render='%s']", name))
if sel.Length() == 0 {
return "", fmt.Errorf("Render %s not found", name)
}
// Set the page request data
option := core.ParserOption{
Theme: r.Request.Theme,
Locale: r.Request.Locale,
Debug: r.Request.DebugMode(),
DisableCache: r.Request.DisableCache(),
Route: r.Request.URL.Path,
Root: c.Root,
Script: c.Script,
Imports: c.Imports,
Request: r.Request,
}
// Parse the template
parser := core.NewTemplateParser(data, &option)
err = parser.RenderSelection(sel)
if err != nil {
return "", fmt.Errorf("Parser error: %w", err)
}
sel.Find("[sui-hide]").Remove()
parser.Tidy(sel)
html, err = sel.Html()
if err != nil {
return "", fmt.Errorf("Html error: %w", err)
}
return html, nil
}
// TemplateRender render the template asset
func TemplateRender(process *process.Process) interface{} {
process.ValidateArgNums(4)
sui := get(process)
tmpl, err := sui.GetTemplate(process.ArgsString(1))
if err != nil {
exception.New(err.Error(), 500).Throw()
}
opt := process.ArgsMap(4, map[string]interface{}{})
params, ok := opt["params"].(map[string]interface{})
if !ok {
params = map[string]interface{}{}
}
root, err := sui.PublicRoot(params)
if err != nil {
exception.New(err.Error(), 500).Throw()
}
source := process.ArgsString(2)
page := tmpl.CreatePage(source)
route := page.Get().Route
doc, _, err := page.Get().Build(core.NewBuildContext(nil), &core.BuildOption{
PublicRoot: root,
IgnoreDocument: true,
JitMode: true,
})
if err != nil {
exception.New(err.Error(), 500).Throw()
return nil
}
data := process.ArgsMap(3)
option := core.ParserOption{
Theme: opt["theme"],
Locale: opt["locale"],
Debug: false,
DisableCache: true,
Route: route,
Root: root,
Script: nil,
Imports: nil,
Request: nil,
}
parser := core.NewTemplateParser(core.Data(data), &option)
sel := doc.Find("body")
err = parser.RenderSelection(sel)
if err != nil {
exception.New(err.Error(), 500).Throw()
}
sel.Find("[sui-hide]").Remove()
parser.Tidy(sel)
html, err := sel.Html()
if err != nil {
exception.New(err.Error(), 500).Throw()
}
return html
}