Files
Gardomatic/internal/web/pagination.go
T
kleiax 904d14b64c
CI / test (push) Canceled after 0s
Initial commit
2026-09-12 22:22:17 +02:00

82 lines
1.7 KiB
Go

package web
import (
"net/http"
"net/url"
"strconv"
)
const defaultCollectionPageSize = 20
type paginationData struct {
Page int
TotalPages int
PreviousURL string
NextURL string
}
func paginateCollection[T any](r *http.Request, values []T) ([]T, *paginationData) {
pageSize := collectionPageSize(r)
totalPages := (len(values) + pageSize - 1) / pageSize
if totalPages <= 1 {
return values, nil
}
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
if page < 1 {
page = 1
}
if page > totalPages {
page = totalPages
}
start := (page - 1) * pageSize
end := min(start+pageSize, len(values))
pagination := &paginationData{Page: page, TotalPages: totalPages}
if page > 1 {
pagination.PreviousURL = collectionPageURL(r.URL, page-1)
}
if page < totalPages {
pagination.NextURL = collectionPageURL(r.URL, page+1)
}
return values[start:end], pagination
}
func collectionPageSize(r *http.Request) int {
userSuffix := ""
if user, ok := userFromContext(r.Context()); ok {
userSuffix = "." + strconv.Itoa(user.ID)
}
for _, cookieName := range []string{"gardomatic.entries-per-page" + userSuffix, "gardomatic.tasks-per-page" + userSuffix} {
cookie, err := r.Cookie(cookieName)
if err != nil {
continue
}
pageSize, err := strconv.Atoi(cookie.Value)
if err == nil && validCollectionPageSize(pageSize) {
return pageSize
}
}
return defaultCollectionPageSize
}
func validCollectionPageSize(pageSize int) bool {
switch pageSize {
case 10, 20, 50, 100:
return true
default:
return false
}
}
func collectionPageURL(current *url.URL, page int) string {
query := current.Query()
query.Set("page", strconv.Itoa(page))
path := current.Path
if path == "" {
path = "?"
} else {
path += "?"
}
return path + query.Encode()
}