Further improve post title rendering

This commit is contained in:
Jan-Lukas Else 2021-08-05 08:09:34 +02:00
parent 4c1f7fcde4
commit 4c8c147c4c
21 changed files with 71 additions and 64 deletions

View File

@ -106,7 +106,7 @@ func (a *goBlog) toASNote(p *post) *asNote {
AttributedTo: a.apIri(a.cfg.Blogs[p.Blog]),
}
// Name and Type
if title := a.renderMdTitle(p.Title()); title != "" {
if title := p.RenderedTitle; title != "" {
as.Name = title
as.Type = "Article"
} else {

View File

@ -17,7 +17,7 @@ import (
func (a *goBlog) checkAllExternalLinks() {
// Get all published posts without parameters
posts, err := a.db.getPosts(&postsRequestConfig{status: statusPublished, withoutParameters: true})
posts, err := a.getPosts(&postsRequestConfig{status: statusPublished, withoutParameters: true})
if err != nil {
log.Println(err.Error())
return

View File

@ -41,7 +41,7 @@ func (a *goBlog) serveEditorPost(w http.ResponseWriter, r *http.Request) {
a.serveError(w, r, err.Error(), http.StatusBadRequest)
return
}
post, err := a.db.getPost(parsedURL.Path)
post, err := a.getPost(parsedURL.Path)
if err != nil {
a.serveError(w, r, err.Error(), http.StatusBadRequest)
return

View File

@ -42,7 +42,7 @@ func (a *goBlog) generateFeed(blog string, f feedType, w http.ResponseWriter, r
}
for _, p := range posts {
feed.Add(&feeds.Item{
Title: a.renderMdTitle(p.Title()),
Title: p.RenderedTitle,
Link: &feeds.Link{Href: a.fullPostURL(p)},
Description: a.postSummary(p),
Id: p.Path,

View File

@ -20,7 +20,7 @@ func (a *goBlog) serveGeoMap(w http.ResponseWriter, r *http.Request) {
blog := r.Context().Value(blogKey).(string)
bc := a.cfg.Blogs[blog]
allPostsWithLocation, err := a.db.getPosts(&postsRequestConfig{
allPostsWithLocation, err := a.getPosts(&postsRequestConfig{
blog: blog,
status: statusPublished,
parameter: a.cfg.Micropub.LocationParam,

View File

@ -33,30 +33,28 @@ func (a *goBlog) initMarkdown() {
emoji.Emoji,
),
}
publicAddress := ""
if srv := a.cfg.Server; srv != nil {
publicAddress = srv.PublicAddress
}
a.md = goldmark.New(append(defaultGoldmarkOptions, goldmark.WithExtensions(&customExtension{
absoluteLinks: false,
publicAddress: a.cfg.Server.PublicAddress,
publicAddress: publicAddress,
}))...)
a.absoluteMd = goldmark.New(append(defaultGoldmarkOptions, goldmark.WithExtensions(&customExtension{
absoluteLinks: true,
publicAddress: a.cfg.Server.PublicAddress,
publicAddress: publicAddress,
}))...)
a.titleMd = goldmark.New(
goldmark.WithParser(
// Override, no need for special Markdown parsers
parser.NewParser(
parser.WithBlockParsers(
util.Prioritized(parser.NewHTMLBlockParser(), 900),
util.Prioritized(parser.NewParagraphParser(), 1000)),
parser.WithInlineParsers(
util.Prioritized(parser.NewRawHTMLParser(), 400),
),
parser.WithInlineParsers(),
parser.WithParagraphTransformers(),
),
),
goldmark.WithRendererOptions(
html.WithUnsafe(),
),
goldmark.WithExtensions(
extension.Typographer,
emoji.Emoji,

View File

@ -73,6 +73,7 @@ func Test_markdown(t *testing.T) {
assert.Equal(t, "3. **Test**", app.renderMdTitle("3. **Test**"))
assert.Equal(t, "Tests", app.renderMdTitle("Test's"))
assert.Equal(t, "😂", app.renderMdTitle(":joy:"))
assert.Equal(t, "<b></b>", app.renderMdTitle("<b></b>"))
// Template func

View File

@ -40,7 +40,7 @@ func (a *goBlog) serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
a.serveError(w, r, err.Error(), http.StatusBadRequest)
return
}
p, err := a.db.getPost(u.Path)
p, err := a.getPost(u.Path)
if err != nil {
a.serveError(w, r, err.Error(), http.StatusBadRequest)
return
@ -49,7 +49,7 @@ func (a *goBlog) serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
} else {
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
posts, err := a.db.getPosts(&postsRequestConfig{
posts, err := a.getPosts(&postsRequestConfig{
limit: limit,
offset: offset,
})
@ -473,7 +473,7 @@ func (a *goBlog) micropubUpdate(w http.ResponseWriter, r *http.Request, u string
a.serveError(w, r, err.Error(), http.StatusBadRequest)
return
}
p, err := a.db.getPost(uu.Path)
p, err := a.getPost(uu.Path)
if err != nil {
a.serveError(w, r, err.Error(), http.StatusBadRequest)
return

View File

@ -30,6 +30,7 @@ type post struct {
Priority int
// Not persisted
Slug string
RenderedTitle string
renderCache map[bool]template.HTML
renderMutex sync.RWMutex
}
@ -45,7 +46,7 @@ const (
)
func (a *goBlog) servePost(w http.ResponseWriter, r *http.Request) {
p, err := a.db.getPost(r.URL.Path)
p, err := a.getPost(r.URL.Path)
if err == errPostNotFound {
a.serve404(w, r)
return
@ -89,12 +90,12 @@ func (a *goBlog) redirectToRandomPost(rw http.ResponseWriter, r *http.Request) {
type postPaginationAdapter struct {
config *postsRequestConfig
nums int64
db *database
a *goBlog
}
func (p *postPaginationAdapter) Nums() (int64, error) {
if p.nums == 0 {
nums, _ := p.db.countPosts(p.config)
nums, _ := p.a.db.countPosts(p.config)
p.nums = int64(nums)
}
return p.nums, nil
@ -105,7 +106,7 @@ func (p *postPaginationAdapter) Slice(offset, length int, data interface{}) erro
modifiedConfig.offset = offset
modifiedConfig.limit = length
posts, err := p.db.getPosts(&modifiedConfig)
posts, err := p.a.getPosts(&modifiedConfig)
reflect.ValueOf(data).Elem().Set(reflect.ValueOf(&posts).Elem())
return err
}
@ -247,7 +248,7 @@ func (a *goBlog) serveIndex(w http.ResponseWriter, r *http.Request) {
publishedDay: ic.day,
status: status,
priorityOrder: true,
}, db: a.db}, a.cfg.Blogs[blog].Pagination)
}, a: a}, a.cfg.Blogs[blog].Pagination)
p.SetPage(pageNo)
var posts []*post
err := p.Results(&posts)

View File

@ -190,7 +190,7 @@ func (db *database) savePost(p *post, o *postCreationOptions) error {
}
func (a *goBlog) deletePost(path string) error {
p, err := a.db.deletePost(path)
p, err := a.deletePostFromDb(path)
if err != nil || p == nil {
return err
}
@ -201,17 +201,17 @@ func (a *goBlog) deletePost(path string) error {
return nil
}
func (db *database) deletePost(path string) (*post, error) {
func (a *goBlog) deletePostFromDb(path string) (*post, error) {
if path == "" {
return nil, nil
}
db.pcm.Lock()
defer db.pcm.Unlock()
p, err := db.getPost(path)
a.db.pcm.Lock()
defer a.db.pcm.Unlock()
p, err := a.getPost(path)
if err != nil {
return nil, err
}
_, err = db.exec(
_, err = a.db.exec(
`begin;
delete from posts where path = ?;
delete from post_parameters where path = ?;
@ -222,7 +222,7 @@ func (db *database) deletePost(path string) (*post, error) {
if err != nil {
return nil, err
}
db.rebuildFTSIndex()
a.db.rebuildFTSIndex()
return p, nil
}
@ -389,10 +389,10 @@ func (d *database) loadPostParameters(posts []*post, parameters ...string) (err
return nil
}
func (d *database) getPosts(config *postsRequestConfig) (posts []*post, err error) {
func (a *goBlog) getPosts(config *postsRequestConfig) (posts []*post, err error) {
// Query posts
query, queryParams := buildPostsQuery(config, "path, coalesce(content, ''), coalesce(published, ''), coalesce(updated, ''), blog, coalesce(section, ''), status, priority")
rows, err := d.query(query, queryParams...)
rows, err := a.db.query(query, queryParams...)
if err != nil {
return nil, err
}
@ -417,16 +417,22 @@ func (d *database) getPosts(config *postsRequestConfig) (posts []*post, err erro
posts = append(posts, p)
}
if !config.withoutParameters {
err = d.loadPostParameters(posts, config.withOnlyParameters...)
err = a.db.loadPostParameters(posts, config.withOnlyParameters...)
if err != nil {
return nil, err
}
}
// Render post title
for _, p := range posts {
if t := p.Title(); t != "" {
p.RenderedTitle = a.renderMdTitle(t)
}
}
return posts, nil
}
func (d *database) getPost(path string) (*post, error) {
posts, err := d.getPosts(&postsRequestConfig{path: path, limit: 1})
func (a *goBlog) getPost(path string) (*post, error) {
posts, err := a.getPosts(&postsRequestConfig{path: path, limit: 1})
if err != nil {
return nil, err
} else if len(posts) == 0 {

View File

@ -29,6 +29,7 @@ func Test_postsDb(t *testing.T) {
},
}
_ = app.initDatabase(false)
app.initMarkdown()
now := toLocalSafe(time.Now().String())
nowPlus1Hour := toLocalSafe(time.Now().Add(1 * time.Hour).String())
@ -51,7 +52,7 @@ func Test_postsDb(t *testing.T) {
must.NoError(err)
// Check post
p, err := app.db.getPost("/test/abc")
p, err := app.getPost("/test/abc")
must.NoError(err)
is.Equal("/test/abc", p.Path)
is.Equal("ABC", p.Content)
@ -75,7 +76,7 @@ func Test_postsDb(t *testing.T) {
is.Len(pp, 0)
// Check drafts
drafts, _ := app.db.getPosts(&postsRequestConfig{
drafts, _ := app.getPosts(&postsRequestConfig{
blog: "en",
status: statusDraft,
})
@ -90,7 +91,7 @@ func Test_postsDb(t *testing.T) {
is.Equal(0, count)
// Delete post
_, err = app.db.deletePost("/test/abc")
_, err = app.deletePostFromDb("/test/abc")
must.NoError(err)
// Check that there is no post
@ -220,6 +221,7 @@ func Test_ftsWithoutTitle(t *testing.T) {
},
}
_ = app.initDatabase(false)
app.initMarkdown()
err := app.db.savePost(&post{
Path: "/test/abc",
@ -232,7 +234,7 @@ func Test_ftsWithoutTitle(t *testing.T) {
}, &postCreationOptions{new: true})
require.NoError(t, err)
ps, err := app.db.getPosts(&postsRequestConfig{
ps, err := app.getPosts(&postsRequestConfig{
search: "ABC",
})
assert.NoError(t, err)
@ -250,6 +252,7 @@ func Test_postsPriority(t *testing.T) {
},
}
_ = app.initDatabase(false)
app.initMarkdown()
err := app.db.savePost(&post{
Path: "/test/abc",
@ -272,7 +275,7 @@ func Test_postsPriority(t *testing.T) {
}, &postCreationOptions{new: true})
require.NoError(t, err)
ps, err := app.db.getPosts(&postsRequestConfig{
ps, err := app.getPosts(&postsRequestConfig{
priorityOrder: true,
})
require.NoError(t, err)

View File

@ -109,7 +109,7 @@ func (a *goBlog) postTranslations(p *post) []*post {
if translationkey == "" {
return nil
}
posts, err := a.db.getPosts(&postsRequestConfig{
posts, err := a.getPosts(&postsRequestConfig{
parameter: "translationkey",
parameterValue: translationkey,
})

View File

@ -153,7 +153,7 @@ func (a *goBlog) serveSitemapBlogPosts(w http.ResponseWriter, r *http.Request) {
// Create sitemap
sm := sitemap.New()
// Request posts
posts, _ := a.db.getPosts(&postsRequestConfig{
posts, _ := a.getPosts(&postsRequestConfig{
status: statusPublished,
blog: r.Context().Value(blogKey).(string),
withoutParameters: true,

View File

@ -16,7 +16,7 @@ const telegramBaseURL = "https://api.telegram.org/bot"
func (a *goBlog) initTelegram() {
a.pPostHooks = append(a.pPostHooks, func(p *post) {
if tg := a.cfg.Blogs[p.Blog].Telegram; tg.enabled() && p.isPublishedSectionPost() {
if html := tg.generateHTML(a.renderMdTitle(p.Title()), a.fullPostURL(p), a.shortPostURL(p)); html != "" {
if html := tg.generateHTML(p.RenderedTitle, a.fullPostURL(p), a.shortPostURL(p)); html != "" {
if err := a.send(tg, html, "HTML"); err != nil {
log.Printf("Failed to send post to Telegram: %v", err)
}

View File

@ -140,9 +140,7 @@ func Test_telegram(t *testing.T) {
p := &post{
Path: "/test",
Parameters: map[string][]string{
"title": {"Title"},
},
RenderedTitle: "Title",
Published: time.Now().String(),
Section: "test",
Blog: "en",

View File

@ -1,10 +1,10 @@
{{ define "photosummary" }}
<article class="h-entry border-bottom">
{{ if gt .Data.Priority 0 }}<p>📌 {{ string .Blog.Lang "pinned" }}</p>{{ end }}
{{ if .Data.Title }}
{{ if .Data.RenderedTitle }}
<h2 class="p-name">
<a class="u-url" href="{{ .Data.Path }}">
{{ mdtitle .Data.Title }}
{{ .Data.RenderedTitle }}
</a>
</h2>
{{ end }}

View File

@ -1,5 +1,5 @@
{{ define "title" }}
<title>{{ with .Data.Title }}{{ mdtitle . }} - {{end}}{{ mdtitle .Blog.Title }}</title>
<title>{{ with .Data.RenderedTitle }}{{ . }} - {{end}}{{ mdtitle .Blog.Title }}</title>
{{ include "postheadmeta" . }}
{{ with shorturl .Data }}<link rel="shortlink" href="{{ . }}">{{ end }}
{{ end }}
@ -8,7 +8,7 @@
<main class=h-entry>
<article>
<data class="u-url hide" value="{{ absolute .Data.Path }}"></data>
{{ with .Data.Title }}<h1 class=p-name>{{ mdtitle . }}</h1>{{ end }}
{{ with .Data.RenderedTitle }}<h1 class=p-name>{{ . }}</h1>{{ end }}
{{ include "postmeta" . }}
{{ include "postactions" . }}
{{ if .Data.Content }}

View File

@ -1,6 +1,6 @@
{{ define "postactions" }}
<div class="p flex" id="post-actions">
<a href="https://www.addtoany.com/share#url={{ absolute .Data.Path }}{{ with .Data.Title }}&title={{ mdtitle . }}{{ end }}" target="_blank" rel="nofollow noopener noreferrer" class="button">{{ string .Blog.Lang "share" }}</a>&nbsp;
<a href="https://www.addtoany.com/share#url={{ absolute .Data.Path }}{{ with .Data.RenderedTitle }}&title={{ . }}{{ end }}" target="_blank" rel="nofollow noopener noreferrer" class="button">{{ string .Blog.Lang "share" }}</a>&nbsp;
<a id="translateBtn" href="https://translate.google.com/translate?u={{ absolute .Data.Path }}" target="_blank" rel="nofollow noopener noreferrer" class="button">{{ string .Blog.Lang "translate" }}</a>&nbsp;
<script defer src="{{ asset "js/translate.js" }}"></script>
<button id="speakBtn" class="hide" data-speak="{{ string .Blog.Lang "speak" }}" data-stopspeak="{{ string .Blog.Lang "stopspeak" }}"></button>

View File

@ -3,9 +3,9 @@
<meta property="og:url" content="{{ . }}">
<meta property="twitter:url" content="{{ . }}">
{{ end }}
{{ with .Data.Title }}
<meta property="og:title" content="{{ mdtitle . }}">
<meta property="twitter:title" content="{{ mdtitle . }}">
{{ with .Data.RenderedTitle }}
<meta property="og:title" content="{{ . }}">
<meta property="twitter:title" content="{{ . }}">
{{ end }}
{{ with summary .Data }}
<meta name="description" content="{{ . }}">

View File

@ -3,7 +3,7 @@
{{ include "summaryandpostmeta" . }}
{{ $translations := (translations .Data) }}
{{ if gt (len $translations) 0 }}
<div>{{ string .Blog.Lang "translations" }}: {{ $delimiter := "" }}{{ range $i, $t := $translations }}{{ $delimiter }}<a href="{{ $t.Path }}" translate="no">{{ mdtitle $t.Title }}</a>{{ $delimiter = ", " }}{{ end }}</div>
<div>{{ string .Blog.Lang "translations" }}: {{ $delimiter := "" }}{{ range $i, $t := $translations }}{{ $delimiter }}<a href="{{ $t.Path }}" translate="no">{{ $t.RenderedTitle }}</a>{{ $delimiter = ", " }}{{ end }}</div>
{{ end }}
{{ $short := shorturl .Data }}
{{ if $short }}<div>{{ string .Blog.Lang "shorturl" }} <a href="{{ $short }}" rel="shortlink">{{ $short }}</a></div>{{ end }}

View File

@ -1,10 +1,10 @@
{{ define "summary" }}
<article class="h-entry border-bottom">
{{ if gt .Data.Priority 0 }}<p>📌 {{ string .Blog.Lang "pinned" }}</p>{{ end }}
{{ if .Data.Title }}
{{ if .Data.RenderedTitle }}
<h2 class="p-name">
<a class="u-url" href="{{ .Data.Path }}">
{{ mdtitle .Data.Title }}
{{ .Data.RenderedTitle }}
</a>
</h2>
{{ end }}