cruk-searchkit
Version:
Set of overriden and new searchkit components designed specifically for Cancer Research UK
175 lines (152 loc) • 4.55 kB
JSX
import React from 'react';
import bem from 'bem-cn';
import {
block,
PaginationHelper,
Paginator,
Pagination,
ItemComponent,
FastClick
} from 'searchkit';
import {
map
} from 'lodash';
import sanitizeHtml from 'sanitize-html-react';
import scroll from 'scroll';
// Specify the main BEM class that will be used over this component.
const bemPager = bem('cr-simple-pager')
/**
* This file is a mess of extending all sorts, makes me sad inside! This is
* because we've got a specific way we want the pagination to look.
*/
/**
* Define a custom itemComponent class for us to use.
*/
class CRUKSearchkitPaginationItemComponent extends ItemComponent {
render() {
const {onClick, disabled, itemKey, label, className} = this.props
let safeLabel = {__html: label};
let content = typeof itemKey === 'string' ?
<a data-qa="label" dangerouslySetInnerHTML={safeLabel} className={bemPager('link')}></a> :
<span data-qa="label" className={bemPager('indicator')} href={'#' + itemKey} dangerouslySetInnerHTML={safeLabel}></span>;
return (
<FastClick handler={onClick}>
<li className={disabled ? className + ' disabled' : className} data-qa="option" data-key={itemKey}>
{content}
</li>
</FastClick>
)
}
}
/**
* Define our basic pagination class which will spit out a simple pager aligned
* more to Bootstrap than searchkit.
*/
class CRUKSearchkitPagination extends Pagination {
static propTypes = {
blockSearch: React.PropTypes.bool,
...Pagination.propTypes
}
constructor(props) {
super();
this.state = {
clicked: 0
};
this.changeAndScroll = this.changeAndScroll.bind(this);
}
componentWillUpdate() {
if (this.state.clicked === 2) {
const position = this.getAbsPosition(document.getElementById('searchPrototypeApp'));
scroll.top(document.querySelector('body'), position);
// IE and Firefox Hack
document.documentElement.scrollTop = 0;
this.setState({clicked: 0});
}
}
getAbsPosition = (element) => {
let el = element;
let el2 = el;
let curtop = 0;
if (document.getElementById || document.all) {
do {
curtop += el.offsetTop - el.scrollTop;
el = el.offsetParent;
el2 = el2.parentNode;
while (el2 !== el) {
curtop -= el2.scrollTop;
el2 = el2.parentNode;
}
} while (el.offsetParent);
} else if (document.layers) {
curtop += el.y;
}
return curtop;
}
changeAndScroll(key) {
this.setState({clicked: 1}, () => {
this.setPage(key);
this.setState({clicked: 2});
});
}
render() {
if (!this.hasHits()) return null;
/**
* Inject the page number item into the middle of the array.
*/
let items = [];
let currentPage = this.getCurrentPage();
let totalPages = this.getTotalPages();
let currentPageItem = {
disabled: true,
key: currentPage,
label: totalPages > 1 ? 'Page ' + currentPage + ' of ' + totalPages : 'Page 1',
page: currentPage,
className: 'current'
}
/**
* Remove items so as not to show links that do nothing.
*/
if (totalPages === 1) {
items[0] = currentPageItem;
}
else {
items = this.getPages();
items[0].className = 'previous';
items[1].className = 'next';
items.splice(1, 0, currentPageItem);
// Remove next.
if (totalPages === currentPage) {
items = items.slice(0, 2);
}
}
const view = map(items, (option) => {
const label = option.title || option.label || option.key
return React.createElement(CRUKSearchkitPaginationItemComponent, {
label: label,
onClick: () => this.changeAndScroll(option.key),
key: option.key,
itemKey: option.key,
disabled: option.disabled,
className: bemPager(option.className)
})
})
// If search is blocked, on empty search preformed do not render component.
if (this.props.blockSearch) return null;
return <nav aria-label="Select a different page">
<ul className={bemPager}>
{view}
</ul>
</nav>
}
}
/**
* Alter the default props.
*/
CRUKSearchkitPagination.defaultProps['translations'] = {
'pagination.previous': '<span class="glyphicon glyphicon-chevron-left"></span> Prev',
'pagination.next': 'Next <span class="glyphicon glyphicon-chevron-right"></span>'
};
/**
* Export the class.
*/
export default CRUKSearchkitPagination