2 * Copyright © 2018 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 import React from 'react';
18 import PropTypes from 'prop-types';
20 class InfiniteScroll extends React.Component {
22 this.pageLoaded = this.props.pageStart;
23 this.scrollEl = this.getScrollElement();
24 this.attachScrollListener();
27 componentDidUpdate() {
28 this.attachScrollListener();
31 componentWillUnmount() {
32 this.detachScrollListener();
35 getParentElement(el) {
40 if (this.props.useWindow) {
44 return this.getParentElement(this.scrollComponent);
47 detachScrollListener() {
48 this.scrollEl.removeEventListener(
53 window.removeEventListener(
60 attachScrollListener() {
61 if (!this.props.hasMore || !this.scrollEl) {
66 capture: this.props.useCapture,
70 this.scrollEl.addEventListener('scroll', this.scrollListener, options);
71 window.addEventListener('resize', this.scrollListener, options);
73 if (this.props.initialLoad) {
74 this.scrollListener();
78 scrollListener = () => {
79 const el = this.scrollComponent;
80 const scrollEl = window;
81 const parentNode = this.getParentElement(el);
84 if (this.props.useWindow) {
86 document.documentElement ||
87 document.body.parentNode ||
90 scrollEl.pageYOffset !== undefined
91 ? scrollEl.pageYOffset
95 this.calculateTopPosition(el) +
96 (el.offsetHeight - scrollTop - window.innerHeight);
100 parentNode.scrollTop -
101 parentNode.clientHeight;
104 // Here we make sure the element is visible as well as checking the offset
105 if (offset < Number(this.props.threshold) && el.offsetParent !== null) {
106 this.detachScrollListener();
107 // Call loadMore after detachScrollListener to allow for non-async loadMore functions
108 if (typeof this.props.loadMore === 'function') {
109 this.props.loadMore((this.pageLoaded += 1));
114 calculateTopPosition(el) {
118 return el.offsetTop + this.calculateTopPosition(el.offsetParent);
122 const { children, element } = this.props;
126 this.scrollComponent = node;
130 const childrenArray = [children];
132 return React.createElement(element, props, childrenArray);
136 InfiniteScroll.propTypes = {
137 children: PropTypes.node.isRequired,
138 element: PropTypes.node,
139 hasMore: PropTypes.bool,
140 initialLoad: PropTypes.bool,
141 loadMore: PropTypes.func.isRequired,
142 pageStart: PropTypes.number,
143 threshold: PropTypes.number,
144 useCapture: PropTypes.bool,
145 useWindow: PropTypes.bool
148 InfiniteScroll.defaultProps = {
158 export default InfiniteScroll;