aboutsummaryrefslogtreecommitdiff
path: root/dom
diff options
context:
space:
mode:
Diffstat (limited to 'dom')
-rw-r--r--dom/css_class.go45
-rw-r--r--dom/html.go119
2 files changed, 164 insertions, 0 deletions
diff --git a/dom/css_class.go b/dom/css_class.go
new file mode 100644
index 0000000..998dd50
--- /dev/null
+++ b/dom/css_class.go
@@ -0,0 +1,45 @@
+package dom
+
+import "strings"
+
+type ClassList map[string]struct{}
+
+func (cl ClassList) set(e Element) Element {
+ if len(cl) == 0 {
+ return e
+ }
+ classes := ""
+ for k := range cl {
+ classes += k + " "
+ }
+ classes = strings.TrimSpace(classes)
+ return e.SetAttribute("class", classes)
+}
+
+func (cl ClassList) Has(v string) bool {
+ _, ok := cl[v]
+ return ok
+}
+
+func (cl ClassList) Add(v string) ClassList {
+ cl[v] = struct{}{}
+ return cl
+}
+
+func (cl ClassList) Remove(v string) ClassList {
+ delete(cl, v)
+ return cl
+}
+
+func (cl ClassList) Toggle(v string) ClassList {
+ if cl.Has(v) {
+ cl.Remove(v)
+ } else {
+ cl.Add(v)
+ }
+ return cl
+}
+
+func NewClassList() ClassList {
+ return ClassList(make(map[string]struct{}))
+}
diff --git a/dom/html.go b/dom/html.go
new file mode 100644
index 0000000..a7dc434
--- /dev/null
+++ b/dom/html.go
@@ -0,0 +1,119 @@
+package dom
+
+import (
+ "fmt"
+ "html/template"
+)
+
+func render(tag string, attributes map[string]string, endSlash bool) template.HTML {
+ base := fmt.Sprintf(`<%s`, tag)
+ for k, v := range attributes {
+ base += fmt.Sprintf(` %s="%s"`, k, v)
+ }
+ if !endSlash {
+ return template.HTML(base + `>`)
+ }
+ return template.HTML(base + ` />`)
+}
+
+type Element interface {
+ Render() template.HTML
+ HasAttribute(string) bool
+ SetAttribute(string, string) Element
+ RemoveAttribute(string) Element
+ ClassList() ClassList
+}
+
+type LiteralElement template.HTML
+
+func (e LiteralElement) Render() template.HTML {
+ return template.HTML(e)
+}
+
+func (LiteralElement) HasAttribute(string) bool {
+ return false
+}
+
+func (e LiteralElement) SetAttribute(string, string) Element {
+ return e
+}
+
+func (e LiteralElement) RemoveAttribute(string) Element {
+ return e
+}
+
+func (e LiteralElement) ClassList() ClassList {
+ return nil
+}
+
+func NewLiteralElement(s template.HTML) LiteralElement {
+ return LiteralElement(s)
+}
+
+type VoidElement struct {
+ Tag string
+ attributes map[string]string
+ cl ClassList
+}
+
+func (e VoidElement) Render() template.HTML {
+ e.cl.set(e)
+ return render(e.Tag, e.attributes, true)
+}
+
+func (e VoidElement) HasAttribute(k string) bool {
+ _, ok := e.attributes[k]
+ return ok
+}
+
+func (e VoidElement) SetAttribute(k, v string) Element {
+ e.attributes[k] = v
+ return e
+}
+
+func (e VoidElement) RemoveAttribute(k string) Element {
+ delete(e.attributes, k)
+ return e
+}
+
+func (e VoidElement) ClassList() ClassList {
+ return e.cl
+}
+
+func NewVoidElement(tag string) VoidElement {
+ return VoidElement{tag, make(map[string]string), NewClassList()}
+}
+
+func NewImg(src, alt string) Element {
+ return NewVoidElement("img").SetAttribute("alt", alt).SetAttribute("src", src)
+}
+
+type ContentElement struct {
+ VoidElement
+ Contents []Element
+}
+
+func (e ContentElement) Render() template.HTML {
+ e.cl.set(e)
+ base := render(e.Tag, e.attributes, false)
+ for _, el := range e.Contents {
+ base += el.Render()
+ }
+ return base + template.HTML(fmt.Sprintf(`</%s>`, e.VoidElement.Tag))
+}
+
+func NewContentElement(tag string, contents []Element) ContentElement {
+ return ContentElement{NewVoidElement(tag), contents}
+}
+
+func NewLiteralContentElement(tag string, content template.HTML) Element {
+ return NewContentElement(tag, []Element{NewLiteralElement(content)})
+}
+
+func NewParagraph(content template.HTML) Element {
+ return NewLiteralContentElement("p", content)
+}
+
+func NewHeading(level uint, content template.HTML) Element {
+ return NewLiteralContentElement(fmt.Sprintf("h%d", level), content)
+}