htmgo/h/render.go

146 lines
2.8 KiB
Go
Raw Normal View History

2024-01-22 15:22:16 +00:00
package h
import (
"fmt"
"strings"
2024-09-11 00:52:18 +00:00
"time"
2024-01-22 15:22:16 +00:00
)
const FlagSkip = "skip"
2024-09-11 00:52:18 +00:00
const FlagText = "text"
const FlagRaw = "raw"
2024-09-11 17:31:40 +00:00
const FlagAttributeList = "x-attribute-list"
const FlagChildrenList = "x-children-list"
2024-01-22 15:22:16 +00:00
type Builder struct {
builder *strings.Builder
root *Node
}
func (page Builder) render() {
page.renderNode(page.root)
}
func insertAttribute(node *Node, name string, value string) {
existing := node.attributes[name]
if existing != "" {
node.attributes[name] = existing + " " + value
} else {
node.attributes[name] = value
}
}
func (page Builder) renderNode(node *Node) {
if node.tag != "" {
page.builder.WriteString(fmt.Sprintf("<%s", node.tag))
index := 0
if node.attributes == nil {
node.attributes = map[string]string{}
}
flatChildren := make([]Renderable, 0)
2024-09-11 17:31:40 +00:00
for _, child := range node.children {
c := child.Render()
2024-09-11 17:31:40 +00:00
flatChildren = append(flatChildren, child)
if c.tag == FlagChildrenList {
for _, gc := range c.children {
2024-09-11 17:31:40 +00:00
flatChildren = append(flatChildren, gc)
}
c.tag = FlagSkip
2024-09-11 17:31:40 +00:00
}
}
if len(flatChildren) > 0 {
node.children = flatChildren
}
2024-01-22 15:22:16 +00:00
for _, child := range node.children {
2024-09-11 00:52:18 +00:00
c := child.Render()
2024-09-11 00:52:18 +00:00
if child == nil {
continue
}
if c.tag == "class" {
insertAttribute(node, "class", c.value)
c.tag = FlagSkip
2024-01-22 15:22:16 +00:00
}
if c.tag == FlagAttributeList {
for _, gc := range c.children {
gcr := gc.Render()
for key, value := range gcr.attributes {
2024-09-11 00:52:18 +00:00
insertAttribute(node, key, value)
}
gcr.tag = FlagSkip
2024-09-11 00:52:18 +00:00
}
c.tag = FlagSkip
2024-09-11 00:52:18 +00:00
}
if c.tag == "attribute" {
for key, value := range c.attributes {
2024-01-22 15:22:16 +00:00
insertAttribute(node, key, value)
}
c.tag = FlagSkip
2024-01-22 15:22:16 +00:00
}
}
for key, value := range node.attributes {
if index == 0 {
page.builder.WriteString(" ")
}
page.builder.WriteString(key)
page.builder.WriteString("=")
page.builder.WriteRune('"')
page.builder.WriteString(value)
page.builder.WriteRune('"')
if index < len(node.attributes) {
page.builder.WriteRune(' ')
}
index += 1
}
page.builder.WriteString(">")
if node.text != "" {
page.builder.WriteString(node.text)
}
}
for _, child := range node.children {
2024-09-11 00:52:18 +00:00
if child == nil {
continue
}
c := child.Render()
if c.tag == FlagText {
page.builder.WriteString(c.text)
2024-09-11 00:52:18 +00:00
continue
}
if c.tag == FlagRaw {
page.builder.WriteString(c.value)
2024-09-11 00:52:18 +00:00
continue
}
if c.tag != FlagSkip {
page.renderNode(c)
2024-01-22 15:22:16 +00:00
}
}
if node.tag != "" {
page.builder.WriteString(fmt.Sprintf("</%s>", node.tag))
}
}
func Render(node Renderable) string {
2024-09-11 00:52:18 +00:00
start := time.Now()
2024-01-22 15:22:16 +00:00
builder := strings.Builder{}
page := Builder{
builder: &builder,
root: node.Render(),
2024-01-22 15:22:16 +00:00
}
page.render()
d := page.builder.String()
2024-09-11 00:52:18 +00:00
duration := time.Since(start)
fmt.Printf("render took %s\n", duration)
2024-01-22 15:22:16 +00:00
return d
}