~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.


87895734 Peter John

3 years ago
improve gsx
Files changed (3) hide show
  1. gsx/gsx.go +40 -67
  2. gsx/gsx_test.go +2 -2
  3. readme.md +20 -2
gsx/gsx.go CHANGED
@@ -2,13 +2,13 @@ package gsx
2
2
 
3
3
  import (
4
4
  "bytes"
5
+ "fmt"
5
6
  "io"
6
7
  "reflect"
7
8
  "regexp"
8
9
  "runtime"
9
10
  "strings"
10
11
 
11
- "github.com/alecthomas/repr"
12
12
  "golang.org/x/net/html"
13
13
  "golang.org/x/net/html/atom"
14
14
  )
@@ -23,6 +23,7 @@ var (
23
23
  compMap = map[string]ComponentFunc{}
24
24
  funcMap = map[string]interface{}{}
25
25
  styles = ""
26
+ refRegex = regexp.MustCompile(`{(.*?)}`)
26
27
  )
27
28
 
28
29
  type (
@@ -105,7 +106,7 @@ func convert(ref string, i interface{}) interface{} {
105
106
  return nil
106
107
  }
107
108
 
108
- func subsRef(ctx map[string]interface{}, ref string) interface{} {
109
+ func getRefValue(ctx map[string]interface{}, ref string) interface{} {
109
110
  if f, ok := funcMap[ref]; ok {
110
111
  return f.(func() string)()
111
112
  } else {
@@ -120,6 +121,20 @@ func subsRef(ctx map[string]interface{}, ref string) interface{} {
120
121
  }
121
122
  }
122
123
 
124
+ func removeBrackets(v string) string {
125
+ return strings.ReplaceAll(strings.ReplaceAll(v, "{", ""), "}", "")
126
+ }
127
+
128
+ func substituteString(ctx map[string]interface{}, v string) string {
129
+ found := refRegex.FindString(v)
130
+ if found != "" {
131
+ varName := removeBrackets(found)
132
+ varValue := fmt.Sprintf("%v", getRefValue(ctx, varName))
133
+ return strings.ReplaceAll(v, found, varValue)
134
+ }
135
+ return v
136
+ }
137
+
123
138
  func populateChildren(n, replaceNode1 *html.Node) {
124
139
  if n.Data == "{children}" { // first
125
140
  replaceNode1.NextSibling = &html.Node{}
@@ -150,33 +165,35 @@ func populateChildren(n, replaceNode1 *html.Node) {
150
165
 
151
166
  func populate(ctx Html, n *html.Node) {
152
167
  if n.Type == html.TextNode {
168
+ if n.Data != "" && strings.Contains(n.Data, "{") && n.Data != "{children}" {
153
- // if n.Data != "" {
169
+ n.Data = substituteString(ctx, n.Data)
154
- // }
170
+ }
155
171
  } else if n.Type == html.ElementNode {
156
- repr.Println("dd", n.Data)
157
172
  for i, at := range n.Attr {
158
- // if len(param.Value.KV) != 0 {
159
- // values := []string{}
160
- // for _, kv := range param.Value.KV {
161
- // if subsRef(ctx, kv.Value) == true {
162
- // values = append(values, kv.Key)
163
- // }
164
- // }
165
173
  if at.Val != "" && strings.Contains(at.Val, "{") {
166
174
  if at.Key == "class" {
167
- repr.Println(at)
168
- } else {
169
- re := regexp.MustCompile(`{(.*?)}`)
170
- found := re.FindString(at.Val)
171
- if found != "" {
175
+ classes := ""
172
- varName := strings.ReplaceAll(strings.ReplaceAll(found, "{", ""), "}", "")
176
+ kvstrings := strings.Split(strings.TrimSpace(removeBrackets(at.Val)), ",")
177
+ for _, kv := range kvstrings {
178
+ kvarray := strings.Split(kv, ":")
179
+ k := strings.TrimSpace(kvarray[0])
180
+ v := strings.TrimSpace(kvarray[1])
173
- varValue := subsRef(ctx, varName).(string)
181
+ varValue := getRefValue(ctx, v)
174
- n.Attr[i] = html.Attribute{
182
+ if varValue.(bool) {
175
- Namespace: at.Namespace,
176
- Key: at.Key,
183
+ classes += k
177
- Val: strings.ReplaceAll(at.Val, found, varValue),
178
184
  }
179
185
  }
186
+ n.Attr[i] = html.Attribute{
187
+ Namespace: at.Namespace,
188
+ Key: at.Key,
189
+ Val: classes,
190
+ }
191
+ } else {
192
+ n.Attr[i] = html.Attribute{
193
+ Namespace: at.Namespace,
194
+ Key: at.Key,
195
+ Val: substituteString(ctx, at.Val),
196
+ }
180
197
  }
181
198
  }
182
199
  }
@@ -193,10 +210,6 @@ func populate(ctx Html, n *html.Node) {
193
210
  }
194
211
  result := reflect.ValueOf(comp.Func).Call(args)
195
212
  compNode := result[0].Interface().(Node)
196
- // html.Render(os.Stdout, componentNode)
197
- // println("")
198
- // html.Render(os.Stdout, n)
199
- // println("")
200
213
  if n.FirstChild != nil {
201
214
  newChild := &html.Node{}
202
215
  *newChild = *n.FirstChild
@@ -213,13 +226,6 @@ func populate(ctx Html, n *html.Node) {
213
226
  }
214
227
 
215
228
  // func render(x *Xml, ctx map[string]interface{}) string {
216
- // if x.Value != nil {
217
- // if x.Value.Ref != "" {
218
- // s += space + " " + subsRef(ctx, x.Value.Ref).(string) + "\n"
219
- // } else if x.Value.Str != "" {
220
- // s += space + " " + strings.ReplaceAll(x.Value.Str, `"`, "") + "\n"
221
- // }
222
- // }
223
229
  // if x.Name == "For" {
224
230
  // ctxKey := getAttribute("key", x.Attributes)
225
231
  // ctxName := getAttribute("itemKey", x.Attributes)
@@ -233,38 +239,5 @@ func populate(ctx Html, n *html.Node) {
233
239
  // s += render(x.Children[0], ctx) + "\n"
234
240
  // }
235
241
  // }
236
- // } else {
237
- // if comp, ok := compMap[x.Name]; ok {
238
- // } else {
239
- // found := false
240
- // for _, t := range htmlTags {
241
- // if t == x.Name {
242
- // found = true
243
- // }
244
- // }
245
- // if !found {
246
- // panic(fmt.Errorf("Comp not found %s", x.Name))
247
- // }
248
- // for _, c := range x.Children {
249
- // ctx["_space"] = space + " "
250
- // s += render(c, ctx) + "\n"
251
- // }
252
- // }
253
242
  // }
254
- // s += space + "</" + x.Name + ">"
255
- // return s
256
- // }
257
-
258
- // <script>
259
- // document.addEventListener('alpine:init', () => {
260
- // Alpine.store('todos', {
261
- // list: [],
262
- // count: 0,
263
- // })
264
- // })
265
- // </script>
266
-
267
- // patch: {
268
- // { "op": "add", "path": "/todos/list", "value": { "id": "123", "text": "123" } },
269
243
  // }
270
- //
gsx/gsx_test.go CHANGED
@@ -54,11 +54,11 @@ func TestHtml(t *testing.T) {
54
54
  </div>
55
55
  <div>
56
56
  Test
57
- <button>click</button>
57
+ <button>{WebsiteName}</button>
58
58
  </div>
59
59
  </div>
60
60
  `).String()
61
- expected := "<div><div>123<todo key=\"todo\"><li id=\"todo-b1a7359c-ebb4-11ec-8ea0-0242ac120002\" class=\"{ completed: todo.Completed }\"><div class=\"view\"><span>{todo.Text}</span></div><div class=\"container\"><h2>Title</h2><h3>Sub title</h3></div><div class=\"count\"><span>{todo.Completed}</span></div></li></todo></div><div>Test<button>click</button></div></div>"
61
+ expected := "<div><div>123<todo key=\"todo\"><li id=\"todo-b1a7359c-ebb4-11ec-8ea0-0242ac120002\" class=\"completed\"><div class=\"view\"><span>My first todo</span></div><div class=\"container\"><h2>Title</h2><h3>Sub title</h3></div><div class=\"count\"><span>true</span></div></li></todo></div><div>Test<button>My Website</button></div></div>"
62
62
  // actual := Html(ctx).Render(`
63
63
  // <ul id="todo-list" class="relative">
64
64
  // <For key="todos" itemKey="todo">
readme.md CHANGED
@@ -220,6 +220,24 @@ func main() {
220
220
  }
221
221
  ```
222
222
 
223
- # TODO:
223
+ ## TODO:
224
224
  Add inline css formatting
225
- ADd inline html formatting
225
+ ADd inline html formatting
226
+
227
+ ## Ideas:
228
+ ```js
229
+ <script>
230
+ document.addEventListener('alpine:init', () => {
231
+ Alpine.store('todos', {
232
+ list: [],
233
+ count: 0,
234
+ })
235
+ })
236
+ </script>
237
+
238
+ // Send patches in all Post API's instead of data
239
+ [
240
+ { "op": "add", "path": "/todos/list-", "value": { "id": "123", "text": "123" } },
241
+ { "op": "replace", "path": "/todos/count", "value": 1 } ,
242
+ ]
243
+ ```