github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/net/http/htmlfrag/html.go (about) 1 // Package htmlfrag contains convenience functions to generate html fragments. 2 package htmlfrag 3 4 import ( 5 "bytes" 6 "fmt" 7 "io" 8 "net/http" 9 "strings" 10 "time" 11 12 "github.com/pbberlin/tools/stringspb" 13 ) 14 15 var sp func(format string, a ...interface{}) string = fmt.Sprintf 16 17 // GetSpanner is a simple helper to output 18 // aligned html elements 19 // for backend or debug pages 20 // where the template package is not imperative 21 func GetSpanner() func(interface{}, int) string { 22 23 cntr := 0 24 style := ` 25 <style> 26 .ib { 27 vertical-align:middle; 28 display:inline-block; 29 width:95px; 30 } 31 </style> 32 ` 33 return func(i interface{}, w int) string { 34 35 s1 := fmt.Sprint(i) 36 sw := fmt.Sprint(w) 37 s2 := fmt.Sprintf("<span class='ib' style='width:" + sw + "px;'>" + s1 + "</span>") 38 39 if cntr < 1 { 40 s2 = style + "\n\n" + s2 41 } 42 cntr++ 43 44 return s2 45 } 46 47 } 48 49 // Wb is a helper to write an inline block with an link inside. 50 // If url is omitted, a newline + a chapter-header is rendered. 51 func Wb(buf1 io.Writer, linktext, url string, descs ...string) { 52 53 wstr := func(w io.Writer, s string) { 54 w.Write([]byte(s)) 55 } 56 57 if url == "" { 58 wstr(buf1, "<br>\n") 59 } 60 61 if url == "nobr" { // hack, indicating no break 62 url = "" 63 } 64 65 desc := "" 66 if len(descs) > 0 { 67 desc = descs[0] 68 } 69 70 const styleX = "display:inline-block; width:13%; margin: 4px 0px; margin-right:12px; vertical-align:top" 71 72 wstr(buf1, "<span style='"+styleX+"'>\n") 73 if url == "" { 74 wstr(buf1, "\t<b>"+linktext+"</b>\n") 75 } else { 76 wstr(buf1, "\t<a target='_app' href='"+url+"' >"+linktext+"</a>\n") 77 if desc != "" { 78 wstr(buf1, "<br>\n ") 79 wstr(buf1, "<span style='"+styleX+";width:90%;font-size:80%'>\n") 80 wstr(buf1, desc) 81 wstr(buf1, "</span>\n") 82 } 83 } 84 wstr(buf1, "</span>\n") 85 } 86 87 // CSSColumnsWidth creates CSS classes with w[1...nCols] 88 // for any number of screen widths 89 // Thus you can write <div class='w2'> ... 90 // and you get an element 2/nCols wide 91 // and adapting to changes in the browser window 92 // CSS class wmax equals the largest wx class. 93 // CSS class wn holds the simple column minus a system wide margin, currently 10 pix 94 func CSSColumnsWidth(nCols int) string { 95 96 // this is not really for the vertical scrollbar 97 // but some slack is required, I don't know why 98 // to prevent too early wrapping of blocks 99 const wScrollbar = 16 100 101 // this should not be required either 102 // since we use 'box-sizing: border-box;' 103 // to internalize all paddings and margins and borders :( 104 const wMarginsPaddings = 10 105 106 ret := new(bytes.Buffer) 107 108 // the stepping is the max wasted space 109 for w := 600; w <= 1600; w = w + 50 { 110 111 ret.WriteString(sp("\n\t@media (min-width: %vpx) {\n\t\t", w)) 112 //ret.WriteString(sp("\n\t@media (min-device-width: %vpx) {\n\t\t", w)) 113 114 colWidthGross := (w - wScrollbar) / nCols 115 colWidthNet := colWidthGross - wMarginsPaddings 116 117 s := sp(".wn { width: %vpx; } ", colWidthNet) 118 ret.WriteString(s) 119 120 for c := 1; c <= nCols; c++ { 121 s := sp(".w%v{ width: %vpx; } ", c, c*colWidthGross) 122 ret.WriteString(s) 123 } 124 s2 := sp(".wmax{ width: %vpx; } ", nCols*colWidthGross) 125 ret.WriteString(s2) 126 127 ret.WriteString("\n\t}") 128 129 } 130 131 return fmt.Sprintf(" /* generated by htmlfrag.CSSColumnsWidth()*/ \n%v\n", ret) 132 } 133 134 // CSSColumnsHeight is similar to ...Width except: 135 // 'min-height' attributes are generated 136 func CSSRowsHeight(nRows int) string { 137 138 // This is so revolting - 139 // but since the logic is still in development, it prevents duplicate code 140 s := CSSColumnsWidth(nRows) 141 142 var widthToHeight = strings.NewReplacer("wn", "hn", 143 "wmax", "hmax", 144 "w1", "h1", 145 "w2", "h2", 146 "w3", "h3", 147 "w4", "h4", 148 "w5", "h5", 149 "w6", "h6", 150 "w7", "h7", 151 "w8", "h8", 152 "min-width", "min-height", 153 "width", "min-height") 154 s = widthToHeight.Replace(s) 155 156 return s 157 } 158 159 func SetNocacheHeaders(w http.ResponseWriter) { 160 161 w.Header().Set("Expires", "Mon, 26 Jul 1990 05:00:00 GMT") 162 163 tn := time.Now() 164 tn = tn.Add(-10 * time.Second) 165 tns := tn.Format(http.TimeFormat) 166 w.Header().Set("Last-Modified", tns) 167 w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate") 168 w.Header().Set("Cache-Control", "post-check=0, pre-check=0") 169 w.Header().Set("Pragma", "no-cache") 170 171 // if plainOrHtml { 172 // w.Header().Set("Content-Type", "text/plain; charset=utf-8") 173 // } else { 174 // w.Header().Set("Content-Type", "text/html; charset=utf-8") 175 // } 176 177 } 178 func CacheHeaders(w http.ResponseWriter) { 179 180 w.Header().Set("Cache-control", "max-age=2592000") //30days (60sec * 60min * 24hours * 30days) 181 w.Header().Set("Cache-control", "public") 182 183 tn := time.Now() 184 tn = tn.Add(-1 * 24 * 365 * time.Hour) 185 tns := tn.Format(http.TimeFormat) 186 w.Header().Set("Last-Modified", tns) 187 // w.Header().Set("Date", tns) 188 189 } 190 191 func CookieDump(r *http.Request) string { 192 str := "" 193 c := r.Cookies() 194 for _, v := range c { 195 s := fmt.Sprintf("%v", v) 196 s = stringspb.Ellipsoider(s, 50) 197 str += fmt.Sprintf("%v<br>\n", s) 198 } 199 return str 200 }