diff options
author | Markus Wüstenberg | 2020-10-22 09:07:57 +0200 |
---|---|---|
committer | GitHub | 2020-10-22 09:07:57 +0200 |
commit | 6d2fb0eeb15d6b9774f127517d160137251264a4 (patch) | |
tree | d571a516f25e85dd4086521d73a419573d776df2 | |
parent | f2a2b949704e2faa7117dd33aae8da551a4baf8e (diff) | |
download | gomponents-6d2fb0eeb15d6b9774f127517d160137251264a4.tar.lz gomponents-6d2fb0eeb15d6b9774f127517d160137251264a4.tar.zst gomponents-6d2fb0eeb15d6b9774f127517d160137251264a4.zip |
Add Group function to group Nodes (#29)
-rw-r--r-- | el/document.go | 12 | ||||
-rw-r--r-- | el/form.go | 16 | ||||
-rw-r--r-- | el/inline.go | 10 | ||||
-rw-r--r-- | el/media.go | 2 | ||||
-rw-r--r-- | el/section.go | 12 | ||||
-rw-r--r-- | gomponents.go | 47 | ||||
-rw-r--r-- | gomponents_test.go | 22 |
7 files changed, 78 insertions, 43 deletions
diff --git a/el/document.go b/el/document.go index 8520cd7..370a124 100644 --- a/el/document.go +++ b/el/document.go @@ -55,15 +55,3 @@ func Style(children ...g.Node) g.NodeFunc { func Base(children ...g.Node) g.NodeFunc { return g.El("base", children...) } - -func prepend(node g.Node, nodes []g.Node) []g.Node { - newNodes := []g.Node{node} - newNodes = append(newNodes, nodes...) - return newNodes -} - -func prepend2(node1, node2 g.Node, nodes []g.Node) []g.Node { - newNodes := []g.Node{node1, node2} - newNodes = append(newNodes, nodes...) - return newNodes -} diff --git a/el/form.go b/el/form.go index 9ada591..25f89c7 100644 --- a/el/form.go +++ b/el/form.go @@ -13,40 +13,40 @@ func Button(children ...g.Node) g.NodeFunc { // Form returns an element with name "form", the given action and method attributes, and the given children. func Form(action, method string, children ...g.Node) g.NodeFunc { - return g.El("form", prepend2(g.Attr("action", action), g.Attr("method", method), children)...) + return g.El("form", g.Attr("action", action), g.Attr("method", method), g.Group(children)) } // Input returns an element with name "input", the given type and name attributes, and the given children. // Note that "type" is a keyword in Go, so the parameter is called typ. func Input(typ, name string, children ...g.Node) g.NodeFunc { - return g.El("input", prepend2(g.Attr("type", typ), g.Attr("name", name), children)...) + return g.El("input", g.Attr("type", typ), g.Attr("name", name), g.Group(children)) } // Label returns an element with name "label", the given for attribute, and the given children. // Note that "for" is a keyword in Go, so the parameter is called forr. func Label(forr string, children ...g.Node) g.NodeFunc { - return g.El("label", prepend(g.Attr("for", forr), children)...) + return g.El("label", g.Attr("for", forr), g.Group(children)) } // Option returns an element with name "option", the given text content and value attribute, and the given children. func Option(text, value string, children ...g.Node) g.NodeFunc { - return g.El("option", prepend2(g.Attr("value", value), g.Text(text), children)...) + return g.El("option", g.Attr("value", value), g.Text(text), g.Group(children)) } // Progress returns an element with name "progress", the given value and max attributes, and the given children. func Progress(value, max float64, children ...g.Node) g.NodeFunc { - return g.El("progress", prepend2( + return g.El("progress", g.Attr("value", fmt.Sprintf("%v", value)), g.Attr("max", fmt.Sprintf("%v", max)), - children)...) + g.Group(children)) } // Select returns an element with name "select", the given name attribute, and the given children. func Select(name string, children ...g.Node) g.NodeFunc { - return g.El("select", prepend(g.Attr("name", name), children)...) + return g.El("select", g.Attr("name", name), g.Group(children)) } // Textarea returns an element with name "textarea", the given name attribute, and the given children. func Textarea(name string, children ...g.Node) g.NodeFunc { - return g.El("textarea", prepend(g.Attr("name", name), children)...) + return g.El("textarea", g.Attr("name", name), g.Group(children)) } diff --git a/el/inline.go b/el/inline.go index f9ae39f..e0530d3 100644 --- a/el/inline.go +++ b/el/inline.go @@ -9,21 +9,21 @@ func Span(children ...g.Node) g.NodeFunc { } func A(href string, children ...g.Node) g.NodeFunc { - return g.El("a", prepend(g.Attr("href", href), children)...) + return g.El("a", g.Attr("href", href), g.Group(children)) } func B(text string, children ...g.Node) g.NodeFunc { - return g.El("b", prepend(g.Text(text), children)...) + return g.El("b", g.Text(text), g.Group(children)) } func Strong(text string, children ...g.Node) g.NodeFunc { - return g.El("strong", prepend(g.Text(text), children)...) + return g.El("strong", g.Text(text), g.Group(children)) } func I(text string, children ...g.Node) g.NodeFunc { - return g.El("i", prepend(g.Text(text), children)...) + return g.El("i", g.Text(text), g.Group(children)) } func Em(text string, children ...g.Node) g.NodeFunc { - return g.El("em", prepend(g.Text(text), children)...) + return g.El("em", g.Text(text), g.Group(children)) } diff --git a/el/media.go b/el/media.go index 4a19865..89787da 100644 --- a/el/media.go +++ b/el/media.go @@ -5,5 +5,5 @@ import ( ) func Img(src, alt string, children ...g.Node) g.NodeFunc { - return g.El("img", prepend2(g.Attr("src", src), g.Attr("alt", alt), children)...) + return g.El("img", g.Attr("src", src), g.Attr("alt", alt), g.Group(children)) } diff --git a/el/section.go b/el/section.go index 3c31ebc..f49a39c 100644 --- a/el/section.go +++ b/el/section.go @@ -31,32 +31,32 @@ func Header(children ...g.Node) g.NodeFunc { // H1 returns an element with name "h1", the given text content, and the given children. func H1(text string, children ...g.Node) g.NodeFunc { - return g.El("h1", prepend(g.Text(text), children)...) + return g.El("h1", g.Text(text), g.Group(children)) } // H2 returns an element with name "h2", the given text content, and the given children. func H2(text string, children ...g.Node) g.NodeFunc { - return g.El("h2", prepend(g.Text(text), children)...) + return g.El("h2", g.Text(text), g.Group(children)) } // H3 returns an element with name "h3", the given text content, and the given children. func H3(text string, children ...g.Node) g.NodeFunc { - return g.El("h3", prepend(g.Text(text), children)...) + return g.El("h3", g.Text(text), g.Group(children)) } // H4 returns an element with name "h4", the given text content, and the given children. func H4(text string, children ...g.Node) g.NodeFunc { - return g.El("h4", prepend(g.Text(text), children)...) + return g.El("h4", g.Text(text), g.Group(children)) } // H5 returns an element with name "h5", the given text content, and the given children. func H5(text string, children ...g.Node) g.NodeFunc { - return g.El("h5", prepend(g.Text(text), children)...) + return g.El("h5", g.Text(text), g.Group(children)) } // H6 returns an element with name "h6", the given text content, and the given children. func H6(text string, children ...g.Node) g.NodeFunc { - return g.El("h6", prepend(g.Text(text), children)...) + return g.El("h6", g.Text(text), g.Group(children)) } // HGroup returns an element with name "hgroup" and the given children. diff --git a/gomponents.go b/gomponents.go index 52d5355..c0aa510 100644 --- a/gomponents.go +++ b/gomponents.go @@ -64,17 +64,7 @@ func El(name string, children ...Node) NodeFunc { } for _, c := range children { - 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()) + renderChild(c, &inside, &outside) } b.WriteString(inside.String()) @@ -93,6 +83,26 @@ func El(name string, children ...Node) NodeFunc { } } +func renderChild(c Node, inside, outside *strings.Builder) { + if g, ok := c.(group); ok { + for _, groupC := range g.children { + renderChild(groupC, inside, outside) + } + return + } + if p, ok := c.(Placer); ok { + switch p.Place() { + case Inside: + inside.WriteString(c.Render()) + case Outside: + outside.WriteString(c.Render()) + } + return + } + // If c doesn't implement Placer, default to outside + outside.WriteString(c.Render()) +} + // Attr creates an attr DOM Node. // If one parameter is passed, it's a name-only attribute (like "required"). // If two parameters are passed, it's a name-value attribute (like `class="header"`). @@ -156,3 +166,18 @@ func Write(w io.Writer, n Node) error { _, err := w.Write([]byte(n.Render())) return err } + +type group struct { + children []Node +} + +func (g group) Render() string { + panic("cannot render group") +} + +// Group multiple Nodes into one Node. Useful for concatenation of Nodes in variadic functions. +// The resulting Node cannot Render directly, trying it will panic. +// Render must happen through a parent element created with El or a helper. +func Group(children []Node) Node { + return group{children: children} +} diff --git a/gomponents_test.go b/gomponents_test.go index 0e397cb..db9256c 100644 --- a/gomponents_test.go +++ b/gomponents_test.go @@ -133,3 +133,25 @@ func TestWrite(t *testing.T) { } }) } + +func TestGroup(t *testing.T) { + t.Run("groups multiple nodes into one", func(t *testing.T) { + children := []g.Node{g.El("div", g.Attr("id", "hat")), g.El("div")} + e := g.El("div", g.Attr("class", "foo"), g.El("div"), g.Group(children)) + assert.Equal(t, `<div class="foo"><div /><div id="hat" /><div /></div>`, e) + }) + + t.Run("panics on direct render", func(t *testing.T) { + e := g.Group(nil) + panicced := false + defer func() { + if err := recover(); err != nil { + panicced = true + } + }() + e.Render() + if !panicced { + t.FailNow() + } + }) +} |