Created
September 7, 2022 13:14
-
-
Save mherchel/39c2e97e67ef9a44942e6b9858561a0e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
(function () { | |
/* | |
* Fetch more data like views_load_more. | |
* | |
* @todos | |
* Add Quicklink integration when https://github.com/GoogleChromeLabs/quicklink/issues/54 is resolved. | |
*/ | |
Drupal.behaviors.load_more = { | |
'attach': function (context) { | |
const contentContainerSelector = drupalSettings.lullabotcom.loadMore.contentContainerSelector; | |
const contentContainer = context.querySelector(contentContainerSelector); | |
const pagerContainer = context.querySelector(drupalSettings.lullabotcom.loadMore.pagerSelector); | |
const currentURL = window.location.protocol + '//' + window.location.host + window.location.pathname; | |
function handleClick() { | |
const pageToFetch = getPageNumberFromURL() + 1; | |
pagerContainer.querySelector('.load-more').classList.add('is-loading'); | |
window.location.hash = 'page' + pageToFetch; | |
fetchData(pageToFetch) | |
.then(data => appendDatatoView(data)); | |
} | |
// Looks at the hash and returns the current page. | |
function getPageNumberFromURL() { | |
return parseInt(location.hash ? location.hash.replace('#page', '') : 1); | |
} | |
/** | |
* Load all previous pages including the current page (as indicated by the hash) into the DOM. | |
*/ | |
function loadPreviousPages() { | |
const currentPageNumber = getPageNumberFromURL(); | |
const pagePromises = []; | |
const pagesData = {}; | |
// If we're on the initial page (no hash exists), exit. | |
if (currentPageNumber === 1) return; | |
// If the data is already loaded, abort. | |
if (!contentContainer || contentContainer.classList.contains('is-loaded')) return; | |
pagerContainer.querySelector('.load-more').classList.add('is-loading'); | |
// Loop through pages starting on page 2 through the current page, and fetch data. | |
for (let i = 2; i <= currentPageNumber; i++) { | |
// Add all promises to array, so we can call Promises.all on it later. | |
pagePromises.push( | |
fetchData(i) | |
.then(pageData => { | |
// Create an object containing arrays of elements (one-indexed). | |
pagesData[i - 1] = pageData; | |
}) | |
); | |
} | |
// When all fetches have completed, combine into one giant array, and pass to appendDatatoView(). | |
Promise.all(pagePromises).then(() => { | |
let combinedPagesArr = []; | |
for (let i = 1; i <= Object.keys(pagesData).length; i++) { | |
combinedPagesArr.push(...pagesData[i]); | |
} | |
appendDatatoView(combinedPagesArr); | |
// CSS class to indicate the data is loaded. | |
contentContainer.classList.add('is-loaded'); | |
}); | |
} | |
/** | |
* Fetch data in the specified page. | |
* @param pageToFetch Number of the page to fetch | |
* @returns { Promise } Promise object which returns an array of elements. | |
* */ | |
function fetchData(pageToFetch) { | |
// Get page's querystring and update the 'page' parameter. | |
const urlParams = new URLSearchParams(window.location.search); | |
urlParams.set('page', pageToFetch - 1); // Views pages are zero indexed. | |
const fetchURL = currentURL + '?' + urlParams.toString(); | |
return fetch(fetchURL).then(response => { | |
return response.text(); | |
}).then(htmlText => { | |
const parser = new DOMParser; | |
const pageNodeList = parser.parseFromString(htmlText, 'text/html').querySelectorAll(contentContainerSelector + ' > *'); | |
// Convert nodelist to array. | |
const pageDataArray = Array.from(pageNodeList); | |
// Create and prepend page number anchor to pageDataArray if there is data. | |
if (pageDataArray.length) { | |
const pageAnchor = parser.parseFromString(`<a href="#page${pageToFetch}" class="visually-hidden page-anchor">Page ${pageToFetch}</a>`, 'text/html').querySelector('a'); | |
pageDataArray.unshift(pageAnchor); | |
} | |
return pageDataArray; | |
}); | |
} | |
/** | |
* Append data to the DOM. | |
* @param data Array of elements | |
*/ | |
function appendDatatoView(data) { | |
// If no more data is to be had, hide the button. | |
if (!data.length) { | |
pagerContainer.querySelector('.load-more').classList.add('u-hidden'); | |
return; | |
} | |
const contentHtml = document.createDocumentFragment(); | |
data.forEach((currentValue) => { | |
contentHtml.append(currentValue); | |
}); | |
contentContainer.append(contentHtml); | |
// Focus the last page anchor for a11y. | |
const pageAnchors = contentContainer.querySelectorAll('a.page-anchor'); | |
pageAnchors[pageAnchors.length - 1].focus(); | |
pagerContainer.querySelector('.load-more').classList.remove('is-loading'); | |
Drupal.announce('Additional data has been loaded.'); | |
} | |
loadPreviousPages(); | |
if (pagerContainer) { | |
pagerContainer.querySelector('.load-more__button').addEventListener('click', handleClick); | |
} | |
}, | |
}; | |
}) (); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment