diff --git a/sui/api/api.go b/sui/api/api.go
index 7dfad437..74522334 100644
--- a/sui/api/api.go
+++ b/sui/api/api.go
@@ -10,6 +10,26 @@ var dsl = []byte(`
"guard": "bearer-jwt",
"group": "__yao/sui/v1",
"paths": [
+ {
+ "label": "Render",
+ "description": "Render the frontend page",
+ "path": "/render/*route",
+ "method": "POST",
+ "guard": "-",
+ "process": "sui.Render",
+ "in": [":context", "$param.route", ":payload"],
+ "out": { "status": 200, "type": "text/html; charset=utf-8" }
+ },
+ {
+ "label": "Run",
+ "description": "Run the backend script, with Api prefix method",
+ "path": "/run/*route",
+ "guard": "-",
+ "method": "POST",
+ "process": "sui.Run",
+ "in": [":context", "$param.route", ":payload"],
+ "out": { "status": 200, "type": "application/json" }
+ },
{
"path": "/:id/setting",
"method": "GET",
diff --git a/sui/api/process.go b/sui/api/process.go
index 5459bb62..093f1d09 100644
--- a/sui/api/process.go
+++ b/sui/api/process.go
@@ -20,6 +20,9 @@ func init() {
process.RegisterGroup("sui", map[string]process.Handler{
"setting": Setting,
+ "render": Render,
+ "run": Run,
+
"template.get": TemplateGet,
"template.find": TemplateFind,
"template.asset": TemplateAsset,
diff --git a/sui/api/render.go b/sui/api/render.go
new file mode 100644
index 00000000..b01ddbf2
--- /dev/null
+++ b/sui/api/render.go
@@ -0,0 +1,104 @@
+package api
+
+import (
+ "fmt"
+
+ "github.com/gin-gonic/gin"
+ "github.com/yaoapp/gou/process"
+ "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("
%s
", err.Error())
+ }
+
+ c, _, err := r.MakeCache()
+ if err != nil {
+ return fmt.Sprintf(" %s
", err.Error())
+ }
+
+ if c == nil {
+ return fmt.Sprintf(" Cache not found
")
+ }
+
+ data, ok := payload["data"].(map[string]interface{})
+ if !ok {
+ return fmt.Sprintf(" Data not found
")
+ }
+
+ name, ok := payload["name"].(string)
+ if !ok {
+ return fmt.Sprintf(" Name not found
")
+ }
+
+ html, err := r.renderHTML(c, name, c.HTML, core.Data(data))
+ if err != nil {
+ return fmt.Sprintf(" %s
", 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
+}
diff --git a/sui/api/run.go b/sui/api/run.go
new file mode 100644
index 00000000..b4aaa388
--- /dev/null
+++ b/sui/api/run.go
@@ -0,0 +1,8 @@
+package api
+
+import "github.com/yaoapp/gou/process"
+
+// Run the backend script, with Api prefix method
+func Run(process *process.Process) interface{} {
+ return nil
+}
diff --git a/sui/core/injections.go b/sui/core/injections.go
index 65f7a072..923c8620 100644
--- a/sui/core/injections.go
+++ b/sui/core/injections.go
@@ -284,13 +284,15 @@ const pageEventScriptTmpl = `
const compEventScriptTmpl = `
if (document.querySelector("[s\\:event=%s]")) {
- document.querySelector("[s\\:event=%s]").addEventListener("%s", function (event) {
- const dataKeys = %s;
- const jsonKeys = %s;
- const root = __sui_component_root(this, "%s");
- handler = new %s(root).%s;
- const target = event.target || null;
- __sui_event_handler(event, dataKeys, jsonKeys, target, root, handler);
+ let elms = document.querySelectorAll("[s\\:event=%s]");
+ elms.forEach(function (element) {
+ element.addEventListener("%s", function (event) {
+ const dataKeys = %s;
+ const jsonKeys = %s;
+ const root = __sui_component_root(element, "%s");
+ handler = new %s(root).%s;
+ __sui_event_handler(event, dataKeys, jsonKeys, element, root, handler);
+ });
});
}
`
diff --git a/sui/core/parser.go b/sui/core/parser.go
index 86edb613..b4d7367f 100644
--- a/sui/core/parser.go
+++ b/sui/core/parser.go
@@ -68,17 +68,19 @@ var keepWords = map[string]bool{
}
var allowUsePropAttrs = map[string]bool{
- "s:if": true,
- "s:elif": true,
- "s:for": true,
- "s:event": true,
+ "s:if": true,
+ "s:elif": true,
+ "s:for": true,
+ "s:event": true,
+ "s:render": true,
}
var keepAttrs = map[string]bool{
- "s:ns": true,
- "s:cn": true,
- "s:ready": true,
- "s:event": true,
+ "s:ns": true,
+ "s:cn": true,
+ "s:ready": true,
+ "s:event": true,
+ "s:render": true,
}
// NewTemplateParser create a new template parser
@@ -157,7 +159,7 @@ func (parser *TemplateParser) Render(html string) (string, error) {
if parser.option != nil && (parser.option.Request != nil || parser.option.Preview) {
// Remove the sui-hide attribute
doc.Find("[sui-hide]").Remove()
- parser.tidy(doc.Selection)
+ parser.Tidy(doc.Selection)
}
// fmt.Println(doc.Html())
@@ -837,13 +839,13 @@ func (parser *TemplateParser) show(sel *goquery.Selection) {
// sel.SetAttr("style", style)
}
-func (parser *TemplateParser) tidy(s *goquery.Selection) {
+func (parser *TemplateParser) Tidy(s *goquery.Selection) {
s.Contents().Each(func(i int, child *goquery.Selection) {
node := child.Get(0)
if _, exist := child.Attr("s:jit"); node.Data == "slot" || exist {
- parser.tidy(child)
+ parser.Tidy(child)
parser.removeWrapper(child)
return
}
@@ -872,7 +874,7 @@ func (parser *TemplateParser) tidy(s *goquery.Selection) {
}
node.Attr = attrs
- parser.tidy(child)
+ parser.Tidy(child)
})
}