aboutsummaryrefslogtreecommitdiff
path: root/dom/html.go
blob: 3e8117fe1dae796c3e4385583eff1da2de21d932 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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 template.HTML) Element {
	return NewVoidElement("img").SetAttribute("alt", string(alt)).SetAttribute("src", string(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)
}