mirror of https://github.com/jlelse/GoBlog
Further improve post title rendering
This commit is contained in:
parent
4c1f7fcde4
commit
4c8c147c4c
|
@ -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 {
|
||||
|
|
2
check.go
2
check.go
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
2
feeds.go
2
feeds.go
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
16
markdown.go
16
markdown.go
|
@ -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,
|
||||
|
|
|
@ -73,6 +73,7 @@ func Test_markdown(t *testing.T) {
|
|||
assert.Equal(t, "3. **Test**", app.renderMdTitle("3. **Test**"))
|
||||
assert.Equal(t, "Test’s", app.renderMdTitle("Test's"))
|
||||
assert.Equal(t, "😂", app.renderMdTitle(":joy:"))
|
||||
assert.Equal(t, "<b></b>", app.renderMdTitle("<b></b>"))
|
||||
|
||||
// Template func
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
11
posts.go
11
posts.go
|
@ -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)
|
||||
|
|
30
postsDb.go
30
postsDb.go
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
@ -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="{{ . }}">
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
Loading…
Reference in New Issue