Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: milo/appengine/settings/funcs.go

Issue 2748073006: Milo Refactor: Remove theme support (Closed)
Patch Set: Fix builder.html pointer Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package settings
6
7 import (
8 "bytes"
9 "fmt"
10 "html/template"
11 "strings"
12 "time"
13
14 "github.com/luci/luci-go/milo/api/resp"
15 )
16
17 // A collection of useful templating functions
18
19 // funcMap is what gets fed into the template bundle.
20 var funcMap = template.FuncMap{
21 "humanDuration": humanDuration,
22 "parseRFC3339": parseRFC3339,
23 "linkify": linkify,
24 "linkifySet": linkifySet,
25 "obfuscateEmail": obfuscateEmail,
26 "localTime": localTime,
27 "shortHash": shortHash,
28 "startswith": strings.HasPrefix,
29 "sub": sub,
30 "consoleHeader": consoleHeader,
31 }
32
33 // localTime returns a <span> element with t in human format
34 // that will be converted to local timezone in the browser.
35 // Recommended usage: {{ .Date | localTime "N/A" }}
36 func localTime(ifZero string, t time.Time) template.HTML {
37 if t.IsZero() {
38 return template.HTML(template.HTMLEscapeString(ifZero))
39 }
40 milliseconds := t.UnixNano() / 1e6
41 return template.HTML(fmt.Sprintf(
42 `<span class="local-time" data-timestamp="%d">%s</span>`,
43 milliseconds,
44 t.Format(time.RFC850)))
45 }
46
47 func consoleHeader(brs []resp.BuilderRef) template.HTML {
48 // First, split things into nice rows and find the max depth.
49 cat := make([][]string, len(brs))
50 depth := 0
51 for i, b := range brs {
52 cat[i] = b.Category
53 if len(cat[i]) > depth {
54 depth = len(cat[i])
55 }
56 }
57
58 result := ""
59 for row := 0; row < depth; row++ {
60 result += "<tr><th></th>"
61 // "" is the first node, " " is an empty node.
62 current := ""
63 colspan := 0
64 for _, br := range cat {
65 colspan++
66 var s string
67 if row >= len(br) {
68 s = " "
69 } else {
70 s = br[row]
71 }
72 if s != current || current == " " {
73 if current != "" || current == " " {
74 result += fmt.Sprintf(`<th colspan="%d"> %s</th>`, colspan, current)
75 colspan = 0
76 }
77 current = s
78 }
79 }
80 if colspan != 0 {
81 result += fmt.Sprintf(`<th colspan="%d">%s</th>`, colspa n, current)
82 }
83 result += "</tr>"
84 }
85
86 // Last row: The actual builder shortnames.
87 result += "<tr><th></th>"
88 for _, br := range brs {
89 result += fmt.Sprintf("<th>%s</th>", br.ShortName)
90 }
91 result += "</tr>"
92 return template.HTML(result)
93 }
94
95 // humanDuration translates d into a human readable string of x units y units,
96 // where x and y could be in days, hours, minutes, or seconds, whichever is the
97 // largest.
98 func humanDuration(d time.Duration) string {
99 t := int64(d.Seconds())
100 day := t / 86400
101 hr := (t % 86400) / 3600
102
103 if day > 0 {
104 if hr != 0 {
105 return fmt.Sprintf("%d days %d hrs", day, hr)
106 }
107 return fmt.Sprintf("%d days", day)
108 }
109
110 min := (t % 3600) / 60
111 if hr > 0 {
112 if min != 0 {
113 return fmt.Sprintf("%d hrs %d mins", hr, min)
114 }
115 return fmt.Sprintf("%d hrs", hr)
116 }
117
118 sec := t % 60
119 if min > 0 {
120 if sec != 0 {
121 return fmt.Sprintf("%d mins %d secs", min, sec)
122 }
123 return fmt.Sprintf("%d mins", min)
124 }
125
126 if sec != 0 {
127 return fmt.Sprintf("%d secs", sec)
128 }
129
130 if d > time.Millisecond {
131 return fmt.Sprintf("%d ms", d/time.Millisecond)
132 }
133
134 return "0"
135 }
136
137 // obfuscateEmail converts an email@address.com into email<junk>@address.com
138 // if it is an email.
139 func obfuscateEmail(email string) template.HTML {
140 email = template.HTMLEscapeString(email)
141 return template.HTML(strings.Replace(
142 email, "@", "<span style=\"display:none\">ohnoyoudont</span>@", -1))
143 }
144
145 // parseRFC3339 parses time represented as a RFC3339 or RFC3339Nano string.
146 // If cannot parse, returns zero time.
147 func parseRFC3339(s string) time.Time {
148 t, err := time.Parse(time.RFC3339, s)
149 if err == nil {
150 return t
151 }
152 t, err = time.Parse(time.RFC3339Nano, s)
153 if err == nil {
154 return t
155 }
156 return time.Time{}
157 }
158
159 // linkifyTemplate is the template used in "linkify". Because the template,
160 // itself recursively invokes "linkify", we will initialize it in explicitly
161 // in "init()".
162 //
163 // linkifySetTemplate is the template used in "linkifySet".
164 var linkifyTemplate, linkifySetTemplate *template.Template
165
166 // linkify turns a resp.LinkSet struct into a canonical link.
167 func linkify(link *resp.Link) template.HTML {
168 if link == nil {
169 return ""
170 }
171 buf := bytes.Buffer{}
172 if err := linkifyTemplate.Execute(&buf, link); err != nil {
173 panic(err)
174 }
175 return template.HTML(buf.Bytes())
176 }
177
178 // linkifySet turns a resp.Link struct into a canonical link.
179 func linkifySet(linkSet resp.LinkSet) template.HTML {
180 if len(linkSet) == 0 {
181 return ""
182 }
183 buf := bytes.Buffer{}
184 if err := linkifySetTemplate.Execute(&buf, linkSet); err != nil {
185 panic(err)
186 }
187 return template.HTML(buf.Bytes())
188 }
189
190 // sub subtracts one number from another, because apparently go templates aren't
191 // smart enough to do that.
192 func sub(a, b int) int {
193 return a - b
194 }
195
196 // shortHash abbriviates a git hash into 6 characters.
197 func shortHash(s string) string {
198 if len(s) > 6 {
199 return s[0:6]
200 }
201 return s
202 }
203
204 func init() {
205 linkifySetTemplate = template.Must(
206 template.New("linkifySet").
207 Funcs(template.FuncMap{
208 "linkify": linkify,
209 }).Parse(
210 `{{ range $i, $link := . }}` +
211 `{{ if gt $i 0 }} {{ end }}` +
212 `{{ $link | linkify}}` +
213 `{{ end }}`))
214
215 linkifyTemplate = template.Must(
216 template.New("linkify").
217 Parse(
218 `<a href="{{.URL}}">` +
219 `{{if .Img}}<img src="{{.Img}}"{{if .Alt }} alt="{{.Alt}}"{{end}}>` +
220 `{{else if .Alias}}[{{.Label}}]` +
221 `{{else}}{{.Label}}{{end}}` +
222 `</a>`))
223 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698