diff --git a/elem.go b/elem.go index 2b9c2a1..d1dc068 100644 --- a/elem.go +++ b/elem.go @@ -53,16 +53,21 @@ var booleanAttrs = map[string]struct{}{ attrs.Selected: {}, } +type RenderOptions struct { + DisablePreamble bool +} + type Node interface { - RenderTo(builder *strings.Builder) + RenderTo(builder *strings.Builder, opts RenderOptions) Render() string + RenderWithOptions(opts RenderOptions) string } // NoneNode represents a node that renders nothing. type NoneNode struct{} // RenderTo for NoneNode does nothing. -func (n NoneNode) RenderTo(builder *strings.Builder) { +func (n NoneNode) RenderTo(builder *strings.Builder, opts RenderOptions) { // Intentionally left blank to render nothing } @@ -71,9 +76,14 @@ func (n NoneNode) Render() string { return "" } +// RenderWithOptions for NoneNode returns an empty string. +func (n NoneNode) RenderWithOptions(opts RenderOptions) string { + return "" +} + type TextNode string -func (t TextNode) RenderTo(builder *strings.Builder) { +func (t TextNode) RenderTo(builder *strings.Builder, opts RenderOptions) { builder.WriteString(string(t)) } @@ -81,9 +91,13 @@ func (t TextNode) Render() string { return string(t) } +func (t TextNode) RenderWithOptions(opts RenderOptions) string { + return string(t) +} + type RawNode string -func (r RawNode) RenderTo(builder *strings.Builder) { +func (r RawNode) RenderTo(builder *strings.Builder, opts RenderOptions) { builder.WriteString(string(r)) } @@ -91,17 +105,25 @@ func (r RawNode) Render() string { return string(r) } +func (t RawNode) RenderWithOptions(opts RenderOptions) string { + return string(t) +} + type CommentNode string -func (c CommentNode) RenderTo(builder *strings.Builder) { +func (c CommentNode) RenderTo(builder *strings.Builder, opts RenderOptions) { builder.WriteString("") } func (c CommentNode) Render() string { + return c.RenderWithOptions(RenderOptions{}) +} + +func (c CommentNode) RenderWithOptions(opts RenderOptions) string { var builder strings.Builder - c.RenderTo(&builder) + c.RenderTo(&builder, opts) return builder.String() } @@ -111,11 +133,11 @@ type Element struct { Children []Node } -func (e *Element) RenderTo(builder *strings.Builder) { +func (e *Element) RenderTo(builder *strings.Builder, opts RenderOptions) { // The HTML tag needs a doctype preamble in order to ensure // browsers don't render in legacy/quirks mode // https://developer.mozilla.org/en-US/docs/Glossary/Doctype - if e.Tag == "html" { + if !opts.DisablePreamble && e.Tag == "html" { builder.WriteString("") } @@ -146,7 +168,7 @@ func (e *Element) RenderTo(builder *strings.Builder) { // Build the content for _, child := range e.Children { - child.RenderTo(builder) + child.RenderTo(builder, opts) } // Append closing tag @@ -174,8 +196,12 @@ func (e *Element) renderAttrTo(attrName string, builder *strings.Builder) { } func (e *Element) Render() string { + return e.RenderWithOptions(RenderOptions{}) +} + +func (e *Element) RenderWithOptions(opts RenderOptions) string { var builder strings.Builder - e.RenderTo(&builder) + e.RenderTo(&builder, opts) return builder.String() } diff --git a/elements_test.go b/elements_test.go index 6ec6fa4..2278c0f 100644 --- a/elements_test.go +++ b/elements_test.go @@ -3,8 +3,6 @@ package elem import ( "testing" - "github.com/chasefleming/elem-go/styles" - "github.com/chasefleming/elem-go/attrs" "github.com/stretchr/testify/assert" ) @@ -29,6 +27,18 @@ func TestHtml(t *testing.T) { assert.Equal(t, expected, el.Render()) } +func TestHtmlWithOptions(t *testing.T) { + expected := `
Welcome to Elem!
` + el := Html(attrs.Props{attrs.Lang: "en"}, + Head(nil, + Meta(attrs.Props{attrs.Charset: "UTF-8"}), + Title(nil, Text("Elem Page")), + ), + Body(nil, P(nil, Text("Welcome to Elem!"))), + ) + assert.Equal(t, expected, el.RenderWithOptions(RenderOptions{DisablePreamble: true})) +} + // ========== Text Formatting and Structure ========== func TestA(t *testing.T) { @@ -269,7 +279,7 @@ func TestScript(t *testing.T) { func TestStyle(t *testing.T) { expected := `` cssContent := `.test-class {color: #333;}` - el := Style(attrs.Props{attrs.Type: "text/css"}, styles.CSS(cssContent)) + el := Style(attrs.Props{attrs.Type: "text/css"}, TextNode(cssContent)) assert.Equal(t, expected, el.Render()) } diff --git a/styles/styles.go b/styles/styles.go index 9e72899..798b99e 100644 --- a/styles/styles.go +++ b/styles/styles.go @@ -3,6 +3,8 @@ package styles import ( "sort" "strings" + + "github.com/chasefleming/elem-go" ) // Props is a map of CSS properties @@ -38,7 +40,7 @@ func (p Props) ToInline() string { type CSSNode string // RenderTo satisfies part of the Node interface by allowing CSSNode to be written to a strings.Builder -func (cn CSSNode) RenderTo(builder *strings.Builder) { +func (cn CSSNode) RenderTo(builder *strings.Builder, opts elem.RenderOptions) { builder.WriteString(string(cn)) } diff --git a/styles/styles_test.go b/styles/styles_test.go index 0582cc2..de5b313 100644 --- a/styles/styles_test.go +++ b/styles/styles_test.go @@ -1,10 +1,18 @@ package styles import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) +func TestCSS(t *testing.T) { + cssContent := `.test-class {color: #333;}` + expected := `.test-class {color: #333;}` + el := CSS(cssContent) + assert.Equal(t, expected, el.Render()) +} + func TestStyleToInline(t *testing.T) { style := Props{ BackgroundColor: "blue", @@ -36,3 +44,4 @@ func TestStyleString_UnorderedKeys(t *testing.T) { } assert.Equal(t, "background-color: blue; color: white; font-size: 16px; outline-style: solid;", style.ToInline()) } +