forked from ungerik/go-start
/
shortcuts.go
265 lines (220 loc) · 6.9 KB
/
shortcuts.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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
package view
import (
"fmt"
"html"
"reflect"
)
///////////////////////////////////////////////////////////////////////////////
// Shortcuts
// ViewOrError returns a DynamicView that renders view if err is nil or
// else renders the error.
func ViewOrError(view View, err error) DynamicView {
return DynamicView(
func(ctx *Context) (View, error) {
if err != nil {
return nil, err
}
return view, nil
},
)
}
// Escape HTML escapes a string.
func Escape(text string) HTML {
return HTML(html.EscapeString(text))
}
// Printf creates an unescaped HTML string.
func Printf(text string, args ...interface{}) HTML {
return HTML(fmt.Sprintf(text, args...))
}
// PrintfEscape creates an escaped HTML string.
func PrintfEscape(text string, args ...interface{}) HTML {
return Escape(fmt.Sprintf(text, args...))
}
// A creates a HTML link.
func A(url interface{}, content ...interface{}) *Link {
return &Link{Model: NewLinkModel(url, content...)}
}
// A creates a HTML link.
func A_nofollow(url interface{}, content ...interface{}) *Link {
return &Link{Model: NewLinkModelRel(url, "nofollow", content...)}
}
// A_blank creates a HTML link with target="_blank"
func A_blank(url interface{}, content ...interface{}) *Link {
return &Link{NewWindow: true, Model: NewLinkModel(url, content...)}
}
// A_blank creates a HTML link with target="_blank" and rel="nofollow"
func A_blank_nofollow(url interface{}, content ...interface{}) *Link {
return &Link{NewWindow: true, Model: NewLinkModelRel(url, "nofollow", content...)}
}
func STYLE(css string) HTML {
return Printf("<style>%s</style>", css)
}
func StylesheetLink(url string) HTML {
return Printf("<link rel='stylesheet' href='%s'>", url)
}
func SCRIPT(script string) HTML {
return Printf("<script>%s</script>", script)
}
func ScriptLink(url string) HTML {
return Printf("<script src='%s'></script>", url)
}
func RSSLink(title string, url URL) View {
return RenderView(
func(ctx *Context) error {
href := url.URL(ctx)
ctx.Response.Printf("<link rel='alternate' type='application/rss+xml' title='%s' href='%s'>", title, href)
return nil
},
)
}
// Img creates a HTML img element for an URL with optional width and height.
// The first int of dimensions is width, the second one height.
func IMG(url string, dimensions ...int) *Image {
var width int
var height int
dimCount := len(dimensions)
if dimCount >= 1 {
width = dimensions[0]
if dimCount >= 2 {
height = dimensions[1]
}
}
return &Image{Src: url, Width: width, Height: height}
}
func SECTION(class string, content ...interface{}) View {
return &ShortTag{Tag: "section", Class: class, Content: WrapContents(content...)}
}
// Creates a Div object with a HTML class attribute and optional content.
func DIV(class string, content ...interface{}) *Div {
return &Div{Class: class, Content: WrapContents(content...)}
}
func SPAN(class string, content ...interface{}) *Span {
return &Span{Class: class, Content: WrapContents(content...)}
}
func DivClearBoth() HTML {
return HTML("<div style='clear:both'></div>")
}
func CANVAS(class string, width, height int) *Canvas {
return &Canvas{Class: class, Width: width, Height: height}
}
func BR() HTML {
return HTML("<br/>")
}
func HR() HTML {
return HTML("<hr/>")
}
func P(content ...interface{}) View {
return &ShortTag{Tag: "p", Content: WrapContents(content...)}
}
func H1(content ...interface{}) View {
return &ShortTag{Tag: "h1", Content: WrapContents(content...)}
}
func H2(content ...interface{}) View {
return &ShortTag{Tag: "h2", Content: WrapContents(content...)}
}
func H3(content ...interface{}) View {
return &ShortTag{Tag: "h3", Content: WrapContents(content...)}
}
func H4(content ...interface{}) View {
return &ShortTag{Tag: "h4", Content: WrapContents(content...)}
}
func H5(content ...interface{}) View {
return &ShortTag{Tag: "h5", Content: WrapContents(content...)}
}
func H6(content ...interface{}) View {
return &ShortTag{Tag: "h6", Content: WrapContents(content...)}
}
func B(content ...interface{}) View {
return &ShortTag{Tag: "b", Content: WrapContents(content...)}
}
func I(content ...interface{}) View {
return &ShortTag{Tag: "i", Content: WrapContents(content...)}
}
func Q(content ...interface{}) View {
return &ShortTag{Tag: "q", Content: WrapContents(content...)}
}
func DEL(content ...interface{}) View {
return &ShortTag{Tag: "del", Content: WrapContents(content...)}
}
func EM(content ...interface{}) View {
return &ShortTag{Tag: "em", Content: WrapContents(content...)}
}
func STRONG(content ...interface{}) View {
return &ShortTag{Tag: "strong", Content: WrapContents(content...)}
}
func DFN(content ...interface{}) View {
return &ShortTag{Tag: "dfn", Content: WrapContents(content...)}
}
func CODE(content ...interface{}) View {
return &ShortTag{Tag: "code", Content: WrapContents(content...)}
}
func PRE(content ...interface{}) View {
return &ShortTag{Tag: "pre", Content: WrapContents(content...)}
}
func ABBR(longTitle, abbreviation string) View {
return &ShortTag{Tag: "abbr", Attribs: map[string]string{"title": longTitle}, Content: Escape(abbreviation)}
}
// Ul is a shortcut to create an unordered list by wrapping items as HTML views.
// NewView will be called for every passed item.
func UL(items ...interface{}) *List {
model := make(ViewsListModel, len(items))
for i, item := range items {
model[i] = NewView(item)
}
return &List{Model: model}
}
// Ul is a shortcut to create an ordered list by wrapping items as HTML views.
// NewView will be called for every passed item.
func OL(items ...interface{}) *List {
list := UL(items...)
list.Ordered = true
return list
}
// Encapsulates content as View.
// Strings or fmt.Stringer implementations will be HTML escaped.
// View implementations will be passed through.
func NewView(content interface{}) View {
if content == nil {
return nil
}
if view, ok := content.(View); ok {
return view
}
if stringer, ok := content.(fmt.Stringer); ok {
return Escape(stringer.String())
}
v := reflect.ValueOf(content)
if v.Kind() != reflect.String {
panic(fmt.Errorf("Invalid content type: %T (must be gostart/view.View, fmt.Stringer or a string)", content))
}
return Escape(v.String())
}
// Encapsulates multiple content arguments as views by calling NewView() for every one of them.
func NewViews(contents ...interface{}) Views {
count := len(contents)
if count == 0 {
return nil
}
views := make(Views, count)
for i, content := range contents {
views[i] = NewView(content)
}
return views
}
// Encapsulates multiple content arguments as View by calling NewView() for every one of them.
// It is more efficient for one view because the view is passed through instead of wrapped
// with a Views slice like NewViews does.
func WrapContents(contents ...interface{}) View {
count := len(contents)
switch count {
case 0:
return nil
case 1:
return NewView(contents[0])
}
views := make(Views, count)
for i, content := range contents {
views[i] = NewView(content)
}
return views
}