Repository: couchdb-fauxton Updated Branches: refs/heads/master b2195ac7d -> 5ee99031f
Pagination component update This refactors the <Pagination /> element to make it a bit more generic. Namely: - max visible pages that appear in pagination is now configurable - can add a callback function to be called when the user clicks a pagination link, instead of just outputting an href on the <a> tags Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/5ee99031 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/5ee99031 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/5ee99031 Branch: refs/heads/master Commit: 5ee99031f04c70b79719a0c958927f7cec3c3702 Parents: b2195ac Author: Ben Keen <ben.k...@gmail.com> Authored: Wed Nov 25 15:11:23 2015 -0800 Committer: Ben Keen <ben.k...@gmail.com> Committed: Fri Nov 27 10:53:18 2015 -0800 ---------------------------------------------------------------------- app/addons/fauxton/components.react.jsx | 67 ++++++++++++-------- .../fauxton/tests/componentsSpec.react.jsx | 44 +++++++++++++ 2 files changed, 85 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5ee99031/app/addons/fauxton/components.react.jsx ---------------------------------------------------------------------- diff --git a/app/addons/fauxton/components.react.jsx b/app/addons/fauxton/components.react.jsx index b8bad67..784c514 100644 --- a/app/addons/fauxton/components.react.jsx +++ b/app/addons/fauxton/components.react.jsx @@ -234,34 +234,36 @@ function (app, FauxtonAPI, React, ZeroClipboard) { } }); - var Pagination = React.createClass({ - getInitialState: function () { - return {}; - }, + var Pagination = React.createClass({ getDefaultProps: function () { return { perPage: FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE, + onClick: null, page: 1, - total: 0 + total: 0, + urlPrefix: '', + urlSuffix: '', + maxNavPages: 10 }; }, getVisiblePages: function (page, totalPages) { var from, to; - if (totalPages < 10) { + if (totalPages < this.props.maxNavPages) { from = 1; to = totalPages + 1; } else { - from = page - 5; - to = page + 5; + var halfMaxNavPages = Math.floor(this.props.maxNavPages / 2); + from = page - halfMaxNavPages; + to = page + halfMaxNavPages; if (from <= 1) { from = 1; - to = 11; + to = this.props.maxNavPages + 1; } if (to > totalPages + 1) { - from = totalPages - 9; + from = totalPages - (this.props.maxNavPages - 1); to = totalPages + 1; } } @@ -271,33 +273,46 @@ function (app, FauxtonAPI, React, ZeroClipboard) { }; }, - createItemsForPage: function (visiblePages, page, prefix, suffix) { + createItemsForPage: function (visiblePages) { return _.range(visiblePages.from, visiblePages.to).map(function (i) { return ( - <li key={i} className={(page === i ? "active" : null)}> - <a href={prefix + i + suffix}>{i}</a> + <li key={i} className={(this.props.page === i ? 'active' : null)}> + {this.getLink(i, i)} </li> ); - }); + }.bind(this)); + }, + + getLink: function (i, label) { + if (this.props.onClick) { + return ( + <a onClick={this.props.onClick.bind(null, i)} dangerouslySetInnerHTML={{__html: label}}></a> + ); + } + return ( + <a href={this.props.urlPrefix + i + this.props.urlSuffix} dangerouslySetInnerHTML={{__html: label}}></a> + ); + }, + + getTotalPages: function () { + return this.props.total === 0 ? 1 : Math.ceil(this.props.total / this.props.perPage); }, render: function () { - var page = this.state.page || this.props.page; - var total = this.state.total || this.props.total; - var perPage = this.props.perPage; - var prefix = this.props.urlPrefix || ""; - var suffix = this.props.urlSuffix || ""; - var totalPages = total === 0 ? 1 : Math.ceil(total / perPage); - var visiblePages = this.getVisiblePages(page, totalPages); - var rangeItems = this.createItemsForPage(visiblePages, page, prefix, suffix); + var totalPages = this.getTotalPages(); + var visiblePages = this.getVisiblePages(this.props.page, totalPages); + var rangeItems = this.createItemsForPage(visiblePages); + var prevPage = Math.max(this.props.page - 1, 1); + var nextPage = Math.min(this.props.page + 1, totalPages); + return ( <ul className="pagination"> - <li className={(page === 1 ? "disabled" : null)}> - <a href={prefix + Math.max(page - 1, 1) + suffix}>«</a> + <li className={(this.props.page === 1 ? "disabled" : null)}> + {this.getLink(prevPage, '«')} </li> {rangeItems} - <li className={(page < totalPages ? null : "disabled")}> - <a href={prefix + Math.min(page + 1, totalPages) + suffix}>»</a> + <li className={(this.props.page < totalPages ? null : "disabled")}> + {this.getLink(nextPage, '»')} </li> </ul> ); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5ee99031/app/addons/fauxton/tests/componentsSpec.react.jsx ---------------------------------------------------------------------- diff --git a/app/addons/fauxton/tests/componentsSpec.react.jsx b/app/addons/fauxton/tests/componentsSpec.react.jsx index c478c78..fd53843 100644 --- a/app/addons/fauxton/tests/componentsSpec.react.jsx +++ b/app/addons/fauxton/tests/componentsSpec.react.jsx @@ -202,6 +202,50 @@ define([ assert.equal("30", lis[10].innerText); }); + it('limits the number of total pages when customized', function () { + var maxNavPages = 15; + var pageEl = TestUtils.renderIntoDocument( + <Views.Pagination page={1} total={1000} maxNavPages={maxNavPages} />, + container + ); + var lis = pageEl.getDOMNode().getElementsByTagName("li"); + assert.equal(1 + maxNavPages + 1, lis.length); + }); + + it('calls callback method when supplied', function () { + var spy = sinon.spy(); + var pageEl = TestUtils.renderIntoDocument( + <Views.Pagination page={1} total={100} onClick={spy} />, + container + ); + var links = React.findDOMNode(pageEl).getElementsByTagName("a"); + + TestUtils.Simulate.click(links[3]); + + // confirm it gets called + assert.ok(spy.calledOnce); + + // confirm it's called with the pagination number (3) + assert.ok(spy.calledWith(3)); + }); + + it('calls callback method with correct values for prev and next', function () { + var spy = sinon.spy(); + + var currentPage = 5; + var pageEl = TestUtils.renderIntoDocument( + <Views.Pagination page={currentPage} total={200} onClick={spy} />, + container + ); + var links = React.findDOMNode(pageEl).getElementsByTagName("a"); + + TestUtils.Simulate.click(links[0]); + assert.ok(spy.calledWith(currentPage - 1)); + + TestUtils.Simulate.click(links[11]); // last index + assert.ok(spy.calledWith(currentPage + 1)); + }); + });