Browse Source

Improve live editor preview to show real post preview

master
Jan-Lukas Else 1 month ago
parent
commit
a3f2a5090b
  1. 3
      app.go
  2. 46
      editor.go
  3. 5
      go.mod
  4. 11
      go.sum
  5. 6
      micropub.go
  6. 3
      original-assets/styles/styles.scss
  7. 1
      render.go
  8. 3
      templates/assets/css/styles.css
  9. 11
      templates/assets/js/mdpreview.js
  10. 10
      templates/editorpreview.gohtml
  11. 7
      templates/posttax.gohtml
  12. 12
      websockets.go

3
app.go

@ -10,6 +10,7 @@ import (
ts "git.jlel.se/jlelse/template-strings"
ct "github.com/elnormous/contenttype"
"github.com/go-fed/httpsig"
"github.com/gorilla/websocket"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"github.com/yuin/goldmark"
"go.goblog.app/app/pkgs/minify"
@ -77,4 +78,6 @@ type goBlog struct {
// Tor
torAddress string
torHostname string
// WebSockets
wsUpgrader *websocket.Upgrader
}

46
editor.go

@ -3,6 +3,7 @@ package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -10,7 +11,6 @@ import (
"net/url"
"strings"
"github.com/gorilla/websocket"
"github.com/microcosm-cc/bluemonday"
"go.goblog.app/app/pkgs/contenttype"
"gopkg.in/yaml.v3"
@ -26,12 +26,9 @@ func (a *goBlog) serveEditor(w http.ResponseWriter, r *http.Request) {
})
}
var upgrader = websocket.Upgrader{
EnableCompression: true,
}
func (a *goBlog) serveEditorPreview(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
blog := r.Context().Value(blogKey).(string)
c, err := a.webSocketUpgrader().Upgrade(w, r, nil)
if err != nil {
return
}
@ -43,9 +40,9 @@ func (a *goBlog) serveEditorPreview(w http.ResponseWriter, r *http.Request) {
break
}
// Create preview
preview, err := a.createMarkdownPreview(message)
preview, err := a.createMarkdownPreview(blog, message)
if err != nil {
continue
preview = []byte(err.Error())
}
// Write preview to socket
err = c.WriteMessage(mt, preview)
@ -55,14 +52,33 @@ func (a *goBlog) serveEditorPreview(w http.ResponseWriter, r *http.Request) {
}
}
func (a *goBlog) createMarkdownPreview(markdown []byte) (rendered []byte, err error) {
mdString := string(markdown)
if split := strings.Split(mdString, "---\n"); len(split) >= 3 && len(strings.TrimSpace(split[0])) == 0 {
// Remove frontmatter from content
mdString = strings.Join(split[2:], "---\n")
func (a *goBlog) createMarkdownPreview(blog string, markdown []byte) (rendered []byte, err error) {
p := post{
Content: string(markdown),
Blog: blog,
Path: "/editor/preview",
Published: localNowString(),
}
err = a.computeExtraPostParameters(&p)
if err != nil {
return nil, err
}
if t := p.Title(); t != "" {
p.RenderedTitle = a.renderMdTitle(t)
}
// Render post
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/editor/preview", nil)
a.render(rec, req, templateEditorPreview, &renderData{
BlogString: p.Blog,
Data: &p,
})
res := rec.Result()
if res.StatusCode != http.StatusOK {
return nil, errors.New("failed to render preview")
}
// Render markdown
rendered, err = a.renderMarkdown(mdString, true)
defer res.Body.Close()
rendered, err = io.ReadAll(res.Body)
if err != nil {
return nil, err
}

5
go.mod

@ -45,7 +45,7 @@ require (
// master
github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
golang.org/x/net v0.0.0-20211029224645-99673261e6eb
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
tailscale.com v1.16.2
@ -90,7 +90,6 @@ require (
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.3.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/tailscale/certstore v0.0.0-20210528134328-066c94b793d3 // indirect
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
@ -100,7 +99,7 @@ require (
go4.org/intern v0.0.0-20210108033219-3eb7198706b2 // indirect
go4.org/mem v0.0.0-20201119185036-c04c5a6ff174 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 // indirect
golang.org/x/sys v0.0.0-20211031064116-611d5d643895 // indirect
golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
golang.zx2c4.com/wireguard v0.0.0-20210905140043-2ef39d47540c // indirect

11
go.sum

@ -79,7 +79,6 @@ github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 h1:t8KYCwSKsOEZBFELI4Pn/phbp38iJ1RRAkDFNin1aak=
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
@ -424,8 +423,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk=
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -585,8 +582,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3 h1:VrJZAjbekhoRn7n5FBujY31gboH+iB3pdLxn3gE9FjU=
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
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=
@ -685,8 +682,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211031064116-611d5d643895 h1:iaNpwpnrgL5jzWS0vCNnfa8HqzxveCFpFx3uC/X4Tps=
golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c h1:QOfDMdrf/UwlVR0UBq2Mpr58UzNtvgJRXA4BgPfFACs=
golang.org/x/sys v0.0.0-20211102061401-a2f17f7b995c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=

6
micropub.go

@ -407,6 +407,12 @@ func (a *goBlog) computeExtraPostParameters(p *post) error {
}
}
}
// Remove all parameters where there are just empty strings
for pk, pvs := range p.Parameters {
if len(pvs) == 0 || strings.Join(pvs, "") == "" {
delete(p.Parameters, pk)
}
}
return nil
}

3
original-assets/styles/styles.scss

@ -113,6 +113,9 @@ form {
input, textarea, select {
margin-bottom: 5px;
}
textarea {
display: block;
}
}
form.fw {

1
render.go

@ -39,6 +39,7 @@ const (
templateBlogroll = "blogroll"
templateGeoMap = "geomap"
templateContact = "contact"
templateEditorPreview = "editorpreview"
)
func (a *goBlog) initRendering() error {

3
templates/assets/css/styles.css

@ -77,6 +77,9 @@ button:focus, .button:focus, input:focus, textarea:focus, select:focus {
form input, form textarea, form select {
margin-bottom: 5px;
}
form textarea {
display: block;
}
blockquote {
border-left: 5px solid #000;

11
templates/assets/js/mdpreview.js

@ -24,6 +24,7 @@
console.log("Preview-Websocket closed")
previewContainer.classList.add('hide')
previewContainer.classList.remove('preview')
previewContainer.innerHTML = ''
ws = null
}
ws.onmessage = function (evt) {
@ -34,10 +35,14 @@
console.log("Preview-Websocket error: " + evt.data)
}
// Add listener
let timeout = null
element.addEventListener('input', function () {
if (ws) {
ws.send(element.value)
}
clearTimeout(timeout)
timeout = setTimeout(function () {
if (ws) {
ws.send(element.value)
}
}, 500)
})
})
})()

10
templates/editorpreview.gohtml

@ -0,0 +1,10 @@
{{ define "editorpreview" }}
{{ with .Data.RenderedTitle }}<h1>{{ . }}</h1>{{ end }}
{{ include "summaryandpostmeta" . }}
{{ if .Data.Content }}
<div>
{{ content .Data true }}
</div>
{{ end }}
{{ include "posttax" . }}
{{ end }}

7
templates/posttax.gohtml

@ -3,12 +3,13 @@
{{ $blog := .Blog }}
{{ range $i, $tax := $blog.Taxonomies }}
{{ $tvs := sort (ps $post $tax.Name) }}
{{ if $tvs }}
<p><b>{{ mdtitle $tax.Title }}</b>:
{{ if $tvs }}{{ if not (eq (len $tvs) 0) }}
<p>
<b>{{ mdtitle $tax.Title }}</b>:
{{ range $j, $tv := $tvs }}
<a class="p-category" rel="tag" href="{{ $blog.RelativePath ( printf "/%s/%s" $tax.Name (urlize $tv) ) }}">{{ mdtitle $tv }}</a>
{{ end }}
</p>
{{ end }}
{{ end }}{{ end }}
{{ end }}
{{ end }}

12
websockets.go

@ -0,0 +1,12 @@
package main
import "github.com/gorilla/websocket"
func (a *goBlog) webSocketUpgrader() *websocket.Upgrader {
if a.wsUpgrader == nil {
a.wsUpgrader = &websocket.Upgrader{
EnableCompression: true,
}
}
return a.wsUpgrader
}
Loading…
Cancel
Save