refactor: Copy slots in BuildAsComponent method

This commit is contained in:
Max 2024-07-07 00:51:07 +08:00
parent 6542c6e46b
commit 57e72a698d
4 changed files with 108 additions and 21 deletions

View file

@ -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 )

View file

@ -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{},

View file

@ -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 {

View file

@ -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