mirror of
https://github.com/jlelse/GoBlog
synced 2024-06-14 14:17:09 +00:00
Improve blogstats and load table using JS (because it's slow)
This commit is contained in:
parent
026ae9469a
commit
59e491ee0a
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
@ -26,7 +27,8 @@ func serveBlogroll(w http.ResponseWriter, r *http.Request) {
|
|||
return getBlogrollOutlines(c)
|
||||
})
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
log.Println("Failed to get outlines:", err.Error())
|
||||
serveError(w, r, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if appConfig.Cache != nil && appConfig.Cache.Enable {
|
||||
|
@ -54,7 +56,8 @@ func serveBlogrollExport(w http.ResponseWriter, r *http.Request) {
|
|||
return getBlogrollOutlines(c)
|
||||
})
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
log.Println("Failed to get outlines:", err.Error())
|
||||
serveError(w, r, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if appConfig.Cache != nil && appConfig.Cache.Enable {
|
||||
|
|
20
blogstats.go
20
blogstats.go
|
@ -8,6 +8,18 @@ import (
|
|||
)
|
||||
|
||||
func serveBlogStats(w http.ResponseWriter, r *http.Request) {
|
||||
blog := r.Context().Value(blogContextKey).(string)
|
||||
canonical := blogPath(blog) + appConfig.Blogs[blog].BlogStats.Path
|
||||
render(w, r, templateBlogStats, &renderData{
|
||||
BlogString: blog,
|
||||
Canonical: canonical,
|
||||
Data: map[string]interface{}{
|
||||
"TableUrl": canonical + ".table.html",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func serveBlogStatsTable(w http.ResponseWriter, r *http.Request) {
|
||||
blog := r.Context().Value(blogContextKey).(string)
|
||||
// Start timing
|
||||
t := servertiming.FromContext(r.Context()).NewMetric("sq").Start()
|
||||
|
@ -17,6 +29,7 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) {
|
|||
status: statusPublished,
|
||||
}
|
||||
query, params := buildPostsQuery(prq)
|
||||
query = "select path, mdtext(content) as content, published, substr(published, 1, 4) as year, substr(published, 6, 2) as month from (" + query + ")"
|
||||
postCount := "coalesce(count(distinct path), 0) as postcount"
|
||||
charCount := "coalesce(sum(coalesce(length(distinct content), 0)), 0)"
|
||||
wordCount := "coalesce(sum(wordcount(distinct content)), 0) as wordcount"
|
||||
|
@ -36,7 +49,7 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
// Count posts per year
|
||||
rows, err := appDbQuery("select *, "+wordsPerPost+" from (select substr(published, 1, 4) as year, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' group by year order by year desc)", params...)
|
||||
rows, err := appDbQuery("select *, "+wordsPerPost+" from (select year, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' group by year order by year desc)", params...)
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -66,7 +79,7 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) {
|
|||
months := map[string][]statsTableType{}
|
||||
month := statsTableType{}
|
||||
for _, year := range years {
|
||||
rows, err = appDbQuery("select *, "+wordsPerPost+" from (select substr(published, 6, 2) as month, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' and substr(published, 1, 4) = @year group by month order by month desc)", append(params, sql.Named("year", year.Name))...)
|
||||
rows, err = appDbQuery("select *, "+wordsPerPost+" from (select month, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' and year = @year group by month order by month desc)", append(params, sql.Named("year", year.Name))...)
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -83,9 +96,8 @@ func serveBlogStats(w http.ResponseWriter, r *http.Request) {
|
|||
// Stop timing
|
||||
t.Stop()
|
||||
// Render
|
||||
render(w, r, templateBlogStats, &renderData{
|
||||
render(w, r, templateBlogStatsTable, &renderData{
|
||||
BlogString: blog,
|
||||
Canonical: blogPath(blog) + appConfig.Blogs[blog].BlogStats.Path,
|
||||
Data: map[string]interface{}{
|
||||
"total": total,
|
||||
"years": years,
|
||||
|
|
|
@ -25,6 +25,9 @@ func initDatabase() (err error) {
|
|||
if err := c.RegisterFunc("wordcount", wordCount, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.RegisterFunc("mdtext", renderText, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
|
7
http.go
7
http.go
|
@ -478,7 +478,12 @@ func buildDynamicRouter() (*chi.Mux, error) {
|
|||
// Stats
|
||||
if blogConfig.BlogStats != nil && blogConfig.BlogStats.Enabled {
|
||||
statsPath := blogPath + blogConfig.BlogStats.Path
|
||||
r.With(privateModeHandler...).With(cacheMiddleware, sbm).Get(statsPath, serveBlogStats)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(privateModeHandler...)
|
||||
r.Use(cacheMiddleware, sbm)
|
||||
r.Get(statsPath, serveBlogStats)
|
||||
r.Get(statsPath+".table.html", serveBlogStatsTable)
|
||||
})
|
||||
}
|
||||
|
||||
// Date archives
|
||||
|
|
13
markdown.go
13
markdown.go
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
kemoji "github.com/kyokomi/emoji/v2"
|
||||
"github.com/yuin/goldmark"
|
||||
emoji "github.com/yuin/goldmark-emoji"
|
||||
|
@ -54,6 +55,18 @@ func renderMarkdown(source string, absoluteLinks bool) (rendered []byte, err err
|
|||
return buffer.Bytes(), err
|
||||
}
|
||||
|
||||
func renderText(s string) string {
|
||||
h, err := renderMarkdown(s, false)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
d, err := goquery.NewDocumentFromReader(bytes.NewReader(h))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return d.Text()
|
||||
}
|
||||
|
||||
// Extensions etc...
|
||||
|
||||
// All emojis from emoji lib
|
||||
|
|
|
@ -35,6 +35,7 @@ const (
|
|||
templateLogin = "login"
|
||||
templateStaticHome = "statichome"
|
||||
templateBlogStats = "blogstats"
|
||||
templateBlogStatsTable = "blogstatstable"
|
||||
templateComment = "comment"
|
||||
templateCaptcha = "captcha"
|
||||
templateCommentsAdmin = "commentsadmin"
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
(function () {
|
||||
Array.from(document.getElementsByClassName('statsyear')).forEach(element => {
|
||||
element.addEventListener('click', function () {
|
||||
Array.from(document.getElementsByClassName('statsmonth')).forEach(c => {
|
||||
if (element.dataset.year == c.dataset.year) {
|
||||
c.classList.contains('hide') ? c.classList.remove('hide') : c.classList.add('hide')
|
||||
}
|
||||
let loadingEl = document.getElementById('loading')
|
||||
let tableUrl = loadingEl.dataset.table
|
||||
|
||||
let tableReq = new XMLHttpRequest()
|
||||
tableReq.open('GET', tableUrl)
|
||||
tableReq.onload = function() {
|
||||
if (tableReq.status == 200) {
|
||||
loadingEl.outerHTML = tableReq.responseText
|
||||
Array.from(document.getElementsByClassName('statsyear')).forEach(element => {
|
||||
element.addEventListener('click', function () {
|
||||
Array.from(document.getElementsByClassName('statsmonth')).forEach(c => {
|
||||
if (element.dataset.year == c.dataset.year) {
|
||||
c.classList.contains('hide') ? c.classList.remove('hide') : c.classList.add('hide')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
tableReq.send()
|
||||
})()
|
|
@ -6,52 +6,7 @@
|
|||
<main>
|
||||
{{ with .Blog.BlogStats.Title }}<h1>{{ . }}</h1>{{ end }}
|
||||
{{ with .Blog.BlogStats.Description }}{{ md . }}{{ end }}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tal">{{ string .Blog.Lang "year" }}</th>
|
||||
<th class="tar">{{ string .Blog.Lang "posts" }}</th>
|
||||
<th class="tar">~{{ string .Blog.Lang "chars" }}</th>
|
||||
<th class="tar">~{{ string .Blog.Lang "words" }}</th>
|
||||
<th class="tar">~{{ string .Blog.Lang "wordsperpost" }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ $months := .Data.months }}
|
||||
{{ range $year := .Data.years }}
|
||||
<tr class="statsyear" data-year="{{ $year.Name }}">
|
||||
<td class="tal">{{ $year.Name }}</td>
|
||||
<td class="tar">{{ $year.Posts }}</td>
|
||||
<td class="tar">{{ $year.Chars }}</td>
|
||||
<td class="tar">{{ $year.Words }}</td>
|
||||
<td class="tar">{{ $year.WordsPerPost }}</td>
|
||||
</tr>
|
||||
{{ range $month := (index $months $year.Name) }}
|
||||
<tr class="statsmonth hide" data-year="{{ $year.Name }}">
|
||||
<td class="tal">{{ $year.Name }}-{{ $month.Name }}</td>
|
||||
<td class="tar">{{ $month.Posts }}</td>
|
||||
<td class="tar">{{ $month.Chars }}</td>
|
||||
<td class="tar">{{ $month.Words }}</td>
|
||||
<td class="tar">{{ $month.WordsPerPost }}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<tr>
|
||||
<td class="tal">{{ string .Blog.Lang "withoutdate" }}</td>
|
||||
<td class="tar">{{ .Data.withoutdate.Posts }}</td>
|
||||
<td class="tar">{{ .Data.withoutdate.Chars }}</td>
|
||||
<td class="tar">{{ .Data.withoutdate.Words }}</td>
|
||||
<td class="tar">{{ .Data.withoutdate.WordsPerPost }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tal"><b>{{ string .Blog.Lang "total" }}</b></td>
|
||||
<td class="tar">{{ .Data.total.Posts }}</td>
|
||||
<td class="tar">{{ .Data.total.Chars }}</td>
|
||||
<td class="tar">{{ .Data.total.Words }}</td>
|
||||
<td class="tar">{{ .Data.total.WordsPerPost }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p id="loading" data-table="{{.Data.TableUrl}}">{{ string .Blog.Lang "loading" }}</p>
|
||||
<script defer src="{{ asset "js/blogstats.js" }}"></script>
|
||||
</main>
|
||||
{{ end }}
|
||||
|
|
48
templates/blogstatstable.gohtml
Normal file
48
templates/blogstatstable.gohtml
Normal file
|
@ -0,0 +1,48 @@
|
|||
{{ define "blogstatstable" }}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tal">{{ string .Blog.Lang "year" }}</th>
|
||||
<th class="tar">{{ string .Blog.Lang "posts" }}</th>
|
||||
<th class="tar">~{{ string .Blog.Lang "chars" }}</th>
|
||||
<th class="tar">~{{ string .Blog.Lang "words" }}</th>
|
||||
<th class="tar">~{{ string .Blog.Lang "wordsperpost" }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ $months := .Data.months }}
|
||||
{{ range $year := .Data.years }}
|
||||
<tr class="statsyear" data-year="{{ $year.Name }}">
|
||||
<td class="tal">{{ $year.Name }}</td>
|
||||
<td class="tar">{{ $year.Posts }}</td>
|
||||
<td class="tar">{{ $year.Chars }}</td>
|
||||
<td class="tar">{{ $year.Words }}</td>
|
||||
<td class="tar">{{ $year.WordsPerPost }}</td>
|
||||
</tr>
|
||||
{{ range $month := (index $months $year.Name) }}
|
||||
<tr class="statsmonth hide" data-year="{{ $year.Name }}">
|
||||
<td class="tal">{{ $year.Name }}-{{ $month.Name }}</td>
|
||||
<td class="tar">{{ $month.Posts }}</td>
|
||||
<td class="tar">{{ $month.Chars }}</td>
|
||||
<td class="tar">{{ $month.Words }}</td>
|
||||
<td class="tar">{{ $month.WordsPerPost }}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<tr>
|
||||
<td class="tal">{{ string .Blog.Lang "withoutdate" }}</td>
|
||||
<td class="tar">{{ .Data.withoutdate.Posts }}</td>
|
||||
<td class="tar">{{ .Data.withoutdate.Chars }}</td>
|
||||
<td class="tar">{{ .Data.withoutdate.Words }}</td>
|
||||
<td class="tar">{{ .Data.withoutdate.WordsPerPost }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tal"><b>{{ string .Blog.Lang "total" }}</b></td>
|
||||
<td class="tar">{{ .Data.total.Posts }}</td>
|
||||
<td class="tar">{{ .Data.total.Chars }}</td>
|
||||
<td class="tar">{{ .Data.total.Words }}</td>
|
||||
<td class="tar">{{ .Data.total.WordsPerPost }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{ end }}
|
|
@ -12,6 +12,7 @@ editor: "Editor"
|
|||
interactions: "Interaktionen & Kommentare"
|
||||
interactionslabel: "Hast du eine Antwort hierzu veröffentlicht? Füge hier die URL ein."
|
||||
likeof: "Gefällt mir von"
|
||||
loading: "Laden..."
|
||||
next: "Weiter"
|
||||
noposts: "Hier sind keine Posts."
|
||||
oldcontent: "⚠️ Dieser Eintrag ist bereits über ein Jahr alt. Er ist möglicherweise nicht mehr aktuell. Meinungen können sich geändert haben."
|
||||
|
|
|
@ -19,6 +19,7 @@ indieauth: "IndieAuth"
|
|||
interactions: "Interactions & Comments"
|
||||
interactionslabel: "Have you published a response to this? Paste the URL here."
|
||||
likeof: "Like of"
|
||||
loading: "Loading..."
|
||||
login: "Login"
|
||||
logout: "Logout"
|
||||
nameopt: "Name (optional)"
|
||||
|
|
Loading…
Reference in New Issue
Block a user