226 lines
5.4 KiB
JavaScript
226 lines
5.4 KiB
JavaScript
/** @format */
|
|
|
|
/**
|
|
* External dependencies
|
|
*/
|
|
import { __, sprintf } from '@wordpress/i18n';
|
|
import { Component } from '@wordpress/element';
|
|
import { IconButton, SelectControl } from '@wordpress/components';
|
|
import classNames from 'classnames';
|
|
import PropTypes from 'prop-types';
|
|
import { isFinite, noop, uniqueId } from 'lodash';
|
|
|
|
/**
|
|
* Internal dependencies
|
|
*/
|
|
import './style.scss';
|
|
|
|
const PER_PAGE_OPTIONS = [ 25, 50, 75, 100 ];
|
|
|
|
/**
|
|
* Use `Pagination` to allow navigation between pages that represent a collection of items.
|
|
* The component allows for selecting a new page and items per page options.
|
|
*/
|
|
class Pagination extends Component {
|
|
constructor( props ) {
|
|
super( props );
|
|
|
|
this.previousPage = this.previousPage.bind( this );
|
|
this.nextPage = this.nextPage.bind( this );
|
|
this.onPageValueChange = this.onPageValueChange.bind( this );
|
|
this.perPageChange = this.perPageChange.bind( this );
|
|
this.selectInputValue = this.selectInputValue.bind( this );
|
|
}
|
|
|
|
previousPage( event ) {
|
|
event.stopPropagation();
|
|
const { page, onPageChange } = this.props;
|
|
if ( page - 1 < 1 ) {
|
|
return;
|
|
}
|
|
onPageChange( page - 1 );
|
|
}
|
|
|
|
nextPage( event ) {
|
|
event.stopPropagation();
|
|
const { page, onPageChange } = this.props;
|
|
if ( page + 1 > this.pageCount ) {
|
|
return;
|
|
}
|
|
onPageChange( page + 1 );
|
|
}
|
|
|
|
perPageChange( perPage ) {
|
|
const { onPerPageChange, onPageChange, total, page } = this.props;
|
|
|
|
onPerPageChange( parseInt( perPage ) );
|
|
const newMaxPage = Math.ceil( total / parseInt( perPage ) );
|
|
if ( page > newMaxPage ) {
|
|
onPageChange( newMaxPage );
|
|
}
|
|
}
|
|
|
|
onPageValueChange( event ) {
|
|
const { onPageChange } = this.props;
|
|
const newPage = parseInt( event.target.value, 10 );
|
|
|
|
if ( isFinite( newPage ) && this.pageCount && this.pageCount >= newPage ) {
|
|
onPageChange( newPage );
|
|
}
|
|
}
|
|
|
|
selectInputValue( event ) {
|
|
event.target.select();
|
|
}
|
|
|
|
renderPageArrows() {
|
|
const { page } = this.props;
|
|
|
|
if ( this.pageCount <= 1 ) {
|
|
return null;
|
|
}
|
|
|
|
const previousLinkClass = classNames( 'woocommerce-pagination__link', {
|
|
'is-active': page > 1,
|
|
} );
|
|
|
|
const nextLinkClass = classNames( 'woocommerce-pagination__link', {
|
|
'is-active': page < this.pageCount,
|
|
} );
|
|
|
|
return (
|
|
<div className="woocommerce-pagination__page-arrows">
|
|
<span
|
|
className="woocommerce-pagination__page-arrows-label"
|
|
role="status"
|
|
aria-live="polite"
|
|
>
|
|
{ sprintf( __( 'Page %d of %d', 'wc-admin' ), page, this.pageCount ) }
|
|
</span>
|
|
<div className="woocommerce-pagination__page-arrows-buttons">
|
|
<IconButton
|
|
className={ previousLinkClass }
|
|
disabled={ ! ( page > 1 ) }
|
|
onClick={ this.previousPage }
|
|
icon="arrow-left-alt2"
|
|
label={ __( 'Previous Page', 'wc-admin' ) }
|
|
size={ 18 }
|
|
/>
|
|
<IconButton
|
|
className={ nextLinkClass }
|
|
disabled={ ! ( page < this.pageCount ) }
|
|
onClick={ this.nextPage }
|
|
icon="arrow-right-alt2"
|
|
label={ __( 'Next Page', 'wc-admin' ) }
|
|
size={ 18 }
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderPagePicker() {
|
|
const { page } = this.props;
|
|
const isError = page < 1 || page > this.pageCount;
|
|
const inputClass = classNames( 'woocommerce-pagination__page-picker-input', {
|
|
'has-error': isError,
|
|
} );
|
|
|
|
const instanceId = uniqueId( 'woocommerce-pagination-page-picker-' );
|
|
return (
|
|
<div className="woocommerce-pagination__page-picker">
|
|
<label htmlFor={ instanceId } className="woocommerce-pagination__page-picker-label">
|
|
{ __( 'Go to page', 'wc-admin' ) }
|
|
<input
|
|
id={ instanceId }
|
|
className={ inputClass }
|
|
aria-invalid={ isError }
|
|
type="number"
|
|
onClick={ this.selectInputValue }
|
|
onChange={ this.onPageValueChange }
|
|
value={ page }
|
|
min={ 1 }
|
|
max={ this.pageCount }
|
|
/>
|
|
</label>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderPerPagePicker() {
|
|
// TODO Replace this with a styleized Select drop-down/control?
|
|
const pickerOptions = PER_PAGE_OPTIONS.map( option => {
|
|
return { value: option, label: option };
|
|
} );
|
|
|
|
return (
|
|
<div className="woocommerce-pagination__per-page-picker">
|
|
<SelectControl
|
|
label={ __( 'Rows per page', 'wc-admin' ) }
|
|
value={ this.props.perPage }
|
|
onChange={ this.perPageChange }
|
|
options={ pickerOptions }
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
const { total, perPage, className } = this.props;
|
|
this.pageCount = Math.ceil( total / perPage );
|
|
|
|
const classes = classNames( 'woocommerce-pagination', className );
|
|
|
|
if ( this.pageCount <= 1 ) {
|
|
return (
|
|
( total > PER_PAGE_OPTIONS[ 0 ] && (
|
|
<div className={ classes }>{ this.renderPerPagePicker() }</div>
|
|
) ) ||
|
|
null
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={ classes }>
|
|
{ this.renderPageArrows() }
|
|
{ this.renderPagePicker() }
|
|
{ this.renderPerPagePicker() }
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
Pagination.propTypes = {
|
|
/**
|
|
* The current page of the collection.
|
|
*/
|
|
page: PropTypes.number.isRequired,
|
|
/**
|
|
* A function to execute when the page is changed.
|
|
*/
|
|
onPageChange: PropTypes.func,
|
|
/**
|
|
* The amount of results that are being displayed per page.
|
|
*/
|
|
perPage: PropTypes.number.isRequired,
|
|
/**
|
|
* A function to execute when the per page option is changed.
|
|
*/
|
|
onPerPageChange: PropTypes.func,
|
|
/**
|
|
* The total number of results.
|
|
*/
|
|
total: PropTypes.number.isRequired,
|
|
/**
|
|
* Additional classNames.
|
|
*/
|
|
className: PropTypes.string,
|
|
};
|
|
|
|
Pagination.defaultProps = {
|
|
onPageChange: noop,
|
|
onPerPageChange: noop,
|
|
};
|
|
|
|
export default Pagination;
|