Skip to content

Commit

Permalink
[added] Pagination component
Browse files Browse the repository at this point in the history
  • Loading branch information
roadman authored and roadmanfong committed Jun 7, 2015
1 parent 12d6ddb commit 5734ec3
Show file tree
Hide file tree
Showing 11 changed files with 402 additions and 14 deletions.
1 change: 1 addition & 0 deletions docs/examples/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"PageHeader",
"PageItem",
"Pager",
"Pagination",
"Panel",
"PanelGroup",
"Popover",
Expand Down
30 changes: 30 additions & 0 deletions docs/examples/PaginationAdvanced.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const PaginationAdvanced = React.createClass({
getInitialState() {
return {
activePage: 1
};
},

handleSelect(event, selectedEvent) {
this.setState({
activePage: selectedEvent.eventKey
});
},

render() {
return (
<Pagination
prev={true}
next={true}
first={true}
last={true}
ellipsis={true}
items={20}
maxButtons={5}
activePage={this.state.activePage}
onSelect={this.handleSelect} />
);
}
});

React.render(<PaginationAdvanced />, mountNode);
41 changes: 41 additions & 0 deletions docs/examples/PaginationBasic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const PaginationBasic = React.createClass({
getInitialState() {
return {
activePage: 1
};
},

handleSelect(event, selectedEvent){
this.setState({
activePage: selectedEvent.eventKey
});
},

render() {
return (
<div>
<Pagination
bsSize='large'
items={10}
activePage={this.state.activePage}
onSelect={this.handleSelect} />
<br />

<Pagination
bsSize='medium'
items={10}
activePage={this.state.activePage}
onSelect={this.handleSelect} />
<br />

<Pagination
bsSize='small'
items={10}
activePage={this.state.activePage}
onSelect={this.handleSelect} />
</div>
);
}
});

React.render(<PaginationBasic />, mountNode);
40 changes: 27 additions & 13 deletions docs/src/ComponentsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,19 @@ const ComponentsPage = React.createClass({
<ReactPlayground codeText={Samples.PagerDisabled} />
</div>

{/* Pagination */}
<div className='bs-docs-section'>
<h1 id='pagination' className='page-header'>Pagination <small>Pagination</small></h1>
<h2 id='pagination-examples'>Example pagination</h2>

<p>Provide pagination links for your site or app with the multi-page pagination component. Set <code>items</code> to the number of pages. <code>activePage</code> prop dictates which page is active</p>
<ReactPlayground codeText={Samples.PaginationBasic} />

<p>More options such as <code>first</code>, <code>last</code>, <code>previous</code>, <code>next</code> and <code>ellipsis</code>.</p>
<ReactPlayground codeText={Samples.PaginationAdvanced} />

</div>

{/* Alerts */}
<div className='bs-docs-section'>
<h1 id='alerts' className='page-header'>Alert messages <small>Alert</small></h1>
Expand Down Expand Up @@ -654,19 +667,20 @@ const ComponentsPage = React.createClass({
<NavItem href='#navbars' key={10}>Navbars</NavItem>
<NavItem href='#tabs' key={11}>Togglable tabs</NavItem>
<NavItem href='#pager' key={12}>Pager</NavItem>
<NavItem href='#alerts' key={13}>Alerts</NavItem>
<NavItem href='#carousels' key={14}>Carousels</NavItem>
<NavItem href='#grids' key={15}>Grids</NavItem>
<NavItem href='#thumbnail' key={16}>Thumbnail</NavItem>
<NavItem href='#listgroup' key={17}>List group</NavItem>
<NavItem href='#labels' key={18}>Labels</NavItem>
<NavItem href='#badges' key={19}>Badges</NavItem>
<NavItem href='#jumbotron' key={20}>Jumbotron</NavItem>
<NavItem href='#page-header' key={21}>Page Header</NavItem>
<NavItem href='#wells' key={22}>Wells</NavItem>
<NavItem href='#glyphicons' key={23}>Glyphicons</NavItem>
<NavItem href='#tables' key={24}>Tables</NavItem>
<NavItem href='#input' key={25}>Input</NavItem>
<NavItem href='#pagination' key={13}>Pagination</NavItem>
<NavItem href='#alerts' key={14}>Alerts</NavItem>
<NavItem href='#carousels' key={15}>Carousels</NavItem>
<NavItem href='#grids' key={16}>Grids</NavItem>
<NavItem href='#thumbnail' key={17}>Thumbnail</NavItem>
<NavItem href='#listgroup' key={18}>List group</NavItem>
<NavItem href='#labels' key={19}>Labels</NavItem>
<NavItem href='#badges' key={20}>Badges</NavItem>
<NavItem href='#jumbotron' key={21}>Jumbotron</NavItem>
<NavItem href='#page-header' key={22}>Page Header</NavItem>
<NavItem href='#wells' key={23}>Wells</NavItem>
<NavItem href='#glyphicons' key={24}>Glyphicons</NavItem>
<NavItem href='#tables' key={25}>Tables</NavItem>
<NavItem href='#input' key={26}>Input</NavItem>
</Nav>
<a className='back-to-top' href='#top'>
Back to top
Expand Down
2 changes: 2 additions & 0 deletions docs/src/ReactPlayground.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import * as modOverlayMixin from '../../src/OverlayMixin';
import * as modPageHeader from '../../src/PageHeader';
import * as modPageItem from '../../src/PageItem';
import * as modPager from '../../src/Pager';
import * as modPagination from '../../src/Pagination';
import * as modPanel from '../../src/Panel';
import * as modPanelGroup from '../../src/PanelGroup';
import * as modPopover from '../../src/Popover';
Expand Down Expand Up @@ -83,6 +84,7 @@ const OverlayTrigger = modOverlayTrigger.default;
const OverlayMixin = modOverlayMixin.default;
const PageHeader = modPageHeader.default;
const PageItem = modPageItem.default;
const Pagination = modPagination.default;
const Pager = modPager.default;
const Panel = modPanel.default;
const PanelGroup = modPanelGroup.default;
Expand Down
4 changes: 3 additions & 1 deletion docs/src/Samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default {
ButtonGroupNested: require('fs').readFileSync(__dirname + '/../examples/ButtonGroupNested.js', 'utf8'),
ButtonGroupVertical: require('fs').readFileSync(__dirname + '/../examples/ButtonGroupVertical.js', 'utf8'),
ButtonGroupJustified: require('fs').readFileSync(__dirname + '/../examples/ButtonGroupJustified.js', 'utf8'),
ButtonGroupBlock: require('fs').readFileSync(__dirname + '/../examples/ButtonGroupBlock.js', 'utf8'),
ButtonGroupBlock: require('fs').readFileSync(__dirname + '/../examples/ButtonGroupBlock.js', 'utf8'),
DropdownButtonBasic: require('fs').readFileSync(__dirname + '/../examples/DropdownButtonBasic.js', 'utf8'),
SplitButtonBasic: require('fs').readFileSync(__dirname + '/../examples/SplitButtonBasic.js', 'utf8'),
DropdownButtonSizes: require('fs').readFileSync(__dirname + '/../examples/DropdownButtonSizes.js', 'utf8'),
Expand Down Expand Up @@ -65,6 +65,8 @@ export default {
PagerDefault: require('fs').readFileSync(__dirname + '/../examples/PagerDefault.js', 'utf8'),
PagerAligned: require('fs').readFileSync(__dirname + '/../examples/PagerAligned.js', 'utf8'),
PagerDisabled: require('fs').readFileSync(__dirname + '/../examples/PagerDisabled.js', 'utf8'),
PaginationBasic: require('fs').readFileSync(__dirname + '/../examples/PaginationBasic.js', 'utf8'),
PaginationAdvanced: require('fs').readFileSync(__dirname + '/../examples/PaginationAdvanced.js', 'utf8'),
AlertBasic: require('fs').readFileSync(__dirname + '/../examples/AlertBasic.js', 'utf8'),
AlertDismissable: require('fs').readFileSync(__dirname + '/../examples/AlertDismissable.js', 'utf8'),
AlertAutoDismissable: require('fs').readFileSync(__dirname + '/../examples/AlertAutoDismissable.js', 'utf8'),
Expand Down
167 changes: 167 additions & 0 deletions src/Pagination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import React from 'react';
import classNames from 'classnames';
import BootstrapMixin from './BootstrapMixin';
import PaginationButton from './PaginationButton';

const Pagination = React.createClass({
mixins: [BootstrapMixin],

propTypes: {
activePage: React.PropTypes.number,
items: React.PropTypes.number,
maxButtons: React.PropTypes.number,
ellipsis: React.PropTypes.bool,
first: React.PropTypes.bool,
last: React.PropTypes.bool,
prev: React.PropTypes.bool,
next: React.PropTypes.bool,
onSelect: React.PropTypes.func
},

getDefaultProps() {
return {
activePage: 1,
items: 1,
maxButtons: 0,
first: false,
last: false,
prev: false,
next: false,
ellipsis: true,
bsClass: 'pagination'
};
},

renderPageButtons() {
let pageButtons = [];
let startPage, endPage, hasHiddenPagesBefore, hasHiddenPagesAfter;
let {
maxButtons,
activePage,
items,
onSelect,
ellipsis
} = this.props;

if(maxButtons){
let hiddenPagesBefore = activePage - parseInt(maxButtons / 2);
startPage = hiddenPagesBefore > 1 ? hiddenPagesBefore : 1;
hasHiddenPagesAfter = startPage + maxButtons <= items;

if(!hasHiddenPagesAfter){
endPage = items;
startPage = items - maxButtons + 1;
} else {
endPage = startPage + maxButtons - 1;
}
} else {
startPage = 1;
endPage = items;
}

for(let pagenumber = startPage; pagenumber <= endPage; pagenumber++){
pageButtons.push(
<PaginationButton
key={pagenumber}
eventKey={pagenumber}
active={pagenumber === activePage}
onSelect={onSelect}>
{pagenumber}
</PaginationButton>
);
}

if(maxButtons && hasHiddenPagesAfter && ellipsis){
pageButtons.push(
<PaginationButton
key='ellipsis'
disabled>
<span aria-label='More'>...</span>
</PaginationButton>
);
}

return pageButtons;
},

renderPrev() {
if(!this.props.prev){
return null;
}

return (
<PaginationButton
key='prev'
eventKey={this.props.activePage - 1}
disabled={this.props.activePage === 1}
onSelect={this.props.onSelect}>
<span aria-label='Previous'>&lsaquo;</span>
</PaginationButton>
);
},

renderNext() {
if(!this.props.next){
return null;
}

return (
<PaginationButton
key='next'
eventKey={this.props.activePage + 1}
disabled={this.props.activePage === this.props.items}
onSelect={this.props.onSelect}>
<span aria-label='Next'>&rsaquo;</span>
</PaginationButton>
);
},

renderFirst() {
if(!this.props.first){
return null;
}

return (
<PaginationButton
key='first'
eventKey={1}
disabled={this.props.activePage === 1 }
onSelect={this.props.onSelect}>
<span aria-label='First'>&laquo;</span>
</PaginationButton>
);
},

renderLast() {
if(!this.props.last){
return null;
}

return (
<PaginationButton
key='last'
eventKey={this.props.items}
disabled={this.props.activePage === this.props.items}
onSelect={this.props.onSelect}>
<span aria-label='Last'>&raquo;</span>
</PaginationButton>
);
},

render() {
let classes = this.getBsClassSet();
return (
<ul
{...this.props}
className={classNames(this.props.className, classes)}>
{this.renderFirst()}
{this.renderPrev()}
{this.renderPageButtons()}
{this.renderNext()}
{this.renderLast()}
</ul>
);
}
});

export default Pagination;
51 changes: 51 additions & 0 deletions src/PaginationButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import classNames from 'classnames';
import BootstrapMixin from './BootstrapMixin';
import createSelectedEvent from './utils/createSelectedEvent';

const PaginationButton = React.createClass({
mixins: [BootstrapMixin],

propTypes: {
className: React.PropTypes.string,
eventKey: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
]),
onSelect: React.PropTypes.func,
disabled: React.PropTypes.bool,
active: React.PropTypes.bool
},

getDefaultProps() {
return {
active: false,
disabled: false
};
},

handleClick(event) {
// This would go away once SafeAnchor is available
event.preventDefault();

if (this.props.onSelect) {
let selectedEvent = createSelectedEvent(this.props.eventKey);
this.props.onSelect(event, selectedEvent);
}
},

render() {
let classes = this.getBsClassSet();

classes.active = this.props.active;
classes.disabled = this.props.disabled;

return (
<li className={classNames(this.props.className, classes)}>
<a href='#' onClick={this.handleClick}>{this.props.children}</a>
</li>
);
}
});

export default PaginationButton;

0 comments on commit 5734ec3

Please sign in to comment.