UNPKG

react-bootstrap

Version:

Bootstrap 3 components build with React

123 lines (98 loc) 3.27 kB
/* global window, document */ import React from './react-es6'; import domUtils from './domUtils'; var AffixMixin = { propTypes: { offset: React.PropTypes.number, offsetTop: React.PropTypes.number, offsetBottom: React.PropTypes.number }, getInitialState: function () { return { affixClass: 'affix-top' }; }, getPinnedOffset: function (DOMNode) { if (this.pinnedOffset) { return this.pinnedOffset; } DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, ''); DOMNode.className += DOMNode.className.length ? ' affix' : 'affix'; this.pinnedOffset = domUtils.getOffset(DOMNode).top - window.pageYOffset; return this.pinnedOffset; }, checkPosition: function () { var DOMNode, scrollHeight, scrollTop, position, offsetTop, offsetBottom, affix, affixType, affixPositionTop; // TODO: or not visible if (!this.isMounted()) { return; } DOMNode = this.getDOMNode(); scrollHeight = document.documentElement.offsetHeight; scrollTop = window.pageYOffset; position = domUtils.getOffset(DOMNode); offsetTop; offsetBottom; if (this.affixed === 'top') { position.top += scrollTop; } offsetTop = this.props.offsetTop != null ? this.props.offsetTop : this.props.offset; offsetBottom = this.props.offsetBottom != null ? this.props.offsetBottom : this.props.offset; if (offsetTop == null && offsetBottom == null) { return; } if (offsetTop == null) { offsetTop = 0; } if (offsetBottom == null) { offsetBottom = 0; } if (this.unpin != null && (scrollTop + this.unpin <= position.top)) { affix = false; } else if (offsetBottom != null && (position.top + DOMNode.offsetHeight >= scrollHeight - offsetBottom)) { affix = 'bottom'; } else if (offsetTop != null && (scrollTop <= offsetTop)) { affix = 'top'; } else { affix = false; } if (this.affixed === affix) { return; } if (this.unpin != null) { DOMNode.style.top = ''; } affixType = 'affix' + (affix ? '-' + affix : ''); this.affixed = affix; this.unpin = affix === 'bottom' ? this.getPinnedOffset(DOMNode) : null; if (affix === 'bottom') { DOMNode.className = DOMNode.className.replace(/affix-top|affix-bottom|affix/, 'affix-top'); affixPositionTop = scrollHeight - offsetBottom - DOMNode.offsetHeight - domUtils.getOffset(DOMNode).top; } this.setState({ affixClass: affixType, affixPositionTop: affixPositionTop }); }, checkPositionWithEventLoop: function () { setTimeout(this.checkPosition, 0); }, componentDidMount: function () { window.addEventListener('scroll', this.checkPosition); document.addEventListener('click', this.checkPositionWithEventLoop); }, componentWillUnmount: function () { window.removeEventListener('scroll', this.checkPosition); document.addEventListener('click', this.checkPositionWithEventLoop); }, componentDidUpdate: function (prevProps, prevState) { if (prevState.affixClass === this.state.affixClass) { this.checkPositionWithEventLoop(); } } }; export default = AffixMixin;