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{}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-11 23:41:21 +00:00
|
|
|
flatChildren := make([]Renderable, 0)
|
2024-09-11 17:31:40 +00:00
|
|
|
for _, child := range node.children {
|
2024-09-11 23:41:21 +00:00
|
|
|
c := child.Render()
|
2024-09-11 17:31:40 +00:00
|
|
|
flatChildren = append(flatChildren, child)
|
2024-09-11 23:41:21 +00:00
|
|
|
if c.tag == FlagChildrenList {
|
|
|
|
|
for _, gc := range c.children {
|
2024-09-11 17:31:40 +00:00
|
|
|
flatChildren = append(flatChildren, gc)
|
|
|
|
|
}
|
2024-09-11 23:41:21 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
if child == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-12 02:06:34 +00:00
|
|
|
c := child.Render()
|
|
|
|
|
|
2024-09-11 23:41:21 +00:00
|
|
|
if c.tag == "class" {
|
|
|
|
|
insertAttribute(node, "class", c.value)
|
|
|
|
|
c.tag = FlagSkip
|
2024-01-22 15:22:16 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-11 23:41:21 +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)
|
|
|
|
|
}
|
2024-09-11 23:41:21 +00:00
|
|
|
gcr.tag = FlagSkip
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|
2024-09-11 23:41:21 +00:00
|
|
|
c.tag = FlagSkip
|
2024-09-11 00:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-11 23:41:21 +00:00
|
|
|
if c.tag == "attribute" {
|
|
|
|
|
for key, value := range c.attributes {
|
2024-01-22 15:22:16 +00:00
|
|
|
insertAttribute(node, key, value)
|
|
|
|
|
}
|
2024-09-11 23:41:21 +00:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-11 23:41:21 +00:00
|
|
|
c := child.Render()
|
|
|
|
|
|
|
|
|
|
if c.tag == FlagText {
|
|
|
|
|
page.builder.WriteString(c.text)
|
2024-09-11 00:52:18 +00:00
|
|
|
continue
|
|
|
|
|
}
|
2024-09-11 23:41:21 +00:00
|
|
|
if c.tag == FlagRaw {
|
|
|
|
|
page.builder.WriteString(c.value)
|
2024-09-11 00:52:18 +00:00
|
|
|
continue
|
|
|
|
|
}
|
2024-09-11 23:41:21 +00:00
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-11 23:41:21 +00:00
|
|
|
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,
|
2024-09-11 23:41:21 +00:00
|
|
|
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)
|
2024-09-12 02:06:34 +00:00
|
|
|
fmt.Printf("render took %d\n", duration.Microseconds())
|
2024-01-22 15:22:16 +00:00
|
|
|
return d
|
|
|
|
|
}
|