Loading static/components/pieces/Pagination.js +14 −2 Original line number Diff line number Diff line import PaginationControls from "./PaginationControls.js" const ELEMENTS_PER_PAGE = 25 export default { view(vnode) { // TODO Implement actually pages, not just a single page with only the first 100 elements. return vnode.attrs.elements.take(100).toArray() const elements = vnode.attrs.elements.toArray() const totalPages = Math.ceil(elements.length / ELEMENTS_PER_PAGE) const currentPageIndex = 0 const startIndex = currentPageIndex * ELEMENTS_PER_PAGE return [ elements.slice(startIndex, startIndex + ELEMENTS_PER_PAGE), // TODO Actually change the contents on page change m(PaginationControls, { currentPage: currentPageIndex + 1, totalPages, onPageChange: console.log }) ] } } static/model/SongListModel.jsdeleted 100644 → 0 +0 −145 Original line number Diff line number Diff line import Song from "./Song.js" const SongListModel = { currentPage: 1, itemsPerPage: 60, // Wie vom Benutzer angegeben totalPagesComputed: 1, onbeforeupdate: function (vnode, old) { if ( vnode.attrs.currentView !== old.attrs.currentView || (vnode.attrs.query || "") !== (old.attrs.query || "") ) { this.currentPage = 1 } return true }, onPageChange: function (newPage) { if (newPage >= 1 && newPage <= this.totalPagesComputed) { this.currentPage = newPage } }, getProcessedSongsForView: function (viewFilter, query) { let initialSongsForView = [] let messageFromTabFilter = null // Nachricht rein basierend auf Tab-Auswahl // 1. Songs basierend auf dem aktuellen Tab (View) filtern switch (viewFilter) { case "favorites": initialSongsForView = (Song.all || []).filter( song => song.favorite, ) if (initialSongsForView.length === 0) { // Überhaupt keine Favoriten messageFromTabFilter = "Du hast noch keine Favoriten markiert." } break case "popular": // initialSongsForView bleibt leer messageFromTabFilter = "Die Liste der beliebten Songs ist bald verfügbar!" break case "all": default: initialSongsForView = Song.all || [] if (initialSongsForView.length === 0) { messageFromTabFilter = "Keine Songs in der Bibliothek." } break } let songsAfterSearch = initialSongsForView.slice() let composedMessage = null // Endgültige Nachricht für den Benutzer // 2. Suchbegriff anwenden und Nachrichten erstellen const trimmedQuery = query ? query.trim() : "" if (trimmedQuery !== "") { const lowerQuery = trimmedQuery.toLowerCase() songsAfterSearch = initialSongsForView.filter( song => (song.title && song.title.toLowerCase().includes(lowerQuery)) || (song.artist && song.artist.toLowerCase().includes(lowerQuery)), ) if (viewFilter === "favorites") { const totalFavoritesOverall = initialSongsForView.length // Anzahl Favoriten vor der Suche const favoritesFoundBySearch = songsAfterSearch.length if (totalFavoritesOverall > 0) { if (favoritesFoundBySearch > 0) { composedMessage = { type: "filtered_favorites_some_hidden", showing: favoritesFoundBySearch, total: totalFavoritesOverall, } } else { composedMessage = { type: "filtered_favorites_none_found_by_search", total: totalFavoritesOverall, } } } } } else { // Kein Suchbegriff aktiv composedMessage = messageFromTabFilter } const totalFilteredItems = songsAfterSearch.length // Gesamtanzahl der Items nach Filterung/Suche (über alle Seiten) // 3. Paginierungslogik const totalPages = Math.ceil(totalFilteredItems / this.itemsPerPage) || 1 this.totalPagesComputed = totalPages // Sicherstellen, dass currentPage innerhalb gültiger Grenzen liegt if (this.currentPage > totalPages) this.currentPage = totalPages if (this.currentPage < 1) this.currentPage = 1 const startIndex = (this.currentPage - 1) * this.itemsPerPage const paginatedSongs = songsAfterSearch.slice( startIndex, startIndex + this.itemsPerPage, ) // 4. Songs für die aktuelle Seite nach Künstler gruppieren const groups = {} if (paginatedSongs.length > 0) { paginatedSongs.forEach(song => { groups[song.artist] = groups[song.artist] || [] groups[song.artist].push(song) }) } const sortedArtistNames = Object.keys(groups).sort((a, b) => a.localeCompare(b), ) const finalGroupedSongsOnPage = {} sortedArtistNames.forEach(artist => { finalGroupedSongsOnPage[artist] = groups[artist].sort((a, b) => a.title.localeCompare(b.title), ) }) // 5. Endgültige Nachricht, falls nach Filterung/Suche gar keine Items da sind (über alle Seiten) // und noch keine spezifischere Nachricht (z.B. Favoriten-Logik) gesetzt wurde. if (totalFilteredItems === 0 && !composedMessage) { composedMessage = "Keine Songs entsprechen den aktuellen Kriterien." } return { groupedSongs: finalGroupedSongsOnPage, message: composedMessage, hasContentOnPage: paginatedSongs.length > 0, currentPage: this.currentPage, totalPages: totalPages, totalFilteredItems: totalFilteredItems, } }, } export default SongListModel Loading
static/components/pieces/Pagination.js +14 −2 Original line number Diff line number Diff line import PaginationControls from "./PaginationControls.js" const ELEMENTS_PER_PAGE = 25 export default { view(vnode) { // TODO Implement actually pages, not just a single page with only the first 100 elements. return vnode.attrs.elements.take(100).toArray() const elements = vnode.attrs.elements.toArray() const totalPages = Math.ceil(elements.length / ELEMENTS_PER_PAGE) const currentPageIndex = 0 const startIndex = currentPageIndex * ELEMENTS_PER_PAGE return [ elements.slice(startIndex, startIndex + ELEMENTS_PER_PAGE), // TODO Actually change the contents on page change m(PaginationControls, { currentPage: currentPageIndex + 1, totalPages, onPageChange: console.log }) ] } }
static/model/SongListModel.jsdeleted 100644 → 0 +0 −145 Original line number Diff line number Diff line import Song from "./Song.js" const SongListModel = { currentPage: 1, itemsPerPage: 60, // Wie vom Benutzer angegeben totalPagesComputed: 1, onbeforeupdate: function (vnode, old) { if ( vnode.attrs.currentView !== old.attrs.currentView || (vnode.attrs.query || "") !== (old.attrs.query || "") ) { this.currentPage = 1 } return true }, onPageChange: function (newPage) { if (newPage >= 1 && newPage <= this.totalPagesComputed) { this.currentPage = newPage } }, getProcessedSongsForView: function (viewFilter, query) { let initialSongsForView = [] let messageFromTabFilter = null // Nachricht rein basierend auf Tab-Auswahl // 1. Songs basierend auf dem aktuellen Tab (View) filtern switch (viewFilter) { case "favorites": initialSongsForView = (Song.all || []).filter( song => song.favorite, ) if (initialSongsForView.length === 0) { // Überhaupt keine Favoriten messageFromTabFilter = "Du hast noch keine Favoriten markiert." } break case "popular": // initialSongsForView bleibt leer messageFromTabFilter = "Die Liste der beliebten Songs ist bald verfügbar!" break case "all": default: initialSongsForView = Song.all || [] if (initialSongsForView.length === 0) { messageFromTabFilter = "Keine Songs in der Bibliothek." } break } let songsAfterSearch = initialSongsForView.slice() let composedMessage = null // Endgültige Nachricht für den Benutzer // 2. Suchbegriff anwenden und Nachrichten erstellen const trimmedQuery = query ? query.trim() : "" if (trimmedQuery !== "") { const lowerQuery = trimmedQuery.toLowerCase() songsAfterSearch = initialSongsForView.filter( song => (song.title && song.title.toLowerCase().includes(lowerQuery)) || (song.artist && song.artist.toLowerCase().includes(lowerQuery)), ) if (viewFilter === "favorites") { const totalFavoritesOverall = initialSongsForView.length // Anzahl Favoriten vor der Suche const favoritesFoundBySearch = songsAfterSearch.length if (totalFavoritesOverall > 0) { if (favoritesFoundBySearch > 0) { composedMessage = { type: "filtered_favorites_some_hidden", showing: favoritesFoundBySearch, total: totalFavoritesOverall, } } else { composedMessage = { type: "filtered_favorites_none_found_by_search", total: totalFavoritesOverall, } } } } } else { // Kein Suchbegriff aktiv composedMessage = messageFromTabFilter } const totalFilteredItems = songsAfterSearch.length // Gesamtanzahl der Items nach Filterung/Suche (über alle Seiten) // 3. Paginierungslogik const totalPages = Math.ceil(totalFilteredItems / this.itemsPerPage) || 1 this.totalPagesComputed = totalPages // Sicherstellen, dass currentPage innerhalb gültiger Grenzen liegt if (this.currentPage > totalPages) this.currentPage = totalPages if (this.currentPage < 1) this.currentPage = 1 const startIndex = (this.currentPage - 1) * this.itemsPerPage const paginatedSongs = songsAfterSearch.slice( startIndex, startIndex + this.itemsPerPage, ) // 4. Songs für die aktuelle Seite nach Künstler gruppieren const groups = {} if (paginatedSongs.length > 0) { paginatedSongs.forEach(song => { groups[song.artist] = groups[song.artist] || [] groups[song.artist].push(song) }) } const sortedArtistNames = Object.keys(groups).sort((a, b) => a.localeCompare(b), ) const finalGroupedSongsOnPage = {} sortedArtistNames.forEach(artist => { finalGroupedSongsOnPage[artist] = groups[artist].sort((a, b) => a.title.localeCompare(b.title), ) }) // 5. Endgültige Nachricht, falls nach Filterung/Suche gar keine Items da sind (über alle Seiten) // und noch keine spezifischere Nachricht (z.B. Favoriten-Logik) gesetzt wurde. if (totalFilteredItems === 0 && !composedMessage) { composedMessage = "Keine Songs entsprechen den aktuellen Kriterien." } return { groupedSongs: finalGroupedSongsOnPage, message: composedMessage, hasContentOnPage: paginatedSongs.length > 0, currentPage: this.currentPage, totalPages: totalPages, totalFilteredItems: totalFilteredItems, } }, } export default SongListModel