Add preview button to edit post page

This commit is contained in:
Brian Picciano 2022-05-20 11:06:21 -06:00
parent 2c4b617dde
commit f69ed83de7
3 changed files with 117 additions and 64 deletions

View File

@ -222,6 +222,7 @@ func (a *api) handler() http.Handler {
"DELETE": authMiddleware(auther,
formMiddleware(a.deletePostHandler()),
),
"PREVIEW": formMiddleware(a.previewPostHandler()),
}),
))
v2Mux.Handle("/assets/", http.StripPrefix("/assets",

View File

@ -16,6 +16,59 @@ import (
"github.com/mediocregopher/blog.mediocregopher.com/srv/post"
)
type postTplPayload struct {
post.StoredPost
SeriesPrevious, SeriesNext *post.StoredPost
Body template.HTML
}
func (a *api) postToPostTplPayload(storedPost post.StoredPost) (postTplPayload, error) {
parserExt := parser.CommonExtensions | parser.AutoHeadingIDs
parser := parser.NewWithExtensions(parserExt)
htmlFlags := html.CommonFlags | html.HrefTargetBlank
htmlRenderer := html.NewRenderer(html.RendererOptions{Flags: htmlFlags})
renderedBody := markdown.ToHTML([]byte(storedPost.Body), parser, htmlRenderer)
tplPayload := postTplPayload{
StoredPost: storedPost,
Body: template.HTML(renderedBody),
}
if series := storedPost.Series; series != "" {
seriesPosts, err := a.params.PostStore.GetBySeries(series)
if err != nil {
return postTplPayload{}, fmt.Errorf(
"fetching posts for series %q: %w", series, err,
)
}
var foundThis bool
for i := range seriesPosts {
seriesPost := seriesPosts[i]
if seriesPost.ID == storedPost.ID {
foundThis = true
continue
}
if !foundThis {
tplPayload.SeriesPrevious = &seriesPost
continue
}
tplPayload.SeriesNext = &seriesPost
break
}
}
return tplPayload, nil
}
func (a *api) renderPostHandler() http.Handler {
tpl := a.mustParseBasedTpl("post.html")
@ -42,53 +95,16 @@ func (a *api) renderPostHandler() http.Handler {
return
}
parserExt := parser.CommonExtensions | parser.AutoHeadingIDs
parser := parser.NewWithExtensions(parserExt)
tplPayload, err := a.postToPostTplPayload(storedPost)
htmlFlags := html.CommonFlags | html.HrefTargetBlank
htmlRenderer := html.NewRenderer(html.RendererOptions{Flags: htmlFlags})
renderedBody := markdown.ToHTML([]byte(storedPost.Body), parser, htmlRenderer)
tplPayload := struct {
post.StoredPost
SeriesPrevious, SeriesNext *post.StoredPost
Body template.HTML
}{
StoredPost: storedPost,
Body: template.HTML(renderedBody),
}
if series := storedPost.Series; series != "" {
seriesPosts, err := a.params.PostStore.GetBySeries(series)
if err != nil {
apiutil.InternalServerError(
rw, r,
fmt.Errorf("fetching posts for series %q: %w", series, err),
)
return
}
var foundThis bool
for i := range seriesPosts {
seriesPost := seriesPosts[i]
if seriesPost.ID == storedPost.ID {
foundThis = true
continue
}
if !foundThis {
tplPayload.SeriesPrevious = &seriesPost
continue
}
tplPayload.SeriesNext = &seriesPost
break
}
if err != nil {
apiutil.InternalServerError(
rw, r, fmt.Errorf(
"generating template payload for post with id %q: %w",
id, err,
),
)
return
}
executeTemplate(rw, r, tpl, tplPayload)
@ -169,21 +185,28 @@ func (a *api) editPostHandler() http.Handler {
})
}
func postFromPostReq(r *http.Request) post.Post {
p := post.Post{
ID: r.PostFormValue("id"),
Title: r.PostFormValue("title"),
Description: r.PostFormValue("description"),
Tags: strings.Fields(r.PostFormValue("tags")),
Series: r.PostFormValue("series"),
}
p.Body = strings.TrimSpace(r.PostFormValue("body"))
// textareas encode newlines as CRLF for historical reasons
p.Body = strings.ReplaceAll(p.Body, "\r\n", "\n")
return p
}
func (a *api) postPostHandler() http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
p := post.Post{
ID: r.PostFormValue("id"),
Title: r.PostFormValue("title"),
Description: r.PostFormValue("description"),
Tags: strings.Fields(r.PostFormValue("tags")),
Series: r.PostFormValue("series"),
}
p.Body = strings.TrimSpace(r.PostFormValue("body"))
// textareas encode newlines as CRLF for historical reasons
p.Body = strings.ReplaceAll(p.Body, "\r\n", "\n")
p := postFromPostReq(r)
if err := a.params.PostStore.Set(p, time.Now()); err != nil {
apiutil.InternalServerError(
@ -225,3 +248,27 @@ func (a *api) deletePostHandler() http.Handler {
})
}
func (a *api) previewPostHandler() http.Handler {
tpl := a.mustParseBasedTpl("post.html")
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
storedPost := post.StoredPost{
Post: postFromPostReq(r),
PublishedAt: time.Now(),
}
tplPayload, err := a.postToPostTplPayload(storedPost)
if err != nil {
apiutil.InternalServerError(
rw, r, fmt.Errorf("generating template payload: %w", err),
)
return
}
executeTemplate(rw, r, tpl, tplPayload)
})
}

View File

@ -1,11 +1,5 @@
{{ define "body" }}
<p>
<a href="{{ BlogURL "posts/" }}">
<button>Back to Posts</button>
</a>
</p>
<form method="POST" action="{{ BlogURL "posts/" }}">
{{ .CSRFFormInput }}
@ -87,7 +81,18 @@
</div>
</div>
<input type="submit" value="Save" />
<input
type="submit"
value="Preview"
formaction="{{ BlogURL "posts/" }}{{ .Payload.ID }}?method=preview"
formtarget="_blank"
/>
<input type="submit" value="Save" formaction="{{ BlogURL "posts/" }}" />
<a href="{{ BlogURL "posts/" }}">
<button type="button">Cancel</button>
</a>
</form>