From f75501a72b4c0a527ced4b6da0ccd8d56e595a10 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Wed, 14 Mar 2018 16:15:35 +0100 Subject: [PATCH] Scrolling animelist --- pages/animelist/animelist.pixy | 109 ++++++++++++++++++--------------- pages/animelist/status.pixy | 8 +-- pages/embed/embed.pixy | 2 +- pages/home/animelist.go | 58 ++++++++++++++++-- pages/home/home.pixy | 4 +- pages/index.go | 6 ++ 6 files changed, 125 insertions(+), 62 deletions(-) diff --git a/pages/animelist/animelist.pixy b/pages/animelist/animelist.pixy index 70aa5c86..4e6cda70 100644 --- a/pages/animelist/animelist.pixy +++ b/pages/animelist/animelist.pixy @@ -16,77 +16,84 @@ component AnimeLists(animeLists map[string]*arn.AnimeList, viewUser *arn.User, u if len(animeLists[arn.AnimeListStatusWatching].Items) > 0 .anime-list-container h3.status-name Watching - AnimeList(animeLists[arn.AnimeListStatusWatching], viewUser, user) + AnimeList(animeLists[arn.AnimeListStatusWatching].Items, -1, viewUser, user) if len(animeLists[arn.AnimeListStatusCompleted].Items) > 0 .anime-list-container h3.status-name Completed - AnimeList(animeLists[arn.AnimeListStatusCompleted], viewUser, user) + AnimeList(animeLists[arn.AnimeListStatusCompleted].Items, -1, viewUser, user) if len(animeLists[arn.AnimeListStatusPlanned].Items) > 0 .anime-list-container h3.status-name Planned - AnimeList(animeLists[arn.AnimeListStatusPlanned], viewUser, user) + AnimeList(animeLists[arn.AnimeListStatusPlanned].Items, -1, viewUser, user) if len(animeLists[arn.AnimeListStatusHold].Items) > 0 .anime-list-container h3.status-name On hold - AnimeList(animeLists[arn.AnimeListStatusHold], viewUser, user) + AnimeList(animeLists[arn.AnimeListStatusHold].Items, -1, viewUser, user) if len(animeLists[arn.AnimeListStatusDropped].Items) > 0 .anime-list-container h3.status-name Dropped - AnimeList(animeLists[arn.AnimeListStatusDropped], viewUser, user) + AnimeList(animeLists[arn.AnimeListStatusDropped].Items, -1, viewUser, user) -component AnimeList(animeList *arn.AnimeList, viewUser *arn.User, user *arn.User) - .anime-list - each item in animeList.Items - .anime-list-item.mountable(title=item.Notes, data-api="/api/animelist/" + animeList.UserID + "/field/Items[AnimeID=\"" + item.AnimeID + "\"]") - .anime-list-item-image-container - a.anime-list-item-image-link.ajax(href=item.Anime().Link()) - img.anime-list-item-image.lazy(data-src=item.Anime().Image("small"), data-webp="true", alt=item.Anime().Title.ByUser(user)) +component AnimeList(animeListItems []*arn.AnimeListItem, nextIndex int, viewUser *arn.User, user *arn.User) + #load-more-target.anime-list + AnimeListScrollable(animeListItems, viewUser, user) + + if nextIndex != -1 + .buttons + LoadMore(nextIndex) - .anime-list-item-name - a.ajax(href=item.Link(animeList.User().Nick))= item.Anime().Title.ByUser(user) +component AnimeListScrollable(animeListItems []*arn.AnimeListItem, viewUser *arn.User, user *arn.User) + each item in animeListItems + .anime-list-item.mountable(title=item.Notes, data-api="/api/animelist/" + viewUser.ID + "/field/Items[AnimeID=\"" + item.AnimeID + "\"]") + .anime-list-item-image-container + a.anime-list-item-image-link.ajax(href=item.Anime().Link()) + img.anime-list-item-image.lazy(data-src=item.Anime().Image("small"), data-webp="true", alt=item.Anime().Title.ByUser(user)) - .anime-list-item-actions - if user != nil && item.Status == arn.AnimeListStatusWatching - //- if user.ID == "KpdWUlPzR" - //- a(href=arn.Nyaa.GetLink(item.Anime()), title="Search on Nyaa", target="_blank", rel="noopener") - //- RawIcon("download") - //- else - if item.Anime().EpisodeByNumber(item.Episodes + 1) != nil - for _, link := range item.Anime().EpisodeByNumber(item.Episodes + 1).Links - a(href=link, title="Watch episode " + toString(item.Episodes + 1) + " on twist.moe", target="_blank", rel="noopener") - RawIcon("eye") + .anime-list-item-name + a.ajax(href=item.Link(viewUser.Nick))= item.Anime().Title.ByUser(user) - .anime-list-item-airing-date - if (item.Status == arn.AnimeListStatusWatching || item.Status == arn.AnimeListStatusPlanned) && item.Anime().UpcomingEpisode() != nil - span.utc-airing-date(data-start-date=item.Anime().UpcomingEpisode().Episode.AiringDate.Start, data-end-date=item.Anime().UpcomingEpisode().Episode.AiringDate.End, data-episode-number=item.Anime().UpcomingEpisode().Episode.Number) + .anime-list-item-actions + if user != nil && item.Status == arn.AnimeListStatusWatching + //- if user.ID == "KpdWUlPzR" + //- a(href=arn.Nyaa.GetLink(item.Anime()), title="Search on Nyaa", target="_blank", rel="noopener") + //- RawIcon("download") + //- else + if item.Anime().EpisodeByNumber(item.Episodes + 1) != nil + for _, link := range item.Anime().EpisodeByNumber(item.Episodes + 1).Links + a(href=link, title="Watch episode " + toString(item.Episodes + 1) + " on twist.moe", target="_blank", rel="noopener") + RawIcon("eye") - if item.Status != arn.AnimeListStatusCompleted - .anime-list-item-episodes - .anime-list-item-episodes-watched - .action(contenteditable=utils.SameUser(user, viewUser), data-field="Episodes", data-type="number", data-trigger="focusout", data-action="save")= item.Episodes - - if item.Status == arn.AnimeListStatusWatching - .plus-episode.action(data-action="increaseEpisode", data-trigger="click") + - else - .plus-episode-dummy + + .anime-list-item-airing-date + if (item.Status == arn.AnimeListStatusWatching || item.Status == arn.AnimeListStatusPlanned) && item.Anime().UpcomingEpisode() != nil + span.utc-airing-date(data-start-date=item.Anime().UpcomingEpisode().Episode.AiringDate.Start, data-end-date=item.Anime().UpcomingEpisode().Episode.AiringDate.End, data-episode-number=item.Anime().UpcomingEpisode().Episode.Number) - .anime-list-item-episodes-separator / - .anime-list-item-episodes-max= item.Anime().EpisodeCountString() + if item.Status != arn.AnimeListStatusCompleted + .anime-list-item-episodes + .anime-list-item-episodes-watched + .action(contenteditable=utils.SameUser(user, viewUser), data-field="Episodes", data-type="number", data-trigger="focusout", data-action="save")= item.Episodes + + if item.Status == arn.AnimeListStatusWatching + .plus-episode.action(data-action="increaseEpisode", data-trigger="click") + + else + .plus-episode-dummy + - .anime-list-item-rating(title="Overall rating") - .action(contenteditable=utils.SameUser(user, viewUser), data-field="Rating.Overall", data-type="number", data-trigger="focusout", data-action="save")= utils.FormatRating(item.Rating.Overall) - - //- if item.Status == arn.AnimeListStatusCompleted - //- .anime-list-item-rating(title="Story rating") - //- span.rating-label S: - //- .action(contenteditable=utils.SameUser(user, viewUser), data-field="Rating.Story", data-type="number", data-trigger="focusout", data-action="save")= fmt.Sprintf("%.1f", item.Rating.Story) - //- .anime-list-item-rating(title="Visuals rating") - //- span.rating-label V: - //- .action(contenteditable=utils.SameUser(user, viewUser), data-field="Rating.Visuals", data-type="number", data-trigger="focusout", data-action="save")= fmt.Sprintf("%.1f", item.Rating.Visuals) - //- .anime-list-item-rating(title="Soundtrack rating") - //- span.rating-label M: - //- .action(contenteditable=utils.SameUser(user, viewUser), data-field="Rating.Soundtrack", data-type="number", data-trigger="focusout", data-action="save")= fmt.Sprintf("%.1f", item.Rating.Soundtrack) + .anime-list-item-episodes-separator / + .anime-list-item-episodes-max= item.Anime().EpisodeCountString() + + .anime-list-item-rating(title="Overall rating") + .action(contenteditable=utils.SameUser(user, viewUser), data-field="Rating.Overall", data-type="number", data-trigger="focusout", data-action="save")= utils.FormatRating(item.Rating.Overall) + + //- if item.Status == arn.AnimeListStatusCompleted + //- .anime-list-item-rating(title="Story rating") + //- span.rating-label S: + //- .action(contenteditable=utils.SameUser(user, viewUser), data-field="Rating.Story", data-type="number", data-trigger="focusout", data-action="save")= fmt.Sprintf("%.1f", item.Rating.Story) + //- .anime-list-item-rating(title="Visuals rating") + //- span.rating-label V: + //- .action(contenteditable=utils.SameUser(user, viewUser), data-field="Rating.Visuals", data-type="number", data-trigger="focusout", data-action="save")= fmt.Sprintf("%.1f", item.Rating.Visuals) + //- .anime-list-item-rating(title="Soundtrack rating") + //- span.rating-label M: + //- .action(contenteditable=utils.SameUser(user, viewUser), data-field="Rating.Soundtrack", data-type="number", data-trigger="focusout", data-action="save")= fmt.Sprintf("%.1f", item.Rating.Soundtrack) diff --git a/pages/animelist/status.pixy b/pages/animelist/status.pixy index 0b5a591e..e74b2890 100644 --- a/pages/animelist/status.pixy +++ b/pages/animelist/status.pixy @@ -1,12 +1,12 @@ component ProfileAnimeListFilteredByStatus(animeList *arn.AnimeList, viewUser *arn.User, user *arn.User, status string, uri string) ProfileHeader(viewUser, user, uri) - AnimeListFilteredByStatus(animeList, viewUser, user, status) + AnimeListFilteredByStatus(animeList.Items, -1, viewUser, user, status) -component AnimeListFilteredByStatus(animeList *arn.AnimeList, viewUser *arn.User, user *arn.User, status string) - if len(animeList.Items) == 0 +component AnimeListFilteredByStatus(animeListItems []*arn.AnimeListItem, nextIndex int, viewUser *arn.User, user *arn.User, status string) + if len(animeListItems) == 0 p.no-data.mountable= viewUser.Nick + " hasn't added any anime to this list yet." else .anime-list-container //- h3.status-name= arn.ListItemStatusName(status) - AnimeList(animeList, viewUser, user) \ No newline at end of file + AnimeList(animeListItems, nextIndex, viewUser, user) \ No newline at end of file diff --git a/pages/embed/embed.pixy b/pages/embed/embed.pixy index ec199041..8a2883c7 100644 --- a/pages/embed/embed.pixy +++ b/pages/embed/embed.pixy @@ -1,5 +1,5 @@ component BrowserExtension(watchingList *arn.AnimeList, viewUser *arn.User, user *arn.User) - AnimeList(watchingList, viewUser, user) + AnimeList(watchingList.Items, -1, viewUser, user) component ExtensionNavigation(user *arn.User) nav.extension-navigation diff --git a/pages/home/animelist.go b/pages/home/animelist.go index feb079c5..8ff418f4 100644 --- a/pages/home/animelist.go +++ b/pages/home/animelist.go @@ -8,8 +8,11 @@ import ( "github.com/animenotifier/notify.moe/components" "github.com/animenotifier/notify.moe/pages/frontpage" "github.com/animenotifier/notify.moe/utils" + "github.com/animenotifier/notify.moe/utils/infinitescroll" ) +const maxAnimeListItems = 50 + // FilterByStatus returns a handler for the given anime list item status. func FilterByStatus(status string) aero.Handle { return func(ctx *aero.Context) string { @@ -19,20 +22,67 @@ func FilterByStatus(status string) aero.Handle { return frontpage.Get(ctx) } - return AnimeList(ctx, user, status) + return AnimeListItems(ctx, user, status) } } -// AnimeList sends the anime list with the given status for given user. -func AnimeList(ctx *aero.Context, user *arn.User, status string) string { +// // AnimeList sends the anime list with the given status for given user. +// func AnimeList(ctx *aero.Context, user *arn.User, status string) string { +// viewUser := user +// animeList := viewUser.AnimeList() + +// if animeList == nil { +// return ctx.Error(http.StatusNotFound, "Anime list not found", nil) +// } + +// animeList = animeList.FilterStatus(status) +// animeList.Sort() +// items := animeList.Items + +// if len(items) > maxAnimeListItems { +// items = items[:maxAnimeListItems] +// } + +// fmt.Println(len(items)) + +// return ctx.HTML(components.Home(items, viewUser, user, status)) +// } + +// AnimeListItems renders the anime list items. +func AnimeListItems(ctx *aero.Context, user *arn.User, status string) string { viewUser := user + index, _ := ctx.GetInt("index") + + // Fetch all eligible items animeList := viewUser.AnimeList() if animeList == nil { return ctx.Error(http.StatusNotFound, "Anime list not found", nil) } + animeList = animeList.FilterStatus(status) + + // Sort the items animeList.Sort() - return ctx.HTML(components.Home(animeList.FilterStatus(status), viewUser, user, status)) + // These are all animer list items for the given status + allItems := animeList.Items + + // Slice the part that we need + items := allItems[index:] + + if len(items) > maxAnimeListItems { + items = items[:maxAnimeListItems] + } + + // Next index + nextIndex := infinitescroll.NextIndex(ctx, len(allItems), maxAnimeListItems, index) + + // In case we're scrolling, send items only (without the page frame) + if index > 0 { + return ctx.HTML(components.AnimeListScrollable(items, viewUser, user)) + } + + // Otherwise, send the full page + return ctx.HTML(components.Home(items, nextIndex, viewUser, user, status)) } diff --git a/pages/home/home.pixy b/pages/home/home.pixy index 6ab77741..52b0333b 100644 --- a/pages/home/home.pixy +++ b/pages/home/home.pixy @@ -1,3 +1,3 @@ -component Home(animeList *arn.AnimeList, viewUser *arn.User, user *arn.User, status string) +component Home(animeListItems []*arn.AnimeListItem, nextIndex int, viewUser *arn.User, user *arn.User, status string) StatusTabs("/animelist") - AnimeListFilteredByStatus(animeList, viewUser, user, status) \ No newline at end of file + AnimeListFilteredByStatus(animeListItems, nextIndex, viewUser, user, status) \ No newline at end of file diff --git a/pages/index.go b/pages/index.go index b03afe35..28eb446f 100644 --- a/pages/index.go +++ b/pages/index.go @@ -189,6 +189,12 @@ func Configure(app *aero.Application) { l.Page("/animelist/hold", home.FilterByStatus(arn.AnimeListStatusHold)) l.Page("/animelist/dropped", home.FilterByStatus(arn.AnimeListStatusDropped)) + l.Page("/animelist/watching/from/:index", home.FilterByStatus(arn.AnimeListStatusWatching)) + l.Page("/animelist/completed/from/:index", home.FilterByStatus(arn.AnimeListStatusCompleted)) + l.Page("/animelist/planned/from/:index", home.FilterByStatus(arn.AnimeListStatusPlanned)) + l.Page("/animelist/hold/from/:index", home.FilterByStatus(arn.AnimeListStatusHold)) + l.Page("/animelist/dropped/from/:index", home.FilterByStatus(arn.AnimeListStatusDropped)) + // Compare l.Page("/compare/animelist/:nick-1/:nick-2", compare.AnimeList)