diff --git a/framework/h/base.go b/framework/h/base.go index beb79a9..ac7851b 100644 --- a/framework/h/base.go +++ b/framework/h/base.go @@ -5,17 +5,18 @@ import ( "net/http" "reflect" "runtime" + "strings" ) type Headers = map[string]string type Partial struct { Headers *Headers - Root string + Root *Element } -func (p *Partial) Render() string { - return p.Root +func (p *Partial) Render(builder *strings.Builder) { + p.Root.Render(builder) } type Page struct { @@ -30,23 +31,23 @@ func NewPage(root Ren) *Page { } } -func NewPageWithHttpMethod(httpMethod string, root Ren) *Page { +func NewPageWithHttpMethod(httpMethod string, root *Element) *Page { return &Page{ HttpMethod: httpMethod, Root: root, } } -func NewPartialWithHeaders(headers *Headers, root Ren) *Partial { +func NewPartialWithHeaders(headers *Headers, root *Element) *Partial { return &Partial{ Headers: headers, - Root: root.Render(), + Root: root, } } -func NewPartial(root Ren) *Partial { +func NewPartial(root *Element) *Partial { return &Partial{ - Root: root.Render(), + Root: root, } } diff --git a/framework/h/lifecycle.go b/framework/h/lifecycle.go index 24beee7..5428965 100644 --- a/framework/h/lifecycle.go +++ b/framework/h/lifecycle.go @@ -69,12 +69,12 @@ func Increment(amount int) JsCommand { func SetInnerHtml(r Ren) JsCommand { // language=JavaScript - return JsCommand{Command: fmt.Sprintf("this.innerHTML = `%s`", r.Render())} + return JsCommand{Command: fmt.Sprintf("this.innerHTML = `%s`", Render(r))} } func SetOuterHtml(r Ren) JsCommand { // language=JavaScript - return JsCommand{Command: fmt.Sprintf("this.outerHTML = `%s`", r.Render())} + return JsCommand{Command: fmt.Sprintf("this.outerHTML = `%s`", Render(r))} } func AddAttribute(name, value string) JsCommand { diff --git a/framework/h/render.go b/framework/h/render.go index ec4a140..1ce50c4 100644 --- a/framework/h/render.go +++ b/framework/h/render.go @@ -2,13 +2,15 @@ package h import ( "fmt" + "strings" "time" ) func Render(node Ren) string { start := time.Now() - html := node.Render() + builder := &strings.Builder{} + node.Render(builder) duration := time.Since(start) fmt.Printf("render took %d microseconds\n", duration.Microseconds()) - return html + return builder.String() } diff --git a/framework/h/renderer.go b/framework/h/renderer.go index 732acee..57d9060 100644 --- a/framework/h/renderer.go +++ b/framework/h/renderer.go @@ -5,15 +5,13 @@ import ( "strings" ) -func (node *Element) Render() string { - builder := &strings.Builder{} - +func (node *Element) Render(builder *strings.Builder) { // some elements may not have a tag, such as a Fragment if node.tag != "" { builder.WriteString("<" + node.tag) builder.WriteString(" ") for name, value := range node.attributes { - builder.WriteString(NewAttribute(name, value).Render()) + NewAttribute(name, value).Render(builder) } } @@ -34,9 +32,9 @@ func (node *Element) Render() string { for _, child := range node.children { switch child.(type) { case *AttributeMap: - builder.WriteString(child.(*AttributeMap).Render()) + child.Render(builder) case *LifeCycle: - builder.WriteString(child.(*LifeCycle).Render()) + child.Render(builder) } } @@ -53,52 +51,42 @@ func (node *Element) Render() string { case *LifeCycle: continue default: - builder.WriteString(child.Render()) + child.Render(builder) } } if node.tag != "" { builder.WriteString("") } - - str := builder.String() - return str } -func (a *AttributeR) Render() string { - return fmt.Sprintf(`%s="%s"`, a.Name, a.Value) +func (a *AttributeR) Render(builder *strings.Builder) { + builder.WriteString(fmt.Sprintf(`%s="%s"`, a.Name, a.Value)) } -func (t *TextContent) Render() string { - return t.Content +func (t *TextContent) Render(builder *strings.Builder) { + builder.WriteString(t.Content) } -func (r *RawContent) Render() string { - return r.Content +func (r *RawContent) Render(builder *strings.Builder) { + builder.WriteString(r.Content) } -func (c *ChildList) Render() string { - builder := &strings.Builder{} +func (c *ChildList) Render(builder *strings.Builder) { for _, child := range c.Children { - builder.WriteString(child.Render()) + child.Render(builder) } - str := builder.String() - return str } -func (m *AttributeMap) Render() string { - builder := &strings.Builder{} +func (m *AttributeMap) Render(builder *strings.Builder) { m2 := m.ToMap() for k, v := range m2 { - builder.WriteString(NewAttribute(k, v).Render()) + NewAttribute(k, v).Render(builder) } - - str := builder.String() - return str } -func (l *LifeCycle) Render() string { +func (l *LifeCycle) Render(builder *strings.Builder) { m := make(map[string]string) for event, commands := range l.handlers { @@ -114,8 +102,7 @@ func (l *LifeCycle) Render() string { children = append(children, Attribute(event, js)) } - result := Children(children...).Render() - return result + Children(children...).Render(builder) } func (m *AttributeMap) ToMap() map[string]string { diff --git a/framework/h/tag.go b/framework/h/tag.go index 21dce56..b9a4fb8 100644 --- a/framework/h/tag.go +++ b/framework/h/tag.go @@ -14,7 +14,7 @@ type Element struct { children []Ren } -func (node *Element) AppendChild(child Ren) Ren { +func (node *Element) AppendChild(child Ren) *Element { node.children = append(node.children, child) return node } @@ -363,7 +363,7 @@ func List[T any](items []T, mapper func(item T, index int) *Element) *Element { return node } -func Fragment(children ...Ren) Ren { +func Fragment(children ...Ren) *Element { return &Element{ tag: "", children: children, @@ -541,11 +541,11 @@ func NewSwap(selector string, content *Element) SwapArg { } } -func OobSwap(ctx *RequestContext, content *Element) Ren { +func OobSwap(ctx *RequestContext, content *Element) *Element { return OobSwapWithSelector(ctx, "", content) } -func OobSwapWithSelector(ctx *RequestContext, selector string, content *Element) Ren { +func OobSwapWithSelector(ctx *RequestContext, selector string, content *Element) *Element { if ctx == nil || ctx.Get("HX-Request") == "" { return Empty() } diff --git a/framework/h/util.go b/framework/h/util.go index 5d9fd72..16b962f 100644 --- a/framework/h/util.go +++ b/framework/h/util.go @@ -4,10 +4,11 @@ import ( "encoding/json" "github.com/labstack/echo/v4" "net/url" + "strings" ) type Ren interface { - Render() string + Render(builder *strings.Builder) } func Ternary[T any](value bool, a T, b T) T { diff --git a/todo-list/partials/task/task.go b/todo-list/partials/task/task.go index 87e74d1..6ff2052 100644 --- a/todo-list/partials/task/task.go +++ b/todo-list/partials/task/task.go @@ -215,7 +215,8 @@ func UpdateName(ctx *h.RequestContext) *h.Partial { return h.NewPartial(h.Div(h.Text("failed to update"))) } - return h.NewPartial(h.OobSwap(ctx, Task(task, false))) + return h.NewPartial( + h.OobSwap(ctx, Task(task, false))) } func EditNameForm(ctx *h.RequestContext) *h.Partial {