Merge pull request #529 from trheyi/main
[add] support for attributes in BuildForImport method and template parser to support printing data
This commit is contained in:
commit
7869f3e225
5 changed files with 136 additions and 21 deletions
|
|
@ -123,7 +123,12 @@ func (r *Request) Render() (string, int, error) {
|
|||
data["$global"] = global
|
||||
}
|
||||
|
||||
parser := core.NewTemplateParser(data, nil)
|
||||
printData := false
|
||||
if r.Query != nil && r.Query.Has("__sui_print_data") {
|
||||
printData = true
|
||||
}
|
||||
|
||||
parser := core.NewTemplateParser(data, &core.ParserOption{PrintData: printData})
|
||||
html, err := parser.Render(c.HTML)
|
||||
if err != nil {
|
||||
return "", 500, fmt.Errorf("render error, please re-complie the page %s", err.Error())
|
||||
|
|
|
|||
|
|
@ -52,13 +52,25 @@ func (page *Page) Build(option *BuildOption) (*goquery.Document, []string, error
|
|||
}
|
||||
|
||||
// BuildForImport build the page for import
|
||||
func (page *Page) BuildForImport(option *BuildOption, slots map[string]interface{}) (string, string, string, []string, error) {
|
||||
func (page *Page) BuildForImport(option *BuildOption, slots map[string]interface{}, attrs map[string]string) (string, string, string, []string, error) {
|
||||
warnings := []string{}
|
||||
html, err := page.BuildHTML(option)
|
||||
if err != nil {
|
||||
warnings = append(warnings, err.Error())
|
||||
}
|
||||
|
||||
data := map[string]interface{}{}
|
||||
if slots != nil {
|
||||
for k, v := range slots {
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if attrs != nil {
|
||||
data["$prop"] = attrs
|
||||
page.Attrs = attrs
|
||||
}
|
||||
|
||||
// Add Style & Script & Warning
|
||||
doc, err := NewDocument([]byte(html))
|
||||
if err != nil {
|
||||
|
|
@ -83,7 +95,6 @@ func (page *Page) BuildForImport(option *BuildOption, slots map[string]interface
|
|||
}
|
||||
|
||||
body := doc.Selection.Find("body")
|
||||
|
||||
if body.Length() > 1 {
|
||||
body.SetHtml("<div>" + html + "</div>")
|
||||
}
|
||||
|
|
@ -96,7 +107,7 @@ func (page *Page) BuildForImport(option *BuildOption, slots map[string]interface
|
|||
}
|
||||
|
||||
// Replace the slots
|
||||
html, _ = Data(slots).ReplaceUse(slotRe, html)
|
||||
html, _ = Data(data).ReplaceUse(slotRe, html)
|
||||
return html, style, script, warnings, nil
|
||||
}
|
||||
|
||||
|
|
@ -122,6 +133,7 @@ func (page *Page) parse(doc *goquery.Document, option *BuildOption, warnings []s
|
|||
continue
|
||||
}
|
||||
|
||||
sel.SetAttr("parsed", "true")
|
||||
ipage, err := tmpl.Page(name)
|
||||
if err != nil {
|
||||
sel.ReplaceWith(fmt.Sprintf("<!-- %s -->", err.Error()))
|
||||
|
|
@ -136,6 +148,7 @@ func (page *Page) parse(doc *goquery.Document, option *BuildOption, warnings []s
|
|||
continue
|
||||
}
|
||||
|
||||
// Set the parent
|
||||
slots := map[string]interface{}{}
|
||||
for _, slot := range sel.Find("slot").Nodes {
|
||||
slotSel := goquery.NewDocumentFromNode(slot)
|
||||
|
|
@ -150,15 +163,37 @@ func (page *Page) parse(doc *goquery.Document, option *BuildOption, warnings []s
|
|||
slots[slotName] = strings.TrimSpace(slotHTML)
|
||||
}
|
||||
|
||||
// Set Attrs
|
||||
attrs := map[string]string{}
|
||||
if sel.Length() > 0 {
|
||||
if page.Attrs != nil {
|
||||
parentProps := Data{"$prop": page.Attrs}
|
||||
for k, v := range page.Attrs {
|
||||
if k == "is" {
|
||||
continue
|
||||
}
|
||||
attrs[k], _ = parentProps.ReplaceUse(slotRe, v)
|
||||
}
|
||||
} else {
|
||||
for _, attr := range sel.Nodes[0].Attr {
|
||||
if attr.Key == "is" {
|
||||
continue
|
||||
}
|
||||
attrs[attr.Key] = attr.Val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p := ipage.Get()
|
||||
namespace := fmt.Sprintf("__page_%s_%d", strings.ReplaceAll(name, "/", "_"), idx)
|
||||
html, style, script, warns, err := ipage.Get().BuildForImport(&BuildOption{
|
||||
html, style, script, warns, err := p.BuildForImport(&BuildOption{
|
||||
SSR: option.SSR,
|
||||
AssetRoot: option.AssetRoot,
|
||||
IgnoreAssetRoot: option.IgnoreAssetRoot,
|
||||
KeepPageTag: option.KeepPageTag,
|
||||
IgnoreDocument: true,
|
||||
Namespace: namespace,
|
||||
}, slots)
|
||||
}, slots, attrs)
|
||||
|
||||
if err != nil {
|
||||
sel.ReplaceWith(fmt.Sprintf("<!-- %s -->", err.Error()))
|
||||
|
|
@ -184,6 +219,11 @@ func (page *Page) parse(doc *goquery.Document, option *BuildOption, warnings []s
|
|||
}
|
||||
|
||||
sel.SetAttr("s:slots", slotsAttr)
|
||||
|
||||
// Set Attrs
|
||||
for k, v := range attrs {
|
||||
sel.SetAttr(k, v)
|
||||
}
|
||||
continue
|
||||
}
|
||||
sel.ReplaceWithHtml(fmt.Sprintf("\n%s\n%s\n%s\n", style, html, script))
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ var options = []expr.Option{
|
|||
func (data Data) New(stmt string) (*vm.Program, error) {
|
||||
stmt = strings.TrimSpace(strings.TrimRight(strings.TrimLeft(stmt, "{{ "), "}}"))
|
||||
stmt = strings.TrimSpace(strings.TrimRight(strings.TrimLeft(stmt, "[{ "), "}]"))
|
||||
// ' => ' " => "
|
||||
stmt = strings.ReplaceAll(stmt, "'", "'")
|
||||
stmt = strings.ReplaceAll(stmt, """, "\"")
|
||||
return expr.Compile(stmt, append([]expr.Option{expr.Env(data)}, options...)...)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
|
|
@ -28,8 +29,9 @@ type Mapping struct {
|
|||
|
||||
// ParserOption parser option
|
||||
type ParserOption struct {
|
||||
Editor bool `json:"editor,omitempty"`
|
||||
Preview bool `json:"preview,omitempty"`
|
||||
Editor bool `json:"editor,omitempty"`
|
||||
Preview bool `json:"preview,omitempty"`
|
||||
PrintData bool `json:"print_data,omitempty"`
|
||||
}
|
||||
|
||||
// NewTemplateParser create a new template parser
|
||||
|
|
@ -50,12 +52,18 @@ func NewTemplateParser(data Data, option *ParserOption) *TemplateParser {
|
|||
|
||||
// Render parses and renders the HTML template
|
||||
func (parser *TemplateParser) Render(html string) (string, error) {
|
||||
reader := bytes.NewReader([]byte(fmt.Sprintf("<root>%s</root>", html)))
|
||||
|
||||
if !strings.Contains(html, "<html") {
|
||||
html = fmt.Sprintf(`<!DOCTYPE html><html lang="en">%s</html>`, html)
|
||||
}
|
||||
|
||||
reader := bytes.NewReader([]byte(html))
|
||||
doc, err := goquery.NewDocumentFromReader(reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
root := doc.Selection.Find("root")
|
||||
|
||||
root := doc.Selection.Find("html")
|
||||
parser.parseNode(root.Nodes[0])
|
||||
|
||||
// Replace the nodes
|
||||
|
|
@ -64,9 +72,36 @@ func (parser *TemplateParser) Render(html string) (string, error) {
|
|||
delete(parser.replace, sel)
|
||||
}
|
||||
|
||||
// fmt.Println(root.Html())
|
||||
// Print the data
|
||||
jsPrintData := ""
|
||||
if parser.option != nil && parser.option.PrintData {
|
||||
jsPrintData = "console.log(__sui_data);\n"
|
||||
}
|
||||
|
||||
// Append the data to the body
|
||||
body := doc.Find("body")
|
||||
if body.Length() > 0 {
|
||||
data, err := jsoniter.MarshalToString(parser.data)
|
||||
if err != nil {
|
||||
data, _ = jsoniter.MarshalToString(map[string]string{"error": err.Error()})
|
||||
}
|
||||
body.AppendHtml("<script>\n" +
|
||||
"try { " +
|
||||
`var __sui_data = ` + data + ";\n" +
|
||||
"} catch (e) { console.log('init data error:', e); }\n" +
|
||||
jsPrintData +
|
||||
"</script>\n",
|
||||
)
|
||||
}
|
||||
|
||||
// For editor
|
||||
if parser.option != nil && parser.option.Editor {
|
||||
return doc.Find("body").Html()
|
||||
}
|
||||
|
||||
// fmt.Println(doc.Html())
|
||||
// fmt.Println(parser.errors)
|
||||
return root.Html()
|
||||
return doc.Html()
|
||||
}
|
||||
|
||||
// Parse parses and renders the HTML template
|
||||
|
|
@ -108,6 +143,37 @@ func (parser *TemplateParser) parseElementNode(sel *goquery.Selection) {
|
|||
if _, exist := sel.Attr("s:for"); exist {
|
||||
parser.forStatementNode(sel)
|
||||
}
|
||||
|
||||
// Parse the attributes
|
||||
parser.parseElementAttrs(sel)
|
||||
}
|
||||
|
||||
func (parser *TemplateParser) parseElementAttrs(sel *goquery.Selection) {
|
||||
if len(sel.Nodes) < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if sel.AttrOr("parsed", "false") == "true" {
|
||||
return
|
||||
}
|
||||
|
||||
attrs := sel.Nodes[0].Attr
|
||||
for _, attr := range attrs {
|
||||
parser.sequence = parser.sequence + 1
|
||||
res, hasStmt := parser.data.Replace(attr.Val)
|
||||
if hasStmt {
|
||||
bindings := strings.TrimSpace(attr.Val)
|
||||
key := fmt.Sprintf("%v", parser.sequence)
|
||||
parser.mapping[attr.Key] = Mapping{
|
||||
Key: key,
|
||||
Type: "attr",
|
||||
Value: bindings,
|
||||
}
|
||||
sel.SetAttr(attr.Key, res)
|
||||
bindname := fmt.Sprintf("s:bind:%s", attr.Key)
|
||||
sel.SetAttr(bindname, bindings)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (parser *TemplateParser) parseTextNode(node *html.Node) {
|
||||
|
|
|
|||
|
|
@ -25,15 +25,16 @@ type Setting struct {
|
|||
|
||||
// Page is the struct for the page
|
||||
type Page struct {
|
||||
Route string `json:"route"`
|
||||
Name string `json:"name,omitempty"`
|
||||
TemplateID string `json:"-"`
|
||||
SuiID string `json:"-"`
|
||||
Config *PageConfig `json:"-"`
|
||||
Path string `json:"-"`
|
||||
Codes SourceCodes `json:"-"`
|
||||
Document []byte `json:"-"`
|
||||
GlobalData []byte `json:"-"`
|
||||
Route string `json:"route"`
|
||||
Name string `json:"name,omitempty"`
|
||||
TemplateID string `json:"-"`
|
||||
SuiID string `json:"-"`
|
||||
Config *PageConfig `json:"-"`
|
||||
Path string `json:"-"`
|
||||
Codes SourceCodes `json:"-"`
|
||||
Document []byte `json:"-"`
|
||||
GlobalData []byte `json:"-"`
|
||||
Attrs map[string]string `json:"-"`
|
||||
}
|
||||
|
||||
// PageTreeNode is the struct for the page tree node
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue