about summary refs log tree commit diff stats
path: root/gomponents.go
diff options
context:
space:
mode:
authorMarkus Wüstenberg2020-09-24 13:19:52 +0200
committerGitHub2020-09-24 13:19:52 +0200
commit4c109f9f1d4db4733d267ece171a533521029bdb (patch)
tree555c4ef5ad7281e8e36431d31968ade85c61aa72 /gomponents.go
parentf27cb0c05f23785189979e57c831eb798e1da1f1 (diff)
downloadgomponents-4c109f9f1d4db4733d267ece171a533521029bdb.tar.lz
gomponents-4c109f9f1d4db4733d267ece171a533521029bdb.tar.zst
gomponents-4c109f9f1d4db4733d267ece171a533521029bdb.zip
Introduce Placer interface (#18)
When implemented, the `Place` method of the `Placer` interface tells `Render` in `El` where to put a Node. This is relevant for helpers that want to be rendered like attributes, inside the parent element.

Fixes the bug where `attr.Classes` was rendered outside the element.
Diffstat (limited to 'gomponents.go')
-rw-r--r--gomponents.go44
1 files changed, 36 insertions, 8 deletions
diff --git a/gomponents.go b/gomponents.go
index 21d3e75..73d0545 100644
--- a/gomponents.go
+++ b/gomponents.go
@@ -19,6 +19,20 @@ type Node interface {
 	Render() string
 }
 
+// Placer can be implemented to tell Render functions where to place the string representation of a Node
+// in the parent element.
+type Placer interface {
+	Place() Placement
+}
+
+// Placement is used with the Placer interface.
+type Placement int
+
+const (
+	Outside = Placement(iota)
+	Inside
+)
+
 // NodeFunc is render function that is also a Node.
 type NodeFunc func() string
 
@@ -26,6 +40,10 @@ func (n NodeFunc) Render() string {
 	return n()
 }
 
+func (n NodeFunc) Place() Placement {
+	return Outside
+}
+
 // String satisfies fmt.Stringer.
 func (n NodeFunc) String() string {
 	return n.Render()
@@ -35,7 +53,7 @@ func (n NodeFunc) String() string {
 // Use this if no convenience creator exists.
 func El(name string, children ...Node) NodeFunc {
 	return func() string {
-		var b, attrString, childrenString strings.Builder
+		var b, inside, outside strings.Builder
 
 		b.WriteString("<")
 		b.WriteString(name)
@@ -46,22 +64,28 @@ func El(name string, children ...Node) NodeFunc {
 		}
 
 		for _, c := range children {
-			if _, ok := c.(attr); ok {
-				attrString.WriteString(c.Render())
-			} else {
-				childrenString.WriteString(c.Render())
+			if p, ok := c.(Placer); ok {
+				switch p.Place() {
+				case Inside:
+					inside.WriteString(c.Render())
+				case Outside:
+					outside.WriteString(c.Render())
+				}
+				continue
 			}
+			// If c doesn't implement Placer, default to outside
+			outside.WriteString(c.Render())
 		}
 
-		b.WriteString(attrString.String())
+		b.WriteString(inside.String())
 
-		if childrenString.Len() == 0 {
+		if outside.Len() == 0 {
 			b.WriteString("/>")
 			return b.String()
 		}
 
 		b.WriteString(">")
-		b.WriteString(childrenString.String())
+		b.WriteString(outside.String())
 		b.WriteString("</")
 		b.WriteString(name)
 		b.WriteString(">")
@@ -97,6 +121,10 @@ func (a attr) Render() string {
 	return fmt.Sprintf(` %v="%v"`, a.name, *a.value)
 }
 
+func (a attr) Place() Placement {
+	return Inside
+}
+
 // String satisfies fmt.Stringer.
 func (a attr) String() string {
 	return a.Render()