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
|
package dom
import (
"fmt"
"html"
"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
}
type LiteralElement struct {
Content string
}
func (e LiteralElement) Render() template.HTML {
return template.HTML(html.EscapeString(e.Content))
}
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 NewLiteralElement(s string) LiteralElement {
return LiteralElement{s}
}
type VoidElement struct {
Tag string
attributes map[string]string
}
func (e VoidElement) Render() template.HTML {
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 NewVoidElement(tag string) VoidElement {
return VoidElement{tag, make(map[string]string)}
}
func NewImg(src, alt string) Element {
return NewVoidElement("img").SetAttribute("src", src).SetAttribute("alt", alt)
}
type ContentElement struct {
VoidElement
Content Element
}
func (e ContentElement) Render() template.HTML {
base := render(e.Tag, e.attributes, false)
base += e.Content.Render()
return base + template.HTML(fmt.Sprintf(`</%s>`, e.VoidElement.Tag))
}
func NewContentElement(tag string, content Element) ContentElement {
return ContentElement{NewVoidElement(tag), content}
}
func NewParagraph(content string) Element {
return NewContentElement("p", NewLiteralElement(content))
}
|