From 43e629de1af95ebd69b662ee432553f9727111d2 Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Sun, 16 Apr 2023 00:04:26 +0200 Subject: [PATCH 1/8] self closing tags do not exist in HTML https://developer.mozilla.org/en-US/docs/Glossary/Void_element#self-closing_tags --- html/elements.go | 10 +++++----- html/render.go | 9 ++------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/html/elements.go b/html/elements.go index 7bc87f8..affee67 100644 --- a/html/elements.go +++ b/html/elements.go @@ -16,10 +16,10 @@ func Iframe(attr Attributes, children ...Block) Block { return newElement("iframe", attr, children, 0) } func Link(attr Attributes, children ...Block) Block { - return newElement("link", attr, children, SelfClose) + return newElement("link", attr, children, Void) } func Img(attr Attributes, children ...Block) Block { - return newElement("img", attr, children, SelfClose) + return newElement("img", attr, children, Void) } func Meta(attr Attributes, children ...Block) Block { return newElement("meta", attr, children, Void) @@ -100,11 +100,11 @@ func Strong(attr Attributes, children ...Block) Block { return newElement("strong", attr, children, 0) } func Input(attr Attributes, children ...Block) Block { - return newElement("input", attr, children, SelfClose) + return newElement("input", attr, children, Void) } func Br() Block { - return newElement("br", nil, nil, SelfClose) + return newElement("br", nil, nil, Void) } func Hr(attr Attributes) Block { - return newElement("hr", attr, nil, SelfClose) + return newElement("hr", attr, nil, Void) } diff --git a/html/render.go b/html/render.go index cbf4efb..0db41aa 100644 --- a/html/render.go +++ b/html/render.go @@ -164,11 +164,7 @@ func renderHTML(c Block, w io.Writer, ctx *renderCtx) error { } w.Write([]byte(" " + v.Key + "=\"" + html.EscapeString(fmt.Sprint(v.Value)) + "\"")) } - if el.Options&SelfClose != 0 { - w.Write([]byte("/>")) - } else { - w.Write([]byte(">")) - } + w.Write([]byte(">")) if len(el.Children) > 0 { if !ctx.minified && el.Options&NoWhitespace == 0 { w.Write([]byte{'\n'}) @@ -187,7 +183,7 @@ func renderHTML(c Block, w io.Writer, ctx *renderCtx) error { } ctx.exit(item) } - if el.Options&Void+el.Options&SelfClose == 0 { + if el.Options&Void == 0 { if !ctx.minified && el.Options&NoWhitespace == 0 && len(el.Children) > 0 { w.Write(bytes.Repeat([]byte{' '}, ctx.level*indentation)) } @@ -236,7 +232,6 @@ type Option int8 const ( Void Option = 1 << iota - SelfClose CSSElement JSElement NoWhitespace From 43af0bea039aab7789910d4633c514a2cfcaf2c2 Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Sun, 16 Apr 2023 00:04:46 +0200 Subject: [PATCH 2/8] collect all HTML elements for code generation --- blocks.go | 9 ---- elements.go | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 5 +++ 3 files changed, 128 insertions(+), 9 deletions(-) delete mode 100644 blocks.go create mode 100644 elements.go create mode 100644 main.go diff --git a/blocks.go b/blocks.go deleted file mode 100644 index 6e55bcc..0000000 --- a/blocks.go +++ /dev/null @@ -1,9 +0,0 @@ -package blocks - -type Blocks []Block - -func (Blocks) Render() Block { return nil } - -type Block interface { - Render() Block -} diff --git a/elements.go b/elements.go new file mode 100644 index 0000000..a0eff76 --- /dev/null +++ b/elements.go @@ -0,0 +1,123 @@ +package main + +import "github.com/mbertschler/blocks/html" + +type element struct { + Name string + Option html.Option +} + +var elements = []element{ + {Name: "a"}, + {Name: "abbr"}, + {Name: "address"}, + {Name: "area"}, + {Name: "article"}, + {Name: "aside"}, + {Name: "audio"}, + {Name: "b"}, + {Name: "base"}, + {Name: "bdi"}, + {Name: "bdo"}, + {Name: "blockquote"}, + {Name: "body"}, + {Name: "br", Option: html.Void}, + {Name: "button"}, + {Name: "canvas"}, + {Name: "caption"}, + {Name: "cite"}, + {Name: "code"}, + {Name: "col"}, + {Name: "colgroup"}, + {Name: "data"}, + {Name: "datalist"}, + {Name: "dd"}, + {Name: "del"}, + {Name: "details"}, + {Name: "dfn"}, + {Name: "dialog"}, + {Name: "div"}, + {Name: "dl"}, + {Name: "dt"}, + {Name: "em"}, + {Name: "embed"}, + {Name: "fieldset"}, + {Name: "figcaption"}, + {Name: "figure"}, + {Name: "footer"}, + {Name: "form"}, + {Name: "h1"}, + {Name: "h2"}, + {Name: "h3"}, + {Name: "h4"}, + {Name: "h5"}, + {Name: "h6"}, + {Name: "head"}, + {Name: "header"}, + {Name: "hgroup"}, + {Name: "hr", Option: html.Void}, + {Name: "html"}, + {Name: "i"}, + {Name: "iframe"}, + {Name: "img", Option: html.Void}, + {Name: "input", Option: html.Void}, + {Name: "ins"}, + {Name: "kbd"}, + {Name: "label"}, + {Name: "legend"}, + {Name: "li"}, + {Name: "link", Option: html.Void}, + {Name: "main"}, + {Name: "map"}, + {Name: "mark"}, + {Name: "menu"}, + {Name: "meta", Option: html.Void}, + {Name: "meter"}, + {Name: "nav"}, + {Name: "noscript"}, + {Name: "object"}, + {Name: "ol"}, + {Name: "optgroup"}, + {Name: "option"}, + {Name: "output"}, + {Name: "p"}, + {Name: "picture"}, + {Name: "portal"}, + {Name: "pre", Option: html.NoWhitespace}, + {Name: "progress"}, + {Name: "q"}, + {Name: "rp"}, + {Name: "rt"}, + {Name: "ruby"}, + {Name: "s"}, + {Name: "samp"}, + {Name: "script", Option: html.JSElement}, + {Name: "section"}, + {Name: "select"}, + {Name: "slot"}, + {Name: "small"}, + {Name: "source"}, + {Name: "span"}, + {Name: "strong"}, + {Name: "style", Option: html.CSSElement}, + {Name: "sub"}, + {Name: "summary"}, + {Name: "sup"}, + {Name: "table"}, + {Name: "tbody"}, + {Name: "td"}, + {Name: "template"}, + {Name: "textarea", Option: html.NoWhitespace}, + {Name: "tfoot"}, + {Name: "th"}, + {Name: "thead"}, + {Name: "time"}, + {Name: "title"}, + {Name: "tr"}, + {Name: "track"}, + {Name: "u"}, + {Name: "ul"}, + {Name: "var"}, + {Name: "video"}, + {Name: "wbr"}, +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..7905807 --- /dev/null +++ b/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + +} From e54dc15d3670f086e2df0b0f614358b0b82fb316 Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Tue, 25 Apr 2023 00:22:25 +0200 Subject: [PATCH 3/8] remove css package that I never used --- examples/css/css.go | 46 --------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 examples/css/css.go diff --git a/examples/css/css.go b/examples/css/css.go deleted file mode 100644 index d8c505d..0000000 --- a/examples/css/css.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/mbertschler/blocks/css" -) - -func main() { - root := css.Blocks{ - css.New("body", - css.L("position", "relative"), - css.L("display", "block"), - ), - HeadBlock{size: 32}, - ParagraphBlock("sans-serif"), - } - out, err := css.RenderString(root) - if err != nil { - fmt.Println("Error:", err) - } - fmt.Println(out) - - out, err = css.RenderMinifiedString(root) - if err != nil { - fmt.Println("Error:", err) - } - fmt.Println(out) -} - -type HeadBlock struct { - size int -} - -func (h HeadBlock) RenderCSS() css.Block { - return css.New("h1", - css.L("font-size", fmt.Sprint(h.size, "px")), - ) -} - -func ParagraphBlock(font string) css.Block { - return css.New("p", - css.L("font-family", font), - ) - -} From b9b4ab6a62a27d229aa85d659b5ada96774bdd7a Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Tue, 25 Apr 2023 00:29:17 +0200 Subject: [PATCH 4/8] escape HTML comments too --- html/render.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/html/render.go b/html/render.go index 0db41aa..35c8aad 100644 --- a/html/render.go +++ b/html/render.go @@ -8,8 +8,6 @@ import ( "io" ) -var renderDebug = true - type UnsafeString string type Text string type Comment string @@ -147,7 +145,7 @@ func renderHTML(c Block, w io.Writer, ctx *renderCtx) error { if !ctx.minified { w.Write(bytes.Repeat([]byte{' '}, ctx.level*indentation)) } - w.Write([]byte("")) + w.Write([]byte("")) if !ctx.minified { w.Write([]byte{'\n'}) } From eee5ccbadff7de3a3fc3192a4ab34d64db58b006 Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Tue, 25 Apr 2023 00:29:37 +0200 Subject: [PATCH 5/8] collect attributes for generation --- attributes.go | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++ elements.go | 2 + 2 files changed, 133 insertions(+) create mode 100644 attributes.go diff --git a/attributes.go b/attributes.go new file mode 100644 index 0000000..df94975 --- /dev/null +++ b/attributes.go @@ -0,0 +1,131 @@ +package main + +type attribute struct { + Name string + IsURL bool +} + +var attributes = []attribute{ + {Name: "accept"}, + {Name: "accept-charset"}, + {Name: "accesskey"}, + {Name: "action", IsURL: true}, + {Name: "align"}, + {Name: "allow"}, + {Name: "alt"}, + {Name: "async"}, + {Name: "autocapitalize"}, + {Name: "autocomplete"}, + {Name: "autofocus"}, + {Name: "autoplay"}, + {Name: "background", IsURL: true}, + {Name: "bgcolor"}, + {Name: "border"}, + {Name: "buffered"}, + {Name: "capture"}, + {Name: "challenge"}, + {Name: "charset"}, + {Name: "checked"}, + {Name: "cite", IsURL: true}, + {Name: "class"}, + {Name: "code"}, + {Name: "codebase", IsURL: true}, + {Name: "color"}, + {Name: "cols"}, + {Name: "colspan"}, + {Name: "content"}, + {Name: "contenteditable"}, + {Name: "contextmenu"}, + {Name: "controls"}, + {Name: "coords"}, + {Name: "crossorigin"}, + {Name: "data", IsURL: true}, + {Name: "data-*"}, + {Name: "datetime"}, + {Name: "decoding"}, + {Name: "default"}, + {Name: "defer"}, + {Name: "dir"}, + {Name: "dirname"}, + {Name: "disabled"}, + {Name: "download"}, + {Name: "draggable"}, + {Name: "enctype"}, + {Name: "for"}, + {Name: "form"}, + {Name: "formaction", IsURL: true}, + {Name: "formenctype"}, + {Name: "formmethod"}, + {Name: "formnovalidate"}, + {Name: "formtarget"}, + {Name: "headers"}, + {Name: "height"}, + {Name: "hidden"}, + {Name: "high"}, + {Name: "href", IsURL: true}, + {Name: "hreflang"}, + {Name: "http-equiv"}, + {Name: "id"}, + {Name: "integrity"}, + {Name: "inputmode"}, + {Name: "ismap"}, + {Name: "itemprop"}, + {Name: "keytype"}, + {Name: "kind"}, + {Name: "label"}, + {Name: "lang"}, + {Name: "list"}, + {Name: "loop"}, + {Name: "low"}, + {Name: "max"}, + {Name: "maxlength"}, + {Name: "minlength"}, + {Name: "media"}, + {Name: "method"}, + {Name: "min"}, + {Name: "multiple"}, + {Name: "muted"}, + {Name: "name"}, + {Name: "novalidate"}, + {Name: "open"}, + {Name: "optimum"}, + {Name: "pattern"}, + {Name: "ping"}, + {Name: "placeholder"}, + {Name: "playsinline"}, + {Name: "poster", IsURL: true}, + {Name: "preload"}, + {Name: "readonly"}, + {Name: "referrerpolicy"}, + {Name: "rel"}, + {Name: "required"}, + {Name: "reversed"}, + {Name: "role"}, + {Name: "rows"}, + {Name: "rowspan"}, + {Name: "sandbox"}, + {Name: "scope"}, + {Name: "selected"}, + {Name: "shape"}, + {Name: "size"}, + {Name: "sizes"}, + {Name: "slot"}, + {Name: "span"}, + {Name: "spellcheck"}, + {Name: "src", IsURL: true}, + {Name: "srcdoc"}, + {Name: "srclang"}, + {Name: "srcset"}, + {Name: "start"}, + {Name: "step"}, + {Name: "style"}, + {Name: "tabindex"}, + {Name: "target"}, + {Name: "title"}, + {Name: "translate"}, + {Name: "type"}, + {Name: "usemap", IsURL: true}, + {Name: "value"}, + {Name: "width"}, + {Name: "wrap"}, +} diff --git a/elements.go b/elements.go index a0eff76..f40f494 100644 --- a/elements.go +++ b/elements.go @@ -7,6 +7,8 @@ type element struct { Option html.Option } +// Source: https://developer.mozilla.org/en-US/docs/Web/HTML/Element +// taken from the sidebar, deprecated elements removed var elements = []element{ {Name: "a"}, {Name: "abbr"}, From a8d8f4b02f803ffb22f2194f60a3447d81b986a1 Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Sat, 29 Apr 2023 19:26:38 +0200 Subject: [PATCH 6/8] generate elements and attributes, extract attributes into its own package --- attributes.go | 34 +- elements.go | 18 +- examples/components/counter.go | 20 +- examples/html/html.go | 9 +- go.mod | 2 +- html/attr/attributes.go | 21 + html/attr/attributes_gen.go | 729 +++++++++++++++++++++++++++++++++ html/attributes.go | 127 ------ html/bench_test.go | 4 +- html/elements.go | 109 +---- html/elements_gen.go | 341 +++++++++++++++ html/render.go | 20 +- main.go | 91 ++++ 13 files changed, 1253 insertions(+), 272 deletions(-) create mode 100644 html/attr/attributes.go create mode 100644 html/attr/attributes_gen.go delete mode 100644 html/attributes.go create mode 100644 html/elements_gen.go diff --git a/attributes.go b/attributes.go index df94975..0e3797a 100644 --- a/attributes.go +++ b/attributes.go @@ -9,7 +9,7 @@ var attributes = []attribute{ {Name: "accept"}, {Name: "accept-charset"}, {Name: "accesskey"}, - {Name: "action", IsURL: true}, + {Name: "action"}, {Name: "align"}, {Name: "allow"}, {Name: "alt"}, @@ -18,7 +18,7 @@ var attributes = []attribute{ {Name: "autocomplete"}, {Name: "autofocus"}, {Name: "autoplay"}, - {Name: "background", IsURL: true}, + {Name: "background"}, {Name: "bgcolor"}, {Name: "border"}, {Name: "buffered"}, @@ -26,10 +26,10 @@ var attributes = []attribute{ {Name: "challenge"}, {Name: "charset"}, {Name: "checked"}, - {Name: "cite", IsURL: true}, + {Name: "cite"}, {Name: "class"}, {Name: "code"}, - {Name: "codebase", IsURL: true}, + {Name: "codebase"}, {Name: "color"}, {Name: "cols"}, {Name: "colspan"}, @@ -39,8 +39,8 @@ var attributes = []attribute{ {Name: "controls"}, {Name: "coords"}, {Name: "crossorigin"}, - {Name: "data", IsURL: true}, - {Name: "data-*"}, + {Name: "data"}, + // {Name: "data-*"}, // special case {Name: "datetime"}, {Name: "decoding"}, {Name: "default"}, @@ -53,7 +53,7 @@ var attributes = []attribute{ {Name: "enctype"}, {Name: "for"}, {Name: "form"}, - {Name: "formaction", IsURL: true}, + {Name: "formaction"}, {Name: "formenctype"}, {Name: "formmethod"}, {Name: "formnovalidate"}, @@ -62,7 +62,7 @@ var attributes = []attribute{ {Name: "height"}, {Name: "hidden"}, {Name: "high"}, - {Name: "href", IsURL: true}, + {Name: "href"}, {Name: "hreflang"}, {Name: "http-equiv"}, {Name: "id"}, @@ -93,7 +93,7 @@ var attributes = []attribute{ {Name: "ping"}, {Name: "placeholder"}, {Name: "playsinline"}, - {Name: "poster", IsURL: true}, + {Name: "poster"}, {Name: "preload"}, {Name: "readonly"}, {Name: "referrerpolicy"}, @@ -112,7 +112,7 @@ var attributes = []attribute{ {Name: "slot"}, {Name: "span"}, {Name: "spellcheck"}, - {Name: "src", IsURL: true}, + {Name: "src"}, {Name: "srcdoc"}, {Name: "srclang"}, {Name: "srcset"}, @@ -124,8 +124,20 @@ var attributes = []attribute{ {Name: "title"}, {Name: "translate"}, {Name: "type"}, - {Name: "usemap", IsURL: true}, + {Name: "usemap"}, {Name: "value"}, {Name: "width"}, {Name: "wrap"}, } + +var attributesFileTemplate = `// Code generated by blocks; DO NOT EDIT. +package attr + +{{range . -}} +func {{ .FuncName }}(value any) Attributes { + return Attributes{AttrPair{Key: "{{ .AttrName }}", Value: value}} +} +func (a Attributes) {{ .FuncName }}(value any) Attributes { + return append(a, AttrPair{Key: "{{ .AttrName }}", Value: value}) +} +{{ end }}` diff --git a/elements.go b/elements.go index f40f494..562adf6 100644 --- a/elements.go +++ b/elements.go @@ -4,7 +4,7 @@ import "github.com/mbertschler/blocks/html" type element struct { Name string - Option html.Option + Option html.ElementOption } // Source: https://developer.mozilla.org/en-US/docs/Web/HTML/Element @@ -123,3 +123,19 @@ var elements = []element{ {Name: "video"}, {Name: "wbr"}, } + +var elementsFileTemplate = `// Code generated by blocks. DO NOT EDIT. +package html + +import "github.com/mbertschler/blocks/html/attr" + +{{range . -}} +{{ if .NoChildren -}} +func {{ .FuncName }}(attr attr.Attributes) Block { + return newElement("{{ .TagName }}", attr, nil, Void) +} +{{ else -}} +func {{ .FuncName }}(attr attr.Attributes, children ...Block) Block { + return newElement("{{ .TagName }}", attr, children, {{ .Option }}) +} +{{ end }}{{ end }}` diff --git a/examples/components/counter.go b/examples/components/counter.go index 9297fec..54ea1ca 100644 --- a/examples/components/counter.go +++ b/examples/components/counter.go @@ -5,7 +5,9 @@ import ( "fmt" "github.com/gin-gonic/gin" + "github.com/mbertschler/blocks/html" + "github.com/mbertschler/blocks/html/attr" ) type Counter struct { @@ -27,15 +29,15 @@ func counterLayout(main html.Block) html.Block { html.Doctype("html"), html.Html(nil, html.Head(nil, - html.Meta(html.Charset("utf-8")), + html.Meta(attr.Charset("utf-8")), html.Title(nil, html.Text("Blocks")), - html.Link(html.Rel("stylesheet").Href("https://cdn.jsdelivr.net/npm/simpledotcss@2.2.0/simple.min.css")), - html.Link(html.Rel("stylesheet").Href("/dist/bundle.css")), + html.Link(attr.Rel("stylesheet").Href("https://cdn.jsdelivr.net/npm/simpledotcss@2.2.0/simple.min.css")), + html.Link(attr.Rel("stylesheet").Href("/dist/bundle.css")), ), html.Body(nil, main, - html.A(html.Href("/"), html.Text("TodoMVC Example")), - html.Script(html.Src("/dist/bundle.js")), + html.A(attr.Href("/"), html.Text("TodoMVC Example")), + html.Script(attr.Src("/dist/bundle.js")), ), ), } @@ -60,12 +62,12 @@ func (c *Counter) RenderBlock(ctx *gin.Context) (html.Block, error) { if err != nil { return nil, err } - block := html.Div(html.Id("counter"), + block := html.Div(attr.Id("counter"), html.H3(nil, html.Text("Counter")), - html.P(html.Id("count"), html.Text(fmt.Sprintf("Current count: %d", counter.Count))), - html.Button(html.Class("ga").Attr("ga-on", "click").Attr("ga-action", "Counter.Decrease"), html.Text("-")), + html.P(attr.Id("count"), html.Text(fmt.Sprintf("Current count: %d", counter.Count))), + html.Button(attr.Class("ga").Attr("ga-on", "click").Attr("ga-action", "Counter.Decrease"), html.Text("-")), html.Text(" "), - html.Button(html.Class("ga").Attr("ga-on", "click").Attr("ga-action", "Counter.Increase"), html.Text("+")), + html.Button(attr.Class("ga").Attr("ga-on", "click").Attr("ga-action", "Counter.Increase"), html.Text("+")), ) return block, nil } diff --git a/examples/html/html.go b/examples/html/html.go index 5e9c0d8..bef29b1 100644 --- a/examples/html/html.go +++ b/examples/html/html.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/mbertschler/blocks/html" + "github.com/mbertschler/blocks/html/attr" ) func main() { @@ -12,7 +13,7 @@ func main() { html.Doctype("html"), html.Html(nil, // Option 2: struct that implements Block interface (RenderHTML() Block) - HeadBlock{html.Name("key").Content("super")}, + HeadBlock{attr.Name("key").Content("super")}, // Option 3: function that returns a Block BodyBlock("Hello, world! :)
"), ), @@ -31,7 +32,7 @@ func main() { } type HeadBlock struct { - html.Attributes + attr.Attributes } func (h HeadBlock) RenderHTML() html.Block { @@ -42,10 +43,10 @@ func (h HeadBlock) RenderHTML() html.Block { func BodyBlock(in string) html.Block { return html.Body(nil, - html.Main(html.Class("main-class\" href=\"/evil/link"), + html.Main(attr.Class("main-class\" href=\"/evil/link"), html.H1(nil, html.Text(in), - html.Br(), + html.Br(nil), html.UnsafeString(in), ), ), diff --git a/go.mod b/go.mod index 9070614..f9e43c8 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/mbertschler/blocks -go 1.12 +go 1.20 diff --git a/html/attr/attributes.go b/html/attr/attributes.go new file mode 100644 index 0000000..f206e4c --- /dev/null +++ b/html/attr/attributes.go @@ -0,0 +1,21 @@ +package attr + +type Attributes []AttrPair +type AttrPair struct { + Key string + Value any +} + +func Attr(key string, value interface{}) Attributes { + return Attributes{AttrPair{Key: key, Value: value}} +} +func (a Attributes) Attr(key string, id interface{}) Attributes { + return append(a, AttrPair{Key: key, Value: id}) +} + +func DataAttr(key string, value interface{}) Attributes { + return Attributes{AttrPair{Key: "data-" + key, Value: value}} +} +func (a Attributes) DataAttr(key string, value interface{}) Attributes { + return append(a, AttrPair{Key: "data-" + key, Value: value}) +} diff --git a/html/attr/attributes_gen.go b/html/attr/attributes_gen.go new file mode 100644 index 0000000..13af25b --- /dev/null +++ b/html/attr/attributes_gen.go @@ -0,0 +1,729 @@ +// Code generated by blocks; DO NOT EDIT. +package attr + +func Accept(value any) Attributes { + return Attributes{AttrPair{Key: "accept", Value: value}} +} +func (a Attributes) Accept(value any) Attributes { + return append(a, AttrPair{Key: "accept", Value: value}) +} +func AcceptCharset(value any) Attributes { + return Attributes{AttrPair{Key: "accept-charset", Value: value}} +} +func (a Attributes) AcceptCharset(value any) Attributes { + return append(a, AttrPair{Key: "accept-charset", Value: value}) +} +func Accesskey(value any) Attributes { + return Attributes{AttrPair{Key: "accesskey", Value: value}} +} +func (a Attributes) Accesskey(value any) Attributes { + return append(a, AttrPair{Key: "accesskey", Value: value}) +} +func Action(value any) Attributes { + return Attributes{AttrPair{Key: "action", Value: value}} +} +func (a Attributes) Action(value any) Attributes { + return append(a, AttrPair{Key: "action", Value: value}) +} +func Align(value any) Attributes { + return Attributes{AttrPair{Key: "align", Value: value}} +} +func (a Attributes) Align(value any) Attributes { + return append(a, AttrPair{Key: "align", Value: value}) +} +func Allow(value any) Attributes { + return Attributes{AttrPair{Key: "allow", Value: value}} +} +func (a Attributes) Allow(value any) Attributes { + return append(a, AttrPair{Key: "allow", Value: value}) +} +func Alt(value any) Attributes { + return Attributes{AttrPair{Key: "alt", Value: value}} +} +func (a Attributes) Alt(value any) Attributes { + return append(a, AttrPair{Key: "alt", Value: value}) +} +func Async(value any) Attributes { + return Attributes{AttrPair{Key: "async", Value: value}} +} +func (a Attributes) Async(value any) Attributes { + return append(a, AttrPair{Key: "async", Value: value}) +} +func Autocapitalize(value any) Attributes { + return Attributes{AttrPair{Key: "autocapitalize", Value: value}} +} +func (a Attributes) Autocapitalize(value any) Attributes { + return append(a, AttrPair{Key: "autocapitalize", Value: value}) +} +func Autocomplete(value any) Attributes { + return Attributes{AttrPair{Key: "autocomplete", Value: value}} +} +func (a Attributes) Autocomplete(value any) Attributes { + return append(a, AttrPair{Key: "autocomplete", Value: value}) +} +func Autofocus(value any) Attributes { + return Attributes{AttrPair{Key: "autofocus", Value: value}} +} +func (a Attributes) Autofocus(value any) Attributes { + return append(a, AttrPair{Key: "autofocus", Value: value}) +} +func Autoplay(value any) Attributes { + return Attributes{AttrPair{Key: "autoplay", Value: value}} +} +func (a Attributes) Autoplay(value any) Attributes { + return append(a, AttrPair{Key: "autoplay", Value: value}) +} +func Background(value any) Attributes { + return Attributes{AttrPair{Key: "background", Value: value}} +} +func (a Attributes) Background(value any) Attributes { + return append(a, AttrPair{Key: "background", Value: value}) +} +func Bgcolor(value any) Attributes { + return Attributes{AttrPair{Key: "bgcolor", Value: value}} +} +func (a Attributes) Bgcolor(value any) Attributes { + return append(a, AttrPair{Key: "bgcolor", Value: value}) +} +func Border(value any) Attributes { + return Attributes{AttrPair{Key: "border", Value: value}} +} +func (a Attributes) Border(value any) Attributes { + return append(a, AttrPair{Key: "border", Value: value}) +} +func Buffered(value any) Attributes { + return Attributes{AttrPair{Key: "buffered", Value: value}} +} +func (a Attributes) Buffered(value any) Attributes { + return append(a, AttrPair{Key: "buffered", Value: value}) +} +func Capture(value any) Attributes { + return Attributes{AttrPair{Key: "capture", Value: value}} +} +func (a Attributes) Capture(value any) Attributes { + return append(a, AttrPair{Key: "capture", Value: value}) +} +func Challenge(value any) Attributes { + return Attributes{AttrPair{Key: "challenge", Value: value}} +} +func (a Attributes) Challenge(value any) Attributes { + return append(a, AttrPair{Key: "challenge", Value: value}) +} +func Charset(value any) Attributes { + return Attributes{AttrPair{Key: "charset", Value: value}} +} +func (a Attributes) Charset(value any) Attributes { + return append(a, AttrPair{Key: "charset", Value: value}) +} +func Checked(value any) Attributes { + return Attributes{AttrPair{Key: "checked", Value: value}} +} +func (a Attributes) Checked(value any) Attributes { + return append(a, AttrPair{Key: "checked", Value: value}) +} +func Cite(value any) Attributes { + return Attributes{AttrPair{Key: "cite", Value: value}} +} +func (a Attributes) Cite(value any) Attributes { + return append(a, AttrPair{Key: "cite", Value: value}) +} +func Class(value any) Attributes { + return Attributes{AttrPair{Key: "class", Value: value}} +} +func (a Attributes) Class(value any) Attributes { + return append(a, AttrPair{Key: "class", Value: value}) +} +func Code(value any) Attributes { + return Attributes{AttrPair{Key: "code", Value: value}} +} +func (a Attributes) Code(value any) Attributes { + return append(a, AttrPair{Key: "code", Value: value}) +} +func Codebase(value any) Attributes { + return Attributes{AttrPair{Key: "codebase", Value: value}} +} +func (a Attributes) Codebase(value any) Attributes { + return append(a, AttrPair{Key: "codebase", Value: value}) +} +func Color(value any) Attributes { + return Attributes{AttrPair{Key: "color", Value: value}} +} +func (a Attributes) Color(value any) Attributes { + return append(a, AttrPair{Key: "color", Value: value}) +} +func Cols(value any) Attributes { + return Attributes{AttrPair{Key: "cols", Value: value}} +} +func (a Attributes) Cols(value any) Attributes { + return append(a, AttrPair{Key: "cols", Value: value}) +} +func Colspan(value any) Attributes { + return Attributes{AttrPair{Key: "colspan", Value: value}} +} +func (a Attributes) Colspan(value any) Attributes { + return append(a, AttrPair{Key: "colspan", Value: value}) +} +func Content(value any) Attributes { + return Attributes{AttrPair{Key: "content", Value: value}} +} +func (a Attributes) Content(value any) Attributes { + return append(a, AttrPair{Key: "content", Value: value}) +} +func Contenteditable(value any) Attributes { + return Attributes{AttrPair{Key: "contenteditable", Value: value}} +} +func (a Attributes) Contenteditable(value any) Attributes { + return append(a, AttrPair{Key: "contenteditable", Value: value}) +} +func Contextmenu(value any) Attributes { + return Attributes{AttrPair{Key: "contextmenu", Value: value}} +} +func (a Attributes) Contextmenu(value any) Attributes { + return append(a, AttrPair{Key: "contextmenu", Value: value}) +} +func Controls(value any) Attributes { + return Attributes{AttrPair{Key: "controls", Value: value}} +} +func (a Attributes) Controls(value any) Attributes { + return append(a, AttrPair{Key: "controls", Value: value}) +} +func Coords(value any) Attributes { + return Attributes{AttrPair{Key: "coords", Value: value}} +} +func (a Attributes) Coords(value any) Attributes { + return append(a, AttrPair{Key: "coords", Value: value}) +} +func Crossorigin(value any) Attributes { + return Attributes{AttrPair{Key: "crossorigin", Value: value}} +} +func (a Attributes) Crossorigin(value any) Attributes { + return append(a, AttrPair{Key: "crossorigin", Value: value}) +} +func Data(value any) Attributes { + return Attributes{AttrPair{Key: "data", Value: value}} +} +func (a Attributes) Data(value any) Attributes { + return append(a, AttrPair{Key: "data", Value: value}) +} +func Datetime(value any) Attributes { + return Attributes{AttrPair{Key: "datetime", Value: value}} +} +func (a Attributes) Datetime(value any) Attributes { + return append(a, AttrPair{Key: "datetime", Value: value}) +} +func Decoding(value any) Attributes { + return Attributes{AttrPair{Key: "decoding", Value: value}} +} +func (a Attributes) Decoding(value any) Attributes { + return append(a, AttrPair{Key: "decoding", Value: value}) +} +func Default(value any) Attributes { + return Attributes{AttrPair{Key: "default", Value: value}} +} +func (a Attributes) Default(value any) Attributes { + return append(a, AttrPair{Key: "default", Value: value}) +} +func Defer(value any) Attributes { + return Attributes{AttrPair{Key: "defer", Value: value}} +} +func (a Attributes) Defer(value any) Attributes { + return append(a, AttrPair{Key: "defer", Value: value}) +} +func Dir(value any) Attributes { + return Attributes{AttrPair{Key: "dir", Value: value}} +} +func (a Attributes) Dir(value any) Attributes { + return append(a, AttrPair{Key: "dir", Value: value}) +} +func Dirname(value any) Attributes { + return Attributes{AttrPair{Key: "dirname", Value: value}} +} +func (a Attributes) Dirname(value any) Attributes { + return append(a, AttrPair{Key: "dirname", Value: value}) +} +func Disabled(value any) Attributes { + return Attributes{AttrPair{Key: "disabled", Value: value}} +} +func (a Attributes) Disabled(value any) Attributes { + return append(a, AttrPair{Key: "disabled", Value: value}) +} +func Download(value any) Attributes { + return Attributes{AttrPair{Key: "download", Value: value}} +} +func (a Attributes) Download(value any) Attributes { + return append(a, AttrPair{Key: "download", Value: value}) +} +func Draggable(value any) Attributes { + return Attributes{AttrPair{Key: "draggable", Value: value}} +} +func (a Attributes) Draggable(value any) Attributes { + return append(a, AttrPair{Key: "draggable", Value: value}) +} +func Enctype(value any) Attributes { + return Attributes{AttrPair{Key: "enctype", Value: value}} +} +func (a Attributes) Enctype(value any) Attributes { + return append(a, AttrPair{Key: "enctype", Value: value}) +} +func For(value any) Attributes { + return Attributes{AttrPair{Key: "for", Value: value}} +} +func (a Attributes) For(value any) Attributes { + return append(a, AttrPair{Key: "for", Value: value}) +} +func Form(value any) Attributes { + return Attributes{AttrPair{Key: "form", Value: value}} +} +func (a Attributes) Form(value any) Attributes { + return append(a, AttrPair{Key: "form", Value: value}) +} +func Formaction(value any) Attributes { + return Attributes{AttrPair{Key: "formaction", Value: value}} +} +func (a Attributes) Formaction(value any) Attributes { + return append(a, AttrPair{Key: "formaction", Value: value}) +} +func Formenctype(value any) Attributes { + return Attributes{AttrPair{Key: "formenctype", Value: value}} +} +func (a Attributes) Formenctype(value any) Attributes { + return append(a, AttrPair{Key: "formenctype", Value: value}) +} +func Formmethod(value any) Attributes { + return Attributes{AttrPair{Key: "formmethod", Value: value}} +} +func (a Attributes) Formmethod(value any) Attributes { + return append(a, AttrPair{Key: "formmethod", Value: value}) +} +func Formnovalidate(value any) Attributes { + return Attributes{AttrPair{Key: "formnovalidate", Value: value}} +} +func (a Attributes) Formnovalidate(value any) Attributes { + return append(a, AttrPair{Key: "formnovalidate", Value: value}) +} +func Formtarget(value any) Attributes { + return Attributes{AttrPair{Key: "formtarget", Value: value}} +} +func (a Attributes) Formtarget(value any) Attributes { + return append(a, AttrPair{Key: "formtarget", Value: value}) +} +func Headers(value any) Attributes { + return Attributes{AttrPair{Key: "headers", Value: value}} +} +func (a Attributes) Headers(value any) Attributes { + return append(a, AttrPair{Key: "headers", Value: value}) +} +func Height(value any) Attributes { + return Attributes{AttrPair{Key: "height", Value: value}} +} +func (a Attributes) Height(value any) Attributes { + return append(a, AttrPair{Key: "height", Value: value}) +} +func Hidden(value any) Attributes { + return Attributes{AttrPair{Key: "hidden", Value: value}} +} +func (a Attributes) Hidden(value any) Attributes { + return append(a, AttrPair{Key: "hidden", Value: value}) +} +func High(value any) Attributes { + return Attributes{AttrPair{Key: "high", Value: value}} +} +func (a Attributes) High(value any) Attributes { + return append(a, AttrPair{Key: "high", Value: value}) +} +func Href(value any) Attributes { + return Attributes{AttrPair{Key: "href", Value: value}} +} +func (a Attributes) Href(value any) Attributes { + return append(a, AttrPair{Key: "href", Value: value}) +} +func Hreflang(value any) Attributes { + return Attributes{AttrPair{Key: "hreflang", Value: value}} +} +func (a Attributes) Hreflang(value any) Attributes { + return append(a, AttrPair{Key: "hreflang", Value: value}) +} +func HttpEquiv(value any) Attributes { + return Attributes{AttrPair{Key: "http-equiv", Value: value}} +} +func (a Attributes) HttpEquiv(value any) Attributes { + return append(a, AttrPair{Key: "http-equiv", Value: value}) +} +func Id(value any) Attributes { + return Attributes{AttrPair{Key: "id", Value: value}} +} +func (a Attributes) Id(value any) Attributes { + return append(a, AttrPair{Key: "id", Value: value}) +} +func Integrity(value any) Attributes { + return Attributes{AttrPair{Key: "integrity", Value: value}} +} +func (a Attributes) Integrity(value any) Attributes { + return append(a, AttrPair{Key: "integrity", Value: value}) +} +func Inputmode(value any) Attributes { + return Attributes{AttrPair{Key: "inputmode", Value: value}} +} +func (a Attributes) Inputmode(value any) Attributes { + return append(a, AttrPair{Key: "inputmode", Value: value}) +} +func Ismap(value any) Attributes { + return Attributes{AttrPair{Key: "ismap", Value: value}} +} +func (a Attributes) Ismap(value any) Attributes { + return append(a, AttrPair{Key: "ismap", Value: value}) +} +func Itemprop(value any) Attributes { + return Attributes{AttrPair{Key: "itemprop", Value: value}} +} +func (a Attributes) Itemprop(value any) Attributes { + return append(a, AttrPair{Key: "itemprop", Value: value}) +} +func Keytype(value any) Attributes { + return Attributes{AttrPair{Key: "keytype", Value: value}} +} +func (a Attributes) Keytype(value any) Attributes { + return append(a, AttrPair{Key: "keytype", Value: value}) +} +func Kind(value any) Attributes { + return Attributes{AttrPair{Key: "kind", Value: value}} +} +func (a Attributes) Kind(value any) Attributes { + return append(a, AttrPair{Key: "kind", Value: value}) +} +func Label(value any) Attributes { + return Attributes{AttrPair{Key: "label", Value: value}} +} +func (a Attributes) Label(value any) Attributes { + return append(a, AttrPair{Key: "label", Value: value}) +} +func Lang(value any) Attributes { + return Attributes{AttrPair{Key: "lang", Value: value}} +} +func (a Attributes) Lang(value any) Attributes { + return append(a, AttrPair{Key: "lang", Value: value}) +} +func List(value any) Attributes { + return Attributes{AttrPair{Key: "list", Value: value}} +} +func (a Attributes) List(value any) Attributes { + return append(a, AttrPair{Key: "list", Value: value}) +} +func Loop(value any) Attributes { + return Attributes{AttrPair{Key: "loop", Value: value}} +} +func (a Attributes) Loop(value any) Attributes { + return append(a, AttrPair{Key: "loop", Value: value}) +} +func Low(value any) Attributes { + return Attributes{AttrPair{Key: "low", Value: value}} +} +func (a Attributes) Low(value any) Attributes { + return append(a, AttrPair{Key: "low", Value: value}) +} +func Max(value any) Attributes { + return Attributes{AttrPair{Key: "max", Value: value}} +} +func (a Attributes) Max(value any) Attributes { + return append(a, AttrPair{Key: "max", Value: value}) +} +func Maxlength(value any) Attributes { + return Attributes{AttrPair{Key: "maxlength", Value: value}} +} +func (a Attributes) Maxlength(value any) Attributes { + return append(a, AttrPair{Key: "maxlength", Value: value}) +} +func Minlength(value any) Attributes { + return Attributes{AttrPair{Key: "minlength", Value: value}} +} +func (a Attributes) Minlength(value any) Attributes { + return append(a, AttrPair{Key: "minlength", Value: value}) +} +func Media(value any) Attributes { + return Attributes{AttrPair{Key: "media", Value: value}} +} +func (a Attributes) Media(value any) Attributes { + return append(a, AttrPair{Key: "media", Value: value}) +} +func Method(value any) Attributes { + return Attributes{AttrPair{Key: "method", Value: value}} +} +func (a Attributes) Method(value any) Attributes { + return append(a, AttrPair{Key: "method", Value: value}) +} +func Min(value any) Attributes { + return Attributes{AttrPair{Key: "min", Value: value}} +} +func (a Attributes) Min(value any) Attributes { + return append(a, AttrPair{Key: "min", Value: value}) +} +func Multiple(value any) Attributes { + return Attributes{AttrPair{Key: "multiple", Value: value}} +} +func (a Attributes) Multiple(value any) Attributes { + return append(a, AttrPair{Key: "multiple", Value: value}) +} +func Muted(value any) Attributes { + return Attributes{AttrPair{Key: "muted", Value: value}} +} +func (a Attributes) Muted(value any) Attributes { + return append(a, AttrPair{Key: "muted", Value: value}) +} +func Name(value any) Attributes { + return Attributes{AttrPair{Key: "name", Value: value}} +} +func (a Attributes) Name(value any) Attributes { + return append(a, AttrPair{Key: "name", Value: value}) +} +func Novalidate(value any) Attributes { + return Attributes{AttrPair{Key: "novalidate", Value: value}} +} +func (a Attributes) Novalidate(value any) Attributes { + return append(a, AttrPair{Key: "novalidate", Value: value}) +} +func Open(value any) Attributes { + return Attributes{AttrPair{Key: "open", Value: value}} +} +func (a Attributes) Open(value any) Attributes { + return append(a, AttrPair{Key: "open", Value: value}) +} +func Optimum(value any) Attributes { + return Attributes{AttrPair{Key: "optimum", Value: value}} +} +func (a Attributes) Optimum(value any) Attributes { + return append(a, AttrPair{Key: "optimum", Value: value}) +} +func Pattern(value any) Attributes { + return Attributes{AttrPair{Key: "pattern", Value: value}} +} +func (a Attributes) Pattern(value any) Attributes { + return append(a, AttrPair{Key: "pattern", Value: value}) +} +func Ping(value any) Attributes { + return Attributes{AttrPair{Key: "ping", Value: value}} +} +func (a Attributes) Ping(value any) Attributes { + return append(a, AttrPair{Key: "ping", Value: value}) +} +func Placeholder(value any) Attributes { + return Attributes{AttrPair{Key: "placeholder", Value: value}} +} +func (a Attributes) Placeholder(value any) Attributes { + return append(a, AttrPair{Key: "placeholder", Value: value}) +} +func Playsinline(value any) Attributes { + return Attributes{AttrPair{Key: "playsinline", Value: value}} +} +func (a Attributes) Playsinline(value any) Attributes { + return append(a, AttrPair{Key: "playsinline", Value: value}) +} +func Poster(value any) Attributes { + return Attributes{AttrPair{Key: "poster", Value: value}} +} +func (a Attributes) Poster(value any) Attributes { + return append(a, AttrPair{Key: "poster", Value: value}) +} +func Preload(value any) Attributes { + return Attributes{AttrPair{Key: "preload", Value: value}} +} +func (a Attributes) Preload(value any) Attributes { + return append(a, AttrPair{Key: "preload", Value: value}) +} +func Readonly(value any) Attributes { + return Attributes{AttrPair{Key: "readonly", Value: value}} +} +func (a Attributes) Readonly(value any) Attributes { + return append(a, AttrPair{Key: "readonly", Value: value}) +} +func Referrerpolicy(value any) Attributes { + return Attributes{AttrPair{Key: "referrerpolicy", Value: value}} +} +func (a Attributes) Referrerpolicy(value any) Attributes { + return append(a, AttrPair{Key: "referrerpolicy", Value: value}) +} +func Rel(value any) Attributes { + return Attributes{AttrPair{Key: "rel", Value: value}} +} +func (a Attributes) Rel(value any) Attributes { + return append(a, AttrPair{Key: "rel", Value: value}) +} +func Required(value any) Attributes { + return Attributes{AttrPair{Key: "required", Value: value}} +} +func (a Attributes) Required(value any) Attributes { + return append(a, AttrPair{Key: "required", Value: value}) +} +func Reversed(value any) Attributes { + return Attributes{AttrPair{Key: "reversed", Value: value}} +} +func (a Attributes) Reversed(value any) Attributes { + return append(a, AttrPair{Key: "reversed", Value: value}) +} +func Role(value any) Attributes { + return Attributes{AttrPair{Key: "role", Value: value}} +} +func (a Attributes) Role(value any) Attributes { + return append(a, AttrPair{Key: "role", Value: value}) +} +func Rows(value any) Attributes { + return Attributes{AttrPair{Key: "rows", Value: value}} +} +func (a Attributes) Rows(value any) Attributes { + return append(a, AttrPair{Key: "rows", Value: value}) +} +func Rowspan(value any) Attributes { + return Attributes{AttrPair{Key: "rowspan", Value: value}} +} +func (a Attributes) Rowspan(value any) Attributes { + return append(a, AttrPair{Key: "rowspan", Value: value}) +} +func Sandbox(value any) Attributes { + return Attributes{AttrPair{Key: "sandbox", Value: value}} +} +func (a Attributes) Sandbox(value any) Attributes { + return append(a, AttrPair{Key: "sandbox", Value: value}) +} +func Scope(value any) Attributes { + return Attributes{AttrPair{Key: "scope", Value: value}} +} +func (a Attributes) Scope(value any) Attributes { + return append(a, AttrPair{Key: "scope", Value: value}) +} +func Selected(value any) Attributes { + return Attributes{AttrPair{Key: "selected", Value: value}} +} +func (a Attributes) Selected(value any) Attributes { + return append(a, AttrPair{Key: "selected", Value: value}) +} +func Shape(value any) Attributes { + return Attributes{AttrPair{Key: "shape", Value: value}} +} +func (a Attributes) Shape(value any) Attributes { + return append(a, AttrPair{Key: "shape", Value: value}) +} +func Size(value any) Attributes { + return Attributes{AttrPair{Key: "size", Value: value}} +} +func (a Attributes) Size(value any) Attributes { + return append(a, AttrPair{Key: "size", Value: value}) +} +func Sizes(value any) Attributes { + return Attributes{AttrPair{Key: "sizes", Value: value}} +} +func (a Attributes) Sizes(value any) Attributes { + return append(a, AttrPair{Key: "sizes", Value: value}) +} +func Slot(value any) Attributes { + return Attributes{AttrPair{Key: "slot", Value: value}} +} +func (a Attributes) Slot(value any) Attributes { + return append(a, AttrPair{Key: "slot", Value: value}) +} +func Span(value any) Attributes { + return Attributes{AttrPair{Key: "span", Value: value}} +} +func (a Attributes) Span(value any) Attributes { + return append(a, AttrPair{Key: "span", Value: value}) +} +func Spellcheck(value any) Attributes { + return Attributes{AttrPair{Key: "spellcheck", Value: value}} +} +func (a Attributes) Spellcheck(value any) Attributes { + return append(a, AttrPair{Key: "spellcheck", Value: value}) +} +func Src(value any) Attributes { + return Attributes{AttrPair{Key: "src", Value: value}} +} +func (a Attributes) Src(value any) Attributes { + return append(a, AttrPair{Key: "src", Value: value}) +} +func Srcdoc(value any) Attributes { + return Attributes{AttrPair{Key: "srcdoc", Value: value}} +} +func (a Attributes) Srcdoc(value any) Attributes { + return append(a, AttrPair{Key: "srcdoc", Value: value}) +} +func Srclang(value any) Attributes { + return Attributes{AttrPair{Key: "srclang", Value: value}} +} +func (a Attributes) Srclang(value any) Attributes { + return append(a, AttrPair{Key: "srclang", Value: value}) +} +func Srcset(value any) Attributes { + return Attributes{AttrPair{Key: "srcset", Value: value}} +} +func (a Attributes) Srcset(value any) Attributes { + return append(a, AttrPair{Key: "srcset", Value: value}) +} +func Start(value any) Attributes { + return Attributes{AttrPair{Key: "start", Value: value}} +} +func (a Attributes) Start(value any) Attributes { + return append(a, AttrPair{Key: "start", Value: value}) +} +func Step(value any) Attributes { + return Attributes{AttrPair{Key: "step", Value: value}} +} +func (a Attributes) Step(value any) Attributes { + return append(a, AttrPair{Key: "step", Value: value}) +} +func Style(value any) Attributes { + return Attributes{AttrPair{Key: "style", Value: value}} +} +func (a Attributes) Style(value any) Attributes { + return append(a, AttrPair{Key: "style", Value: value}) +} +func Tabindex(value any) Attributes { + return Attributes{AttrPair{Key: "tabindex", Value: value}} +} +func (a Attributes) Tabindex(value any) Attributes { + return append(a, AttrPair{Key: "tabindex", Value: value}) +} +func Target(value any) Attributes { + return Attributes{AttrPair{Key: "target", Value: value}} +} +func (a Attributes) Target(value any) Attributes { + return append(a, AttrPair{Key: "target", Value: value}) +} +func Title(value any) Attributes { + return Attributes{AttrPair{Key: "title", Value: value}} +} +func (a Attributes) Title(value any) Attributes { + return append(a, AttrPair{Key: "title", Value: value}) +} +func Translate(value any) Attributes { + return Attributes{AttrPair{Key: "translate", Value: value}} +} +func (a Attributes) Translate(value any) Attributes { + return append(a, AttrPair{Key: "translate", Value: value}) +} +func Type(value any) Attributes { + return Attributes{AttrPair{Key: "type", Value: value}} +} +func (a Attributes) Type(value any) Attributes { + return append(a, AttrPair{Key: "type", Value: value}) +} +func Usemap(value any) Attributes { + return Attributes{AttrPair{Key: "usemap", Value: value}} +} +func (a Attributes) Usemap(value any) Attributes { + return append(a, AttrPair{Key: "usemap", Value: value}) +} +func Value(value any) Attributes { + return Attributes{AttrPair{Key: "value", Value: value}} +} +func (a Attributes) Value(value any) Attributes { + return append(a, AttrPair{Key: "value", Value: value}) +} +func Width(value any) Attributes { + return Attributes{AttrPair{Key: "width", Value: value}} +} +func (a Attributes) Width(value any) Attributes { + return append(a, AttrPair{Key: "width", Value: value}) +} +func Wrap(value any) Attributes { + return Attributes{AttrPair{Key: "wrap", Value: value}} +} +func (a Attributes) Wrap(value any) Attributes { + return append(a, AttrPair{Key: "wrap", Value: value}) +} diff --git a/html/attributes.go b/html/attributes.go deleted file mode 100644 index 05c6864..0000000 --- a/html/attributes.go +++ /dev/null @@ -1,127 +0,0 @@ -package html - -func Attr(key string, value interface{}) Attributes { - return Attributes{AttrPair{Key: key, Value: value}} -} -func (a Attributes) Attr(key string, id interface{}) Attributes { - return append(a, AttrPair{Key: key, Value: id}) -} - -func Id(id interface{}) Attributes { - return Attributes{AttrPair{Key: "id", Value: id}} -} -func (a Attributes) Id(id interface{}) Attributes { - return append(a, AttrPair{Key: "id", Value: id}) -} - -func Class(class interface{}) Attributes { - return Attributes{AttrPair{Key: "class", Value: class}} -} -func (a Attributes) Class(class interface{}) Attributes { - return append(a, AttrPair{Key: "class", Value: class}) -} - -func Href(href interface{}) Attributes { - return Attributes{AttrPair{Key: "href", Value: href}} -} -func (a Attributes) Href(href interface{}) Attributes { - return append(a, AttrPair{Key: "href", Value: href}) -} - -func Rel(rel interface{}) Attributes { - return Attributes{AttrPair{Key: "rel", Value: rel}} -} -func (a Attributes) Rel(rel interface{}) Attributes { - return append(a, AttrPair{Key: "rel", Value: rel}) -} - -func Name(name interface{}) Attributes { - return Attributes{AttrPair{Key: "name", Value: name}} -} -func (a Attributes) Name(name interface{}) Attributes { - return append(a, AttrPair{Key: "name", Value: name}) -} - -func (a Attributes) Content(name interface{}) Attributes { - return append(a, AttrPair{Key: "content", Value: name}) -} -func Content(name interface{}) Attributes { - return Attributes{AttrPair{Key: "content", Value: name}} -} - -func Checked() Attributes { - return Attributes{AttrPair{Key: "checked", Value: nil}} -} -func (a Attributes) Checked() Attributes { - return append(a, AttrPair{Key: "checked", Value: nil}) -} - -func Defer() Attributes { - return Attributes{AttrPair{Key: "defer", Value: nil}} -} -func (a Attributes) Defer() Attributes { - return append(a, AttrPair{Key: "defer", Value: nil}) -} - -func Src(src interface{}) Attributes { - return Attributes{AttrPair{Key: "src", Value: src}} -} -func (a Attributes) Src(src interface{}) Attributes { - return append(a, AttrPair{Key: "src", Value: src}) -} - -func Action(action interface{}) Attributes { - return Attributes{AttrPair{Key: "action", Value: action}} -} -func (a Attributes) Action(action interface{}) Attributes { - return append(a, AttrPair{Key: "action", Value: action}) -} - -func Method(method interface{}) Attributes { - return Attributes{AttrPair{Key: "method", Value: method}} -} -func (a Attributes) Method(method interface{}) Attributes { - return append(a, AttrPair{Key: "method", Value: method}) -} - -func Type(typ interface{}) Attributes { - return Attributes{AttrPair{Key: "type", Value: typ}} -} -func (a Attributes) Type(typ interface{}) Attributes { - return append(a, AttrPair{Key: "type", Value: typ}) -} - -func For(fo interface{}) Attributes { - return Attributes{AttrPair{Key: "for", Value: fo}} -} -func (a Attributes) For(fo interface{}) Attributes { - return append(a, AttrPair{Key: "for", Value: fo}) -} - -func Value(value interface{}) Attributes { - return Attributes{AttrPair{Key: "value", Value: value}} -} -func (a Attributes) Value(value interface{}) Attributes { - return append(a, AttrPair{Key: "value", Value: value}) -} - -func Data(key string, value interface{}) Attributes { - return Attributes{AttrPair{Key: "data-" + key, Value: value}} -} -func (a Attributes) Data(key string, value interface{}) Attributes { - return append(a, AttrPair{Key: "data-" + key, Value: value}) -} - -func Charset(charset interface{}) Attributes { - return Attributes{AttrPair{Key: "charset", Value: charset}} -} -func (a Attributes) Charset(charset interface{}) Attributes { - return append(a, AttrPair{Key: "charset", Value: charset}) -} - -func Styles(style string) Attributes { - return Attributes{AttrPair{Key: "style", Value: style}} -} -func (a Attributes) Styles(style string) Attributes { - return append(a, AttrPair{Key: "style", Value: style}) -} diff --git a/html/bench_test.go b/html/bench_test.go index 5c4dbc1..c725836 100644 --- a/html/bench_test.go +++ b/html/bench_test.go @@ -7,6 +7,8 @@ import ( "io/ioutil" "log" "testing" + + "github.com/mbertschler/blocks/html/attr" ) func TestHTMLTemplate(t *testing.T) { @@ -103,7 +105,7 @@ func renderBlocks(print bool) { Doctype("html"), Html(nil, Head(nil, - Meta(Charset("UTF-8")), + Meta(attr.Charset("UTF-8")), Title(nil, Text(d.Title)), ), Body(nil, rows), diff --git a/html/elements.go b/html/elements.go index affee67..fc1eafa 100644 --- a/html/elements.go +++ b/html/elements.go @@ -1,110 +1,7 @@ package html +import "github.com/mbertschler/blocks/html/attr" + func Doctype(arg string) Block { - return newElement("!DOCTYPE", Attributes{{arg, nil}}, nil, Void) -} -func Html(attr Attributes, children ...Block) Block { - return newElement("html", attr, children, 0) -} -func Head(attr Attributes, children ...Block) Block { - return newElement("head", attr, children, 0) -} -func Noscript(attr Attributes, children ...Block) Block { - return newElement("noscript", attr, children, 0) -} -func Iframe(attr Attributes, children ...Block) Block { - return newElement("iframe", attr, children, 0) -} -func Link(attr Attributes, children ...Block) Block { - return newElement("link", attr, children, Void) -} -func Img(attr Attributes, children ...Block) Block { - return newElement("img", attr, children, Void) -} -func Meta(attr Attributes, children ...Block) Block { - return newElement("meta", attr, children, Void) -} -func Title(attr Attributes, children ...Block) Block { - return newElement("title", attr, children, 0) -} -func Body(attr Attributes, children ...Block) Block { - return newElement("body", attr, children, 0) -} -func Button(attr Attributes, children ...Block) Block { - return newElement("button", attr, children, 0) -} -func Style(attr Attributes, children ...Block) Block { - return newElement("style", attr, children, CSSElement) -} -func Script(attr Attributes, children ...Block) Block { - return newElement("script", attr, children, JSElement) -} -func Textarea(attr Attributes, children ...Block) Block { - return newElement("textarea", attr, children, NoWhitespace) -} -func Main(attr Attributes, children ...Block) Block { - return newElement("main", attr, children, 0) -} -func Form(attr Attributes, children ...Block) Block { - return newElement("form", attr, children, 0) -} -func Nav(attr Attributes, children ...Block) Block { - return newElement("nav", attr, children, 0) -} -func Span(attr Attributes, children ...Block) Block { - return newElement("span", attr, children, 0) -} -func I(attr Attributes, children ...Block) Block { - return newElement("i", attr, children, 0) -} -func Div(attr Attributes, children ...Block) Block { - return newElement("div", attr, children, 0) -} -func P(attr Attributes, children ...Block) Block { - return newElement("p", attr, children, 0) -} -func Ul(attr Attributes, children ...Block) Block { - return newElement("ul", attr, children, 0) -} -func Li(attr Attributes, children ...Block) Block { - return newElement("li", attr, children, 0) -} -func A(attr Attributes, children ...Block) Block { - return newElement("a", attr, children, 0) -} -func H1(attr Attributes, children ...Block) Block { - return newElement("h1", attr, children, 0) -} -func H2(attr Attributes, children ...Block) Block { - return newElement("h2", attr, children, 0) -} -func H3(attr Attributes, children ...Block) Block { - return newElement("h3", attr, children, 0) -} -func H4(attr Attributes, children ...Block) Block { - return newElement("h4", attr, children, 0) -} -func H5(attr Attributes, children ...Block) Block { - return newElement("h5", attr, children, 0) -} -func H6(attr Attributes, children ...Block) Block { - return newElement("h6", attr, children, 0) -} -func Pre(attr Attributes, children ...Block) Block { - return newElement("pre", attr, children, NoWhitespace) -} -func Label(attr Attributes, children ...Block) Block { - return newElement("label", attr, children, 0) -} -func Strong(attr Attributes, children ...Block) Block { - return newElement("strong", attr, children, 0) -} -func Input(attr Attributes, children ...Block) Block { - return newElement("input", attr, children, Void) -} -func Br() Block { - return newElement("br", nil, nil, Void) -} -func Hr(attr Attributes) Block { - return newElement("hr", attr, nil, Void) + return newElement("!DOCTYPE", attr.Attributes{{arg, nil}}, nil, Void) } diff --git a/html/elements_gen.go b/html/elements_gen.go new file mode 100644 index 0000000..71a5c2c --- /dev/null +++ b/html/elements_gen.go @@ -0,0 +1,341 @@ +// Code generated by blocks. DO NOT EDIT. +package html + +import "github.com/mbertschler/blocks/html/attr" + +func A(attr attr.Attributes, children ...Block) Block { + return newElement("a", attr, children, 0) +} +func Abbr(attr attr.Attributes, children ...Block) Block { + return newElement("abbr", attr, children, 0) +} +func Address(attr attr.Attributes, children ...Block) Block { + return newElement("address", attr, children, 0) +} +func Area(attr attr.Attributes, children ...Block) Block { + return newElement("area", attr, children, 0) +} +func Article(attr attr.Attributes, children ...Block) Block { + return newElement("article", attr, children, 0) +} +func Aside(attr attr.Attributes, children ...Block) Block { + return newElement("aside", attr, children, 0) +} +func Audio(attr attr.Attributes, children ...Block) Block { + return newElement("audio", attr, children, 0) +} +func B(attr attr.Attributes, children ...Block) Block { + return newElement("b", attr, children, 0) +} +func Base(attr attr.Attributes, children ...Block) Block { + return newElement("base", attr, children, 0) +} +func Bdi(attr attr.Attributes, children ...Block) Block { + return newElement("bdi", attr, children, 0) +} +func Bdo(attr attr.Attributes, children ...Block) Block { + return newElement("bdo", attr, children, 0) +} +func Blockquote(attr attr.Attributes, children ...Block) Block { + return newElement("blockquote", attr, children, 0) +} +func Body(attr attr.Attributes, children ...Block) Block { + return newElement("body", attr, children, 0) +} +func Br(attr attr.Attributes) Block { + return newElement("br", attr, nil, Void) +} +func Button(attr attr.Attributes, children ...Block) Block { + return newElement("button", attr, children, 0) +} +func Canvas(attr attr.Attributes, children ...Block) Block { + return newElement("canvas", attr, children, 0) +} +func Caption(attr attr.Attributes, children ...Block) Block { + return newElement("caption", attr, children, 0) +} +func Cite(attr attr.Attributes, children ...Block) Block { + return newElement("cite", attr, children, 0) +} +func Code(attr attr.Attributes, children ...Block) Block { + return newElement("code", attr, children, 0) +} +func Col(attr attr.Attributes, children ...Block) Block { + return newElement("col", attr, children, 0) +} +func Colgroup(attr attr.Attributes, children ...Block) Block { + return newElement("colgroup", attr, children, 0) +} +func Data(attr attr.Attributes, children ...Block) Block { + return newElement("data", attr, children, 0) +} +func Datalist(attr attr.Attributes, children ...Block) Block { + return newElement("datalist", attr, children, 0) +} +func Dd(attr attr.Attributes, children ...Block) Block { + return newElement("dd", attr, children, 0) +} +func Del(attr attr.Attributes, children ...Block) Block { + return newElement("del", attr, children, 0) +} +func Details(attr attr.Attributes, children ...Block) Block { + return newElement("details", attr, children, 0) +} +func Dfn(attr attr.Attributes, children ...Block) Block { + return newElement("dfn", attr, children, 0) +} +func Dialog(attr attr.Attributes, children ...Block) Block { + return newElement("dialog", attr, children, 0) +} +func Div(attr attr.Attributes, children ...Block) Block { + return newElement("div", attr, children, 0) +} +func Dl(attr attr.Attributes, children ...Block) Block { + return newElement("dl", attr, children, 0) +} +func Dt(attr attr.Attributes, children ...Block) Block { + return newElement("dt", attr, children, 0) +} +func Em(attr attr.Attributes, children ...Block) Block { + return newElement("em", attr, children, 0) +} +func Embed(attr attr.Attributes, children ...Block) Block { + return newElement("embed", attr, children, 0) +} +func Fieldset(attr attr.Attributes, children ...Block) Block { + return newElement("fieldset", attr, children, 0) +} +func Figcaption(attr attr.Attributes, children ...Block) Block { + return newElement("figcaption", attr, children, 0) +} +func Figure(attr attr.Attributes, children ...Block) Block { + return newElement("figure", attr, children, 0) +} +func Footer(attr attr.Attributes, children ...Block) Block { + return newElement("footer", attr, children, 0) +} +func Form(attr attr.Attributes, children ...Block) Block { + return newElement("form", attr, children, 0) +} +func H1(attr attr.Attributes, children ...Block) Block { + return newElement("h1", attr, children, 0) +} +func H2(attr attr.Attributes, children ...Block) Block { + return newElement("h2", attr, children, 0) +} +func H3(attr attr.Attributes, children ...Block) Block { + return newElement("h3", attr, children, 0) +} +func H4(attr attr.Attributes, children ...Block) Block { + return newElement("h4", attr, children, 0) +} +func H5(attr attr.Attributes, children ...Block) Block { + return newElement("h5", attr, children, 0) +} +func H6(attr attr.Attributes, children ...Block) Block { + return newElement("h6", attr, children, 0) +} +func Head(attr attr.Attributes, children ...Block) Block { + return newElement("head", attr, children, 0) +} +func Header(attr attr.Attributes, children ...Block) Block { + return newElement("header", attr, children, 0) +} +func Hgroup(attr attr.Attributes, children ...Block) Block { + return newElement("hgroup", attr, children, 0) +} +func Hr(attr attr.Attributes) Block { + return newElement("hr", attr, nil, Void) +} +func Html(attr attr.Attributes, children ...Block) Block { + return newElement("html", attr, children, 0) +} +func I(attr attr.Attributes, children ...Block) Block { + return newElement("i", attr, children, 0) +} +func Iframe(attr attr.Attributes, children ...Block) Block { + return newElement("iframe", attr, children, 0) +} +func Img(attr attr.Attributes) Block { + return newElement("img", attr, nil, Void) +} +func Input(attr attr.Attributes) Block { + return newElement("input", attr, nil, Void) +} +func Ins(attr attr.Attributes, children ...Block) Block { + return newElement("ins", attr, children, 0) +} +func Kbd(attr attr.Attributes, children ...Block) Block { + return newElement("kbd", attr, children, 0) +} +func Label(attr attr.Attributes, children ...Block) Block { + return newElement("label", attr, children, 0) +} +func Legend(attr attr.Attributes, children ...Block) Block { + return newElement("legend", attr, children, 0) +} +func Li(attr attr.Attributes, children ...Block) Block { + return newElement("li", attr, children, 0) +} +func Link(attr attr.Attributes) Block { + return newElement("link", attr, nil, Void) +} +func Main(attr attr.Attributes, children ...Block) Block { + return newElement("main", attr, children, 0) +} +func Map(attr attr.Attributes, children ...Block) Block { + return newElement("map", attr, children, 0) +} +func Mark(attr attr.Attributes, children ...Block) Block { + return newElement("mark", attr, children, 0) +} +func Menu(attr attr.Attributes, children ...Block) Block { + return newElement("menu", attr, children, 0) +} +func Meta(attr attr.Attributes) Block { + return newElement("meta", attr, nil, Void) +} +func Meter(attr attr.Attributes, children ...Block) Block { + return newElement("meter", attr, children, 0) +} +func Nav(attr attr.Attributes, children ...Block) Block { + return newElement("nav", attr, children, 0) +} +func Noscript(attr attr.Attributes, children ...Block) Block { + return newElement("noscript", attr, children, 0) +} +func Object(attr attr.Attributes, children ...Block) Block { + return newElement("object", attr, children, 0) +} +func Ol(attr attr.Attributes, children ...Block) Block { + return newElement("ol", attr, children, 0) +} +func Optgroup(attr attr.Attributes, children ...Block) Block { + return newElement("optgroup", attr, children, 0) +} +func Option(attr attr.Attributes, children ...Block) Block { + return newElement("option", attr, children, 0) +} +func Output(attr attr.Attributes, children ...Block) Block { + return newElement("output", attr, children, 0) +} +func P(attr attr.Attributes, children ...Block) Block { + return newElement("p", attr, children, 0) +} +func Picture(attr attr.Attributes, children ...Block) Block { + return newElement("picture", attr, children, 0) +} +func Portal(attr attr.Attributes, children ...Block) Block { + return newElement("portal", attr, children, 0) +} +func Pre(attr attr.Attributes, children ...Block) Block { + return newElement("pre", attr, children, NoWhitespace) +} +func Progress(attr attr.Attributes, children ...Block) Block { + return newElement("progress", attr, children, 0) +} +func Q(attr attr.Attributes, children ...Block) Block { + return newElement("q", attr, children, 0) +} +func Rp(attr attr.Attributes, children ...Block) Block { + return newElement("rp", attr, children, 0) +} +func Rt(attr attr.Attributes, children ...Block) Block { + return newElement("rt", attr, children, 0) +} +func Ruby(attr attr.Attributes, children ...Block) Block { + return newElement("ruby", attr, children, 0) +} +func S(attr attr.Attributes, children ...Block) Block { + return newElement("s", attr, children, 0) +} +func Samp(attr attr.Attributes, children ...Block) Block { + return newElement("samp", attr, children, 0) +} +func Script(attr attr.Attributes, children ...Block) Block { + return newElement("script", attr, children, JSElement) +} +func Section(attr attr.Attributes, children ...Block) Block { + return newElement("section", attr, children, 0) +} +func Select(attr attr.Attributes, children ...Block) Block { + return newElement("select", attr, children, 0) +} +func Slot(attr attr.Attributes, children ...Block) Block { + return newElement("slot", attr, children, 0) +} +func Small(attr attr.Attributes, children ...Block) Block { + return newElement("small", attr, children, 0) +} +func Source(attr attr.Attributes, children ...Block) Block { + return newElement("source", attr, children, 0) +} +func Span(attr attr.Attributes, children ...Block) Block { + return newElement("span", attr, children, 0) +} +func Strong(attr attr.Attributes, children ...Block) Block { + return newElement("strong", attr, children, 0) +} +func Style(attr attr.Attributes, children ...Block) Block { + return newElement("style", attr, children, CSSElement) +} +func Sub(attr attr.Attributes, children ...Block) Block { + return newElement("sub", attr, children, 0) +} +func Summary(attr attr.Attributes, children ...Block) Block { + return newElement("summary", attr, children, 0) +} +func Sup(attr attr.Attributes, children ...Block) Block { + return newElement("sup", attr, children, 0) +} +func Table(attr attr.Attributes, children ...Block) Block { + return newElement("table", attr, children, 0) +} +func Tbody(attr attr.Attributes, children ...Block) Block { + return newElement("tbody", attr, children, 0) +} +func Td(attr attr.Attributes, children ...Block) Block { + return newElement("td", attr, children, 0) +} +func Template(attr attr.Attributes, children ...Block) Block { + return newElement("template", attr, children, 0) +} +func Textarea(attr attr.Attributes, children ...Block) Block { + return newElement("textarea", attr, children, NoWhitespace) +} +func Tfoot(attr attr.Attributes, children ...Block) Block { + return newElement("tfoot", attr, children, 0) +} +func Th(attr attr.Attributes, children ...Block) Block { + return newElement("th", attr, children, 0) +} +func Thead(attr attr.Attributes, children ...Block) Block { + return newElement("thead", attr, children, 0) +} +func Time(attr attr.Attributes, children ...Block) Block { + return newElement("time", attr, children, 0) +} +func Title(attr attr.Attributes, children ...Block) Block { + return newElement("title", attr, children, 0) +} +func Tr(attr attr.Attributes, children ...Block) Block { + return newElement("tr", attr, children, 0) +} +func Track(attr attr.Attributes, children ...Block) Block { + return newElement("track", attr, children, 0) +} +func U(attr attr.Attributes, children ...Block) Block { + return newElement("u", attr, children, 0) +} +func Ul(attr attr.Attributes, children ...Block) Block { + return newElement("ul", attr, children, 0) +} +func Var(attr attr.Attributes, children ...Block) Block { + return newElement("var", attr, children, 0) +} +func Video(attr attr.Attributes, children ...Block) Block { + return newElement("video", attr, children, 0) +} +func Wbr(attr attr.Attributes, children ...Block) Block { + return newElement("wbr", attr, children, 0) +} diff --git a/html/render.go b/html/render.go index 35c8aad..33a720a 100644 --- a/html/render.go +++ b/html/render.go @@ -6,6 +6,8 @@ import ( "html" "html/template" "io" + + "github.com/mbertschler/blocks/html/attr" ) type UnsafeString string @@ -211,31 +213,25 @@ func renderHTML(c Block, w io.Writer, ctx *renderCtx) error { return nil } -type Attributes []AttrPair -type AttrPair struct { - Key string - Value interface{} -} - type Element struct { Type string - Attributes + attr.Attributes Children Blocks - Options Option + Options ElementOption } func (Element) RenderHTML() Block { return nil } -type Option int8 +type ElementOption int8 const ( - Void Option = 1 << iota + Void ElementOption = 1 << iota CSSElement JSElement NoWhitespace ) -func newElement(el string, attr Attributes, children []Block, opt Option) Block { +func newElement(el string, attr attr.Attributes, children []Block, opt ElementOption) Block { if len(children) == 0 { return Element{el, attr, nil, opt} } @@ -245,6 +241,6 @@ func newElement(el string, attr Attributes, children []Block, opt Option) Block return Element{el, attr, Blocks(children), opt} } -func Elem(el string, attr Attributes, children ...Block) Block { +func Elem(el string, attr attr.Attributes, children ...Block) Block { return newElement(el, attr, children, 0) } diff --git a/main.go b/main.go index 7905807..230ad97 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,96 @@ package main +import ( + "log" + "os" + "strings" + "text/template" + + "github.com/mbertschler/blocks/html" +) + func main() { + generateElements() + generateAttributes() +} + +func generateElements() { + elementsTemplate, err := template.New("elements").Parse(elementsFileTemplate) + if err != nil { + log.Fatal(err) + } + + file, err := os.Create("html/elements_gen.go") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + data := []elementTemplateData{} + for _, element := range elements { + option := elementOptions[element.Option] + if option == "" { + log.Fatalf("unknown option %d for element %s", element.Option, element.Name) + } + data = append(data, elementTemplateData{ + FuncName: funcName(element.Name), + TagName: element.Name, + Option: option, + NoChildren: element.Option == html.Void, + }) + } + err = elementsTemplate.Execute(file, data) + if err != nil { + log.Fatal(err) + } +} + +var elementOptions = map[html.ElementOption]string{ + 0: "0", + html.Void: "Void", + html.CSSElement: "CSSElement", + html.JSElement: "JSElement", + html.NoWhitespace: "NoWhitespace", +} + +type elementTemplateData struct { + FuncName string + TagName string + Option string + NoChildren bool +} + +func generateAttributes() { + attributesTemplate, err := template.New("attributes").Parse(attributesFileTemplate) + if err != nil { + log.Fatal(err) + } + + file, err := os.Create("html/attr/attributes_gen.go") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + data := []attributeTemplateData{} + for _, attribute := range attributes { + data = append(data, attributeTemplateData{ + FuncName: funcName(attribute.Name), + AttrName: attribute.Name, + }) + } + err = attributesTemplate.Execute(file, data) + if err != nil { + log.Fatal(err) + } +} + +func funcName(name string) string { + title := strings.Title(name) + return strings.ReplaceAll(title, "-", "") +} +type attributeTemplateData struct { + FuncName string + AttrName string } From 88b8665a571986d2dfc7e6c7518bfba9f2244f6f Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Sun, 7 May 2023 19:56:03 +0200 Subject: [PATCH 7/8] fix packages for new package structure of splitting html elements and attributes --- examples/components/todolist.go | 65 +++++++++++++++++---------------- go.work | 2 +- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/examples/components/todolist.go b/examples/components/todolist.go index 4a52c38..770b09f 100644 --- a/examples/components/todolist.go +++ b/examples/components/todolist.go @@ -7,6 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/mbertschler/blocks/html" + "github.com/mbertschler/blocks/html/attr" ) // started work based on the template at 13:45 @@ -87,25 +88,25 @@ func todoLayout(todoApp html.Block, state TodoListState) (html.Block, error) { } return html.Blocks{ html.Doctype("html"), - html.Html(html.Attr("lang", "en"), + html.Html(attr.Attr("lang", "en"), html.Head(nil, - html.Meta(html.Charset("utf-8")), - html.Meta(html.Name("viewport").Content("width=device-width, initial-scale=1")), + html.Meta(attr.Charset("utf-8")), + html.Meta(attr.Name("viewport").Content("width=device-width, initial-scale=1")), html.Title(nil, html.Text("Guiapi • TodoMVC")), - html.Link(html.Rel("stylesheet").Href("https://cdn.jsdelivr.net/npm/todomvc-app-css@2.4.2/index.min.css")), - html.Link(html.Rel("stylesheet").Href("/dist/bundle.css")), + html.Link(attr.Rel("stylesheet").Href("https://cdn.jsdelivr.net/npm/todomvc-app-css@2.4.2/index.min.css")), + html.Link(attr.Rel("stylesheet").Href("/dist/bundle.css")), ), html.Body(nil, todoApp, - html.Elem("footer", html.Class("info"), + html.Elem("footer", attr.Class("info"), html.P(nil, html.Text("Double-click to edit a todo")), - html.P(nil, html.Text("Template by "), html.A(html.Href("http://sindresorhus.com"), html.Text("Sindre Sorhus"))), - html.P(nil, html.Text("Created by "), html.A(html.Href("https://github.com/mbertschler"), html.Text("Martin Bertschler"))), - html.P(nil, html.Text("Part of "), html.A(html.Href("http://todomvc.com"), html.Text("TodoMVC"))), - html.A(html.Href("/counter"), html.Text("Counter Example")), + html.P(nil, html.Text("Template by "), html.A(attr.Href("http://sindresorhus.com"), html.Text("Sindre Sorhus"))), + html.P(nil, html.Text("Created by "), html.A(attr.Href("https://github.com/mbertschler"), html.Text("Martin Bertschler"))), + html.P(nil, html.Text("Part of "), html.A(attr.Href("http://todomvc.com"), html.Text("TodoMVC"))), + html.A(attr.Href("/counter"), html.Text("Counter Example")), ), html.Script(nil, html.JS("var state = "+string(stateJSON)+";")), - html.Script(html.Src("/dist/bundle.js")), + html.Script(attr.Src("/dist/bundle.js")), ), ), }, nil @@ -197,10 +198,10 @@ func (t *TodoList) renderBlock(props *TodoListProps) (html.Block, error) { } } - block := html.Elem("section", html.Class("todoapp"), - html.Elem("header", html.Class("header"), + block := html.Elem("section", attr.Class("todoapp"), + html.Elem("header", attr.Class("header"), html.H1(nil, html.Text("todos")), - html.Input(html.Class("new-todo ga").Attr("placeholder", "What needs to be done?"). + html.Input(attr.Class("new-todo ga").Attr("placeholder", "What needs to be done?"). Attr("autofocus", "").Attr("ga-on", "keydown").Attr("ga-func", "newTodoKeydown")), ), main, @@ -220,11 +221,11 @@ func (t *TodoList) renderMainBlock(todos *StoredTodo, page string, editItemID in } items.Add(t.renderItem(&item, editItemID)) } - main := html.Elem("section", html.Class("main"), - html.Input(html.Class("toggle-all").Attr("type", "checkbox")), - html.Label(html.Class("ga").Attr("for", "toggle-all").Attr("ga-on", "click").Attr("ga-action", "TodoList.ToggleAll"), + main := html.Elem("section", attr.Class("main"), + html.Input(attr.Class("toggle-all").Attr("type", "checkbox")), + html.Label(attr.Class("ga").Attr("for", "toggle-all").Attr("ga-on", "click").Attr("ga-action", "TodoList.ToggleAll"), html.Text("Mark all as complete")), - html.Ul(html.Class("todo-list"), + html.Ul(attr.Class("todo-list"), items, ), ) @@ -236,10 +237,10 @@ func (t *TodoList) renderItem(item *StoredTodoItem, editItemID int) html.Block { return t.renderItemEdit(item, editItemID) } - liAttrs := html.Attr("ga-on", "dblclick"). + liAttrs := attr.Attr("ga-on", "dblclick"). Attr("ga-action", "TodoList.EditItem"). Attr("ga-args", fmt.Sprintf(`{"id":%d}`, item.ID)) - inputAttrs := html.Class("toggle ga").Attr("type", "checkbox"). + inputAttrs := attr.Class("toggle ga").Attr("type", "checkbox"). Attr("ga-on", "click").Attr("ga-action", "TodoList.ToggleItem"). Attr("ga-args", fmt.Sprintf(`{"id":%d}`, item.ID)) if item.Done { @@ -250,10 +251,10 @@ func (t *TodoList) renderItem(item *StoredTodoItem, editItemID int) html.Block { } li := html.Li(liAttrs, - html.Div(html.Class("view"), + html.Div(attr.Class("view"), html.Input(inputAttrs), html.Label(nil, html.Text(item.Text)), - html.Button(html.Class("destroy ga"). + html.Button(attr.Class("destroy ga"). Attr("ga-on", "click").Attr("ga-action", "TodoList.DeleteItem"). Attr("ga-args", fmt.Sprintf(`{"id":%d}`, item.ID))), ), @@ -262,9 +263,9 @@ func (t *TodoList) renderItem(item *StoredTodoItem, editItemID int) html.Block { } func (t *TodoList) renderItemEdit(item *StoredTodoItem, editItemID int) html.Block { - li := html.Li(html.Class("editing"), - html.Div(html.Class("view"), - html.Input(html.Class("edit ga").Attr("ga-init", "initEdit"). + li := html.Li(attr.Class("editing"), + html.Div(attr.Class("view"), + html.Input(attr.Class("edit ga").Attr("ga-init", "initEdit"). Attr("ga-args", fmt.Sprintf(`{"id":%d}`, item.ID)).Attr("value", item.Text)), ), ) @@ -300,24 +301,24 @@ func (t *TodoList) renderFooterBlock(todos *StoredTodo, page string) (html.Block var clearCompletedButton html.Block if someDone { - clearCompletedButton = html.Button(html.Class("clear-completed ga").Attr("ga-on", "click").Attr("ga-action", "TodoList.ClearCompleted"), + clearCompletedButton = html.Button(attr.Class("clear-completed ga").Attr("ga-on", "click").Attr("ga-action", "TodoList.ClearCompleted"), html.Text("Clear completed")) } - footer := html.Elem("footer", html.Class("footer"), - html.Span(html.Class("todo-count"), + footer := html.Elem("footer", attr.Class("footer"), + html.Span(attr.Class("todo-count"), html.Strong(nil, html.Text(fmt.Sprint(leftCount))), html.Text(itemsLeftText), ), - html.Ul(html.Class("filters"), + html.Ul(attr.Class("filters"), html.Li(nil, - html.A(html.Class(allClass+" ga").Href("/").Attr("ga-link", "TodoList.Page").Attr("ga-state", `{"Page":"all"}`), html.Text("All")), + html.A(attr.Class(allClass+" ga").Href("/").Attr("ga-link", "TodoList.Page").Attr("ga-state", `{"Page":"all"}`), html.Text("All")), ), html.Li(nil, - html.A(html.Class(activeClass+" ga").Href("/active").Attr("ga-link", "TodoList.Page").Attr("ga-state", `{"Page":"active"}`), html.Text("Active")), + html.A(attr.Class(activeClass+" ga").Href("/active").Attr("ga-link", "TodoList.Page").Attr("ga-state", `{"Page":"active"}`), html.Text("Active")), ), html.Li(nil, - html.A(html.Class(completedClass+" ga").Href("/completed").Attr("ga-link", "TodoList.Page").Attr("ga-state", `{"Page":"completed"}`), html.Text("Completed")), + html.A(attr.Class(completedClass+" ga").Href("/completed").Attr("ga-link", "TodoList.Page").Attr("ga-state", `{"Page":"completed"}`), html.Text("Completed")), ), ), clearCompletedButton, diff --git a/go.work b/go.work index ef557df..0e83f41 100644 --- a/go.work +++ b/go.work @@ -1,6 +1,6 @@ go 1.20 use ( - ./ + . ./examples/components ) From c3c069837e91cbc125167ffaaffb4928d8c43f92 Mon Sep 17 00:00:00 2001 From: Martin Bertschler Date: Mon, 12 Jun 2023 23:43:18 +0200 Subject: [PATCH 8/8] last commit for now --- examples/components/go.mod | 4 ++-- html/elements.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/components/go.mod b/examples/components/go.mod index 9851777..4a5103b 100644 --- a/examples/components/go.mod +++ b/examples/components/go.mod @@ -1,6 +1,6 @@ -module github.com/mbertschler/blocks/components +module github.com/mbertschler/blocks/examples/components -go 1.20 +go 1.18 require ( github.com/evanw/esbuild v0.17.16 diff --git a/html/elements.go b/html/elements.go index fc1eafa..6b48abb 100644 --- a/html/elements.go +++ b/html/elements.go @@ -3,5 +3,5 @@ package html import "github.com/mbertschler/blocks/html/attr" func Doctype(arg string) Block { - return newElement("!DOCTYPE", attr.Attributes{{arg, nil}}, nil, Void) + return newElement("!DOCTYPE", attr.Attributes{{Key: arg}}, nil, Void) }