From d42a10bbae555c4b6d72952175c492d17a5b42c4 Mon Sep 17 00:00:00 2001 From: AllenFang Date: Sat, 8 Dec 2018 15:18:00 +0800 Subject: [PATCH] implement PaginationListStandalone --- .../react-bootstrap-table2-paginator/index.js | 2 + .../src/page-resolver.js | 13 +-- .../src/pagination-handler.js | 78 ++++++++++++++++++ .../src/pagination-list-adapter.js | 20 +++++ .../src/pagination-list-standalone.js | 57 ++----------- .../src/pagination.js | 2 +- .../src/standalone-adapter.js | 4 +- .../test/page-resolver.test.js | 80 +++++++++---------- .../test/pagination-list-adapter.test.js | 32 ++++++++ .../test/pagination.test.js | 3 +- .../test/standalone-adapter.test.js | 44 ++++++++++ 11 files changed, 229 insertions(+), 106 deletions(-) create mode 100644 packages/react-bootstrap-table2-paginator/src/pagination-handler.js create mode 100644 packages/react-bootstrap-table2-paginator/src/pagination-list-adapter.js create mode 100644 packages/react-bootstrap-table2-paginator/test/pagination-list-adapter.test.js create mode 100644 packages/react-bootstrap-table2-paginator/test/standalone-adapter.test.js diff --git a/packages/react-bootstrap-table2-paginator/index.js b/packages/react-bootstrap-table2-paginator/index.js index 8b20636..b399ffa 100644 --- a/packages/react-bootstrap-table2-paginator/index.js +++ b/packages/react-bootstrap-table2-paginator/index.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import createBaseContext from './src/state-context'; import createDataContext from './src/data-context'; +import PaginationListStandalone from './src/pagination-list-standalone'; export default (options = {}) => ({ createContext: createDataContext, @@ -21,3 +22,4 @@ CustomizableProvider.propTypes = { }; export const PaginationProvider = CustomizableProvider; +export { PaginationListStandalone }; diff --git a/packages/react-bootstrap-table2-paginator/src/page-resolver.js b/packages/react-bootstrap-table2-paginator/src/page-resolver.js index 5146faf..3c17e93 100644 --- a/packages/react-bootstrap-table2-paginator/src/page-resolver.js +++ b/packages/react-bootstrap-table2-paginator/src/page-resolver.js @@ -8,12 +8,6 @@ export default ExtendBase => return (currPage - 1) < pageStartIndex ? pageStartIndex : currPage - 1; } - goToNextPage() { - const { currPage } = this.props; - const { lastPage } = this.state; - return (currPage + 1) > lastPage ? lastPage : currPage + 1; - } - initialState() { const totalPages = this.calculateTotalPage(); const lastPage = this.calculateLastPage(totalPages); @@ -47,8 +41,9 @@ export default ExtendBase => } calculatePages( - totalPages = this.state.totalPages, - lastPage = this.state.lastPage) { + totalPages, + lastPage + ) { const { currPage, paginationSize, @@ -94,7 +89,7 @@ export default ExtendBase => return pages; } - calculatePageStatus(pages = [], lastPage = this.state.lastPage) { + calculatePageStatus(pages = [], lastPage) { const { currPage, pageStartIndex, diff --git a/packages/react-bootstrap-table2-paginator/src/pagination-handler.js b/packages/react-bootstrap-table2-paginator/src/pagination-handler.js new file mode 100644 index 0000000..1ffc973 --- /dev/null +++ b/packages/react-bootstrap-table2-paginator/src/pagination-handler.js @@ -0,0 +1,78 @@ +/* eslint react/prop-types: 0 */ +import React, { Component } from 'react'; + +import pageResolver from './page-resolver'; + +export default WrappedComponent => + class PaginationHandler extends pageResolver(Component) { + constructor(props) { + super(props); + this.handleChangePage = this.handleChangePage.bind(this); + this.handleChangeSizePerPage = this.handleChangeSizePerPage.bind(this); + this.state = this.initialState(); + } + + componentWillReceiveProps(nextProps) { + const { dataSize, currSizePerPage } = nextProps; + if (currSizePerPage !== this.props.currSizePerPage || dataSize !== this.props.dataSize) { + const totalPages = this.calculateTotalPage(currSizePerPage, dataSize); + const lastPage = this.calculateLastPage(totalPages); + this.setState({ totalPages, lastPage }); + } + } + + handleChangeSizePerPage(sizePerPage) { + const { currSizePerPage, onSizePerPageChange } = this.props; + const selectedSize = typeof sizePerPage === 'string' ? parseInt(sizePerPage, 10) : sizePerPage; + let { currPage } = this.props; + if (selectedSize !== currSizePerPage) { + const newTotalPages = this.calculateTotalPage(selectedSize); + const newLastPage = this.calculateLastPage(newTotalPages); + if (currPage > newLastPage) currPage = newLastPage; + onSizePerPageChange(selectedSize, currPage); + } + this.closeDropDown(); + } + + handleChangePage(newPage) { + let page; + const { + currPage, + pageStartIndex, + prePageText, + nextPageText, + lastPageText, + firstPageText, + onPageChange + } = this.props; + const { lastPage } = this.state; + + if (newPage === prePageText) { + page = this.backToPrevPage(); + } else if (newPage === nextPageText) { + page = (currPage + 1) > lastPage ? lastPage : currPage + 1; + } else if (newPage === lastPageText) { + page = lastPage; + } else if (newPage === firstPageText) { + page = pageStartIndex; + } else { + page = parseInt(newPage, 10); + } + if (page !== currPage) { + onPageChange(page); + } + } + + render() { + return ( + + ); + } + }; + diff --git a/packages/react-bootstrap-table2-paginator/src/pagination-list-adapter.js b/packages/react-bootstrap-table2-paginator/src/pagination-list-adapter.js new file mode 100644 index 0000000..a2a8deb --- /dev/null +++ b/packages/react-bootstrap-table2-paginator/src/pagination-list-adapter.js @@ -0,0 +1,20 @@ +/* eslint react/prop-types: 0 */ +import React, { Component } from 'react'; + +import pageResolver from './page-resolver'; + +export default WrappedComponent => + class PaginationListAdapter extends pageResolver(Component) { + render() { + const { lastPage, totalPages, pageButtonRenderer, onPageChange } = this.props; + const pages = this.calculatePageStatus(this.calculatePages(totalPages, lastPage), lastPage); + return ( + + ); + } + }; + diff --git a/packages/react-bootstrap-table2-paginator/src/pagination-list-standalone.js b/packages/react-bootstrap-table2-paginator/src/pagination-list-standalone.js index e5b0320..930ae2a 100644 --- a/packages/react-bootstrap-table2-paginator/src/pagination-list-standalone.js +++ b/packages/react-bootstrap-table2-paginator/src/pagination-list-standalone.js @@ -1,53 +1,12 @@ import React from 'react'; -import pageResolver from './page-resolver'; import PaginationList from './pagination-list'; +import standaloneAdapter from './standalone-adapter'; +import PaginationHandler from './pagination-handler'; +import paginationListAdapter from './pagination-list-adapter'; -export default class PaginationListStandalone extends pageResolver(React.Component) { - constructor(props) { - super(props); - this.handleChangePage = this.handleChangePage.bind(this); - this.state = this.initialState(); - } +const PaginationListStandalone = props => ( + +); - handleChangePage(newPage) { - let page; - const { - currPage, - pageStartIndex, - prePageText, - nextPageText, - lastPageText, - firstPageText, - onPageChange - } = this.props; - const { lastPage } = this.state; - - if (newPage === prePageText) { - page = this.backToPrevPage(); - } else if (newPage === nextPageText) { - page = (currPage + 1) > lastPage ? lastPage : currPage + 1; - } else if (newPage === lastPageText) { - page = lastPage; - } else if (newPage === firstPageText) { - page = pageStartIndex; - } else { - page = parseInt(newPage, 10); - } - - if (page !== currPage) { - onPageChange(page); - } - } - - render() { - const { totalPages, lastPage } = this.state; - const pages = this.calculatePageStatus(this.calculatePages(totalPages), lastPage); - - return ( - - ); - } -} +export default +standaloneAdapter(PaginationHandler(paginationListAdapter(PaginationListStandalone))); diff --git a/packages/react-bootstrap-table2-paginator/src/pagination.js b/packages/react-bootstrap-table2-paginator/src/pagination.js index 9209095..64b1e6a 100644 --- a/packages/react-bootstrap-table2-paginator/src/pagination.js +++ b/packages/react-bootstrap-table2-paginator/src/pagination.js @@ -146,7 +146,7 @@ class Pagination extends pageResolver(Component) { paginationTotalRenderer, hidePageListOnlyOnePage } = this.props; - const pages = this.calculatePageStatus(this.calculatePages(totalPages), lastPage); + const pages = this.calculatePageStatus(this.calculatePages(totalPages, lastPage), lastPage); const [from, to] = this.calculateFromTo(); const pageListClass = cs( 'react-bootstrap-table-pagination-list', diff --git a/packages/react-bootstrap-table2-paginator/src/standalone-adapter.js b/packages/react-bootstrap-table2-paginator/src/standalone-adapter.js index caa89f3..98c16cd 100644 --- a/packages/react-bootstrap-table2-paginator/src/standalone-adapter.js +++ b/packages/react-bootstrap-table2-paginator/src/standalone-adapter.js @@ -1,12 +1,12 @@ /* eslint react/prop-types: 0 */ import React from 'react'; -export default Component => ({ +export default WrappedComponent => ({ page, sizePerPage, ...rest }) => ( - { }); }); - describe('goToNextPage', () => { - const props = createMockProps(); - - describe('when props.currPage is not hitting state.lastPage', () => { - beforeEach(() => { - const mockElement = React.createElement(MockComponent, props, null); - wrapper = shallow(mockElement); - }); - - it('should getting previous page correctly', () => { - const instance = wrapper.instance(); - expect(instance.goToNextPage()).toEqual(props.currPage + 1); - }); - }); - - describe('when props.currPage is hitting state.lastpage', () => { - beforeEach(() => { - props.currPage = 10; - const mockElement = React.createElement(MockComponent, props, null); - wrapper = shallow(mockElement); - }); - - it('should always getting page which must eq props.pageStartIndex', () => { - const instance = wrapper.instance(); - expect(instance.goToNextPage()).toEqual(instance.state.lastPage); - }); - }); - }); - describe('calculateFromTo', () => { const props = createMockProps(); beforeEach(() => { @@ -192,7 +163,7 @@ describe('PageResolver', () => { }); describe('calculatePages', () => { - describe('calculate by state.totalPages and state.lastPage', () => { + describe('calculate by totalPages and lastPage', () => { const props = createMockProps(); beforeEach(() => { const mockElement = React.createElement(MockComponent, props, null); @@ -201,7 +172,7 @@ describe('PageResolver', () => { it('should getting pages list correctly', () => { const instance = wrapper.instance(); - expect(instance.calculatePages()).toEqual( + expect(instance.calculatePages(instance.state.totalPages, instance.state.lastPage)).toEqual( [props.prePageText, 1, 2, 3, 4, 5, props.nextPageText, props.lastPageText]); expect(instance.calculatePages(4, 4)).toEqual( @@ -218,7 +189,9 @@ describe('PageResolver', () => { currPages.forEach((currPage) => { props.currPage = currPage + 1; wrapper = shallow(); - const pageList = wrapper.instance().calculatePages(); + const instance = wrapper.instance(); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); if (props.currPage < 4) { expect(pageList).toEqual( @@ -253,7 +226,9 @@ describe('PageResolver', () => { [1, 3, 5, 8, 10].forEach((paginationSize) => { props.paginationSize = paginationSize; wrapper = shallow(); - const pageList = wrapper.instance().calculatePages(); + const instance = wrapper.instance(); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); const result = pageList.filter(p => indicators.indexOf(p) === -1); expect(result.length).toEqual(props.paginationSize); }); @@ -267,7 +242,9 @@ describe('PageResolver', () => { [1, 2, 3, 4, 5, 6, 7].forEach((currPage) => { props.currPage = currPage; wrapper = shallow(); - const pageList = wrapper.instance().calculatePages(); + const instance = wrapper.instance(); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); expect(pageList.indexOf(props.lastPageText) > -1).toBeTruthy(); }); }); @@ -278,7 +255,9 @@ describe('PageResolver', () => { [10, 9, 8, 7, 6, 5, 4].forEach((currPage) => { props.currPage = currPage; wrapper = shallow(); - const pageList = wrapper.instance().calculatePages(); + const instance = wrapper.instance(); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); expect(pageList.indexOf(props.firstPageText) > -1).toBeTruthy(); }); }); @@ -293,7 +272,9 @@ describe('PageResolver', () => { props.currPage = currPage + 1; props.withFirstAndLast = false; wrapper = shallow(); - const pageList = wrapper.instance().calculatePages(); + const instance = wrapper.instance(); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); expect(pageList.indexOf(props.lastPageText) > -1).toBeFalsy(); expect(pageList.indexOf(props.firstPageText) > -1).toBeFalsy(); }); @@ -311,7 +292,9 @@ describe('PageResolver', () => { }); it('should getting last page correctly', () => { - const pageList = wrapper.instance().calculatePages(); + const instance = wrapper.instance(); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); expect(pageList).toEqual( [props.prePageText, -2, -1, 0, 1, 2, props.nextPageText, props.lastPageText]); }); @@ -329,7 +312,9 @@ describe('PageResolver', () => { }); it('should always having next and previous page indication', () => { - const pageList = wrapper.instance().calculatePages(); + const instance = wrapper.instance(); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); expect(pageList.indexOf(props.nextPageText) > -1).toBeTruthy(); expect(pageList.indexOf(props.prePageText) > -1).toBeTruthy(); }); @@ -345,7 +330,10 @@ describe('PageResolver', () => { }); it('should getting empty array', () => { - expect(wrapper.instance().calculatePages()).toEqual([]); + const instance = wrapper.instance(); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); + expect(pageList).toEqual([]); }); }); }); @@ -360,7 +348,9 @@ describe('PageResolver', () => { const mockElement = React.createElement(MockComponent, props, null); wrapper = shallow(mockElement); instance = wrapper.instance(); - pageStatus = instance.calculatePageStatus(instance.calculatePages()); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); + pageStatus = instance.calculatePageStatus(pageList, instance.state.lastPage); }); it('should returning correct format for page status', () => { @@ -388,8 +378,9 @@ describe('PageResolver', () => { const mockElement = React.createElement(MockComponent, props, null); wrapper = shallow(mockElement); instance = wrapper.instance(); - const pageList = instance.calculatePages(); - pageStatus = instance.calculatePageStatus(pageList); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); + pageStatus = instance.calculatePageStatus(pageList, instance.state.lastPage); expect(pageStatus.find(p => p.page === props.prePageText)).not.toBeDefined(); }); @@ -401,8 +392,9 @@ describe('PageResolver', () => { const mockElement = React.createElement(MockComponent, props, null); wrapper = shallow(mockElement); instance = wrapper.instance(); - const pageList = instance.calculatePages(); - pageStatus = instance.calculatePageStatus(pageList); + const pageList = instance.calculatePages( + instance.state.totalPages, instance.state.lastPage); + pageStatus = instance.calculatePageStatus(pageList, instance.state.lastPage); expect(pageStatus.find(p => p.page === props.nextPageText)).not.toBeDefined(); }); diff --git a/packages/react-bootstrap-table2-paginator/test/pagination-list-adapter.test.js b/packages/react-bootstrap-table2-paginator/test/pagination-list-adapter.test.js new file mode 100644 index 0000000..9217200 --- /dev/null +++ b/packages/react-bootstrap-table2-paginator/test/pagination-list-adapter.test.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import paginationListAdapter from '../src/pagination-list-adapter'; + + +const MockComponent = () => null; + +const PaginationListAdapter = paginationListAdapter(MockComponent); +describe('paginationListAdapter', () => { + let wrapper; + + const props = { + totalPages: 10, + lastPage: 10, + pageButtonRenderer: jest.fn(), + onPageChange: jest.fn() + }; + + describe('render', () => { + beforeEach(() => { + wrapper = shallow(); + }); + + it('should render successfully', () => { + const mockComponent = wrapper.find(MockComponent); + expect(mockComponent).toHaveLength(1); + expect(mockComponent.props().pages).toBeDefined(); + expect(mockComponent.props().pageButtonRenderer).toBeDefined(); + expect(mockComponent.props().onPageChange).toBeDefined(); + }); + }); +}); diff --git a/packages/react-bootstrap-table2-paginator/test/pagination.test.js b/packages/react-bootstrap-table2-paginator/test/pagination.test.js index 54b3fdc..29c04b5 100644 --- a/packages/react-bootstrap-table2-paginator/test/pagination.test.js +++ b/packages/react-bootstrap-table2-paginator/test/pagination.test.js @@ -54,8 +54,9 @@ describe('Pagination', () => { it('should rendering PaginationList component successfully', () => { const paginationList = wrapper.find(PaginationList); + const pageList = instance.calculatePages(instance.state.totalPages, instance.state.lastPage); expect(paginationList.length).toBe(1); - expect(paginationList.prop('pages')).toEqual(instance.calculatePageStatus(instance.calculatePages())); + expect(paginationList.prop('pages')).toEqual(instance.calculatePageStatus(pageList, instance.state.lastPage)); expect(paginationList.prop('onPageChange')).toEqual(instance.handleChangePage); }); diff --git a/packages/react-bootstrap-table2-paginator/test/standalone-adapter.test.js b/packages/react-bootstrap-table2-paginator/test/standalone-adapter.test.js new file mode 100644 index 0000000..beebfa7 --- /dev/null +++ b/packages/react-bootstrap-table2-paginator/test/standalone-adapter.test.js @@ -0,0 +1,44 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import standaloneAdapter from '../src/standalone-adapter'; + + +const MockStandalone = () => null; + +const MockStandaloneWithAdapter = standaloneAdapter(MockStandalone); +describe('standaloneAdapter', () => { + let wrapper; + + const props = { + page: 2, + sizePerPage: 10, + name1: 'A', + name2: 'B' + }; + describe('render', () => { + beforeEach(() => { + wrapper = shallow(); + }); + + it('should render successfully', () => { + expect(wrapper.find(MockStandalone)).toHaveLength(1); + }); + + it('should convert props.page as currPage to child component', () => { + const mockStandalone = wrapper.find(MockStandalone); + expect(mockStandalone.props().currPage).toEqual(props.page); + }); + + it('should convert props.sizePerPage as currSizePerPage to child component', () => { + const mockStandalone = wrapper.find(MockStandalone); + expect(mockStandalone.props().currSizePerPage).toEqual(props.sizePerPage); + }); + + it('should just pass remain props to child component', () => { + const mockStandalone = wrapper.find(MockStandalone); + const { page, sizePerPage, ...origin } = props; + const { currPage, currSizePerPage, ...rest } = mockStandalone.props(); + expect(rest).toEqual(origin); + }); + }); +});