diff --git a/README.md b/README.md index 594b3da3..beed22a2 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ React.render(, container); | nextIcon | specifict the default previous icon | ReactNode \| (props: PaginationProps) => ReactNode | | | jumpPrevIcon | specifict the default previous icon | ReactNode \| (props: PaginationProps) => ReactNode | | | jumpNextIcon | specifict the default previous icon | ReactNode \| (props: PaginationProps) => ReactNode | | - +| pagerCount | show number of pagers | Number | 5 | ## License diff --git a/examples/pagerCount.html b/examples/pagerCount.html new file mode 100644 index 00000000..48cdce85 --- /dev/null +++ b/examples/pagerCount.html @@ -0,0 +1 @@ +placeholder diff --git a/examples/pagerCount.js b/examples/pagerCount.js new file mode 100644 index 00000000..68762380 --- /dev/null +++ b/examples/pagerCount.js @@ -0,0 +1,50 @@ +import 'rc-pagination/assets/index.less'; +import Pagination from 'rc-pagination'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import Select from 'rc-select'; +import 'rc-select/assets/index.css'; + +const itemRender = (current, type, element) => { + const hideItems = ['jump-last', 'jump-first']; + + if (hideItems.includes(type)) { + return null; + } + + return element; +}; + +function onShowSizeChange(current, pageSize) { + console.log(current, pageSize); +} + +ReactDOM.render( +
+

pageCount = 10, hide prev and next jumpers

+ + +

Has `showSizeChanger` and `showQuickJumper`

+ + +

pagerCount less than 3

+ + +

Has `showLessItems` and `pagerCount`

+ + +

The pagerCount is odd

+ + +

The pagerCount is even

+ +
+, document.getElementById('__react-content')); diff --git a/src/Pager.jsx b/src/Pager.jsx index 421f9c9e..067aed90 100644 --- a/src/Pager.jsx +++ b/src/Pager.jsx @@ -25,7 +25,18 @@ const Pager = (props) => { props.onKeyPress(e, props.onClick, props.page); }; + let pageType = 'page'; + if (props.last) { + pageType = 'jump-last'; + } + if (props.first) { + pageType = 'jump-first'; + } + + const itemNode = props.itemRender(props.page, pageType, {props.page}); + return ( + itemNode === null ? null :
  • { onKeyPress={handleKeyPress} tabIndex="0" > - {props.itemRender(props.page, 'page', {props.page})} + {itemNode}
  • ); }; diff --git a/src/Pagination.jsx b/src/Pagination.jsx index 35e7e4eb..e8765114 100644 --- a/src/Pagination.jsx +++ b/src/Pagination.jsx @@ -53,6 +53,7 @@ class Pagination extends React.Component { nextIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), jumpPrevIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), jumpNextIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), + pagerCount: PropTypes.number, }; static defaultProps = { @@ -74,6 +75,7 @@ class Pagination extends React.Component { locale: LOCALE, style: {}, itemRender: defaultItemRender, + pagerCount: 5, }; constructor(props) { @@ -81,9 +83,15 @@ class Pagination extends React.Component { const hasOnChange = props.onChange !== noop; const hasCurrent = ('current' in props); + const hasShowLessItems = ('showLessItems' in props); if (hasCurrent && !hasOnChange) { console.warn('Warning: You provided a `current` prop to a Pagination component without an `onChange` handler. This will render a read-only component.'); // eslint-disable-line } + if (hasShowLessItems && props.showLessItems) { + console.warn( + 'Warning: `showLessItems` is deprecated since 1.18.0. Please use pagerCount instead.' + ) // eslint-disable-line + } let current = props.defaultCurrent; if ('current' in props) { @@ -143,13 +151,17 @@ class Pagination extends React.Component { } getJumpPrevPage = () => { - return Math.max(1, this.state.current - (this.props.showLessItems ? 3 : 5)); + const { showLessItems } = this.props; + const hasPagerCount = this.hasPagerCount(); + return Math.max(1, this.state.current - (showLessItems && !hasPagerCount ? 3 : 5)); } getJumpNextPage = () => { + const { showLessItems } = this.props; + const hasPagerCount = this.hasPagerCount(); return Math.min( calculatePage(undefined, this.state, this.props), - this.state.current + (this.props.showLessItems ? 3 : 5) + this.state.current + (showLessItems && !hasPagerCount ? 3 : 5) ); } @@ -316,6 +328,8 @@ class Pagination extends React.Component { } } + hasPagerCount = () => !(this.props.pagerCount === 5) + render() { // When hideOnSinglePage is true and there is only 1 page, hide the pager if (this.props.hideOnSinglePage === true && this.props.total <= this.state.pageSize) { @@ -334,8 +348,17 @@ class Pagination extends React.Component { let lastPager = null; let gotoButton = null; + const { pagerCount, showLessItems } = props; + // `pagerCount` priority is greater than `showLessItems`. + const hasPagerCount = this.hasPagerCount(); + const boundary = pagerCount === 0 ? 0 : 1; + const pagerCountBoundary = pagerCount % 2 !== 0 ? 0 : boundary; + const boundaryRemainder = hasPagerCount ? pagerCountBoundary : 0; + const halfPagerCount = Math.max(0, Math.floor((pagerCount - 1) / 2)); + const halfHasLessItemsCount = showLessItems ? 1 : halfPagerCount; + const pageBufferSize = hasPagerCount ? halfPagerCount : halfHasLessItemsCount; + const goButton = (props.showQuickJumper && props.showQuickJumper.goButton); - const pageBufferSize = props.showLessItems ? 1 : 2; const { current, pageSize } = this.state; const prevPage = current - 1 > 0 ? current - 1 : 0; @@ -425,7 +448,7 @@ class Pagination extends React.Component { ); } - if (allPages <= 5 + pageBufferSize * 2) { + if (allPages <= pageBufferSize * 2 + boundaryRemainder + 1) { const pagerProps = { locale, rootPrefixCls: prefixCls, @@ -456,8 +479,8 @@ class Pagination extends React.Component { ); } } else { - const prevItemTitle = props.showLessItems ? locale.prev_3 : locale.prev_5; - const nextItemTitle = props.showLessItems ? locale.next_3 : locale.next_5; + const prevItemTitle = showLessItems && !hasPagerCount ? locale.prev_3 : locale.prev_5; + const nextItemTitle = showLessItems && !hasPagerCount ? locale.next_3 : locale.next_5; if (props.showPrevNextJumpers) { let jumpPrevClassString = `${prefixCls}-jump-prev`; if (props.jumpPrevIcon) { @@ -500,6 +523,7 @@ class Pagination extends React.Component { ); } + lastPager = ( ); - let left = Math.max(1, current - pageBufferSize); + let left = Math.max(1, current - pageBufferSize - boundaryRemainder); let right = Math.min(current + pageBufferSize, allPages); if (current - 1 <= pageBufferSize) { - right = 1 + pageBufferSize * 2; + right = 1 + pageBufferSize * 2 + boundaryRemainder; } - if (allPages - current <= pageBufferSize) { - left = allPages - pageBufferSize * 2; + if (allPages - current < pageBufferSize) { + left = allPages - pageBufferSize * 2 - boundaryRemainder; } for (let i = left; i <= right; i++) { @@ -556,13 +581,13 @@ class Pagination extends React.Component { ); } - if (current - 1 >= pageBufferSize * 2 && current !== 1 + 2) { + if (current - boundaryRemainder - 2 > pageBufferSize) { pagerList[0] = React.cloneElement(pagerList[0], { className: `${prefixCls}-item-after-jump-prev`, }); pagerList.unshift(jumpPrev); } - if (allPages - current >= pageBufferSize * 2 && current !== allPages - 2) { + if (allPages - current > pageBufferSize && current !== allPages - pageBufferSize - 1) { pagerList[pagerList.length - 1] = React.cloneElement(pagerList[pagerList.length - 1], { className: `${prefixCls}-item-before-jump-next`, }); diff --git a/tests/Pagination.spec.js b/tests/Pagination.spec.js index 25623d3e..7cd613a3 100644 --- a/tests/Pagination.spec.js +++ b/tests/Pagination.spec.js @@ -813,3 +813,142 @@ describe('data and aria props', () => { }); }); }); + +describe('pagerCount props', () => { + describe('with pagerCount, when hide first, last', () => { + const container = document.createElement('div'); + document.body.appendChild(container); + + const itemRender = (current, type, element) => { + if (type === 'jump-first' || type === 'jump-last') { + return null; + } + return element; + }; + + it('pageCount is 2, total is 10, show 1 pager', (done) => { + ReactDOM.render( + , + container, + function () { + const pagers = TestUtils.scryRenderedDOMComponentsWithClass( + this, + 'rc-pagination-item' + ); + expect(pagers.length).to.be(1); + done(); + } + ); + }); + + it('pageCount is 2, total is 11, show 2 pager', (done) => { + ReactDOM.render( + , + container, + function () { + const pagers = TestUtils.scryRenderedDOMComponentsWithClass( + this, + 'rc-pagination-item' + ); + expect(pagers.length).to.be(2); + done(); + } + ); + }); + + it('should show 10 pagers if pageCount equals 10', (done) => { + ReactDOM.render( + , + container, + function () { + const pagers = TestUtils.scryRenderedDOMComponentsWithClass( + this, + 'rc-pagination-item' + ); + expect(pagers.length).to.be(10); + + const eighthPager = TestUtils.findRenderedDOMComponentWithClass( + this, + 'rc-pagination-item-8' + ); + expect(TestUtils.isDOMComponent(eighthPager)).to.be(true); + Simulate.click(eighthPager); + setTimeout(() => { + const afterPagers = TestUtils.scryRenderedDOMComponentsWithClass( + this, + 'rc-pagination-item' + ); + expect(afterPagers.length).to.be(10); + done(); + }, 10); + } + ); + }); + }); + + describe('pagerCount is even', () => { + it('pageCount is even', (done) => { + const container = document.createElement('div'); + document.body.appendChild(container); + ReactDOM.render( + , + container, + function () { + const pagers = TestUtils.scryRenderedDOMComponentsWithClass( + this, + 'rc-pagination-item' + ); + expect(pagers.length).to.be(9); + + const sixthPager = TestUtils.findRenderedDOMComponentWithClass( + this, + 'rc-pagination-item-6' + ); + expect(TestUtils.isDOMComponent(sixthPager)).to.be(true); + Simulate.click(sixthPager); + setTimeout(() => { + const afterPagers = TestUtils.scryRenderedDOMComponentsWithClass( + this, + 'rc-pagination-item' + ); + expect(afterPagers.length).to.be(10); + done(); + }, 10); + } + ); + }); + + it('defaultCurrent is last page', (done) => { + const container = document.createElement('div'); + document.body.appendChild(container); + ReactDOM.render( + , + container, + function () { + setTimeout(() => { + const pagers = TestUtils.scryRenderedDOMComponentsWithClass( + this, + 'rc-pagination-item' + ); + expect(pagers.length).to.be(8); + + const pager46 = TestUtils.findRenderedDOMComponentWithClass( + this, + 'rc-pagination-item-46' + ); + expect(TestUtils.isDOMComponent(pager46)).to.be(true); + Simulate.click(pager46); + setTimeout(() => { + const afterPagers = TestUtils.scryRenderedDOMComponentsWithClass( + this, + 'rc-pagination-item' + ); + expect(afterPagers.length).to.be(9); + done(); + }, 10); + }, 10); + } + ); + }); + }); +});