Workflow- added getWorkflow call to catalog
[sdc/sdc-workflow-designer.git] / workflow-designer-ui / src / main / frontend / src / shared / scroll / InfiniteScroll.js
1 /*
2 * Copyright © 2018 European Support Limited
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 import React from 'react';
18 import PropTypes from 'prop-types';
19
20 class InfiniteScroll extends React.Component {
21     constructor(props) {
22         super(props);
23         this.state = {
24             initialLoad: false
25         };
26     }
27     componentDidMount() {
28         this.scrollEl = this.getScrollElement();
29         this.attachScrollListener();
30         this.setState({ initialLoad: true });
31     }
32
33     componentDidUpdate() {
34         this.attachScrollListener();
35     }
36
37     componentWillUnmount() {
38         this.detachScrollListener();
39     }
40
41     getParentElement(el) {
42         return el.parentNode;
43     }
44
45     getScrollElement() {
46         if (this.props.useWindow) {
47             return window;
48         }
49
50         return this.getParentElement(this.scrollComponent);
51     }
52
53     detachScrollListener() {
54         this.scrollEl.removeEventListener(
55             'scroll',
56             this.scrollListener,
57             this.props.useCapture
58         );
59         window.removeEventListener(
60             'resize',
61             this.scrollListener,
62             this.props.useCapture
63         );
64     }
65
66     attachScrollListener() {
67         if (!this.props.hasMore || !this.scrollEl) {
68             return;
69         }
70
71         const options = {
72             capture: this.props.useCapture,
73             passive: true
74         };
75
76         this.scrollEl.addEventListener('scroll', this.scrollListener, options);
77         window.addEventListener('resize', this.scrollListener, options);
78
79         this.scrollListener();
80     }
81
82     scrollListener = () => {
83         const el = this.scrollComponent;
84         const scrollEl = window;
85         const parentNode = this.getParentElement(el);
86
87         let offset;
88         if (this.props.useWindow) {
89             const doc =
90                 document.documentElement ||
91                 document.body.parentNode ||
92                 document.body;
93             const scrollTop =
94                 scrollEl.pageYOffset !== undefined
95                     ? scrollEl.pageYOffset
96                     : doc.scrollTop;
97
98             offset =
99                 this.calculateTopPosition(el) +
100                 (el.offsetHeight - scrollTop - window.innerHeight);
101         } else {
102             offset =
103                 el.scrollHeight -
104                 parentNode.scrollTop -
105                 parentNode.clientHeight;
106         }
107
108         // Here we make sure the element is visible as well as checking the offset
109         if (offset < Number(this.props.threshold) && el.offsetParent !== null) {
110             this.detachScrollListener();
111             // Call loadMore after detachScrollListener to allow for non-async loadMore functions
112             if (
113                 typeof this.props.loadMore === 'function' &&
114                 this.state.initialLoad
115             ) {
116                 this.props.loadMore();
117             }
118         }
119     };
120
121     calculateTopPosition(el) {
122         if (!el) {
123             return 0;
124         }
125         return el.offsetTop + this.calculateTopPosition(el.offsetParent);
126     }
127
128     render() {
129         const { children, element } = this.props;
130
131         const props = {
132             ref: node => {
133                 this.scrollComponent = node;
134             }
135         };
136
137         const childrenArray = [children];
138
139         return React.createElement(element, props, childrenArray);
140     }
141 }
142
143 InfiniteScroll.propTypes = {
144     children: PropTypes.node.isRequired,
145     element: PropTypes.node,
146     hasMore: PropTypes.bool,
147     loadMore: PropTypes.func.isRequired,
148     threshold: PropTypes.number,
149     useCapture: PropTypes.bool,
150     useWindow: PropTypes.bool
151 };
152
153 InfiniteScroll.defaultProps = {
154     element: 'div',
155     hasMore: false,
156     threshold: 250,
157     useWindow: true,
158     useCapture: false
159 };
160
161 export default InfiniteScroll;