mirror of
https://github.com/writefreely/writefreely
synced 2025-02-17 16:28:23 +00:00
Merge pull request #438 from Dak425/paginate-tag-collection
Add pagination to tag subpages
This commit is contained in:
commit
dff01a6136
4 changed files with 99 additions and 4 deletions
|
@ -610,6 +610,30 @@ type CollectionPage struct {
|
||||||
CollAlias string
|
CollAlias string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TagCollectionPage struct {
|
||||||
|
CollectionPage
|
||||||
|
Tag string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tcp TagCollectionPage) PrevPageURL(prefix string, n int, tl bool) string {
|
||||||
|
u := fmt.Sprintf("/tag:%s", tcp.Tag)
|
||||||
|
if n > 2 {
|
||||||
|
u += fmt.Sprintf("/page/%d", n-1)
|
||||||
|
}
|
||||||
|
if tl {
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
return "/" + prefix + tcp.Alias + u
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tcp TagCollectionPage) NextPageURL(prefix string, n int, tl bool) string {
|
||||||
|
if tl {
|
||||||
|
return fmt.Sprintf("/tag:%s/page/%d", tcp.Tag, n+1)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("/%s%s/tag:%s/page/%d", prefix, tcp.Alias, tcp.Tag, n+1)
|
||||||
|
}
|
||||||
|
|
||||||
func NewCollectionObj(c *Collection) *CollectionObj {
|
func NewCollectionObj(c *Collection) *CollectionObj {
|
||||||
return &CollectionObj{
|
return &CollectionObj{
|
||||||
Collection: *c,
|
Collection: *c,
|
||||||
|
@ -951,16 +975,29 @@ func handleViewCollectionTag(app *App, w http.ResponseWriter, r *http.Request) e
|
||||||
|
|
||||||
coll := newDisplayCollection(c, cr, page)
|
coll := newDisplayCollection(c, cr, page)
|
||||||
|
|
||||||
|
taggedPostIDs, err := app.db.GetAllPostsTaggedIDs(c, tag, cr.isCollOwner)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ttlPosts := len(taggedPostIDs)
|
||||||
|
pagePosts := coll.Format.PostsPerPage()
|
||||||
|
coll.TotalPages = int(math.Ceil(float64(ttlPosts) / float64(pagePosts)))
|
||||||
|
if coll.TotalPages > 0 && page > coll.TotalPages {
|
||||||
|
redirURL := fmt.Sprintf("/page/%d", coll.TotalPages)
|
||||||
|
if !app.cfg.App.SingleUser {
|
||||||
|
redirURL = fmt.Sprintf("/%s%s%s", cr.prefix, coll.Alias, redirURL)
|
||||||
|
}
|
||||||
|
return impart.HTTPError{http.StatusFound, redirURL}
|
||||||
|
}
|
||||||
|
|
||||||
coll.Posts, _ = app.db.GetPostsTagged(app.cfg, c, tag, page, cr.isCollOwner)
|
coll.Posts, _ = app.db.GetPostsTagged(app.cfg, c, tag, page, cr.isCollOwner)
|
||||||
if coll.Posts != nil && len(*coll.Posts) == 0 {
|
if coll.Posts != nil && len(*coll.Posts) == 0 {
|
||||||
return ErrCollectionPageNotFound
|
return ErrCollectionPageNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve collection
|
// Serve collection
|
||||||
displayPage := struct {
|
displayPage := TagCollectionPage{
|
||||||
CollectionPage
|
|
||||||
Tag string
|
|
||||||
}{
|
|
||||||
CollectionPage: CollectionPage{
|
CollectionPage: CollectionPage{
|
||||||
DisplayCollection: coll,
|
DisplayCollection: coll,
|
||||||
StaticPage: pageForReq(app, r),
|
StaticPage: pageForReq(app, r),
|
||||||
|
|
46
database.go
46
database.go
|
@ -113,6 +113,7 @@ type writestore interface {
|
||||||
|
|
||||||
GetPostsCount(c *CollectionObj, includeFuture bool)
|
GetPostsCount(c *CollectionObj, includeFuture bool)
|
||||||
GetPosts(cfg *config.Config, c *Collection, page int, includeFuture, forceRecentFirst, includePinned bool) (*[]PublicPost, error)
|
GetPosts(cfg *config.Config, c *Collection, page int, includeFuture, forceRecentFirst, includePinned bool) (*[]PublicPost, error)
|
||||||
|
GetAllPostsTaggedIDs(c *Collection, tag string, includeFuture bool) ([]string, error)
|
||||||
GetPostsTagged(cfg *config.Config, c *Collection, tag string, page int, includeFuture bool) (*[]PublicPost, error)
|
GetPostsTagged(cfg *config.Config, c *Collection, tag string, page int, includeFuture bool) (*[]PublicPost, error)
|
||||||
|
|
||||||
GetAPFollowers(c *Collection) (*[]RemoteUser, error)
|
GetAPFollowers(c *Collection) (*[]RemoteUser, error)
|
||||||
|
@ -1195,6 +1196,51 @@ func (db *datastore) GetPosts(cfg *config.Config, c *Collection, page int, inclu
|
||||||
return &posts, nil
|
return &posts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *datastore) GetAllPostsTaggedIDs(c *Collection, tag string, includeFuture bool) ([]string, error) {
|
||||||
|
collID := c.ID
|
||||||
|
|
||||||
|
cf := c.NewFormat()
|
||||||
|
order := "DESC"
|
||||||
|
if cf.Ascending() {
|
||||||
|
order = "ASC"
|
||||||
|
}
|
||||||
|
|
||||||
|
timeCondition := ""
|
||||||
|
if !includeFuture {
|
||||||
|
timeCondition = "AND created <= NOW()"
|
||||||
|
}
|
||||||
|
var rows *sql.Rows
|
||||||
|
var err error
|
||||||
|
if db.driverName == driverSQLite {
|
||||||
|
rows, err = db.Query("SELECT id FROM posts WHERE collection_id = ? AND LOWER(content) regexp ? "+timeCondition+" ORDER BY created "+order, collID, `.*#`+strings.ToLower(tag)+`\b.*`)
|
||||||
|
} else {
|
||||||
|
rows, err = db.Query("SELECT id FROM posts WHERE collection_id = ? AND LOWER(content) RLIKE ? "+timeCondition+" ORDER BY created "+order, collID, "#"+strings.ToLower(tag)+"[[:>:]]")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed selecting tagged posts: %v", err)
|
||||||
|
return nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't retrieve tagged collection posts."}
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
ids := []string{}
|
||||||
|
for rows.Next() {
|
||||||
|
var id string
|
||||||
|
err = rows.Scan(&id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed scanning row: %v", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error after Next() on rows: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetPostsTagged retrieves all posts on the given Collection that contain the
|
// GetPostsTagged retrieves all posts on the given Collection that contain the
|
||||||
// given tag.
|
// given tag.
|
||||||
// It will return future posts if `includeFuture` is true.
|
// It will return future posts if `includeFuture` is true.
|
||||||
|
|
|
@ -217,6 +217,7 @@ func RouteCollections(handler *Handler, r *mux.Router) {
|
||||||
r.HandleFunc("/logout", handler.Web(handleLogOutCollection, UserLevelOptional))
|
r.HandleFunc("/logout", handler.Web(handleLogOutCollection, UserLevelOptional))
|
||||||
r.HandleFunc("/page/{page:[0-9]+}", handler.Web(handleViewCollection, UserLevelReader))
|
r.HandleFunc("/page/{page:[0-9]+}", handler.Web(handleViewCollection, UserLevelReader))
|
||||||
r.HandleFunc("/tag:{tag}", handler.Web(handleViewCollectionTag, UserLevelReader))
|
r.HandleFunc("/tag:{tag}", handler.Web(handleViewCollectionTag, UserLevelReader))
|
||||||
|
r.HandleFunc("/tag:{tag}/page/{page:[0-9]+}", handler.Web(handleViewCollectionTag, UserLevelReader))
|
||||||
r.HandleFunc("/tag:{tag}/feed/", handler.Web(ViewFeed, UserLevelReader))
|
r.HandleFunc("/tag:{tag}/feed/", handler.Web(ViewFeed, UserLevelReader))
|
||||||
r.HandleFunc("/sitemap.xml", handler.AllReader(handleViewSitemap))
|
r.HandleFunc("/sitemap.xml", handler.AllReader(handleViewSitemap))
|
||||||
r.HandleFunc("/feed/", handler.AllReader(ViewFeed))
|
r.HandleFunc("/feed/", handler.AllReader(ViewFeed))
|
||||||
|
|
|
@ -61,6 +61,17 @@
|
||||||
{{if .Posts}}<section id="wrapper" itemscope itemtype="http://schema.org/Blog">{{else}}<div id="wrapper">{{end}}
|
{{if .Posts}}<section id="wrapper" itemscope itemtype="http://schema.org/Blog">{{else}}<div id="wrapper">{{end}}
|
||||||
<h1>{{.Tag}}</h1>
|
<h1>{{.Tag}}</h1>
|
||||||
{{template "posts" .}}
|
{{template "posts" .}}
|
||||||
|
|
||||||
|
{{if gt .TotalPages 1}}<nav id="paging" class="content-container clearfix">
|
||||||
|
{{if or (and .Format.Ascending (lt .CurrentPage .TotalPages)) (isRTL .Direction)}}
|
||||||
|
{{if gt .CurrentPage 1}}<a href="{{.PrevPageURL .Prefix .CurrentPage .IsTopLevel}}">⇠ {{if and .Format.Ascending (lt .CurrentPage .TotalPages)}}Previous{{else}}Newer{{end}}</a>{{end}}
|
||||||
|
{{if lt .CurrentPage .TotalPages}}<a style="float:right;" href="{{.NextPageURL .Prefix .CurrentPage .IsTopLevel}}">{{if and .Format.Ascending (lt .CurrentPage .TotalPages)}}Next{{else}}Older{{end}} ⇢</a>{{end}}
|
||||||
|
{{else}}
|
||||||
|
{{if lt .CurrentPage .TotalPages}}<a href="{{.NextPageURL .Prefix .CurrentPage .IsTopLevel}}">⇠ Older</a>{{end}}
|
||||||
|
{{if gt .CurrentPage 1}}<a style="float:right;" href="{{.PrevPageURL .Prefix .CurrentPage .IsTopLevel}}">Newer ⇢</a>{{end}}
|
||||||
|
{{end}}
|
||||||
|
</nav>{{end}}
|
||||||
|
|
||||||
{{if .Posts}}</section>{{else}}</div>{{end}}
|
{{if .Posts}}</section>{{else}}</div>{{end}}
|
||||||
|
|
||||||
{{ if .Collection.ShowFooterBranding }}
|
{{ if .Collection.ShowFooterBranding }}
|
||||||
|
|
Loading…
Add table
Reference in a new issue