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, "DELETE": authMiddleware(auther,
formMiddleware(a.deletePostHandler()), formMiddleware(a.deletePostHandler()),
), ),
"PREVIEW": formMiddleware(a.previewPostHandler()),
}), }),
)) ))
v2Mux.Handle("/assets/", http.StripPrefix("/assets", v2Mux.Handle("/assets/", http.StripPrefix("/assets",

View File

@ -16,6 +16,59 @@ import (
"github.com/mediocregopher/blog.mediocregopher.com/srv/post" "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 { func (a *api) renderPostHandler() http.Handler {
tpl := a.mustParseBasedTpl("post.html") tpl := a.mustParseBasedTpl("post.html")
@ -42,55 +95,18 @@ func (a *api) renderPostHandler() http.Handler {
return return
} }
parserExt := parser.CommonExtensions | parser.AutoHeadingIDs tplPayload, err := a.postToPostTplPayload(storedPost)
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 := 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 { if err != nil {
apiutil.InternalServerError( apiutil.InternalServerError(
rw, r, rw, r, fmt.Errorf(
fmt.Errorf("fetching posts for series %q: %w", series, err), "generating template payload for post with id %q: %w",
id, err,
),
) )
return 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
}
}
executeTemplate(rw, r, tpl, tplPayload) executeTemplate(rw, r, tpl, tplPayload)
}) })
} }
@ -169,9 +185,7 @@ func (a *api) editPostHandler() http.Handler {
}) })
} }
func (a *api) postPostHandler() http.Handler { func postFromPostReq(r *http.Request) post.Post {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
p := post.Post{ p := post.Post{
ID: r.PostFormValue("id"), ID: r.PostFormValue("id"),
@ -185,6 +199,15 @@ func (a *api) postPostHandler() http.Handler {
// textareas encode newlines as CRLF for historical reasons // textareas encode newlines as CRLF for historical reasons
p.Body = strings.ReplaceAll(p.Body, "\r\n", "\n") 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 := postFromPostReq(r)
if err := a.params.PostStore.Set(p, time.Now()); err != nil { if err := a.params.PostStore.Set(p, time.Now()); err != nil {
apiutil.InternalServerError( apiutil.InternalServerError(
rw, r, fmt.Errorf("storing post with id %q: %w", p.ID, err), rw, r, fmt.Errorf("storing post with id %q: %w", p.ID, err),
@ -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" }} {{ define "body" }}
<p>
<a href="{{ BlogURL "posts/" }}">
<button>Back to Posts</button>
</a>
</p>
<form method="POST" action="{{ BlogURL "posts/" }}"> <form method="POST" action="{{ BlogURL "posts/" }}">
{{ .CSRFFormInput }} {{ .CSRFFormInput }}
@ -87,7 +81,18 @@
</div> </div>
</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> </form>