-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgax_attr.go
216 lines (185 loc) · 5.09 KB
/
gax_attr.go
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package gax
import "fmt"
/*
Short for "attributes". Same as the `Attrs{}` constructor, but uses parentheses,
which is sometimes more convenient. Symmetric with `Attrs.A`.
*/
func A(vals ...Attr) Attrs { return Attrs(vals) }
/*
Short for "attributes from pairs". Recommended way to write attributes, due to
its brevity. Symmetric with `Attrs.AP`.
*/
func AP(pairs ...string) Attrs {
if pairs == nil {
return nil
}
return make(Attrs, 0, len(pairs)/2).AP(pairs...)
}
/*
Short for "attributes". List of arbitrary HTML/XML attributes. Used by `Elem`.
Usually passed to `E` or `Bui.E`.
*/
type Attrs []Attr
/*
Shortcut for appending more attributes. Useful when combining attributes from
hardcoded pairs (via `AP`) with attributes created as `Attr`. For example, you
can write a function that generates a specific attribute, and use this to
append the result.
*/
func (self Attrs) A(vals ...Attr) Attrs { return append(self, vals...) }
/*
Shortcut for appending more attributes from pairs, as if by calling `AP`.
Panics if the argument count is not even.
*/
func (self Attrs) AP(pairs ...string) Attrs {
if len(pairs)%2 != 0 {
panic(fmt.Errorf(`[gax] Attrs.AP expects an even amount of args, got %#v`, pairs))
}
ind := 0
for ind < len(pairs) {
key := pairs[ind]
ind++
val := pairs[ind]
ind++
self = append(self, Attr{key, val})
}
return self
}
/*
Returns a modified version where each attribute with the matching key is
modified via `Attr.Set` to have the given value. If no matching attribute is
found, appends the given key-value as a new attribute. As a special case, if
the key is empty, returns self as-is.
*/
func (self Attrs) Set(key, val string) Attrs {
return self.mut(key, val, Attr.Set)
}
/*
Returns a modified version where each attribute with the matching key is
modified via `Attr.Add` to append the given value to the previous value,
space-separated. If no matching attribute is found, appends the given key-value
as a new attribute. As a special case, if the key is empty, returns self
as-is.
*/
func (self Attrs) Add(key, val string) Attrs {
return self.mut(key, val, Attr.Add)
}
func (self Attrs) mut(key, val string, fun func(Attr, string) Attr) Attrs {
if key == `` || fun == nil {
return self
}
var found bool
for ind := range self {
if self[ind].Name() == key {
self[ind] = fun(self[ind], val)
found = true
}
}
if found {
return self
}
return append(self, Attr{key, val})
}
// Mostly for internal use.
func (self Attrs) AppendTo(buf []byte) []byte {
for _, val := range self {
buf = val.AppendTo(buf)
}
return buf
}
// Implement `fmt.Stringer` for debug purposes. Not used by builder methods.
func (self Attrs) String() string {
return NonEscWri(self.AppendTo(nil)).String()
}
/*
Implement `fmt.GoStringer` for debug purposes. Not used by builder methods.
Represents itself as a call to `AP`, which is the recommended way to write
this.
*/
func (self Attrs) GoString() string {
if self == nil {
return `nil`
}
var buf NonEscWri
_, _ = buf.WriteString(`AP(`)
found := false
for _, val := range self {
if val == (Attr{}) {
continue
}
if !found {
found = true
} else {
_, _ = buf.WriteString(`, `)
}
buf = NonEscWri(appendQuote(buf, val.Name()))
_, _ = buf.WriteString(`, `)
buf = NonEscWri(appendQuote(buf, val.Value()))
}
_, _ = buf.WriteString(`)`)
return buf.String()
}
/*
Represents an arbitrary HTML/XML attribute. Usually part of `Attrs{}`. An
empty/zero attr (equal to `Attr{}`) is ignored during encoding.
*/
type Attr [2]string
/*
Attribute name. If the attr is not equal to `Attr{}`, the name is validated
during encoding. Using an invalid name causes a panic.
*/
func (self Attr) Name() string { return self[0] }
/*
Attribute value. Automatically escaped and quoted when encoding the attr. For
known HTML boolean attrs, listed in `Bool`, the value may be tweaked for better
spec compliance, or the attr may be omitted entirely.
*/
func (self Attr) Value() string { return self[1] }
// Returns a modified version with `.Name` replaced with the given input.
func (self Attr) SetName(val string) Attr {
self[0] = val
return self
}
// Returns a modified version with `.Value` replaced with the given input.
func (self Attr) Set(val string) Attr {
self[1] = val
return self
}
/*
Returns a modified version where the given input is appended to `.Value`,
space-separated if both values are non-empty.
*/
func (self Attr) Add(val string) Attr {
if val == `` {
return self
}
if self.Value() == `` {
return self.Set(val)
}
return self.Set(self.Value() + ` ` + val)
}
// Mostly for internal use.
func (self Attr) AppendTo(buf []byte) []byte {
if self == (Attr{}) {
return buf
}
key, val := self.Name(), self.Value()
validAttr(key)
if Bool.Has(key) {
// Dumb hack. Should revise.
if val == "false" {
return buf
}
val = ""
}
buf = append(buf, ` `...)
buf = append(buf, key...)
buf = append(buf, `="`...)
_, _ = (*AttrWri)(&buf).WriteString(val)
buf = append(buf, `"`...)
return buf
}
// Implement `fmt.Stringer` for debug purposes. Not used by builder methods.
func (self Attr) String() string {
return NonEscWri(self.AppendTo(nil)).String()
}