diff --git a/src/blocks/homepage-articles/view.js b/src/blocks/homepage-articles/view.js index 76a75e106..31ca57d69 100644 --- a/src/blocks/homepage-articles/view.js +++ b/src/blocks/homepage-articles/view.js @@ -38,18 +38,16 @@ function buildLoadMoreHandler( blockWrapperEl ) { const isInfiniteScroll = btnEl.getAttribute( 'data-infinite-scroll' ); // Set initial state flags. - window.isInfiniteScrolling = false; - let isFetching = false; + window.newspackBlocksIsFetching = window.newspackBlocksIsFetching || false; + window.newspackBlocksFetchQueue = window.newspackBlocksFetchQueue || []; let isEndOfData = false; - btnEl.addEventListener( 'click', () => { - // Early return if still fetching or no more posts to render. - if ( isFetching || isEndOfData ) { + const loadMore = () => { + // Early return if no more posts to render. + if ( isEndOfData ) { return false; } - isFetching = true; - blockWrapperEl.classList.remove( 'is-error' ); blockWrapperEl.classList.add( 'is-loading' ); @@ -57,58 +55,74 @@ function buildLoadMoreHandler( blockWrapperEl ) { const requestURL = btnEl.getAttribute( 'data-next' ) + '&exclude_ids=' + getRenderedPostsIds().join( ',' ); + // If there's already a fetch in progress, queue this one to run after it ends. + if ( window.newspackBlocksIsFetching ) { + window.newspackBlocksFetchQueue.push( loadMore ); + return false; + } + + window.newspackBlocksIsFetching = true; fetchWithRetry( { url: requestURL, onSuccess, onError }, fetchRetryCount ); + }; - /** - * @param {Object} data Post data - */ - function onSuccess( data ) { - // Validate received data. - if ( ! isPostsDataValid( data ) ) { - return onError(); - } + /** + * @param {Object} data Post data + */ + function onSuccess( data ) { + // Validate received data. + if ( ! isPostsDataValid( data ) ) { + return onError(); + } - if ( data.items.length ) { - // Render posts' HTML from string. - const postsHTML = data.items.map( item => item.html ).join( '' ); - postsContainerEl.insertAdjacentHTML( 'beforeend', postsHTML ); - } + if ( data.items.length ) { + // Render posts' HTML from string. + const postsHTML = data.items.map( item => item.html ).join( '' ); + postsContainerEl.insertAdjacentHTML( 'beforeend', postsHTML ); + } - if ( data.next ) { - // Save next URL as button's attribute. - btnEl.setAttribute( 'data-next', data.next ); - } + if ( data.next ) { + // Save next URL as button's attribute. + btnEl.setAttribute( 'data-next', data.next ); + } - if ( ! data.items.length || ! data.next ) { - isEndOfData = true; - blockWrapperEl.classList.remove( 'has-more-button' ); - } + if ( ! data.items.length || ! data.next ) { + isEndOfData = true; + blockWrapperEl.classList.remove( 'has-more-button' ); + } - isFetching = false; + onEnd(); + } - blockWrapperEl.classList.remove( 'is-loading' ); + /** + * Handle fetching error + */ + function onError() { + blockWrapperEl.classList.add( 'is-error' ); + onEnd(); + } + + /** + * Callback to run after a fetch request is completed. + */ + function onEnd() { + window.newspackBlocksIsFetching = false; + blockWrapperEl.classList.remove( 'is-loading' ); - window.isInfiniteScrolling = false; + // If there are queued fetches, run the next one. + if ( window.newspackBlocksFetchQueue.length ) { + window.newspackBlocksFetchQueue.shift()(); } + } - /** - * Handle fetching error - */ - function onError() { - isFetching = false; + btnEl.addEventListener( 'click', loadMore ); - blockWrapperEl.classList.remove( 'is-loading' ); - blockWrapperEl.classList.add( 'is-error' ); - } - } ); if ( isInfiniteScroll ) { // Create an intersection observer instance const btnObserver = new IntersectionObserver( entries => { entries.forEach( entry => { - if ( entry.isIntersecting && ! window.isInfiniteScrolling ) { - btnEl.click(); - window.isInfiniteScrolling = true; + if ( entry.isIntersecting ) { + loadMore(); } } ); },