-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revise selection of pagination items
Revise the calculation of the set of page numbers so that the number of pagination items (page numbers and elided-page markers) is consistent regardless of the current page. If each item is rendered at a consistent width, this keeps the controls in the same place as the user navigates through the page list, avoiding mis-clicks due to pages jumping around.
- Loading branch information
1 parent
5c82a76
commit f61c9a1
Showing
4 changed files
with
241 additions
and
71 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,117 @@ | ||
import { pageNumberOptions } from '../pagination'; | ||
|
||
describe('sidebar/util/pagination', () => { | ||
describe('pageNumberOptions', () => { | ||
[ | ||
{ args: [1, 10, 5], expected: [1, 2, 3, 4, null, 10] }, | ||
{ args: [3, 10, 5], expected: [1, 2, 3, 4, null, 10] }, | ||
{ args: [6, 10, 5], expected: [1, null, 5, 6, 7, null, 10] }, | ||
{ args: [9, 10, 5], expected: [1, null, 7, 8, 9, 10] }, | ||
{ args: [2, 3, 5], expected: [1, 2, 3] }, | ||
{ args: [3, 10, 7], expected: [1, 2, 3, 4, 5, 6, null, 10] }, | ||
{ args: [1, 1, 5], expected: [] }, | ||
].forEach(testCase => { | ||
it('should produce expected available page numbers', () => { | ||
assert.deepEqual( | ||
pageNumberOptions(...testCase.args), | ||
testCase.expected, | ||
); | ||
import { paginationItems } from '../pagination'; | ||
|
||
describe('paginationItems', () => { | ||
[ | ||
// Only one page | ||
{ | ||
current: 1, | ||
total: 1, | ||
expected: [], | ||
}, | ||
|
||
// No pages elided. | ||
{ | ||
current: 1, | ||
total: 3, | ||
expected: [1, 2, 3], | ||
}, | ||
|
||
// Pages elided after current. | ||
{ | ||
current: 1, | ||
total: 4, | ||
expected: [1, 2, null, 4], | ||
}, | ||
|
||
// Pages elided before current. | ||
{ | ||
current: 4, | ||
total: 6, | ||
expected: [1, null, 3, 4, 5, 6], | ||
}, | ||
|
||
// Pages elided before and after current. | ||
{ | ||
current: 4, | ||
total: 7, | ||
expected: [1, null, 3, 4, 5, null, 7], | ||
}, | ||
|
||
// Custom boundary count | ||
{ | ||
current: 6, | ||
total: 10, | ||
boundaryCount: 2, | ||
expected: [1, 2, null, 5, 6, 7, null, 9, 10], | ||
}, | ||
|
||
// Custom sibling count | ||
{ | ||
current: 6, | ||
total: 10, | ||
siblingCount: 2, | ||
expected: [1, null, 4, 5, 6, 7, 8, null, 10], | ||
}, | ||
].forEach(({ current, total, boundaryCount, siblingCount, expected }) => { | ||
it('should produce expected items', () => { | ||
const items = paginationItems(current, total, { | ||
boundaryCount, | ||
siblingCount, | ||
}); | ||
assert.deepEqual(items, expected); | ||
}); | ||
}); | ||
|
||
function* configurations() { | ||
for (let boundaryCount = 1; boundaryCount <= 3; boundaryCount++) { | ||
for (let siblingCount = 0; siblingCount <= 2; siblingCount++) { | ||
for (let total = 1; total <= 10; total++) { | ||
yield { total, boundaryCount, siblingCount }; | ||
} | ||
} | ||
} | ||
} | ||
|
||
function isSorted(list) { | ||
return list.every((item, idx) => idx === 0 || item >= list[idx - 1]); | ||
} | ||
|
||
it('should produce expected items for generated configurations', () => { | ||
for (const { total, boundaryCount, siblingCount } of configurations()) { | ||
let expectedItems = null; | ||
for (let current = 1; current <= total; current++) { | ||
const items = paginationItems(current, total, { | ||
boundaryCount, | ||
siblingCount, | ||
}); | ||
|
||
if (total === 1) { | ||
assert.deepEqual(items, []); | ||
continue; | ||
} | ||
|
||
if (expectedItems === null) { | ||
expectedItems = items.length; | ||
} else { | ||
assert.equal( | ||
items.length, | ||
expectedItems, | ||
'different values of `current` produce different numbers of items', | ||
); | ||
} | ||
|
||
assert.include(items, 1, 'first page should be included'); | ||
assert.include(items, current, 'current page should be included'); | ||
assert.include(items, total, 'last page should be included'); | ||
assert.isAtMost( | ||
items.filter(it => it === null).length, | ||
2, | ||
'should have at most two elided page indicators', | ||
); | ||
|
||
const numbers = items.filter(it => typeof it === 'number'); | ||
assert.isTrue(isSorted(numbers), `${numbers.join(', ')} is not sorted`); | ||
} | ||
} | ||
}); | ||
}); |