From 57e72a698d7a4d6f38286c6dfdf38b0e6c283d54 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 7 Jul 2024 00:51:07 +0800 Subject: [PATCH] refactor: Copy slots in BuildAsComponent method --- sui/core/build.go | 57 +++++++++++++++++++++++++++++++------ sui/core/context.go | 2 +- sui/core/data.go | 68 ++++++++++++++++++++++++++++++++++++++------- sui/core/types.go | 2 +- 4 files changed, 108 insertions(+), 21 deletions(-) diff --git a/sui/core/build.go b/sui/core/build.go index 92c4c53e..1aa2a469 100644 --- a/sui/core/build.go +++ b/sui/core/build.go @@ -63,6 +63,7 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume // BuildAsComponent build the page as component func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, option *BuildOption) (string, error) { + if page.parent == nil { return "", fmt.Errorf("The parent page is not set") } @@ -111,19 +112,50 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op first := body.Children().First() page.copyProps(ctx, sel, first, attrs...) + page.copySlots(ctx, sel, first) page.buildComponents(doc, ctx, &opt) + data := Data{"$props": page.Attrs} + data.ReplaceSelectionUse(slotRe, first) html, err = body.Html() if err != nil { return "", err } - - // Update the component - data := Data{"$props": page.Attrs} - html, _ = data.ReplaceUse(slotRe, html) sel.ReplaceWithHtml(html) return html, nil } +func (page *Page) copySlots(ctx *BuildContext, from *goquery.Selection, to *goquery.Selection) error { + slots := from.Find("slot") + if slots.Length() == 0 { + return nil + } + + for i := 0; i < slots.Length(); i++ { + slot := slots.Eq(i) + name, has := slot.Attr("name") + if !has { + continue + } + + // Get the slot + slotSel := to.Find(fmt.Sprintf("slot[name='%s']", name)) + + if slotSel.Length() == 0 { + continue + } + + // Copy the slot + html, err := slot.Html() + if err != nil { + ctx.warnings = append(ctx.warnings, err.Error()) + continue + } + slotSel.SetHtml(html) + } + + return nil +} + func (page *Page) copyProps(ctx *BuildContext, from *goquery.Selection, to *goquery.Selection, extra ...html.Attribute) error { attrs := from.Get(0).Attr prefix := "s:prop" @@ -135,28 +167,29 @@ func (page *Page) copyProps(ctx *BuildContext, from *goquery.Selection, to *goqu continue } - if strings.HasPrefix(attr.Key, "...[{") { + if strings.HasPrefix(attr.Key, "...$props") { data := Data{"$props": page.parent.Attrs} - - val, err := data.Exec(attr.Key[3:]) + val, err := data.Exec(fmt.Sprintf("{{ %s }}", attr.Key[3:])) if err != nil { ctx.warnings = append(ctx.warnings, err.Error()) continue } - switch value := val.(type) { case map[string]string: for key, value := range value { page.Attrs[key] = value key = fmt.Sprintf("%s:%s", prefix, key) to.SetAttr(key, value) - } } continue } val := attr.Val + if strings.HasPrefix(attr.Key, `...\$props`) { + val = fmt.Sprintf("{{ $props.%s }}", attr.Key[9:]) + } + if strings.HasPrefix(attr.Key, "...") { val = attr.Key[3:] } @@ -194,6 +227,12 @@ func (page *Page) buildComponents(doc *goquery.Document, ctx *BuildContext, opti return } + // Slot tag + tagName := sel.Get(0).Data + if tagName == "slot" { + return + } + sel.SetAttr("parsed", "true") // Check if Just-In-Time Component ( "is" has variable ) diff --git a/sui/core/context.go b/sui/core/context.go index 8c4b8414..ed0883f6 100644 --- a/sui/core/context.go +++ b/sui/core/context.go @@ -3,7 +3,7 @@ package core // NewBuildContext create a new build context func NewBuildContext(global *GlobalBuildContext) *BuildContext { return &BuildContext{ - components: map[string]bool{}, + components: map[string]string{}, sequence: 1, scripts: []ScriptNode{}, scriptUnique: map[string]bool{}, diff --git a/sui/core/data.go b/sui/core/data.go index 4908a852..f08997e1 100644 --- a/sui/core/data.go +++ b/sui/core/data.go @@ -6,10 +6,12 @@ import ( "regexp" "strings" + "github.com/PuerkitoBio/goquery" "github.com/expr-lang/expr" "github.com/expr-lang/expr/vm" "github.com/yaoapp/gou/process" "github.com/yaoapp/kun/log" + "golang.org/x/net/html" ) // If set the map value, should keep the space at the end of the statement @@ -86,16 +88,7 @@ func (data Data) ExecString(stmt string) (string, error) { // 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 + return data.ReplaceUse(stmtRe, value) } // ReplaceUse replace the statement use the regexp @@ -112,6 +105,61 @@ func (data Data) ReplaceUse(re *regexp.Regexp, value string) (string, bool) { return res, hasStmt } +// ReplaceSelection replace the statement in the selection +func (data Data) ReplaceSelection(sel *goquery.Selection) bool { + return data.ReplaceSelectionUse(stmtRe, sel) +} + +// ReplaceSelectionUse replace the statement in the selection use the regexp +func (data Data) ReplaceSelectionUse(re *regexp.Regexp, sel *goquery.Selection) bool { + hasStmt := false + for _, node := range sel.Nodes { + ok := data.replaceNodeUse(re, node) + if ok { + hasStmt = true + } + } + return hasStmt +} + +func (data Data) replaceNodeUse(re *regexp.Regexp, node *html.Node) bool { + hasStmt := false + switch node.Type { + case html.TextNode: + v, ok := data.ReplaceUse(re, node.Data) + node.Data = v + if ok { + hasStmt = true + } + break + + case html.ElementNode: + for i := range node.Attr { + // Keepwords + if strings.HasPrefix(node.Attr[i].Key, "s:") || node.Attr[i].Key == "is" { + continue + } + + v, ok := data.ReplaceUse(re, node.Attr[i].Val) + node.Attr[i].Val = v + if ok { + hasStmt = true + } + } + + for c := node.FirstChild; c != nil; c = c.NextSibling { + ok := data.replaceNodeUse(re, c) + if ok { + hasStmt = true + } + } + break + } + + return hasStmt + +} + func _process(args ...any) (interface{}, error) { if len(args) < 1 { diff --git a/sui/core/types.go b/sui/core/types.go index ebeecae5..47add5c5 100644 --- a/sui/core/types.go +++ b/sui/core/types.go @@ -47,7 +47,7 @@ type Page struct { // BuildContext is the struct for the build context type BuildContext struct { - components map[string]bool + components map[string]string jitComponents map[string]bool sequence int doc *goquery.Document