-
-
Save a-am/117eb6dd77285d290eaf1b4ec8038ca1 to your computer and use it in GitHub Desktop.
Simple pagination algorithm
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
// Implementation in ES6 | |
function pagination(c, m) { | |
var current = c, | |
last = m, | |
delta = 2, | |
left = current - delta, | |
right = current + delta + 1, | |
range = [], | |
rangeWithDots = [], | |
l; | |
for (let i = 1; i <= last; i++) { | |
if (i == 1 || i == last || i >= left && i < right) { | |
range.push(i); | |
} | |
} | |
for (let i of range) { | |
if (l) { | |
if (i - l === 2) { | |
rangeWithDots.push(l + 1); | |
} else if (i - l !== 1) { | |
rangeWithDots.push('...'); | |
} | |
} | |
rangeWithDots.push(i); | |
l = i; | |
} | |
return rangeWithDots; | |
} | |
/* | |
Test it: | |
for (let i = 1, l = 20; i <= l; i++) | |
console.log(`Selected page ${i}:`, pagination(i, l)); | |
Expected output: | |
Selected page 1: [1, 2, 3, "...", 20] | |
Selected page 2: [1, 2, 3, 4, "...", 20] | |
Selected page 3: [1, 2, 3, 4, 5, "...", 20] | |
Selected page 4: [1, 2, 3, 4, 5, 6, "...", 20] | |
Selected page 5: [1, 2, 3, 4, 5, 6, 7, "...", 20] | |
Selected page 6: [1, "...", 4, 5, 6, 7, 8, "...", 20] | |
Selected page 7: [1, "...", 5, 6, 7, 8, 9, "...", 20] | |
Selected page 8: [1, "...", 6, 7, 8, 9, 10, "...", 20] | |
Selected page 9: [1, "...", 7, 8, 9, 10, 11, "...", 20] | |
Selected page 10: [1, "...", 8, 9, 10, 11, 12, "...", 20] | |
Selected page 11: [1, "...", 9, 10, 11, 12, 13, "...", 20] | |
Selected page 12: [1, "...", 10, 11, 12, 13, 14, "...", 20] | |
Selected page 13: [1, "...", 11, 12, 13, 14, 15, "...", 20] | |
Selected page 14: [1, "...", 12, 13, 14, 15, 16, "...", 20] | |
Selected page 15: [1, "...", 13, 14, 15, 16, 17, "...", 20] | |
Selected page 16: [1, "...", 14, 15, 16, 17, 18, 19, 20] | |
Selected page 17: [1, "...", 15, 16, 17, 18, 19, 20] | |
Selected page 18: [1, "...", 16, 17, 18, 19, 20] | |
Selected page 19: [1, "...", 17, 18, 19, 20] | |
Selected page 20: [1, "...", 18, 19, 20] | |
*/ |
/**
* Generates an array to be used for pagination
* @param {number} current - The current page
* @param {number} last - The last possible page in the paged list
* @returns {array} List of desired page numbers with ellipsis for unimportant pages
*/
function generatePagination(current, last) {
const offset = 2;
const leftOffset = current - offset;
const rightOffset = current + offset + 1;
/**
* Reduces a list into the page numbers desired in the pagination
* @param {array} accumulator - Growing list of desired page numbers
* @param {*} _ - Throwaway variable to ignore the current value in iteration
* @param {*} idx - The index of the current iteration
* @returns {array} The accumulating list of desired page numbers
*/
function reduceToDesiredPageNumbers(accumulator, _, idx) {
const currIdx = idx + 1;
if (
// Always include first page
currIdx === 1
// Always include last page
|| currIdx === last
// Include if index is between the above defined offsets
|| (currIdx >= leftOffset && currIdx < rightOffset)) {
return [
...accumulator,
currIdx,
];
}
return accumulator;
}
/**
* Transforms a list of desired pages and puts ellipsis in any gaps
* @param {array} accumulator - The growing list of page numbers with ellipsis included
* @param {number} currentPage - The current page in iteration
* @param {number} currIdx - The current index
* @param {array} src - The source array the function was called on
*/
function transformToPagesWithEllipsis(accumulator, currentPage, currIdx, src) {
const prev = src[currIdx - 1];
// Ignore the first number, as we always want the first page
// Include an ellipsis if there is a gap of more than one between numbers
if (prev != null && currentPage - prev !== 1) {
return [
...accumulator,
'...',
currentPage,
];
}
// If page does not meet above requirement, just add it to the list
return [
...accumulator,
currentPage,
];
}
const pageNumbers = Array(last)
.fill()
.reduce(reduceToDesiredPageNumbers, []);
const pageNumbersWithEllipsis = pageNumbers.reduce(transformToPagesWithEllipsis, []);
return pageNumbersWithEllipsis;
}
The output is only different in that it keeps consistent with the two number offset in either direction. See the unit test:
expect(generatePagination(10, 50)).toEqual([1, '...', 8, 9, 10, 11, 12, '...', 50]);
expect(generatePagination(50, 50)).toEqual([1, '...', 48, 49, 50]);
expect(generatePagination(49, 50)).toEqual([1, '...', 47, 48, 49, 50]);
expect(generatePagination(45, 50)).toEqual([1, '...', 43, 44, 45, 46, 47, '...', 50]);
expect(generatePagination(30, 50)).toEqual([1, '...', 28, 29, 30, 31, 32, '...', 50]);
expect(generatePagination(6, 50)).toEqual([1, '...', 4, 5, 6, 7, 8, '...', 50]);
expect(generatePagination(5, 50)).toEqual([1, '...', 3, 4, 5, 6, 7, '...', 50]);
expect(generatePagination(4, 50)).toEqual([1, 2, 3, 4, 5, 6, '...', 50]);
expect(generatePagination(3, 50)).toEqual([1, 2, 3, 4, 5, '...', 50]);
expect(generatePagination(2, 50)).toEqual([1, 2, 3, 4, '...', 50]);
expect(generatePagination(1, 50)).toEqual([1, 2, 3, '...', 50]);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Javascript ES2019 functional version.
Same output as gist's. Remove 2: [a + 1, b] line if you prefer a constant distance from current page ([1, "...", 2, 3, 4] over [1, 2, 3, 4, 5]).