diff --git a/authentication.go b/authentication.go index 55bb35a..98c77b9 100644 --- a/authentication.go +++ b/authentication.go @@ -62,12 +62,12 @@ func (a *goBlog) authMiddleware(next http.Handler) http.Handler { _ = r.ParseForm() b = []byte(r.PostForm.Encode()) } - a.render(w, r, templateLogin, &renderData{ - Data: map[string]interface{}{ - "loginmethod": r.Method, - "loginheaders": base64.StdEncoding.EncodeToString(h), - "loginbody": base64.StdEncoding.EncodeToString(b), - "totp": a.cfg.User.TOTP != "", + a.renderNew(w, r, a.renderLogin, &renderData{ + Data: &loginRenderData{ + loginMethod: r.Method, + loginHeaders: base64.StdEncoding.EncodeToString(h), + loginBody: base64.StdEncoding.EncodeToString(b), + totp: a.cfg.User.TOTP != "", }, }) }) diff --git a/blogroll.go b/blogroll.go index a3da962..f569e91 100644 --- a/blogroll.go +++ b/blogroll.go @@ -29,13 +29,13 @@ func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) { } c := bc.Blogroll can := bc.getRelativePath(defaultIfEmpty(c.Path, defaultBlogrollPath)) - a.render(w, r, templateBlogroll, &renderData{ + a.renderNew(w, r, a.renderBlogroll, &renderData{ Canonical: a.getFullAddress(can), - Data: map[string]interface{}{ - "Title": c.Title, - "Description": c.Description, - "Outlines": outlines, - "Download": can + ".opml", + Data: &blogrollRenderData{ + title: c.Title, + description: c.Description, + outlines: outlines.([]*opml.Outline), + download: can + ".opml", }, }) } diff --git a/blogstats.go b/blogstats.go index b634135..ea6ee56 100644 --- a/blogstats.go +++ b/blogstats.go @@ -25,10 +25,10 @@ func (a *goBlog) initBlogStats() { func (a *goBlog) serveBlogStats(w http.ResponseWriter, r *http.Request) { _, bc := a.getBlog(r) canonical := bc.getRelativePath(defaultIfEmpty(bc.BlogStats.Path, defaultBlogStatsPath)) - a.render(w, r, templateBlogStats, &renderData{ + a.renderNew(w, r, a.renderBlogStats, &renderData{ Canonical: a.getFullAddress(canonical), - Data: map[string]interface{}{ - "TableUrl": canonical + blogStatsTablePath, + Data: &blogStatsRenderData{ + tableUrl: canonical + blogStatsTablePath, }, }) } @@ -43,7 +43,7 @@ func (a *goBlog) serveBlogStatsTable(w http.ResponseWriter, r *http.Request) { return } // Render - a.render(w, r, templateBlogStatsTable, &renderData{ + a.renderNew(w, r, a.renderBlogStatsTable, &renderData{ Data: data, }) } diff --git a/captcha.go b/captcha.go index 396fba8..ae1b66d 100644 --- a/captcha.go +++ b/captcha.go @@ -65,12 +65,12 @@ func (a *goBlog) captchaMiddleware(next http.Handler) http.Handler { // Render captcha _ = ses.Save(r, w) w.Header().Set("Cache-Control", "no-store,max-age=0") - a.renderWithStatusCode(w, r, http.StatusUnauthorized, templateCaptcha, &renderData{ - Data: map[string]string{ - "captchamethod": r.Method, - "captchaheaders": base64.StdEncoding.EncodeToString(h), - "captchabody": base64.StdEncoding.EncodeToString(b), - "captchaid": captchaId, + a.renderNewWithStatusCode(w, r, http.StatusUnauthorized, a.renderCaptcha, &renderData{ + Data: &captchaRenderData{ + captchaMethod: r.Method, + captchaHeaders: base64.StdEncoding.EncodeToString(h), + captchaBody: base64.StdEncoding.EncodeToString(b), + captchaId: captchaId, }, }) }) diff --git a/comments.go b/comments.go index 58367ce..2b3eb71 100644 --- a/comments.go +++ b/comments.go @@ -41,7 +41,7 @@ func (a *goBlog) serveComment(w http.ResponseWriter, r *http.Request) { return } _, bc := a.getBlog(r) - a.render(w, r, templateComment, &renderData{ + a.renderNew(w, r, a.renderComment, &renderData{ Canonical: a.getFullAddress(bc.getRelativePath(path.Join(commentPath, strconv.Itoa(id)))), Data: comment, }) diff --git a/contact.go b/contact.go index ef96e20..ae50365 100644 --- a/contact.go +++ b/contact.go @@ -17,11 +17,11 @@ const defaultContactPath = "/contact" func (a *goBlog) serveContactForm(w http.ResponseWriter, r *http.Request) { _, bc := a.getBlog(r) cc := bc.Contact - a.render(w, r, templateContact, &renderData{ - Data: map[string]interface{}{ - "title": cc.Title, - "description": cc.Description, - "privacy": cc.PrivacyPolicy, + a.renderNew(w, r, a.renderContact, &renderData{ + Data: &contactRenderData{ + title: cc.Title, + description: cc.Description, + privacy: cc.PrivacyPolicy, }, }) } @@ -63,9 +63,9 @@ func (a *goBlog) sendContactSubmission(w http.ResponseWriter, r *http.Request) { // Send notification a.sendNotification(message.String()) // Give feedback - a.render(w, r, templateContact, &renderData{ - Data: map[string]interface{}{ - "sent": true, + a.renderNew(w, r, a.renderContact, &renderData{ + Data: &contactRenderData{ + sent: true, }, }) } diff --git a/editor.go b/editor.go index dc080d5..84d0b88 100644 --- a/editor.go +++ b/editor.go @@ -73,7 +73,7 @@ func (a *goBlog) createMarkdownPreview(blog string, markdown []byte) (rendered [ // Render post var hb htmlBuilder a.renderEditorPreview(&hb, a.cfg.Blogs[blog], p) - rendered = []byte(hb.String()) + rendered = hb.Bytes() return } diff --git a/errors.go b/errors.go index 6eb2d9f..240af4c 100644 --- a/errors.go +++ b/errors.go @@ -8,11 +8,6 @@ import ( "go.goblog.app/app/pkgs/contenttype" ) -type errorData struct { - Title string - Message string -} - func (a *goBlog) serve404(w http.ResponseWriter, r *http.Request) { a.serveError(w, r, fmt.Sprintf("%s was not found", r.RequestURI), http.StatusNotFound) } @@ -40,8 +35,8 @@ func (a *goBlog) serveError(w http.ResponseWriter, r *http.Request, message stri http.Error(w, message, status) return } - a.renderWithStatusCode(w, r, status, templateError, &renderData{ - Data: &errorData{ + a.renderNewWithStatusCode(w, r, status, a.renderError, &renderData{ + Data: &errorRenderData{ Title: fmt.Sprintf("%d %s", status, http.StatusText(status)), Message: message, }, diff --git a/geoMap.go b/geoMap.go index 2eb4a86..9f15db4 100644 --- a/geoMap.go +++ b/geoMap.go @@ -25,10 +25,10 @@ func (a *goBlog) serveGeoMap(w http.ResponseWriter, r *http.Request) { } if len(allPostsWithLocation) == 0 { - a.render(w, r, templateGeoMap, &renderData{ + a.renderNew(w, r, a.renderGeoMap, &renderData{ Canonical: canonical, - Data: map[string]interface{}{ - "nolocations": true, + Data: &geoMapRenderData{ + noLocations: true, }, }) return @@ -85,14 +85,14 @@ func (a *goBlog) serveGeoMap(w http.ResponseWriter, r *http.Request) { tracksJson = string(tracksJsonBytes) } - a.render(w, r, templateGeoMap, &renderData{ + a.renderNew(w, r, a.renderGeoMap, &renderData{ Canonical: canonical, - Data: map[string]interface{}{ - "locations": locationsJson, - "tracks": tracksJson, - "attribution": a.getMapAttribution(), - "minzoom": a.getMinZoom(), - "maxzoom": a.getMaxZoom(), + Data: &geoMapRenderData{ + locations: locationsJson, + tracks: tracksJson, + attribution: a.getMapAttribution(), + minZoom: a.getMinZoom(), + maxZoom: a.getMaxZoom(), }, }) } diff --git a/go.mod b/go.mod index d545fba..b125107 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/spf13/cast v1.4.1 github.com/spf13/viper v1.10.1 github.com/stretchr/testify v1.7.0 - github.com/tdewolff/minify/v2 v2.9.28 + github.com/tdewolff/minify/v2 v2.9.29 github.com/thoas/go-funk v0.9.1 github.com/tkrajina/gpxgo v1.2.0 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 diff --git a/go.sum b/go.sum index 67ed761..36892ef 100644 --- a/go.sum +++ b/go.sum @@ -415,8 +415,8 @@ github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 h1:zrsUcqrG2uQ github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0= github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= -github.com/tdewolff/minify/v2 v2.9.28 h1:70GT62rRyLcH4jbkTFGcy6rktHKGiaSNZb/h8pnuQYw= -github.com/tdewolff/minify/v2 v2.9.28/go.mod h1:6XAjcHM46pFcRE0eztigFPm0Q+Cxsw8YhEWT+rDkcZM= +github.com/tdewolff/minify/v2 v2.9.29 h1:QMVJaCJzWL0mXS33cX792YD074xz4lOhkyBS8hAzYAY= +github.com/tdewolff/minify/v2 v2.9.29/go.mod h1:6XAjcHM46pFcRE0eztigFPm0Q+Cxsw8YhEWT+rDkcZM= github.com/tdewolff/parse/v2 v2.5.27 h1:PL3LzzXaOpmdrknnOlIeO2muIBHAwiKp6TxN1RbU5gI= github.com/tdewolff/parse/v2 v2.5.27/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= diff --git a/original-assets/styles/styles.scss b/original-assets/styles/styles.scss index a5ced6e..3312476 100644 --- a/original-assets/styles/styles.scss +++ b/original-assets/styles/styles.scss @@ -254,7 +254,7 @@ details summary { height: 400px; } -#post-actions { +#post-actions, #posteditactions { @extend .p; display: flex; flex-wrap: wrap; diff --git a/pkgs/minify/minify.go b/pkgs/minify/minify.go index 41a6ac8..54830eb 100644 --- a/pkgs/minify/minify.go +++ b/pkgs/minify/minify.go @@ -39,7 +39,7 @@ func (m *Minifier) Get() *minify.M { func (m *Minifier) Write(w io.Writer, mediatype string, b []byte) (int, error) { mw := m.Get().Writer(mediatype, w) - defer func() { _ = mw.Close() }() + defer mw.Close() return mw.Write(b) } diff --git a/posts.go b/posts.go index acadbf2..20c4854 100644 --- a/posts.go +++ b/posts.go @@ -73,16 +73,16 @@ func (a *goBlog) servePost(w http.ResponseWriter, r *http.Request) { if canonical == "" { canonical = a.fullPostURL(p) } - template := templatePost + renderMethod := a.renderPost if p.Path == a.getRelativePath(p.Blog, "") { - template = templateStaticHome + renderMethod = a.renderStaticHome } w.Header().Add("Link", fmt.Sprintf("<%s>; rel=shortlink", a.shortPostURL(p))) status := http.StatusOK if strings.HasSuffix(string(p.Status), statusDeletedSuffix) { status = http.StatusGone } - a.renderWithStatusCode(w, r, status, template, &renderData{ + a.renderNewWithStatusCode(w, r, status, renderMethod, &renderData{ BlogString: p.Blog, Canonical: canonical, Data: p, @@ -201,23 +201,22 @@ func (a *goBlog) serveDate(w http.ResponseWriter, r *http.Request) { } var title, dPath strings.Builder if year != 0 { - ys := fmt.Sprintf("%0004d", year) - title.WriteString(ys) - dPath.WriteString(ys) + _, _ = fmt.Fprintf(&title, "%0004d", year) + _, _ = fmt.Fprintf(&dPath, "%0004d", year) } else { - title.WriteString("XXXX") - dPath.WriteString("x") + _, _ = title.WriteString("XXXX") + _, _ = dPath.WriteString("x") } if month != 0 { - title.WriteString(fmt.Sprintf("-%02d", month)) - dPath.WriteString(fmt.Sprintf("/%02d", month)) + _, _ = fmt.Fprintf(&title, "-%02d", month) + _, _ = fmt.Fprintf(&dPath, "/%02d", month) } else if day != 0 { - title.WriteString("-XX") - dPath.WriteString("/x") + _, _ = title.WriteString("-XX") + _, _ = dPath.WriteString("/x") } if day != 0 { - title.WriteString(fmt.Sprintf("-%02d", day)) - dPath.WriteString(fmt.Sprintf("/%02d", day)) + _, _ = fmt.Fprintf(&title, "-%02d", day) + _, _ = fmt.Fprintf(&dPath, "/%02d", day) } _, bc := a.getBlog(r) a.serveIndex(w, r.WithContext(context.WithValue(r.Context(), indexConfigKey, &indexConfig{ @@ -339,18 +338,18 @@ func (a *goBlog) serveIndex(w http.ResponseWriter, r *http.Request) { if summaryTemplate == "" { summaryTemplate = defaultSummary } - a.render(w, r, templateIndex, &renderData{ + a.renderNew(w, r, a.renderIndex, &renderData{ Canonical: a.getFullAddress(path), - Data: map[string]interface{}{ - "Title": title, - "Description": description, - "Posts": posts, - "HasPrev": hasPrev, - "HasNext": hasNext, - "First": path, - "Prev": prevPath, - "Next": nextPath, - "SummaryTemplate": summaryTemplate, + Data: &indexRenderData{ + title: title, + description: description, + posts: posts, + hasPrev: hasPrev, + hasNext: hasNext, + first: path, + prev: prevPath, + next: nextPath, + summaryTemplate: summaryTemplate, }, }) } diff --git a/render.go b/render.go index c7d377d..4182b41 100644 --- a/render.go +++ b/render.go @@ -17,25 +17,11 @@ const ( templatesExt = ".gohtml" templateBase = "base" - templatePost = "post" - templateError = "error" - templateIndex = "index" - templateTaxonomy = "taxonomy" - templateSearch = "search" templateEditor = "editor" templateEditorFiles = "editorfiles" - templateLogin = "login" - templateStaticHome = "statichome" - templateBlogStats = "blogstats" - templateBlogStatsTable = "blogstatstable" - templateComment = "comment" - templateCaptcha = "captcha" templateCommentsAdmin = "commentsadmin" templateNotificationsAdmin = "notificationsadmin" templateWebmentionAdmin = "webmentionadmin" - templateBlogroll = "blogroll" - templateGeoMap = "geomap" - templateContact = "contact" templateIndieAuth = "indieauth" ) @@ -45,49 +31,10 @@ func (a *goBlog) initRendering() error { "md": a.safeRenderMarkdownAsHTML, "mdtitle": a.renderMdTitle, "html": wrapStringAsHTML, - // Post specific - "content": a.postHtml, - "shorturl": a.shortPostURL, - "gettrack": a.getTrack, // Code based rendering - "posttax": func(p *post, b *configBlog) template.HTML { + "tor": func(rd *renderData) template.HTML { var hb htmlBuilder - a.renderPostTax(&hb, p, b) - return hb.html() - }, - "postmeta": func(p *post, b *configBlog, typ string) template.HTML { - var hb htmlBuilder - a.renderPostMeta(&hb, p, b, typ) - return hb.html() - }, - "oldcontentwarning": func(p *post, b *configBlog) template.HTML { - var hb htmlBuilder - a.renderOldContentWarning(&hb, p, b) - return hb.html() - }, - "interactions": func(b *configBlog, c string) template.HTML { - var hb htmlBuilder - a.renderInteractions(&hb, b, c) - return hb.html() - }, - "author": func() template.HTML { - var hb htmlBuilder - a.renderAuthor(&hb) - return hb.html() - }, - "postheadmeta": func(p *post, c string) template.HTML { - var hb htmlBuilder - a.renderPostHeadMeta(&hb, p, c) - return hb.html() - }, - "tor": func(b *configBlog, torUsed bool, torAddress string) template.HTML { - var hb htmlBuilder - a.renderTorNotice(&hb, b, torUsed, torAddress) - return hb.html() - }, - "summary": func(bc *configBlog, p *post, typ summaryTyp) template.HTML { - var hb htmlBuilder - a.renderSummary(&hb, bc, p, typ) + a.renderTorNotice(&hb, rd) return hb.html() }, // Others @@ -97,13 +44,11 @@ func (a *goBlog) initRendering() error { "now": localNowString, "asset": a.assetFileName, "string": a.ts.GetTemplateStringVariantFunc(), - "urlize": urlize, "absolute": a.getFullAddress, "opensearch": openSearchUrl, "mbytes": mBytesString, "editortemplate": a.editorPostTemplate, "editorpostdesc": a.editorPostDesc, - "ttsenabled": a.ttsEnabled, } baseTemplate, err := template.New("base").Funcs(templateFunctions).ParseFiles(path.Join(templatesDir, templateBase+templatesExt)) if err != nil { @@ -170,6 +115,24 @@ func (a *goBlog) renderWithStatusCode(w http.ResponseWriter, r *http.Request, st } } +func (a *goBlog) renderNew(w http.ResponseWriter, r *http.Request, f func(*htmlBuilder, *renderData), data *renderData) { + a.renderNewWithStatusCode(w, r, http.StatusOK, f, data) +} + +func (a *goBlog) renderNewWithStatusCode(w http.ResponseWriter, r *http.Request, statusCode int, f func(*htmlBuilder, *renderData), data *renderData) { + // Check render data + a.checkRenderData(r, data) + // Set content type + w.Header().Set(contentType, contenttype.HTMLUTF8) + // Write status code + w.WriteHeader(statusCode) + // Render + minWriter := a.min.Get().Writer(contenttype.HTML, w) + defer minWriter.Close() + hb := newHtmlBuilder(minWriter) + f(hb, data) +} + func (a *goBlog) checkRenderData(r *http.Request, data *renderData) { if data.app == nil { data.app = a diff --git a/search.go b/search.go index a577a3c..7fa80e0 100644 --- a/search.go +++ b/search.go @@ -26,7 +26,7 @@ func (a *goBlog) serveSearch(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, path.Join(servePath, searchEncode(q)), http.StatusFound) return } - a.render(w, r, templateSearch, &renderData{ + a.renderNew(w, r, a.renderSearch, &renderData{ Canonical: a.getFullAddress(servePath), }) } diff --git a/taxonomies.go b/taxonomies.go index 5002b7a..bdd828e 100644 --- a/taxonomies.go +++ b/taxonomies.go @@ -20,11 +20,11 @@ func (a *goBlog) serveTaxonomy(w http.ResponseWriter, r *http.Request) { a.serveError(w, r, err.Error(), http.StatusInternalServerError) return } - a.render(w, r, templateTaxonomy, &renderData{ + a.renderNew(w, r, a.renderTaxonomy, &renderData{ Canonical: a.getFullAddress(r.URL.Path), - Data: map[string]interface{}{ - "Taxonomy": tax, - "ValueGroups": groupStrings(allValues), + Data: &taxonomyRenderData{ + taxonomy: tax, + valueGroups: groupStrings(allValues), }, }) } diff --git a/templates/assets/css/styles.css b/templates/assets/css/styles.css index cb4c01e..515a575 100644 --- a/templates/assets/css/styles.css +++ b/templates/assets/css/styles.css @@ -144,7 +144,7 @@ details summary > *:first-child { border-bottom: 1px solid var(--primary, #000); } -.p, #post-actions, table { +.p, #post-actions, #posteditactions, table { display: block; margin-top: 1em; margin-bottom: 1em; @@ -214,12 +214,12 @@ details summary > *:first-child { height: 400px; } -#post-actions { +#post-actions, #posteditactions { display: flex; flex-wrap: wrap; gap: 5px; } -#post-actions * { +#post-actions *, #posteditactions * { text-align: center; } diff --git a/templates/base.gohtml b/templates/base.gohtml index acfd63a..f483103 100644 --- a/templates/base.gohtml +++ b/templates/base.gohtml @@ -39,7 +39,7 @@ {{ end }}
© {{ dateformat now "2006" }} {{ with .User.Name }}{{ . }}{{ else }}{{ mdtitle .Blog.Title }}{{ end }}
- {{ tor .Blog .TorUsed .TorAddress }} + {{ tor . }} {{ if .EasterEgg }}{{ end }}