-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhtml.go
More file actions
180 lines (158 loc) · 3.03 KB
/
html.go
File metadata and controls
180 lines (158 loc) · 3.03 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//go:generate go run gen/main.go --input=tags --output=tags.go
package wasm
import (
"strconv"
"strings"
_ "syscall/js"
)
type attr string
type flag int
const (
f_drop flag = 1 << iota
f_no_open
f_no_close
f_no_arg
f_tags
)
type frag struct {
strings.Builder
}
type HTML struct {
frag
}
func NewHTML() *HTML {
return new(HTML)
}
// Short hand write
func (h *HTML) Wr(s ...any) {
h.frag.wrAll(s, false)
}
// Text composes the list of elements to a single string
// No tags are allowed, and a string is returned.
func (h *HTML) Text(s ...any) string {
attrs, other, flags := unpack(s)
if (flags & f_drop) != 0 {
return ""
}
if (flags&f_tags) != 0 || len(attrs) > 0 {
panic("Tags in text")
}
f := new(frag)
f.wrAll(other, false)
return f.String()
}
/*
* Modifiers, which set flags to control
* the behaviour.
*/
// If will drop this element if the condition is false
func (h *HTML) If(c bool) flag {
if !c {
return f_drop
} else {
return 0
}
}
// For non-empty tags, do not generate the closing tag
func (h *HTML) Open() flag {
return f_no_close
}
// For non-empty tags, generate the closing tag.
func (h *HTML) Close() flag {
return f_no_open
}
func tag(nm string, elems []any) *frag {
return wrTag(nm, elems, false)
}
func emptyTag(nm string, elems []any) *frag {
return wrTag(nm, elems, true)
}
func wrTag(nm string, elems []any, empty bool) *frag {
f := new(frag)
attrs, other, flags := unpack(elems)
if (flags & f_drop) != 0 {
return f
}
if (flags & f_no_open) == 0 {
f.WriteRune('<')
f.WriteString(nm)
f.wrAll(attrs, true)
f.WriteRune('>')
}
f.wrAll(other, false)
if !empty && (flags&f_no_close) == 0 {
f.WriteString("</")
f.WriteString(nm)
f.WriteRune('>')
}
return f
}
func attrNoArg(nm string, elems []any) attr {
if len(elems) == 0 {
elems = []any{flag(f_no_arg)}
}
return attribute(nm, elems)
}
func attribute(nm string, elems []any) attr {
attrs, other, flags := unpack(elems)
if (flags&f_tags) != 0 || len(attrs) > 0 {
panic("Illegal attribute")
}
if (flags & f_drop) != 0 {
return ""
}
f := new(frag)
// Leave a space before each attribute.
f.WriteString(nm)
if (flags & f_no_arg) == 0 {
f.WriteString("=\"")
f.wrAll(other, false)
f.WriteString("\"")
}
return attr(f.String())
}
func unpack(s []any) ([]any, []any, flag) {
var other []any
var attrs []any
var flags flag
for _, ele := range s {
switch v := ele.(type) {
case *frag:
flags |= f_tags
other = append(other, ele)
case attr:
attrs = append(attrs, ele)
case flag:
flags |= v
default:
other = append(other, ele)
}
}
return attrs, other, flags
}
func (f *frag) wrAll(s []any, space bool) {
for _, ele := range s {
if space {
f.WriteRune(' ')
}
f.wr(ele)
}
}
func (f *frag) wr(s any) {
switch v := s.(type) {
case string:
f.WriteString(v)
case attr:
f.WriteString(string(v))
case []byte:
f.Write(v)
case rune:
f.WriteRune(v)
case int:
f.WriteString(strconv.FormatInt(int64(v), 10))
case *frag:
f.WriteString(v.String())
default:
panic("wr: Unknown type")
}
}