~repos /gromer

#golang#htmx#ssr

git clone https://pyrossh.dev/repos/gromer.git

gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.


93d06b40 Peter John

3 years ago
try golang html parser
Files changed (1) hide show
  1. lib/main.go +133 -0
lib/main.go ADDED
@@ -0,0 +1,133 @@
1
+ package main
2
+
3
+ import (
4
+ "bytes"
5
+ "os"
6
+ "strings"
7
+
8
+ "golang.org/x/net/html"
9
+ "golang.org/x/net/html/atom"
10
+ )
11
+
12
+ type HtmlTag struct {
13
+ Tag string
14
+ Text string
15
+ Attr []html.Attribute
16
+ Children []*HtmlTag
17
+ }
18
+
19
+ var contextNode = &html.Node{
20
+ Type: html.ElementNode,
21
+ Data: "div",
22
+ DataAtom: atom.Lookup([]byte("div")),
23
+ }
24
+
25
+ func Html(tpl string) *html.Node {
26
+ newTpl := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(tpl, "\n", ""), "\r", ""), "\t", "")
27
+ doc, err := html.ParseFragment(bytes.NewBuffer([]byte(newTpl)), contextNode)
28
+ if err != nil {
29
+ panic(err)
30
+ }
31
+ return doc[0]
32
+ }
33
+
34
+ func Todo() *html.Node {
35
+ return Html(`
36
+ <li id="{todo.ID}" class="{ completed: todo.Completed }">
37
+ <div class="view">
38
+ <span>{todo.Text}</span>
39
+ </div>
40
+ {children}
41
+ <div class="count">
42
+ <span>{todo.Count}</span>
43
+ </div>
44
+ </li>
45
+ `)
46
+ }
47
+
48
+ func walkChildren(n, replaceNode1 *html.Node) {
49
+ if n.Data == "{children}" { // first
50
+ replaceNode1.NextSibling = &html.Node{}
51
+ *replaceNode1.NextSibling = *n.NextSibling
52
+ n.Parent.FirstChild = replaceNode1
53
+ return
54
+ }
55
+ if n.NextSibling != nil {
56
+ if n.NextSibling.Data == "{children}" {
57
+ if n.NextSibling.NextSibling != nil { // middle
58
+ replaceNode1.NextSibling = &html.Node{}
59
+ *replaceNode1.NextSibling = *n.NextSibling.NextSibling
60
+ n.NextSibling = replaceNode1
61
+ }
62
+ if n.NextSibling.PrevSibling != nil { // last
63
+ replaceNode1.PrevSibling = &html.Node{}
64
+ *replaceNode1.PrevSibling = *n.NextSibling.PrevSibling
65
+ n.NextSibling = replaceNode1
66
+ }
67
+ } else {
68
+ walkChildren(n.NextSibling, replaceNode1)
69
+ }
70
+ }
71
+ if n.FirstChild != nil {
72
+ walkChildren(n.FirstChild, replaceNode1)
73
+ }
74
+ }
75
+
76
+ func main() {
77
+ // ctx := map[string]interface{}{}
78
+ doc := Html(`
79
+ <div>
80
+ <div>
81
+ 123
82
+ <Todo id={todo.ID} class="{ completed: todo.Completed }">
83
+ <div class="container">
84
+ <h2>Title</h2>
85
+ <h3>Sub title</h3>
86
+ </div>
87
+ </Todo>
88
+ </div>
89
+ <div>
90
+ Test
91
+ <button>click</button>
92
+ </div>
93
+ </div>
94
+ `)
95
+ top := &HtmlTag{}
96
+ var f func(parent *HtmlTag, n *html.Node)
97
+ f = func(parent *HtmlTag, n *html.Node) {
98
+ if n.Type == html.TextNode {
99
+ data := strings.TrimSpace(n.Data)
100
+ if data != "" {
101
+ // data = "{}"
102
+ }
103
+ } else if n.Type == html.ElementNode {
104
+ // repr.Println(n.Data)
105
+ if n.Data == "todo" {
106
+ componentNode := Todo()
107
+ html.Render(os.Stdout, componentNode)
108
+ println("")
109
+ html.Render(os.Stdout, n)
110
+ println("")
111
+ if n.FirstChild != nil {
112
+ newChild := &html.Node{}
113
+ *newChild = *n.FirstChild
114
+ newChild.Parent = nil
115
+ n.RemoveChild(n.FirstChild)
116
+ walkChildren(componentNode.FirstChild, newChild)
117
+ n.AppendChild(componentNode)
118
+ }
119
+ }
120
+ // newParent := &HtmlTag{
121
+ // Tag: n.Data,
122
+ // Attr: n.Attr,
123
+ // }
124
+ // parent.Children = append(parent.Children, newParent)
125
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
126
+ f(nil, c)
127
+ }
128
+ }
129
+ }
130
+ f(top, doc)
131
+ // repr.Println(top)
132
+ html.Render(os.Stdout, doc)
133
+ }