From 3e2594ab9f56960669d88c0fdb3c6c89ed25c21c Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Tue, 13 Mar 2018 22:38:26 +0100 Subject: [PATCH] Rewritten infinite scrolling --- pages/index.go | 8 ++-- pages/quotes/best.go | 59 +++++++---------------------- pages/quotes/fetch.go | 10 +++++ pages/quotes/quotes.go | 61 ++++++++---------------------- pages/quotes/quotes.pixy | 2 +- pages/soundtracks/best.go | 59 +++++++---------------------- pages/soundtracks/fetch.go | 12 ++++++ pages/soundtracks/soundtracks.go | 59 +++++++---------------------- pages/soundtracks/soundtracks.pixy | 6 +-- utils/infinitescroll/NextIndex.go | 21 ++++++++++ 10 files changed, 108 insertions(+), 189 deletions(-) create mode 100644 pages/quotes/fetch.go create mode 100644 pages/soundtracks/fetch.go create mode 100644 utils/infinitescroll/NextIndex.go diff --git a/pages/index.go b/pages/index.go index 7c6166c0..3fd7b32e 100644 --- a/pages/index.go +++ b/pages/index.go @@ -120,9 +120,9 @@ func Configure(app *aero.Application) { l.Page("/quote/:id/edit", quote.Edit) l.Page("/quote/:id/history", quote.History) l.Page("/quotes", quotes.Latest) - l.Page("/quotes/from/:index", quotes.LatestFrom) + l.Page("/quotes/from/:index", quotes.Latest) l.Page("/quotes/best", quotes.Best) - l.Page("/quotes/best/from/:index", quotes.BestFrom) + l.Page("/quotes/best/from/:index", quotes.Best) // Calendar l.Page("/calendar", calendar.Get) @@ -144,9 +144,9 @@ func Configure(app *aero.Application) { // Soundtracks l.Page("/soundtracks", soundtracks.Latest) - l.Page("/soundtracks/from/:index", soundtracks.LatestFrom) + l.Page("/soundtracks/from/:index", soundtracks.Latest) l.Page("/soundtracks/best", soundtracks.Best) - l.Page("/soundtracks/best/from/:index", soundtracks.BestFrom) + l.Page("/soundtracks/best/from/:index", soundtracks.Best) l.Page("/soundtracks/tag/:tag", soundtracks.FilterByTag) l.Page("/soundtracks/tag/:tag/from/:index", soundtracks.FilterByTagFrom) l.Page("/soundtrack/:id", soundtrack.Get) diff --git a/pages/quotes/best.go b/pages/quotes/best.go index f270b691..cc6f92bf 100644 --- a/pages/quotes/best.go +++ b/pages/quotes/best.go @@ -1,70 +1,39 @@ package quotes import ( - "net/http" - "strconv" - "github.com/aerogo/aero" "github.com/animenotifier/arn" "github.com/animenotifier/notify.moe/components" "github.com/animenotifier/notify.moe/utils" + "github.com/animenotifier/notify.moe/utils/infinitescroll" ) -// Best renders the quotes page ordered by the most favorites first. +// Best renders the best quotes. func Best(ctx *aero.Context) string { user := utils.GetUser(ctx) + index, _ := ctx.GetInt("index") - quotes := arn.FilterQuotes(func(track *arn.Quote) bool { - return !track.IsDraft - }) - - arn.SortQuotesPopularFirst(quotes) - - // Limit the number of displayed quotes - loadMoreIndex := 0 - - if len(quotes) > maxQuotes { - quotes = quotes[:maxQuotes] - loadMoreIndex = maxQuotes - } - - return ctx.HTML(components.Quotes(quotes, loadMoreIndex, user)) -} - -// BestFrom renders the quotes from the given index. -func BestFrom(ctx *aero.Context) string { - user := utils.GetUser(ctx) - index, err := ctx.GetInt("index") - - if err != nil { - return ctx.Error(http.StatusBadRequest, "Invalid start index", err) - } - - allQuotes := arn.FilterQuotes(func(track *arn.Quote) bool { - return !track.IsDraft - }) - - if index < 0 || index >= len(allQuotes) { - return ctx.Error(http.StatusBadRequest, "Invalid start index (maximum is "+strconv.Itoa(len(allQuotes))+")", nil) - } + // Fetch all eligible quotes + allQuotes := fetchAll() + // Sort the quotes by date arn.SortQuotesPopularFirst(allQuotes) + // Slice the part that we need quotes := allQuotes[index:] if len(quotes) > maxQuotes { quotes = quotes[:maxQuotes] } - nextIndex := index + maxQuotes + // Next index + nextIndex := infinitescroll.NextIndex(ctx, len(allQuotes), maxQuotes, index) - if nextIndex >= len(allQuotes) { - // End of data - no more scrolling - ctx.Response().Header().Set("X-LoadMore-Index", "-1") - } else { - // Send the index for the next request - ctx.Response().Header().Set("X-LoadMore-Index", strconv.Itoa(nextIndex)) + // In case we're scrolling, send quotes only (without the page frame) + if index > 0 { + return ctx.HTML(components.QuotesScrollable(quotes, user)) } - return ctx.HTML(components.QuotesScrollable(quotes, user)) + // Otherwise, send the full page + return ctx.HTML(components.Quotes(quotes, nextIndex, user)) } diff --git a/pages/quotes/fetch.go b/pages/quotes/fetch.go new file mode 100644 index 00000000..25dd7555 --- /dev/null +++ b/pages/quotes/fetch.go @@ -0,0 +1,10 @@ +package quotes + +import "github.com/animenotifier/arn" + +// fetchAll returns all quotes +func fetchAll() []*arn.Quote { + return arn.FilterQuotes(func(quote *arn.Quote) bool { + return !quote.IsDraft && len(quote.Text.English) > 0 + }) +} diff --git a/pages/quotes/quotes.go b/pages/quotes/quotes.go index e7c7ca02..84002c5c 100644 --- a/pages/quotes/quotes.go +++ b/pages/quotes/quotes.go @@ -1,72 +1,41 @@ package quotes import ( - "net/http" - "strconv" - "github.com/aerogo/aero" "github.com/animenotifier/arn" "github.com/animenotifier/notify.moe/components" "github.com/animenotifier/notify.moe/utils" + "github.com/animenotifier/notify.moe/utils/infinitescroll" ) -const maxQuotes = 9 +const maxQuotes = 12 -// Latest renders the quotes page. +// Latest renders the latest quotes. func Latest(ctx *aero.Context) string { user := utils.GetUser(ctx) + index, _ := ctx.GetInt("index") - quotes := arn.FilterQuotes(func(track *arn.Quote) bool { - return !track.IsDraft - }) - - arn.SortQuotesLatestFirst(quotes) - - // Limit the number of displayed quotes - loadMoreIndex := 0 - - if len(quotes) > maxQuotes { - quotes = quotes[:maxQuotes] - loadMoreIndex = maxQuotes - } - - return ctx.HTML(components.Quotes(quotes, loadMoreIndex, user)) -} - -// LatestFrom renders the quotes from the given index. -func LatestFrom(ctx *aero.Context) string { - user := utils.GetUser(ctx) - index, err := ctx.GetInt("index") - - if err != nil { - return ctx.Error(http.StatusBadRequest, "Invalid start index", err) - } - - allQuotes := arn.FilterQuotes(func(track *arn.Quote) bool { - return !track.IsDraft - }) - - if index < 0 || index >= len(allQuotes) { - return ctx.Error(http.StatusBadRequest, "Invalid start index (maximum is "+strconv.Itoa(len(allQuotes))+")", nil) - } + // Fetch all eligible quotes + allQuotes := fetchAll() + // Sort the quotes by date arn.SortQuotesLatestFirst(allQuotes) + // Slice the part that we need quotes := allQuotes[index:] if len(quotes) > maxQuotes { quotes = quotes[:maxQuotes] } - nextIndex := index + maxQuotes + // Next index + nextIndex := infinitescroll.NextIndex(ctx, len(allQuotes), maxQuotes, index) - if nextIndex >= len(allQuotes) { - // End of data - no more scrolling - ctx.Response().Header().Set("X-LoadMore-Index", "-1") - } else { - // Send the index for the next request - ctx.Response().Header().Set("X-LoadMore-Index", strconv.Itoa(nextIndex)) + // In case we're scrolling, send quotes only (without the page frame) + if index > 0 { + return ctx.HTML(components.QuotesScrollable(quotes, user)) } - return ctx.HTML(components.QuotesScrollable(quotes, user)) + // Otherwise, send the full page + return ctx.HTML(components.Quotes(quotes, nextIndex, user)) } diff --git a/pages/quotes/quotes.pixy b/pages/quotes/quotes.pixy index 22afa5ae..054672e7 100644 --- a/pages/quotes/quotes.pixy +++ b/pages/quotes/quotes.pixy @@ -17,7 +17,7 @@ component Quotes(quotes []*arn.Quote, loadMoreIndex int, user *arn.User) #load-more-target.quotes QuotesScrollable(quotes, user) - if loadMoreIndex != 0 + if loadMoreIndex != -1 .buttons LoadMore(loadMoreIndex) diff --git a/pages/soundtracks/best.go b/pages/soundtracks/best.go index 3395df4b..e0ee9b74 100644 --- a/pages/soundtracks/best.go +++ b/pages/soundtracks/best.go @@ -1,70 +1,39 @@ package soundtracks import ( - "net/http" - "strconv" - "github.com/aerogo/aero" "github.com/animenotifier/arn" "github.com/animenotifier/notify.moe/components" "github.com/animenotifier/notify.moe/utils" + "github.com/animenotifier/notify.moe/utils/infinitescroll" ) -// Best renders the soundtracks page. +// Best renders the best soundtracks. func Best(ctx *aero.Context) string { user := utils.GetUser(ctx) + index, _ := ctx.GetInt("index") - tracks := arn.FilterSoundTracks(func(track *arn.SoundTrack) bool { - return !track.IsDraft && len(track.Media) > 0 - }) - - arn.SortSoundTracksPopularFirst(tracks) - - // Limit the number of displayed tracks - loadMoreIndex := 0 - - if len(tracks) > maxTracks { - tracks = tracks[:maxTracks] - loadMoreIndex = maxTracks - } - - return ctx.HTML(components.SoundTracks(tracks, loadMoreIndex, "", user)) -} - -// BestFrom renders the soundtracks from the given index. -func BestFrom(ctx *aero.Context) string { - user := utils.GetUser(ctx) - index, err := ctx.GetInt("index") - - if err != nil { - return ctx.Error(http.StatusBadRequest, "Invalid start index", err) - } - - allTracks := arn.FilterSoundTracks(func(track *arn.SoundTrack) bool { - return !track.IsDraft && len(track.Media) > 0 - }) - - if index < 0 || index >= len(allTracks) { - return ctx.Error(http.StatusBadRequest, "Invalid start index (maximum is "+strconv.Itoa(len(allTracks))+")", nil) - } + // Fetch all eligible tracks + allTracks := fetchAll() + // Sort the tracks by date arn.SortSoundTracksPopularFirst(allTracks) + // Slice the part that we need tracks := allTracks[index:] if len(tracks) > maxTracks { tracks = tracks[:maxTracks] } - nextIndex := index + maxTracks + // Next index + nextIndex := infinitescroll.NextIndex(ctx, len(allTracks), maxTracks, index) - if nextIndex >= len(allTracks) { - // End of data - no more scrolling - ctx.Response().Header().Set("X-LoadMore-Index", "-1") - } else { - // Send the index for the next request - ctx.Response().Header().Set("X-LoadMore-Index", strconv.Itoa(nextIndex)) + // In case we're scrolling, send soundtracks only (without the page frame) + if index > 0 { + return ctx.HTML(components.SoundTracksScrollable(tracks, user)) } - return ctx.HTML(components.SoundTracksScrollable(tracks, user)) + // Otherwise, send the full page + return ctx.HTML(components.SoundTracks(tracks, nextIndex, "", user)) } diff --git a/pages/soundtracks/fetch.go b/pages/soundtracks/fetch.go new file mode 100644 index 00000000..9b3c6d26 --- /dev/null +++ b/pages/soundtracks/fetch.go @@ -0,0 +1,12 @@ +package soundtracks + +import ( + "github.com/animenotifier/arn" +) + +// fetchAll returns all soundtracks +func fetchAll() []*arn.SoundTrack { + return arn.FilterSoundTracks(func(track *arn.SoundTrack) bool { + return !track.IsDraft && len(track.Media) > 0 + }) +} diff --git a/pages/soundtracks/soundtracks.go b/pages/soundtracks/soundtracks.go index 8107a322..a8f47ffa 100644 --- a/pages/soundtracks/soundtracks.go +++ b/pages/soundtracks/soundtracks.go @@ -1,72 +1,41 @@ package soundtracks import ( - "net/http" - "strconv" - "github.com/aerogo/aero" "github.com/animenotifier/arn" "github.com/animenotifier/notify.moe/components" "github.com/animenotifier/notify.moe/utils" + "github.com/animenotifier/notify.moe/utils/infinitescroll" ) const maxTracks = 12 -// Latest renders the soundtracks page. +// Latest renders the latest soundtracks. func Latest(ctx *aero.Context) string { user := utils.GetUser(ctx) + index, _ := ctx.GetInt("index") - tracks := arn.FilterSoundTracks(func(track *arn.SoundTrack) bool { - return !track.IsDraft && len(track.Media) > 0 - }) - - arn.SortSoundTracksLatestFirst(tracks) - - // Limit the number of displayed tracks - loadMoreIndex := 0 - - if len(tracks) > maxTracks { - tracks = tracks[:maxTracks] - loadMoreIndex = maxTracks - } - - return ctx.HTML(components.SoundTracks(tracks, loadMoreIndex, "", user)) -} - -// LatestFrom renders the soundtracks from the given index. -func LatestFrom(ctx *aero.Context) string { - user := utils.GetUser(ctx) - index, err := ctx.GetInt("index") - - if err != nil { - return ctx.Error(http.StatusBadRequest, "Invalid start index", err) - } - - allTracks := arn.FilterSoundTracks(func(track *arn.SoundTrack) bool { - return !track.IsDraft && len(track.Media) > 0 - }) - - if index < 0 || index >= len(allTracks) { - return ctx.Error(http.StatusBadRequest, "Invalid start index (maximum is "+strconv.Itoa(len(allTracks))+")", nil) - } + // Fetch all eligible tracks + allTracks := fetchAll() + // Sort the tracks by date arn.SortSoundTracksLatestFirst(allTracks) + // Slice the part that we need tracks := allTracks[index:] if len(tracks) > maxTracks { tracks = tracks[:maxTracks] } - nextIndex := index + maxTracks + // Next index + nextIndex := infinitescroll.NextIndex(ctx, len(allTracks), maxTracks, index) - if nextIndex >= len(allTracks) { - // End of data - no more scrolling - ctx.Response().Header().Set("X-LoadMore-Index", "-1") - } else { - // Send the index for the next request - ctx.Response().Header().Set("X-LoadMore-Index", strconv.Itoa(nextIndex)) + // In case we're scrolling, send soundtracks only (without the page frame) + if index > 0 { + return ctx.HTML(components.SoundTracksScrollable(tracks, user)) } - return ctx.HTML(components.SoundTracksScrollable(tracks, user)) + // Otherwise, send the full page + return ctx.HTML(components.SoundTracks(tracks, nextIndex, "", user)) } diff --git a/pages/soundtracks/soundtracks.pixy b/pages/soundtracks/soundtracks.pixy index b85717f7..033b7953 100644 --- a/pages/soundtracks/soundtracks.pixy +++ b/pages/soundtracks/soundtracks.pixy @@ -1,4 +1,4 @@ -component SoundTracks(tracks []*arn.SoundTrack, loadMoreIndex int, tag string, user *arn.User) +component SoundTracks(tracks []*arn.SoundTrack, nextIndex int, tag string, user *arn.User) h1.page-title Soundtracks SoundTracksTabs(tag) @@ -17,9 +17,9 @@ component SoundTracks(tracks []*arn.SoundTrack, loadMoreIndex int, tag string, u #load-more-target.soundtracks SoundTracksScrollable(tracks, user) - if loadMoreIndex != 0 + if nextIndex != -1 .buttons - LoadMore(loadMoreIndex) + LoadMore(nextIndex) component SoundTracksScrollable(tracks []*arn.SoundTrack, user *arn.User) each track in tracks diff --git a/utils/infinitescroll/NextIndex.go b/utils/infinitescroll/NextIndex.go new file mode 100644 index 00000000..de30ccaf --- /dev/null +++ b/utils/infinitescroll/NextIndex.go @@ -0,0 +1,21 @@ +package infinitescroll + +import ( + "strconv" + + "github.com/aerogo/aero" +) + +// NextIndex calculates the next index and sends HTTP header +func NextIndex(ctx *aero.Context, allElementsLength int, elementsPerScroll int, index int) int { + nextIndex := index + elementsPerScroll + + if nextIndex >= allElementsLength { + nextIndex = -1 + } + + // Send the index for the next request + ctx.Response().Header().Set("X-LoadMore-Index", strconv.Itoa(nextIndex)) + + return nextIndex +}