htmgo/framework/h/renderer.go

171 lines
3.7 KiB
Go
Raw Normal View History

package h
import (
"fmt"
2024-09-21 03:59:07 +00:00
"github.com/maddalax/htmgo/framework/hx"
"strings"
)
2024-09-22 15:46:38 +00:00
type RenderContext struct {
builder *strings.Builder
scripts []string
}
func (ctx *RenderContext) AddScript(funcName string, body string) {
script := fmt.Sprintf(`
<script id="%s">
2024-09-25 21:57:13 +00:00
function %s(self) {
2024-09-22 15:46:38 +00:00
%s
}
</script>`, funcName, funcName, body)
ctx.scripts = append(ctx.scripts, script)
}
func (node *Element) Render(context *RenderContext) {
// some elements may not have a tag, such as a Fragment
2024-09-20 02:13:08 +00:00
if node.tag != "" {
2024-09-22 15:46:38 +00:00
context.builder.WriteString("<" + node.tag)
context.builder.WriteString(" ")
2024-09-20 02:13:08 +00:00
for name, value := range node.attributes {
2024-09-22 15:46:38 +00:00
NewAttribute(name, value).Render(context)
}
}
// first pass, flatten the children
flatChildren := make([]Ren, 0)
for _, child := range node.children {
switch child.(type) {
case *ChildList:
flatChildren = append(flatChildren, child.(*ChildList).Children...)
default:
flatChildren = append(flatChildren, child)
}
}
node.children = flatChildren
// second pass, render any attributes within the tag
for _, child := range node.children {
switch child.(type) {
case *AttributeMap:
2024-09-22 15:46:38 +00:00
child.Render(context)
case *LifeCycle:
2024-09-22 15:46:38 +00:00
child.Render(context)
}
}
// close the tag
if node.tag != "" {
2024-09-22 15:46:38 +00:00
context.builder.WriteString(">")
}
// render the children elements that are not attributes
for _, child := range node.children {
switch child.(type) {
case *AttributeMap:
continue
case *LifeCycle:
continue
default:
2024-09-22 15:46:38 +00:00
child.Render(context)
}
}
if node.tag != "" {
2024-09-22 15:46:38 +00:00
renderScripts(context)
context.builder.WriteString("</" + node.tag + ">")
}
}
func renderScripts(context *RenderContext) {
for _, script := range context.scripts {
context.builder.WriteString(script)
}
2024-09-22 15:46:38 +00:00
context.scripts = []string{}
}
2024-09-22 15:46:38 +00:00
func (a *AttributeR) Render(context *RenderContext) {
context.builder.WriteString(fmt.Sprintf(`%s="%s"`, a.Name, a.Value))
}
2024-09-22 15:46:38 +00:00
func (t *TextContent) Render(context *RenderContext) {
context.builder.WriteString(t.Content)
}
2024-09-22 15:46:38 +00:00
func (r *RawContent) Render(context *RenderContext) {
context.builder.WriteString(r.Content)
}
2024-09-22 15:46:38 +00:00
func (c *ChildList) Render(context *RenderContext) {
for _, child := range c.Children {
2024-09-22 15:46:38 +00:00
child.Render(context)
}
}
2024-09-22 15:46:38 +00:00
func (j SimpleJsCommand) Render(context *RenderContext) {
context.builder.WriteString(j.Command)
}
func (j ComplexJsCommand) Render(context *RenderContext) {
context.builder.WriteString(j.Command)
}
func (p *Partial) Render(context *RenderContext) {
p.Root.Render(context)
}
func (m *AttributeMap) Render(context *RenderContext) {
m2 := m.ToMap()
for k, v := range m2 {
2024-09-22 15:46:38 +00:00
context.builder.WriteString(" ")
NewAttribute(k, v).Render(context)
}
}
2024-09-22 15:46:38 +00:00
func (l *LifeCycle) fromAttributeMap(event string, key string, value string, context *RenderContext) {
2024-09-21 03:59:07 +00:00
if key == hx.GetAttr || key == hx.PatchAttr || key == hx.PostAttr {
2024-09-23 02:33:22 +00:00
HxTriggerString(hx.ToHtmxTriggerName(event)).Render(context)
2024-09-21 03:59:07 +00:00
}
2024-09-22 15:46:38 +00:00
Attribute(key, value).Render(context)
2024-09-21 03:59:07 +00:00
}
2024-09-22 15:46:38 +00:00
func (l *LifeCycle) Render(context *RenderContext) {
m := make(map[string]string)
for event, commands := range l.handlers {
m[event] = ""
for _, command := range commands {
2024-09-21 03:59:07 +00:00
switch c := command.(type) {
2024-09-22 15:46:38 +00:00
case SimpleJsCommand:
2024-09-22 16:53:41 +00:00
m[event] += fmt.Sprintf("%s;", c.Command)
2024-09-22 15:46:38 +00:00
case ComplexJsCommand:
context.AddScript(c.TempFuncName, c.Command)
2024-09-25 21:57:13 +00:00
m[event] += fmt.Sprintf("%s(this);", c.TempFuncName)
2024-09-21 03:59:07 +00:00
case *AttributeMap:
for k, v := range c.ToMap() {
2024-09-22 15:46:38 +00:00
l.fromAttributeMap(event, k, v, context)
2024-09-21 03:59:07 +00:00
}
}
}
}
children := make([]Ren, 0)
2024-09-21 03:59:07 +00:00
for event, value := range m {
if value != "" {
children = append(children, Attribute(event, value))
}
}
if len(children) == 0 {
return
}
2024-09-22 15:46:38 +00:00
Children(children...).Render(context)
}