From 1c7195a135e8fb81cd920b8ea66d98677dbad116 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Sun, 30 Jan 2022 16:40:53 +0100 Subject: [PATCH] Breaking! Render everything using go functions, remove custom pages support and now unused template rendering --- app.go | 3 - authentication.go | 2 +- blogroll.go | 2 +- blogstats.go | 4 +- captcha.go | 2 +- comments.go | 2 +- commentsAdmin.go | 14 +- config.go | 9 - contact.go | 4 +- customPages.go | 13 -- editor.go | 18 +- editorFiles.go | 4 +- errors.go | 2 +- example-config.yml | 9 - geoMap.go | 4 +- go.mod | 8 +- go.sum | 16 +- httpRouters.go | 26 --- indieAuthServer.go | 2 +- main.go | 4 - notifications.go | 2 +- original-assets/styles/styles.scss | 10 +- posts.go | 4 +- render.go | 90 +------- search.go | 2 +- sitemap.go | 6 - taxonomies.go | 2 +- templates/assets/css/styles.css | 14 +- templates/base.gohtml | 46 ---- templates/commentsadmin.gohtml | 36 ---- templates/editor.gohtml | 66 ------ templates/webmentionadmin.gohtml | 43 ---- ui.go | 335 ++++++++++++++++++++++++++++- uiComponents.go | 25 +-- ui_test.go | 5 +- utils.go | 5 - webmentionAdmin.go | 16 +- 37 files changed, 410 insertions(+), 445 deletions(-) delete mode 100644 customPages.go delete mode 100644 templates/base.gohtml delete mode 100644 templates/commentsadmin.gohtml delete mode 100644 templates/editor.gohtml delete mode 100644 templates/webmentionadmin.gohtml diff --git a/app.go b/app.go index 006fe4c..7269b8a 100644 --- a/app.go +++ b/app.go @@ -2,7 +2,6 @@ package main import ( "crypto/rsa" - "html/template" "net/http" "sync" @@ -70,8 +69,6 @@ type goBlog struct { min minify.Minifier // Regex Redirects regexRedirects []*regexRedirect - // Rendering - templates map[string]*template.Template // Sessions loginSessions, captchaSessions *dbSessionStore // Shutdown diff --git a/authentication.go b/authentication.go index 98c77b9..f86c6ca 100644 --- a/authentication.go +++ b/authentication.go @@ -62,7 +62,7 @@ func (a *goBlog) authMiddleware(next http.Handler) http.Handler { _ = r.ParseForm() b = []byte(r.PostForm.Encode()) } - a.renderNew(w, r, a.renderLogin, &renderData{ + a.render(w, r, a.renderLogin, &renderData{ Data: &loginRenderData{ loginMethod: r.Method, loginHeaders: base64.StdEncoding.EncodeToString(h), diff --git a/blogroll.go b/blogroll.go index f569e91..d42734b 100644 --- a/blogroll.go +++ b/blogroll.go @@ -29,7 +29,7 @@ func (a *goBlog) serveBlogroll(w http.ResponseWriter, r *http.Request) { } c := bc.Blogroll can := bc.getRelativePath(defaultIfEmpty(c.Path, defaultBlogrollPath)) - a.renderNew(w, r, a.renderBlogroll, &renderData{ + a.render(w, r, a.renderBlogroll, &renderData{ Canonical: a.getFullAddress(can), Data: &blogrollRenderData{ title: c.Title, diff --git a/blogstats.go b/blogstats.go index ea6ee56..e243be1 100644 --- a/blogstats.go +++ b/blogstats.go @@ -25,7 +25,7 @@ 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.renderNew(w, r, a.renderBlogStats, &renderData{ + a.render(w, r, a.renderBlogStats, &renderData{ Canonical: a.getFullAddress(canonical), Data: &blogStatsRenderData{ tableUrl: canonical + blogStatsTablePath, @@ -43,7 +43,7 @@ func (a *goBlog) serveBlogStatsTable(w http.ResponseWriter, r *http.Request) { return } // Render - a.renderNew(w, r, a.renderBlogStatsTable, &renderData{ + a.render(w, r, a.renderBlogStatsTable, &renderData{ Data: data, }) } diff --git a/captcha.go b/captcha.go index ae1b66d..30fcf67 100644 --- a/captcha.go +++ b/captcha.go @@ -65,7 +65,7 @@ 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.renderNewWithStatusCode(w, r, http.StatusUnauthorized, a.renderCaptcha, &renderData{ + a.renderWithStatusCode(w, r, http.StatusUnauthorized, a.renderCaptcha, &renderData{ Data: &captchaRenderData{ captchaMethod: r.Method, captchaHeaders: base64.StdEncoding.EncodeToString(h), diff --git a/comments.go b/comments.go index 2b3eb71..73e74b2 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.renderNew(w, r, a.renderComment, &renderData{ + a.render(w, r, a.renderComment, &renderData{ Canonical: a.getFullAddress(bc.getRelativePath(path.Join(commentPath, strconv.Itoa(id)))), Data: comment, }) diff --git a/commentsAdmin.go b/commentsAdmin.go index bb6a612..d72aa42 100644 --- a/commentsAdmin.go +++ b/commentsAdmin.go @@ -70,13 +70,13 @@ func (a *goBlog) commentsAdmin(w http.ResponseWriter, r *http.Request) { } nextPath = fmt.Sprintf("%s/page/%d", commentsPath, nextPage) // Render - a.render(w, r, templateCommentsAdmin, &renderData{ - Data: map[string]interface{}{ - "Comments": comments, - "HasPrev": hasPrev, - "HasNext": hasNext, - "Prev": prevPath, - "Next": nextPath, + a.render(w, r, a.renderCommentsAdmin, &renderData{ + Data: &commentsRenderData{ + comments: comments, + hasPrev: hasPrev, + hasNext: hasNext, + prev: prevPath, + next: nextPath, }, }) } diff --git a/config.go b/config.go index 5cc8cd1..f99bd0a 100644 --- a/config.go +++ b/config.go @@ -81,7 +81,6 @@ type configBlog struct { Search *configSearch `mapstructure:"search"` BlogStats *configBlogStats `mapstructure:"blogStats"` Blogroll *configBlogroll `mapstructure:"blogroll"` - CustomPages []*configCustomPage `mapstructure:"custompages"` Telegram *configTelegram `mapstructure:"telegram"` PostAsHome bool `mapstructure:"postAsHome"` RandomPost *configRandomPost `mapstructure:"randomPost"` @@ -148,14 +147,6 @@ type configBlogroll struct { Description string `mapstructure:"description"` } -type configCustomPage struct { - Path string `mapstructure:"path"` - Template string `mapstructure:"template"` - Cache bool `mapstructure:"cache"` - CacheExpiration int `mapstructure:"cacheExpiration"` - Data *interface{} `mapstructure:"data"` -} - type configRandomPost struct { Enabled bool `mapstructure:"enabled"` Path string `mapstructure:"path"` diff --git a/contact.go b/contact.go index ae50365..63637c4 100644 --- a/contact.go +++ b/contact.go @@ -17,7 +17,7 @@ const defaultContactPath = "/contact" func (a *goBlog) serveContactForm(w http.ResponseWriter, r *http.Request) { _, bc := a.getBlog(r) cc := bc.Contact - a.renderNew(w, r, a.renderContact, &renderData{ + a.render(w, r, a.renderContact, &renderData{ Data: &contactRenderData{ title: cc.Title, description: cc.Description, @@ -63,7 +63,7 @@ func (a *goBlog) sendContactSubmission(w http.ResponseWriter, r *http.Request) { // Send notification a.sendNotification(message.String()) // Give feedback - a.renderNew(w, r, a.renderContact, &renderData{ + a.render(w, r, a.renderContact, &renderData{ Data: &contactRenderData{ sent: true, }, diff --git a/customPages.go b/customPages.go deleted file mode 100644 index 84401e8..0000000 --- a/customPages.go +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import "net/http" - -const customPageContextKey = "custompage" - -func (a *goBlog) serveCustomPage(w http.ResponseWriter, r *http.Request) { - page := r.Context().Value(customPageContextKey).(*configCustomPage) - a.render(w, r, page.Template, &renderData{ - Canonical: a.getFullAddress(page.Path), - Data: page.Data, - }) -} diff --git a/editor.go b/editor.go index 7ad01af..6af594a 100644 --- a/editor.go +++ b/editor.go @@ -21,8 +21,8 @@ import ( const editorPath = "/editor" func (a *goBlog) serveEditor(w http.ResponseWriter, r *http.Request) { - a.render(w, r, templateEditor, &renderData{ - Data: map[string]interface{}{}, + a.render(w, r, a.renderEditor, &renderData{ + Data: &editorRenderData{}, }) } @@ -89,10 +89,10 @@ func (a *goBlog) serveEditorPost(w http.ResponseWriter, r *http.Request) { a.serveError(w, r, err.Error(), http.StatusBadRequest) return } - a.render(w, r, templateEditor, &renderData{ - Data: map[string]interface{}{ - "UpdatePostURL": a.fullPostURL(post), - "UpdatePostContent": a.postToMfItem(post).Properties.Content[0], + a.render(w, r, a.renderEditor, &renderData{ + Data: &editorRenderData{ + updatePostUrl: a.fullPostURL(post), + updatePostContent: a.postToMfItem(post).Properties.Content[0], }, }) case "updatepost": @@ -188,14 +188,13 @@ func (a *goBlog) editorMicropubPost(w http.ResponseWriter, r *http.Request, medi _ = result.Body.Close() } -func (a *goBlog) editorPostTemplate(blog string) string { +func (a *goBlog) editorPostTemplate(blog string, bc *configBlog) string { var builder strings.Builder marsh := func(param string, i interface{}) { _ = yaml.NewEncoder(&builder).Encode(map[string]interface{}{ param: i, }) } - bc := a.cfg.Blogs[blog] builder.WriteString("---\n") marsh("blog", blog) marsh("section", bc.DefaultSection) @@ -210,8 +209,7 @@ func (a *goBlog) editorPostTemplate(blog string) string { return builder.String() } -func (a *goBlog) editorPostDesc(blog string) string { - bc := a.cfg.Blogs[blog] +func (a *goBlog) editorPostDesc(bc *configBlog) string { t := a.ts.GetTemplateStringVariant(bc.Lang, "editorpostdesc") var paramBuilder, statusBuilder strings.Builder for i, param := range []string{ diff --git a/editorFiles.go b/editorFiles.go index 2f0fcf4..47aedfb 100644 --- a/editorFiles.go +++ b/editorFiles.go @@ -16,7 +16,7 @@ func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) { } // Check if files at all if len(files) == 0 { - a.renderNew(w, r, a.renderEditorFiles, &renderData{ + a.render(w, r, a.renderEditorFiles, &renderData{ Data: &editorFilesRenderData{}, }) return @@ -39,7 +39,7 @@ func (a *goBlog) serveEditorFiles(w http.ResponseWriter, r *http.Request) { return } // Serve HTML - a.renderNew(w, r, a.renderEditorFiles, &renderData{ + a.render(w, r, a.renderEditorFiles, &renderData{ Data: &editorFilesRenderData{ files: files, uses: uses, diff --git a/errors.go b/errors.go index 240af4c..6fc0166 100644 --- a/errors.go +++ b/errors.go @@ -35,7 +35,7 @@ func (a *goBlog) serveError(w http.ResponseWriter, r *http.Request, message stri http.Error(w, message, status) return } - a.renderNewWithStatusCode(w, r, status, a.renderError, &renderData{ + a.renderWithStatusCode(w, r, status, a.renderError, &renderData{ Data: &errorRenderData{ Title: fmt.Sprintf("%d %s", status, http.StatusText(status)), Message: message, diff --git a/example-config.yml b/example-config.yml index b4bda79..c18893d 100644 --- a/example-config.yml +++ b/example-config.yml @@ -222,15 +222,6 @@ blogs: authValue: abc # Authentication value for OPML categories: # Optional, allow only these categories - Blogs - # Custom pages - custompages: - - path: /blogroll # Path - template: blogroll # Template - cache: true # Enable caching - cacheExpiration: 600 # Cache expiration (default uses blog cache TTL) - data: # Data to provide to template - Title: Blogroll - Description: "This are alphabetically sorted lists of blogs and sites I subscribe to." # Redirect to random post randomPost: enabled: true # Enable diff --git a/geoMap.go b/geoMap.go index 9f15db4..0a2e6dc 100644 --- a/geoMap.go +++ b/geoMap.go @@ -25,7 +25,7 @@ func (a *goBlog) serveGeoMap(w http.ResponseWriter, r *http.Request) { } if len(allPostsWithLocation) == 0 { - a.renderNew(w, r, a.renderGeoMap, &renderData{ + a.render(w, r, a.renderGeoMap, &renderData{ Canonical: canonical, Data: &geoMapRenderData{ noLocations: true, @@ -85,7 +85,7 @@ func (a *goBlog) serveGeoMap(w http.ResponseWriter, r *http.Request) { tracksJson = string(tracksJsonBytes) } - a.renderNew(w, r, a.renderGeoMap, &renderData{ + a.render(w, r, a.renderGeoMap, &renderData{ Canonical: canonical, Data: &geoMapRenderData{ locations: locationsJson, diff --git a/go.mod b/go.mod index 86d0eea..8d95d19 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/kaorimatz/go-opml v0.0.0-20210201121027-bc8e2852d7f9 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible github.com/lopezator/migrator v0.3.0 - github.com/mattn/go-sqlite3 v1.14.10 + github.com/mattn/go-sqlite3 v1.14.11 github.com/microcosm-cc/bluemonday v1.0.17 github.com/mmcdole/gofeed v1.1.3 github.com/paulmach/go.geojson v1.4.0 @@ -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.29 + github.com/tdewolff/minify/v2 v2.10.0 github.com/thoas/go-funk v0.9.1 github.com/tkrajina/gpxgo v1.2.0 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 @@ -55,8 +55,8 @@ require ( // master github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38 github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01 - golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8 - golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba + golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/text v0.3.7 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index 099479c..8bac388 100644 --- a/go.sum +++ b/go.sum @@ -314,8 +314,8 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk= -github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsFrzQ= +github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60 h1:tHdB+hQRHU10CfcK0furo6rSNgZ38JT8uPh70c/pFD8= @@ -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.29 h1:QMVJaCJzWL0mXS33cX792YD074xz4lOhkyBS8hAzYAY= -github.com/tdewolff/minify/v2 v2.9.29/go.mod h1:6XAjcHM46pFcRE0eztigFPm0Q+Cxsw8YhEWT+rDkcZM= +github.com/tdewolff/minify/v2 v2.10.0 h1:ovVAHUcjfGrBDf1EIvsodRUVJiZK/28mMose08B7k14= +github.com/tdewolff/minify/v2 v2.10.0/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= @@ -472,8 +472,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8 h1:kACShD3qhmr/3rLmg1yXyt+N4HcwutKyPRB93s54TIU= -golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed h1:YoWVYYAfvQ4ddHv3OKmIvX7NCAhFGTj62VP2l2kfBbA= +golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -553,8 +553,8 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba h1:6u6sik+bn/y7vILcYkK3iwTBWN7WtBvB0+SZswQnbf8= -golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/httpRouters.go b/httpRouters.go index 6775101..2b5428d 100644 --- a/httpRouters.go +++ b/httpRouters.go @@ -128,9 +128,6 @@ func (a *goBlog) blogRouter(blog string, conf *configBlog) func(r chi.Router) { // Search r.Group(a.blogSearchRouter(conf)) - // Custom pages - r.Group(a.blogCustomPagesRouter(conf)) - // Random post r.Group(a.blogRandomRouter(conf)) @@ -295,29 +292,6 @@ func (a *goBlog) blogSearchRouter(conf *configBlog) func(r chi.Router) { } } -// Blog - Custom pages -func (a *goBlog) blogCustomPagesRouter(conf *configBlog) func(r chi.Router) { - return func(r chi.Router) { - r.Use(a.privateModeHandler) - for _, cp := range conf.CustomPages { - r.Group(func(r chi.Router) { - r.Use(middleware.WithValue(customPageContextKey, cp)) - if cp.Cache { - ce := cp.CacheExpiration - if ce == 0 { - ce = a.defaultCacheExpiration() - } - r.Use( - a.cacheMiddleware, - middleware.WithValue(cacheExpirationKey, ce), - ) - } - r.Get(cp.Path, a.serveCustomPage) - }) - } - } -} - // Blog - Random func (a *goBlog) blogRandomRouter(conf *configBlog) func(r chi.Router) { return func(r chi.Router) { diff --git a/indieAuthServer.go b/indieAuthServer.go index f1859f1..73c4593 100644 --- a/indieAuthServer.go +++ b/indieAuthServer.go @@ -31,7 +31,7 @@ func (a *goBlog) indieAuthRequest(w http.ResponseWriter, r *http.Request) { return } // Render page that let's the user authorize the app - a.renderNew(w, r, a.renderIndieAuth, &renderData{ + a.render(w, r, a.renderIndieAuth, &renderData{ Data: iareq, }) } diff --git a/main.go b/main.go index 9e20df7..6dde00e 100644 --- a/main.go +++ b/main.go @@ -154,10 +154,6 @@ func (app *goBlog) initComponents(logging bool) { app.logErrAndQuit("Failed to init template translations:", err.Error()) return } - if err = app.initRendering(); err != nil { // Needs assets and minify - app.logErrAndQuit("Failed to init HTML rendering:", err.Error()) - return - } if err = app.initCache(); err != nil { app.logErrAndQuit("Failed to init HTTP cache:", err.Error()) return diff --git a/notifications.go b/notifications.go index a82f382..a60f3f3 100644 --- a/notifications.go +++ b/notifications.go @@ -154,7 +154,7 @@ func (a *goBlog) notificationsAdmin(w http.ResponseWriter, r *http.Request) { } nextPath = fmt.Sprintf("%s/page/%d", notificationsPath, nextPage) // Render - a.renderNew(w, r, a.renderNotificationsAdmin, &renderData{ + a.render(w, r, a.renderNotificationsAdmin, &renderData{ Data: ¬ificationsRenderData{ notifications: notifications, hasPrev: hasPrev, diff --git a/original-assets/styles/styles.scss b/original-assets/styles/styles.scss index 3312476..6faf317 100644 --- a/original-assets/styles/styles.scss +++ b/original-assets/styles/styles.scss @@ -250,11 +250,7 @@ details summary { margin-bottom: 5px; } -#map { - height: 400px; -} - -#post-actions, #posteditactions { +.actions { @extend .p; display: flex; flex-wrap: wrap; @@ -265,6 +261,10 @@ details summary { } } +#map { + height: 400px; +} + #announcement { @extend .invert; padding: 5px; diff --git a/posts.go b/posts.go index 77e4e6d..ccf92bd 100644 --- a/posts.go +++ b/posts.go @@ -83,7 +83,7 @@ func (a *goBlog) servePost(w http.ResponseWriter, r *http.Request) { if strings.HasSuffix(string(p.Status), statusDeletedSuffix) { status = http.StatusGone } - a.renderNewWithStatusCode(w, r, status, renderMethod, &renderData{ + a.renderWithStatusCode(w, r, status, renderMethod, &renderData{ BlogString: p.Blog, Canonical: canonical, Data: p, @@ -356,7 +356,7 @@ func (a *goBlog) serveIndex(w http.ResponseWriter, r *http.Request) { if summaryTemplate == "" { summaryTemplate = defaultSummary } - a.renderNew(w, r, a.renderIndex, &renderData{ + a.render(w, r, a.renderIndex, &renderData{ Canonical: a.getFullAddress(path), Data: &indexRenderData{ title: title, diff --git a/render.go b/render.go index 8a88967..c88a670 100644 --- a/render.go +++ b/render.go @@ -1,76 +1,12 @@ package main import ( - "html/template" "net/http" - "os" - "path" - "path/filepath" - "strings" "go.goblog.app/app/pkgs/bufferpool" "go.goblog.app/app/pkgs/contenttype" ) -const ( - templatesDir = "templates" - templatesExt = ".gohtml" - - templateBase = "base" - templateEditor = "editor" - templateCommentsAdmin = "commentsadmin" - templateWebmentionAdmin = "webmentionadmin" -) - -func (a *goBlog) initRendering() error { - a.templates = map[string]*template.Template{} - templateFunctions := template.FuncMap{ - "md": a.safeRenderMarkdownAsHTML, - "mdtitle": a.renderMdTitle, - "html": wrapStringAsHTML, - // Code based rendering - "tor": func(rd *renderData) template.HTML { - buf := bufferpool.Get() - hb := newHtmlBuilder(buf) - a.renderTorNotice(hb, rd) - res := template.HTML(buf.String()) - bufferpool.Put(buf) - return res - }, - // Others - "dateformat": dateFormat, - "unixtodate": unixToLocalDateString, - "now": localNowString, - "asset": a.assetFileName, - "string": a.ts.GetTemplateStringVariantFunc(), - "absolute": a.getFullAddress, - "opensearch": openSearchUrl, - "editortemplate": a.editorPostTemplate, - "editorpostdesc": a.editorPostDesc, - } - baseTemplate, err := template.New("base").Funcs(templateFunctions).ParseFiles(path.Join(templatesDir, templateBase+templatesExt)) - if err != nil { - return err - } - err = filepath.Walk(templatesDir, func(p string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.Mode().IsRegular() && path.Ext(p) == templatesExt { - if name := strings.TrimSuffix(path.Base(p), templatesExt); name != templateBase { - if a.templates[name], err = template.Must(baseTemplate.Clone()).New(name).ParseFiles(p); err != nil { - return err - } - } - } - return nil - }) - if err != nil { - return err - } - return nil -} - type renderData struct { BlogString string Canonical string @@ -91,31 +27,11 @@ func (d *renderData) LoggedIn() bool { return d.app.isLoggedIn(d.req) } -func (a *goBlog) render(w http.ResponseWriter, r *http.Request, template string, data *renderData) { - a.renderWithStatusCode(w, r, http.StatusOK, template, data) +func (a *goBlog) render(w http.ResponseWriter, r *http.Request, f func(*htmlBuilder, *renderData), data *renderData) { + a.renderWithStatusCode(w, r, http.StatusOK, f, data) } -func (a *goBlog) renderWithStatusCode(w http.ResponseWriter, r *http.Request, statusCode int, template string, data *renderData) { - // Check render data - a.checkRenderData(r, data) - // Set content type - w.Header().Set(contentType, contenttype.HTMLUTF8) - // Render template and write minified HTML - buf := bufferpool.Get() - defer bufferpool.Put(buf) - if err := a.templates[template].ExecuteTemplate(buf, template, data); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - w.WriteHeader(statusCode) - _ = a.min.Minify(contenttype.HTML, w, buf) -} - -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) { +func (a *goBlog) renderWithStatusCode(w http.ResponseWriter, r *http.Request, statusCode int, f func(*htmlBuilder, *renderData), data *renderData) { // Check render data a.checkRenderData(r, data) // Set content type diff --git a/search.go b/search.go index 7fa80e0..c38828f 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.renderNew(w, r, a.renderSearch, &renderData{ + a.render(w, r, a.renderSearch, &renderData{ Canonical: a.getFullAddress(servePath), }) } diff --git a/sitemap.go b/sitemap.go index feb41b0..36f10fe 100644 --- a/sitemap.go +++ b/sitemap.go @@ -102,12 +102,6 @@ func (a *goBlog) serveSitemapBlogFeatures(w http.ResponseWriter, r *http.Request Loc: a.getFullAddress(bc.getRelativePath(defaultIfEmpty(cc.Path, defaultContactPath))), }) } - // Custom pages - for _, cp := range bc.CustomPages { - sm.Add(&sitemap.URL{ - Loc: a.getFullAddress(cp.Path), - }) - } // Write sitemap a.writeSitemapXML(w, sm) } diff --git a/taxonomies.go b/taxonomies.go index bdd828e..5204b86 100644 --- a/taxonomies.go +++ b/taxonomies.go @@ -20,7 +20,7 @@ func (a *goBlog) serveTaxonomy(w http.ResponseWriter, r *http.Request) { a.serveError(w, r, err.Error(), http.StatusInternalServerError) return } - a.renderNew(w, r, a.renderTaxonomy, &renderData{ + a.render(w, r, a.renderTaxonomy, &renderData{ Canonical: a.getFullAddress(r.URL.Path), Data: &taxonomyRenderData{ taxonomy: tax, diff --git a/templates/assets/css/styles.css b/templates/assets/css/styles.css index 515a575..b014cf3 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, #posteditactions, table { +.p, .actions, table { display: block; margin-top: 1em; margin-bottom: 1em; @@ -210,19 +210,19 @@ details summary > *:first-child { margin-bottom: 5px; } -#map { - height: 400px; -} - -#post-actions, #posteditactions { +.actions { display: flex; flex-wrap: wrap; gap: 5px; } -#post-actions *, #posteditactions * { +.actions * { text-align: center; } +#map { + height: 400px; +} + #announcement { padding: 5px; text-align: center; diff --git a/templates/base.gohtml b/templates/base.gohtml deleted file mode 100644 index f483103..0000000 --- a/templates/base.gohtml +++ /dev/null @@ -1,46 +0,0 @@ -{{ define "base" }} - - - - - - {{ with .Canonical }}{{ end }} - {{ block "title" . }}{{ mdtitle .Blog.Title }}{{ end }} - - - - - - - - {{ with .User }}{{ range .Identities }}{{ end }}{{ end }} - {{ $os := opensearch .Blog }} - {{ if $os }}{{ end }} - {{ with .Blog.Announcement }}{{ with .Text }}
{{ md . }}
{{ end }}{{ end }} -
-

{{ mdtitle .Blog.Title }}

- {{ with .Blog.Description }}

{{ . }}

{{ end }} - {{ with index .Blog.Menus "main" }} - - {{ end }} - {{ if .LoggedIn }} - - {{ end }} -
- {{ block "main" . }}{{ end }} - - {{ if .EasterEgg }}{{ end }} - -{{ end }} \ No newline at end of file diff --git a/templates/commentsadmin.gohtml b/templates/commentsadmin.gohtml deleted file mode 100644 index 7455c54..0000000 --- a/templates/commentsadmin.gohtml +++ /dev/null @@ -1,36 +0,0 @@ -{{ define "title" }} - {{ string .Blog.Lang "comments" }} - {{ mdtitle .Blog.Title }} -{{ end }} - -{{ define "main" }} -
-

{{ string .Blog.Lang "comments" }}

- {{ $blog := .Blog }} - {{ range $i, $comment := .Data.Comments }} -
-

- ID: {{ $comment.ID }}
- Target: {{ $comment.Target }}
- Name: {{ if $comment.Website }}{{ $comment.Name }}{{ else }}{{ $comment.Name }}{{ end }} -

-

- {{ html $comment.Comment }} -

-
- - -
-
- {{ end }} - {{ if .Data.HasPrev }} -

{{ string .Blog.Lang "prev" }}

- {{ end }} - {{ if .Data.HasNext }} -

{{ string .Blog.Lang "next" }}

- {{ end }} -
-{{ end }} - -{{ define "commentsadmin" }} - {{ template "base" . }} -{{ end }} \ No newline at end of file diff --git a/templates/editor.gohtml b/templates/editor.gohtml deleted file mode 100644 index 3e9b4e6..0000000 --- a/templates/editor.gohtml +++ /dev/null @@ -1,66 +0,0 @@ -{{ define "title" }} - - {{ string .Blog.Lang "editor" }} - {{ mdtitle .Blog.Title }} -{{ end }} - -{{ define "main" }} -
-

{{ string .Blog.Lang "editor" }}

-

{{ string .Blog.Lang "create" }}

- {{ md (editorpostdesc .BlogString) }} -
- - -
- -
- - {{ if .Data.UpdatePostURL }} -

{{ string .Blog.Lang "update" }}

-
- - - -
- -
- {{ end }} - -

{{ string .Blog.Lang "posts" }}

-

{{ string .Blog.Lang "drafts" }}

-

{{ string .Blog.Lang "privateposts" }}

-

{{ string .Blog.Lang "unlistedposts" }}

-

{{ string .Blog.Lang "scheduledposts" }}

-

{{ string .Blog.Lang "deletedposts" }}

- -

{{ string .Blog.Lang "upload" }}

-
- - - -
-

{{ string .Blog.Lang "mediafiles" }}

- -

{{ string .Blog.Lang "location" }}

-
- - -
- -

{{ string .Blog.Lang "gpxhelper" }}

-

{{ string .Blog.Lang "gpxhelperdesc" }}

-
- - - -
- - - - -
-{{ end }} - -{{ define "editor" }} - {{ template "base" . }} -{{ end }} \ No newline at end of file diff --git a/templates/webmentionadmin.gohtml b/templates/webmentionadmin.gohtml deleted file mode 100644 index e083c0c..0000000 --- a/templates/webmentionadmin.gohtml +++ /dev/null @@ -1,43 +0,0 @@ -{{ define "title" }} - {{ string .Blog.Lang "webmentions" }} - {{ mdtitle .Blog.Title }} -{{ end }} - -{{ define "main" }} -
-

{{ string .Blog.Lang "webmentions" }}

- {{ $blog := .Blog }} - {{ $current := .Data.Current }} - {{ range $i, $mention := .Data.Mentions }} -
-

- From: {{ $mention.Source }}
- {{ if not (eq $mention.Source $mention.Url ) }}u-url: {{ $mention.Url }}
{{ end }} - To: {{ $mention.Target }}
- Created: {{ unixtodate $mention.Created }}

- {{ if $mention.Author }}{{ $mention.Author }}
{{ end }} - {{ with $mention.Title }}{{.}}
{{ end }} - {{ with $mention.Content }}{{.}}{{ end }} -

-
- - - {{ if eq $mention.Status "verified" }} - - {{ end }} - - -
-
- {{ end }} - {{ if .Data.HasPrev }} -

{{ string .Blog.Lang "prev" }}

- {{ end }} - {{ if .Data.HasNext }} -

{{ string .Blog.Lang "next" }}

- {{ end }} -
-{{ end }} - -{{ define "webmentionadmin" }} - {{ template "base" . }} -{{ end }} \ No newline at end of file diff --git a/ui.go b/ui.go index dfbc176..810677f 100644 --- a/ui.go +++ b/ui.go @@ -336,7 +336,7 @@ func (a *goBlog) renderComment(h *htmlBuilder, rd *renderData) { hb.writeElementClose("main") // Interactions if rd.CommentsEnabled { - a.renderInteractions(hb, rd.Blog, rd.Canonical) + a.renderInteractions(hb, rd) } }, ) @@ -448,7 +448,7 @@ func (a *goBlog) renderBlogStats(hb *htmlBuilder, rd *renderData) { hb.writeElementClose("main") // Interactions if rd.CommentsEnabled { - a.renderInteractions(hb, rd.Blog, rd.Canonical) + a.renderInteractions(hb, rd) } }, ) @@ -620,7 +620,7 @@ func (a *goBlog) renderGeoMap(hb *htmlBuilder, rd *renderData) { } hb.writeElementClose("main") if rd.CommentsEnabled { - a.renderInteractions(hb, rd.Blog, rd.Canonical) + a.renderInteractions(hb, rd) } }, ) @@ -695,7 +695,7 @@ func (a *goBlog) renderBlogroll(hb *htmlBuilder, rd *renderData) { hb.writeElementClose("main") // Interactions if rd.CommentsEnabled { - a.renderInteractions(hb, rd.Blog, rd.Canonical) + a.renderInteractions(hb, rd) } }, ) @@ -891,7 +891,7 @@ func (a *goBlog) renderPost(hb *htmlBuilder, rd *renderData) { // Post meta a.renderPostMeta(hb, p, rd.Blog, "post") // Post actions - hb.writeElementOpen("div", "id", "post-actions") + hb.writeElementOpen("div", "class", "actions") // Share button hb.writeElementOpen("a", "class", "button", "href", fmt.Sprintf("https://www.addtoany.com/share#url=%s%s", a.shortPostURL(p), funk.ShortIf(p.RenderedTitle != "", "&title="+p.RenderedTitle, "")), "target", "_blank", "rel", "nofollow noopener noreferrer") hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "share")) @@ -964,7 +964,7 @@ func (a *goBlog) renderPost(hb *htmlBuilder, rd *renderData) { hb.writeElementClose("main") // Post edit actions if rd.LoggedIn() { - hb.writeElementOpen("div", "id", "posteditactions") + hb.writeElementOpen("div", "class", "actions") // Update hb.writeElementOpen("form", "method", "post", "action", rd.Blog.RelativePath("/editor")+"#update") hb.writeElementOpen("input", "type", "hidden", "name", "editoraction", "value", "loadupdate") @@ -999,7 +999,7 @@ func (a *goBlog) renderPost(hb *htmlBuilder, rd *renderData) { } // Comments if rd.CommentsEnabled { - a.renderInteractions(hb, rd.Blog, rd.Canonical) + a.renderInteractions(hb, rd) } }, ) @@ -1201,9 +1201,9 @@ func (a *goBlog) renderNotificationsAdmin(hb *htmlBuilder, rd *renderData) { hb.writeElementClose("i") hb.writeElementClose("p") // Message - a.renderMarkdownToWriter(hb, n.Text, false) + _ = a.renderMarkdownToWriter(hb, n.Text, false) // Delete form - hb.writeElementOpen("form", "method", "post", "action", "/notifications/delete") + hb.writeElementOpen("form", "class", "actions", "method", "post", "action", "/notifications/delete") hb.writeElementOpen("input", "type", "hidden", "name", "notificationid", "value", n.ID) hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "delete")) hb.writeElementClose("form") @@ -1215,3 +1215,320 @@ func (a *goBlog) renderNotificationsAdmin(hb *htmlBuilder, rd *renderData) { }, ) } + +type commentsRenderData struct { + comments []*comment + hasPrev, hasNext bool + prev, next string +} + +func (a *goBlog) renderCommentsAdmin(hb *htmlBuilder, rd *renderData) { + crd, ok := rd.Data.(*commentsRenderData) + if !ok { + return + } + a.renderBase( + hb, rd, + func(hb *htmlBuilder) { + a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "comments")) + }, + func(hb *htmlBuilder) { + hb.writeElementOpen("main") + // Title + hb.writeElementOpen("h1") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "comments")) + hb.writeElementClose("h1") + // Notifications + for _, c := range crd.comments { + hb.writeElementOpen("div", "class", "p") + // ID, Target, Name + hb.writeElementOpen("p") + hb.writeEscaped("ID: ") + hb.writeEscaped(fmt.Sprintf("%d", c.ID)) + hb.writeElementOpen("br") + hb.writeEscaped("Target: ") + hb.writeElementOpen("a", "href", c.Target, "target", "_blank") + hb.writeEscaped(c.Target) + hb.writeElementClose("a") + hb.writeElementOpen("br") + hb.writeEscaped("Name: ") + if c.Website != "" { + hb.writeElementOpen("a", "href", c.Website, "target", "_blank", "rel", "nofollow noopener noreferrer ugc") + } + hb.writeEscaped(c.Name) + if c.Website != "" { + hb.writeElementClose("a") + } + hb.writeElementClose("p") + // Comment + hb.writeElementOpen("p") + hb.write(c.Comment) + hb.writeElementClose("p") + // Delete form + hb.writeElementOpen("form", "class", "actions", "method", "post", "action", rd.Blog.getRelativePath("/comment/delete")) + hb.writeElementOpen("input", "type", "hidden", "name", "commentid", "value", c.ID) + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "delete")) + hb.writeElementClose("form") + hb.writeElementClose("div") + } + // Pagination + a.renderPagination(hb, rd.Blog, crd.hasPrev, crd.hasNext, crd.prev, crd.next) + hb.writeElementClose("main") + }, + ) +} + +type webmentionRenderData struct { + mentions []*mention + hasPrev, hasNext bool + prev, current, next string +} + +func (a *goBlog) renderWebmentionAdmin(hb *htmlBuilder, rd *renderData) { + wrd, ok := rd.Data.(*webmentionRenderData) + if !ok { + return + } + a.renderBase( + hb, rd, + func(hb *htmlBuilder) { + a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "webmentions")) + }, + func(hb *htmlBuilder) { + hb.writeElementOpen("main") + // Title + hb.writeElementOpen("h1") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "webmentions")) + hb.writeElementClose("h1") + // Notifications + for _, m := range wrd.mentions { + hb.writeElementOpen("div", "id", fmt.Sprintf("mention-%d", m.ID), "class", "p") + hb.writeElementOpen("p") + // Source + hb.writeEscaped("From: ") + hb.writeElementOpen("a", "href", m.Source, "target", "_blank", "rel", "noopener noreferrer") + hb.writeEscaped(m.Source) + hb.writeElementClose("a") + hb.writeElementOpen("br") + // u-url + if m.Source != m.Url { + hb.writeEscaped("u-url: ") + hb.writeElementOpen("a", "href", m.Url, "target", "_blank", "rel", "noopener noreferrer") + hb.writeEscaped(m.Url) + hb.writeElementClose("a") + hb.writeElementOpen("br") + } + // Target + hb.writeEscaped("To: ") + hb.writeElementOpen("a", "href", m.Target, "target", "_blank") + hb.writeEscaped(m.Target) + hb.writeElementClose("a") + hb.writeElementOpen("br") + // Date + hb.writeEscaped("Created: ") + hb.writeEscaped(unixToLocalDateString(m.Created)) + hb.writeElementOpen("br") + hb.writeElementOpen("br") + // Author + if m.Author != "" { + hb.writeEscaped(m.Author) + hb.writeElementOpen("br") + } + // Title + if m.Title != "" { + hb.writeElementOpen("strong") + hb.writeEscaped(m.Title) + hb.writeElementClose("strong") + hb.writeElementOpen("br") + } + // Content + if m.Content != "" { + hb.writeElementOpen("i") + hb.writeEscaped(m.Content) + hb.writeElementClose("i") + hb.writeElementOpen("br") + } + hb.writeElementClose("p") + // Actions + hb.writeElementOpen("form", "method", "post", "class", "actions") + hb.writeElementOpen("input", "type", "hidden", "name", "mentionid", "value", m.ID) + hb.writeElementOpen("input", "type", "hidden", "name", "redir", "value", fmt.Sprintf("%s#mention-%d", wrd.current, m.ID)) + if m.Status == webmentionStatusVerified { + // Approve verified mention + hb.writeElementOpen("input", "type", "submit", "formaction", "/webmention/approve", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "approve")) + } + // Delete mention + hb.writeElementOpen("input", "type", "submit", "formaction", "/webmention/delete", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "delete")) + // Reverify mention + hb.writeElementOpen("input", "type", "submit", "formaction", "/webmention/reverify", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "reverify")) + hb.writeElementClose("form") + } + // Pagination + a.renderPagination(hb, rd.Blog, wrd.hasPrev, wrd.hasNext, wrd.prev, wrd.next) + hb.writeElementClose("main") + }, + ) +} + +type editorRenderData struct { + updatePostUrl string + updatePostContent string +} + +func (a *goBlog) renderEditor(hb *htmlBuilder, rd *renderData) { + edrd, ok := rd.Data.(*editorRenderData) + if !ok { + return + } + a.renderBase( + hb, rd, + func(hb *htmlBuilder) { + a.renderTitleTag(hb, rd.Blog, a.ts.GetTemplateStringVariant(rd.Blog.Lang, "editor")) + // Chroma CSS + hb.writeElementOpen("link", "rel", "stylesheet", "href", a.assetFileName("css/chroma.css")) + }, + func(hb *htmlBuilder) { + hb.writeElementOpen("main") + // Title + hb.writeElementOpen("h1") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "editor")) + hb.writeElementClose("h1") + + // Create + hb.writeElementOpen("h2") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "create")) + hb.writeElementClose("h2") + _ = a.renderMarkdownToWriter(hb, a.editorPostDesc(rd.Blog), false) + hb.writeElementOpen("form", "method", "post", "class", "fw p") + hb.writeElementOpen("input", "type", "hidden", "name", "h", "value", "entry") + hb.writeElementOpen( + "textarea", + "name", "content", + "class", "monospace h400p formcache mdpreview", + "id", "create-input", + "data-preview", "post-preview", + "data-previewws", rd.Blog.getRelativePath("/editor/preview"), + ) + hb.writeEscaped(a.editorPostTemplate(rd.BlogString, rd.Blog)) + hb.writeElementClose("textarea") + hb.writeElementOpen("div", "id", "post-preview", "class", "hide") + hb.writeElementClose("div") + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "create")) + hb.writeElementClose("form") + + // Update + if edrd.updatePostUrl != "" { + hb.writeElementOpen("h2", "id", "#update") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "update")) + hb.writeElementClose("h2") + hb.writeElementOpen("form", "method", "post", "class", "fw p", "action", "#update") + hb.writeElementOpen("input", "type", "hidden", "name", "editoraction", "value", "updatepost") + hb.writeElementOpen("input", "type", "hidden", "name", "url", "value", edrd.updatePostUrl) + hb.writeElementOpen( + "textarea", + "name", "content", + "class", "monospace h400p mdpreview", + "data-preview", "update-preview", + "data-previewws", rd.Blog.getRelativePath("/editor/preview"), + ) + hb.writeEscaped(edrd.updatePostContent) + hb.writeElementClose("textarea") + hb.writeElementOpen("div", "id", "update-preview", "class", "hide") + hb.writeElementClose("div") + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "update")) + hb.writeElementClose("form") + } + + // Posts + hb.writeElementOpen("h2") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "posts")) + hb.writeElementClose("h2") + // Drafts + hb.writeElementOpen("p") + hb.writeElementOpen("a", "href", rd.Blog.getRelativePath("/editor/drafts")) + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "drafts")) + hb.writeElementClose("a") + hb.writeElementClose("p") + // Private + hb.writeElementOpen("p") + hb.writeElementOpen("a", "href", rd.Blog.getRelativePath("/editor/private")) + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "privateposts")) + hb.writeElementClose("a") + hb.writeElementClose("p") + // Unlisted + hb.writeElementOpen("p") + hb.writeElementOpen("a", "href", rd.Blog.getRelativePath("/editor/unlisted")) + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "unlistedposts")) + hb.writeElementClose("a") + hb.writeElementClose("p") + // Scheduled + hb.writeElementOpen("p") + hb.writeElementOpen("a", "href", rd.Blog.getRelativePath("/editor/scheduled")) + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "scheduledposts")) + hb.writeElementClose("a") + hb.writeElementClose("p") + // Deleted + hb.writeElementOpen("p") + hb.writeElementOpen("a", "href", rd.Blog.getRelativePath("/editor/deleted")) + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "deletedposts")) + hb.writeElementClose("a") + hb.writeElementClose("p") + + // Upload + hb.writeElementOpen("h2") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "upload")) + hb.writeElementClose("h2") + hb.writeElementOpen("form", "class", "fw p", "method", "post", "enctype", "multipart/form-data") + hb.writeElementOpen("input", "type", "hidden", "name", "editoraction", "value", "upload") + hb.writeElementOpen("input", "type", "file", "name", "file") + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "upload")) + hb.writeElementClose("form") + // Media files + hb.writeElementOpen("p") + hb.writeElementOpen("a", "href", rd.Blog.getRelativePath("/editor/files")) + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "mediafiles")) + hb.writeElementClose("a") + hb.writeElementClose("p") + + // Location-Helper + hb.writeElementOpen("h2") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "location")) + hb.writeElementClose("h2") + hb.writeElementOpen("form", "class", "fw p") + hb.writeElementOpen( + "input", "id", "geobtn", "type", "button", + "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "locationget"), + "data-failed", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "locationfailed"), + "data-notsupported", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "locationnotsupported"), + ) + hb.writeElementOpen("input", "id", "geostatus", "type", "text", "class", "hide", "readonly", "") + hb.writeElementClose("form") + + // GPX-Helper + hb.writeElementOpen("h2") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "gpxhelper")) + hb.writeElementClose("h2") + hb.writeElementOpen("p") + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "gpxhelperdesc")) + hb.writeElementClose("p") + hb.writeElementOpen("form", "class", "fw p", "method", "post", "enctype", "multipart/form-data") + hb.writeElementOpen("input", "type", "hidden", "name", "editoraction", "value", "helpgpx") + hb.writeElementOpen("input", "type", "file", "name", "file") + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "upload")) + hb.writeElementClose("form") + + hb.writeElementClose("main") + + // Scripts + // Editor preview + hb.writeElementOpen("script", "src", a.assetFileName("js/mdpreview.js"), "defer", "") + hb.writeElementClose("script") + // Geohelper + hb.writeElementOpen("script", "src", a.assetFileName("js/geohelper.js"), "defer", "") + hb.writeElementClose("script") + // Formcache + hb.writeElementOpen("script", "src", a.assetFileName("js/formcache.js"), "defer", "") + hb.writeElementClose("script") + }, + ) +} diff --git a/uiComponents.go b/uiComponents.go index 2cf6989..576ed14 100644 --- a/uiComponents.go +++ b/uiComponents.go @@ -236,15 +236,12 @@ func (a *goBlog) renderOldContentWarning(hb *htmlBuilder, p *post, b *configBlog hb.writeElementClose("strong") } -func (a *goBlog) renderInteractions(hb *htmlBuilder, b *configBlog, canonical string) { - if b == nil || canonical == "" { - return - } +func (a *goBlog) renderInteractions(hb *htmlBuilder, rd *renderData) { // Start accordion hb.writeElementOpen("details", "class", "p", "id", "interactions") hb.writeElementOpen("summary") hb.writeElementOpen("strong") - hb.writeEscaped(a.ts.GetTemplateStringVariant(b.Lang, "interactions")) + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "interactions")) hb.writeElementClose("strong") hb.writeElementClose("summary") // Render mentions @@ -278,24 +275,24 @@ func (a *goBlog) renderInteractions(hb *htmlBuilder, b *configBlog, canonical st } hb.writeElementClose("ul") } - renderMentions(a.db.getWebmentionsByAddress(canonical)) + renderMentions(a.db.getWebmentionsByAddress(rd.Canonical)) // Show form to send a webmention hb.writeElementOpen("form", "class", "fw p", "method", "post", "action", "/webmention") hb.writeElementOpen("label", "for", "wm-source", "class", "p") - hb.writeEscaped(a.ts.GetTemplateStringVariant(b.Lang, "interactionslabel")) + hb.writeEscaped(a.ts.GetTemplateStringVariant(rd.Blog.Lang, "interactionslabel")) hb.writeElementClose("label") hb.writeElementOpen("input", "id", "wm-source", "type", "url", "name", "source", "placeholder", "URL", "required", "") - hb.writeElementOpen("input", "type", "hidden", "name", "target", "value", canonical) - hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(b.Lang, "send")) + hb.writeElementOpen("input", "type", "hidden", "name", "target", "value", rd.Canonical) + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "send")) hb.writeElementClose("form") // Show form to create a new comment hb.writeElementOpen("form", "class", "fw p", "method", "post", "action", "/comment") - hb.writeElementOpen("input", "type", "hidden", "name", "target", "value", canonical) - hb.writeElementOpen("input", "type", "text", "name", "name", "placeholder", a.ts.GetTemplateStringVariant(b.Lang, "nameopt")) - hb.writeElementOpen("input", "type", "url", "name", "website", "placeholder", a.ts.GetTemplateStringVariant(b.Lang, "websiteopt")) - hb.writeElementOpen("textarea", "name", "comment", "required", "", "placeholder", a.ts.GetTemplateStringVariant(b.Lang, "comment")) + hb.writeElementOpen("input", "type", "hidden", "name", "target", "value", rd.Canonical) + hb.writeElementOpen("input", "type", "text", "name", "name", "placeholder", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "nameopt")) + hb.writeElementOpen("input", "type", "url", "name", "website", "placeholder", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "websiteopt")) + hb.writeElementOpen("textarea", "name", "comment", "required", "", "placeholder", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "comment")) hb.writeElementClose("textarea") - hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(b.Lang, "docomment")) + hb.writeElementOpen("input", "type", "submit", "value", a.ts.GetTemplateStringVariant(rd.Blog.Lang, "docomment")) hb.writeElementClose("form") // Finish accordion hb.writeElementClose("details") diff --git a/ui_test.go b/ui_test.go index 5218dc9..fe9be72 100644 --- a/ui_test.go +++ b/ui_test.go @@ -123,7 +123,10 @@ func Test_renderInteractions(t *testing.T) { buf := &bytes.Buffer{} hb := newHtmlBuilder(buf) - app.renderInteractions(hb, app.cfg.Blogs["default"], "https://example.com/testpost1") + app.renderInteractions(hb, &renderData{ + Blog: app.cfg.Blogs["default"], + Canonical: "https://example.com/testpost1", + }) res := buf.Bytes() _, err = goquery.NewDocumentFromReader(bytes.NewReader(res)) diff --git a/utils.go b/utils.go index 57b2eb4..3b9dd6e 100644 --- a/utils.go +++ b/utils.go @@ -5,7 +5,6 @@ import ( "crypto/sha256" "errors" "fmt" - "html/template" "io" "net/http" "net/http/httptest" @@ -205,10 +204,6 @@ func charCount(s string) (count int) { return count } -func wrapStringAsHTML(s string) template.HTML { - return template.HTML(s) -} - // Check if url has allowed file extension func urlHasExt(rawUrl string, allowed ...string) (ext string, has bool) { u, err := url.Parse(rawUrl) diff --git a/webmentionAdmin.go b/webmentionAdmin.go index 4410150..e3a2dce 100644 --- a/webmentionAdmin.go +++ b/webmentionAdmin.go @@ -95,14 +95,14 @@ func (a *goBlog) webmentionAdmin(w http.ResponseWriter, r *http.Request) { query = "?" + params.Encode() } // Render - a.render(w, r, templateWebmentionAdmin, &renderData{ - Data: map[string]interface{}{ - "Mentions": mentions, - "HasPrev": hasPrev, - "HasNext": hasNext, - "Prev": prevPath + query, - "Current": currentPath + query, - "Next": nextPath + query, + a.render(w, r, a.renderWebmentionAdmin, &renderData{ + Data: &webmentionRenderData{ + mentions: mentions, + hasPrev: hasPrev, + hasNext: hasNext, + prev: prevPath + query, + current: currentPath + query, + next: nextPath + query, }, }) }