Skip to content

Instantly share code, notes, and snippets.

@ha404
Last active March 23, 2016 19:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ha404/a855015f241f8c5b27f7 to your computer and use it in GitHub Desktop.
Save ha404/a855015f241f8c5b27f7 to your computer and use it in GitHub Desktop.
import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import _ from 'lodash';
import { connectToStores } from 'fluxible-addons-react';
import ApplicationStore from '../../stores/ApplicationStore';
import windowSizeChange from '../../actions/windowSizeChange';
import windowScrollChange from '../../actions/windowScrollChange';
const propTypes = {
active: React.PropTypes.bool,
onEnterViewport: React.PropTypes.func,
onScrollChange: React.PropTypes.func,
onResizeChange: React.PropTypes.func,
width: PropTypes.number,
height: PropTypes.number,
offset: PropTypes.number,
debounceDelay: PropTypes.number,
shouldSetScrollContext: PropTypes.bool,
shouldSetResizeContext: PropTypes.bool,
children: PropTypes.node,
};
const defaultProps = {
active: true,
width: 0,
height: 0,
offset: 0,
debounceDelay: 30,
shouldSetScrollContext: false,
shouldSetResizeContext: false,
};
const contextTypes = {
executeAction: PropTypes.func.isRequired,
};
class Sauron extends Component {
constructor() {
super();
this.handleResize = this.handleResize.bind(this);
this.handleScroll = this.handleScroll.bind(this);
this.isElementInViewport = this.isElementInViewport.bind(this);
this.startWatching = this.startWatching.bind(this);
this.stopWatching = this.stopWatching.bind(this);
this.setWindowSizeContext = this.setWindowSizeContext.bind(this);
this.setWindowPosContext = this.setWindowPosContext.bind(this);
}
componentDidMount() {
if (this.props.active) {
this.startWatching();
}
}
componentWillUnmount() {
this.stopWatching();
}
setWindowSizeContext() {
this.context.executeAction(windowSizeChange, {
width: window.innerWidth,
height: window.innerHeight,
});
}
setWindowPosContext() {
this.context.executeAction(windowScrollChange, {
scrollPos: window.pageYOffset || document.documentElement.scrollTop,
});
}
startWatching() {
if (this.props.shouldSetScrollContext) {
this.setWindowPosContext();
}
this.debouncedScroll = _.debounce(this.handleScroll, this.props.debounceDelay);
window.addEventListener('scroll', this.debouncedScroll);
if (this.props.shouldSetResizeContext) {
this.setWindowSizeContext();
}
this.debouncedResize = _.debounce(this.handleResize, this.props.debounceDelay);
window.addEventListener('resize', this.debouncedResize);
this.isElementInViewport();
}
stopWatching() {
window.removeEventListener('resize', this.debouncedResize);
window.removeEventListener('scroll', this.debouncedScroll);
}
handleResize() {
this.isElementInViewport();
if (this.props.shouldSetResizeContext) {
this.setWindowSizeContext();
}
if (this.props.onResizeChange) {
this.props.onResizeChange();
}
}
handleScroll() {
this.isElementInViewport();
if (this.props.shouldSetScrollContext) {
this.setWindowPosContext();
}
if (this.props.onScrollChange) {
this.props.onScrollChange(window.pageYOffset || document.documentElement.scrollTop);
}
}
isElementInViewport(el) {
if (!this.props.active) {
this.stopWatching();
}
const element = element ? el : ReactDOM.findDOMNode(this);
const rect = element.getBoundingClientRect();
const isInTheZoneAutoZone = (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
if (this.props.onEnterViewport) {
this.props.onEnterViewport(isInTheZoneAutoZone);
}
return isInTheZoneAutoZone;
}
render() {
return this.props.children ? this.props.children : <span />;
}
}
Sauron.propTypes = propTypes;
Sauron.defaultProps = defaultProps;
Sauron.contextTypes = contextTypes;
Sauron = connectToStores(Sauron, [ApplicationStore], (context) => (
context.getStore(ApplicationStore).getState()
));
export default Sauron;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment