Skip to content
This repository has been archived by the owner on Jun 28, 2021. It is now read-only.

End of surah loading #289

Merged
merged 3 commits into from
May 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down
51 changes: 51 additions & 0 deletions src/components/LazyLoad/index.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
58 changes: 58 additions & 0 deletions src/components/LazyLoad/spec.js
Original file line number Diff line number Diff line change
@@ -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('<LazyLoad />', () => {
beforeEach(() => {
makeComponent = (isEnd = false, isLoading = false) => {
onLazyLoad = sinon.stub();
wrapper = mount(
<LazyLoad
onLazyLoad={onLazyLoad}
isEnd={isEnd}
isLoading={isLoading}
endComponent={<p>End</p>}
loadingComponent={<p>Loading</p>}
/>
);
};

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;
});
});
108 changes: 38 additions & 70 deletions src/containers/Surah/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -126,8 +127,6 @@ const ayahRangeSize = 30;
export default class Surah extends Component {
constructor() {
super(...arguments);

this.onScroll = this.onScroll.bind(this);
}

state = {
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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');
Expand Down Expand 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;
Expand All @@ -297,38 +262,41 @@ export default class Surah extends Component {
}

renderPagination() {
const { isEndOfSurah, surah } = this.props;
const { lazyLoading } = this.state;

if (isEndOfSurah && !lazyLoading) {
return (
<ul className="pager">
{
surah.id > 1 &&
<li className="previous">
<Link to={`/${surah.id * 1 - 1}`}>
&larr; Previous Surah
</Link>
</li>
}
<li className="text-center">
<Link to={`/${surah.id}`}>
Beginning of Surah
</Link>
</li>
{
surah.id < 114 &&
<li className="next">
<Link to={`/${surah.id * 1 + 1}`}>
Next Surah &rarr;
const { isLoading, isEndOfSurah, surah } = this.props;

return (
<LazyLoad
onLazyLoad={this.lazyLoadAyahs.bind(this)}
isEnd={isEndOfSurah && !isLoading}
isLoading={isLoading}
endComponent={
<ul className="pager">
{
surah.id > 1 &&
<li className="previous">
<Link to={`/${surah.id * 1 - 1}`}>
&larr; Previous Surah
</Link>
</li>
}
<li className="text-center">
<Link to={`/${surah.id}`}>
Beginning of Surah
</Link>
</li>
}
</ul>
);
}

return <p>Loading...</p>;
{
surah.id < 114 &&
<li className="next">
<Link to={`/${surah.id * 1 + 1}`}>
Next Surah &rarr;
</Link>
</li>
}
</ul>
}
loadingComponent={<p>Loading...</p>}
/>
);
}

renderAyahs() {
Expand Down
1 change: 1 addition & 0 deletions src/redux/modules/ayahs.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const initialState = {
current: null,
errored: false,
loaded: false,
loading: false,
entities: {},
result: [],
fontFaces: []
Expand Down