diff --git a/karma.conf.js b/karma.conf.js index 16f52a014..78293811d 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -86,8 +86,8 @@ module.exports = function(config) { plugins:[ new webpack.DefinePlugin({ - __CLIENT__: false, - __SERVER__: true, + __CLIENT__: true, + __SERVER__: false, __DEVELOPMENT__: true, __DEVTOOLS__: false // <-------- DISABLE redux-devtools HERE }) diff --git a/src/components/LazyLoad/index.js b/src/components/LazyLoad/index.js new file mode 100644 index 000000000..a2a804d06 --- /dev/null +++ b/src/components/LazyLoad/index.js @@ -0,0 +1,51 @@ +import React, { Component, PropTypes } from 'react'; +import ReactDOM from 'react-dom'; + +import debug from '../../helpers/debug'; + +export default class LazyLoad extends Component { + static propTypes = { + isLoading: PropTypes.bool.isRequired, + isEnd: PropTypes.bool.isRequired, + isLoaded: PropTypes.bool, + onLazyLoad: PropTypes.func.isRequired, + loadingComponent: PropTypes.any, + endComponent: PropTypes.any, + offset: PropTypes.number + } + + static defaultProps = { + loadingComponent: 'Loading...', + endComponent: 'End.', + offset: 1000 + } + + componentDidMount() { + if (__CLIENT__) { + window.removeEventListener('scroll', this.onScroll, true); + window.addEventListener('scroll', this.onScroll, true); + } + } + + onScroll = () => { + const { isLoading, isEnd, offset } = this.props; + const dom = ReactDOM.findDOMNode(this); + + if ((!isLoading && !isEnd) && (dom.offsetParent || dom).offsetTop - (window.pageYOffset + window.innerHeight) < offset) { + debug('component:LazyLoad', 'onLazyLoad called'); + return this.props.onLazyLoad(); + } + + return false; + } + + render() { + const { isEnd, loadingComponent, endComponent } = this.props; + + if (isEnd) { + return endComponent; + } + + return loadingComponent; + } +} diff --git a/src/components/LazyLoad/spec.js b/src/components/LazyLoad/spec.js new file mode 100644 index 000000000..30c17a29e --- /dev/null +++ b/src/components/LazyLoad/spec.js @@ -0,0 +1,58 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { mount } from 'enzyme'; + +import LazyLoad from './index'; + +let wrapper; +let onLazyLoad; +let makeComponent; + +describe('', () => { + beforeEach(() => { + makeComponent = (isEnd = false, isLoading = false) => { + onLazyLoad = sinon.stub(); + wrapper = mount( + End

} + loadingComponent={

Loading

} + /> + ); + }; + + makeComponent(); + }); + + it('should render', () => { + expect(wrapper).to.be.ok; + }); + + it('should show loading component', () => { + expect(wrapper.text()).to.eql('Loading'); + }); + + it('should show end component when no more lazy loading needed', () => { + makeComponent(true); + expect(wrapper.text()).to.eql('End'); + }); + + it('should call onLazyLoad when not end and not loading', () => { + wrapper.instance().onScroll(); + expect(wrapper.props().onLazyLoad).to.have.been.called; + }); + + it('should not call onLazyLoad when at end', () => { + makeComponent(true); + wrapper.instance().onScroll(); + expect(wrapper.props().onLazyLoad).not.to.have.been.called; + }); + + it('should not call onLazyLoad when loading', () => { + makeComponent(false, true); + wrapper.instance().onScroll(); + expect(wrapper.props().onLazyLoad).not.to.have.been.called; + }); +}); diff --git a/src/containers/Surah/index.js b/src/containers/Surah/index.js index 51b3eda1e..e5133b4ad 100644 --- a/src/containers/Surah/index.js +++ b/src/containers/Surah/index.js @@ -8,6 +8,7 @@ import Col from 'react-bootstrap/lib/Col'; import Helmet from 'react-helmet'; // components +import LazyLoad from '../../components/LazyLoad'; import PageBreak from '../../components/PageBreak'; import Audioplayer from '../../components/Audioplayer'; import ContentDropdown from '../../components/ContentDropdown'; @@ -126,8 +127,6 @@ const ayahRangeSize = 30; export default class Surah extends Component { constructor() { super(...arguments); - - this.onScroll = this.onScroll.bind(this); } state = { @@ -136,31 +135,15 @@ export default class Surah extends Component { componentDidMount() { if (__CLIENT__) { - window.removeEventListener('scroll', this.onScroll, true); - window.addEventListener('scroll', this.onScroll, true); + window.removeEventListener('scroll', this.handleNavbar, true); + window.addEventListener('scroll', this.handleNavbar, true); lastScroll = window.pageYOffset; } } - shouldComponentUpdate(nextProps) { - const sameSurahIdRouting = this.props.params.surahId === nextProps.params.surahId; - const lazyLoadFinished = sameSurahIdRouting && (!this.props.isLoaded && nextProps.isLoaded); - const hasReadingModeChange = this.props.options.isReadingMode !== nextProps.options.isReadingMode; - const hasFontSizeChange = this.props.options.fontSize !== nextProps.options.fontSize; - const hasSurahInfoChange = this.props.options.isShowingSurahInfo !== nextProps.options.isShowingSurahInfo; - - return ( - !sameSurahIdRouting || - lazyLoadFinished || - hasReadingModeChange || - hasFontSizeChange || - hasSurahInfoChange - ); - } - componentWillUnmount() { if (__CLIENT__) { - window.removeEventListener('scroll', this.onScroll, true); + window.removeEventListener('scroll', this.handleNavbar, true); } } @@ -224,7 +207,7 @@ export default class Surah extends Component { return setOptionDispatch(payload); } - handleNavbar() { + handleNavbar = () => { // TODO: This should be done with react! if (window.pageYOffset > lastScroll) { document.querySelector('nav').classList.add('scroll-up'); @@ -254,24 +237,6 @@ export default class Surah extends Component { }, 1000)); // then scroll to it } - onScroll() { - const { isLoading, isEndOfSurah } = this.props; - - this.handleNavbar(); - - if (isEndOfSurah) { - return false; - } - - if (!isLoading && !this.state.lazyLoading && window.pageYOffset > (document.body.scrollHeight - window.innerHeight - 1000)) { - // Reached the end. - this.setState({ - lazyLoading: true - }); - - this.lazyLoadAyahs(); - } - } lazyLoadAyahs(callback) { const { loadAyahsDispatch, ayahIds, surah, options } = this.props; @@ -297,38 +262,41 @@ export default class Surah extends Component { } renderPagination() { - const { isEndOfSurah, surah } = this.props; - const { lazyLoading } = this.state; - - if (isEndOfSurah && !lazyLoading) { - return ( - - ); - } - - return

Loading...

; + { + surah.id < 114 && +
  • + + Next Surah → + +
  • + } + + } + loadingComponent={

    Loading...

    } + /> + ); } renderAyahs() { diff --git a/src/redux/modules/ayahs.js b/src/redux/modules/ayahs.js index e0c45bc3a..33ddf07f8 100644 --- a/src/redux/modules/ayahs.js +++ b/src/redux/modules/ayahs.js @@ -13,6 +13,7 @@ const initialState = { current: null, errored: false, loaded: false, + loading: false, entities: {}, result: [], fontFaces: []