UNPKG

@hypothesis/frontend-shared

Version:

Shared components, styles and utilities for Hypothesis projects

116 lines (113 loc) 4.42 kB
/** * The number of an available pagination page, or `null`, indicating a gap * between sequential numbered pages. */ /** * Determine the set of (pagination) page numbers that should be provided to * a user. * * The result includes a mixture of page numbers that should be shown, plus * `null` values indicating elided page numbers. The goals of the selection * are: * * - To always provide page numbers for the first, last and current pages. * Additional adjacent pages are provided according to the `boundaryCount` * and `siblingCount` options. * - To try and keep the number of pagination items consistent as the current * page changes. If each item is rendered with approximately the same width, * this keeps the overall width of the pagination component and the location * of child controls consistent as the user navigates. This helps to avoid * mis-clicks due to controls moving around under the cursor. * * @param currentPage - The 1-based currently-visible/-active page number. * @param totalPages - The total number of pages * @param options - Options for the number of pages to show at the boundary and * around the current page. */ export function paginationItems(currentPage, totalPages, /* istanbul ignore next */ { boundaryCount = 1, siblingCount = 1 } = {}) { if (totalPages <= 1) { return []; } currentPage = Math.max(1, Math.min(currentPage, totalPages)); boundaryCount = Math.max(boundaryCount, 1); siblingCount = Math.max(siblingCount, 0); const pageNumbers = []; const beforeCurrent = currentPage - 1; const afterCurrent = totalPages - currentPage; const elideBeforeCurrent = boundaryCount + siblingCount < beforeCurrent; let elideBefore = null; if (elideBeforeCurrent) { for (let page = 1; page <= boundaryCount; page++) { pageNumbers.push(page); } elideBefore = { index: pageNumbers.length, count: currentPage - siblingCount - boundaryCount, // Last value in elided range, as we expand backwards value: currentPage - siblingCount - 1 }; pageNumbers.push(null); for (let page = currentPage - siblingCount; page < currentPage; page++) { pageNumbers.push(page); } } else { for (let page = 1; page < currentPage; page++) { pageNumbers.push(page); } } pageNumbers.push(currentPage); const elideAfterCurrent = boundaryCount + siblingCount < afterCurrent; let elideAfter = null; if (elideAfterCurrent) { for (let page = currentPage + 1; page <= currentPage + siblingCount; page++) { pageNumbers.push(page); } elideAfter = { index: pageNumbers.length, count: totalPages - boundaryCount + 1 - (currentPage + siblingCount), // First value in elided range, as we expand forwards value: currentPage + siblingCount + 1 }; pageNumbers.push(null); for (let page = totalPages - boundaryCount + 1; page <= totalPages; page++) { pageNumbers.push(page); } } else { for (let page = currentPage + 1; page <= totalPages; page++) { pageNumbers.push(page); } } // Calculate the maximum number of items we will show for the total number // of pages and options. const maxItems = Math.min( // First and last pages 2 * boundaryCount + // Pages adjacent to current page 2 * siblingCount + // Current page, indicators for elided pages before and after current. 3, totalPages); // To keep the number of items consistent as the current page changes, // expand the elided ranges until we reach the maximum. while (pageNumbers.length < maxItems && ((_elideAfter = elideAfter) !== null && _elideAfter !== void 0 && _elideAfter.count || (_elideBefore = elideBefore) !== null && _elideBefore !== void 0 && _elideBefore.count)) { var _elideAfter, _elideBefore; if (elideAfter && elideAfter.count > 0) { // Expand ahead of current page if possible, starting with numbers closest // to current page. pageNumbers.splice(elideAfter.index, 0, elideAfter.value); ++elideAfter.index; ++elideAfter.value; --elideAfter.count; } else if (elideBefore) { // Otherwise expand behind, starting with numbers closest to current page. pageNumbers.splice(elideBefore.index + 1, 0, elideBefore.value); --elideBefore.value; --elideBefore.count; } } return pageNumbers; } //# sourceMappingURL=pagination.js.map