Last active
July 9, 2023 19:07
-
-
Save kraftdorian/a942e51f391160b8cbc04b0bffb79ee8 to your computer and use it in GitHub Desktop.
Static-size items pagination
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// inspired by https://www.zacfukuda.com/blog/pagination-algorithm | |
// especialy, the left/right surrounding items idea | |
const PaginationItem = { | |
PreviousPage: Symbol('PaginationItem.PreviousPage'), | |
NextPage: Symbol('PaginationItem.NextPage'), | |
}; | |
function paginate( | |
currentPageNumber, | |
totalPagesNumber, | |
maxItemsSize = totalPagesNumber | |
) { | |
if (currentPageNumber > totalPagesNumber) { | |
throw new Error( | |
'current page number is not supposed to be greater than total pages number!' | |
); | |
} else if (maxItemsSize > totalPagesNumber) { | |
throw new Error( | |
'max items size is not supposed to be greater than total pages number!' | |
); | |
} | |
const items = Array.from( | |
{ length: Math.min(totalPagesNumber, maxItemsSize) }, | |
(_, idx) => idx + 1 | |
); | |
if (totalPagesNumber <= maxItemsSize) { | |
// if we have enough pages in total it's fine to return it early | |
return items; | |
} | |
let leftPtr = 0, | |
rightPtr = maxItemsSize - 1; | |
if (currentPageNumber >= 1 && currentPageNumber < totalPagesNumber) { | |
// we display next page item starting from the very first page, but not at the last page | |
items[rightPtr--] = PaginationItem.NextPage; | |
} | |
if (currentPageNumber > 1) { | |
// we display previous page item not at the first page, but until the last page | |
items[leftPtr++] = PaginationItem.PreviousPage; | |
} | |
if (currentPageNumber === 1) { | |
// start with the first page | |
items[leftPtr++] = currentPageNumber; | |
} else if (currentPageNumber > 1 && currentPageNumber < totalPagesNumber) { | |
const spacingRight = rightPtr - leftPtr; // everything without prev/next pages | |
// if current page with items displayed to the right overflows the max items, | |
// then start with first page that still includes the current page and the next/last one. | |
// otherwise it's OK to start with the current page | |
items[leftPtr++] = | |
currentPageNumber + spacingRight > totalPagesNumber | |
? Math.max(1, currentPageNumber - spacingRight + 1) | |
: currentPageNumber; | |
} else { | |
// start with the first page that still includes the last one | |
items[leftPtr++] = currentPageNumber - (rightPtr - leftPtr); | |
} | |
// once start page is established, just start counting by iterating over numeric items | |
for (leftPtr; leftPtr <= rightPtr; leftPtr++) { | |
items[leftPtr] = items[leftPtr - 1] + 1; | |
} | |
return items; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment