js/views/collection.js — the table and pagination
In the code column — js/views/collection.js. renderCollection() gets an already sorted and filtered list from getFilteredFavorites(), works out the pages, and slices out the current one.
The pagination maths is three lines:
const totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
const page = Math.min(currentPage, totalPages); // guard: page may be stale
const pageRows = rows.slice(start, start + pageSize);
Math.min(currentPage, totalPages) matters: if you were on page 5 and a search leaves only 2 pages, currentPage would still be 5 and the table would be empty. We "clamp" it to the real maximum.
The sort headers and initCollection are the delegation pattern again (lesson 3): one listener per header, calling setSort(column). The arrows (▲/▼) update from the current sortKey/sortDir.
Notice what's not here: not a single renderCollection() call after setSort/setPage. It isn't needed — they call notify(), and the main.js subscription (lesson 9) re-renders. The table only describes how the current state looks.
Tip.
renderPaginationdraws a button per page — fine for a few dozen. For thousands of rows you'd show only "1 … 5 6 7 … 40". But the principle is the same: page controls are a derived view of state (currentPage,totalPages), not separately stored state.