diff --git a/web/app/themes/awasqa/functions.php b/web/app/themes/awasqa/functions.php index 7af1c76..6450429 100644 --- a/web/app/themes/awasqa/functions.php +++ b/web/app/themes/awasqa/functions.php @@ -31,7 +31,7 @@ // WPML logic require_once(__DIR__ . '/src/wpml.php'); -$ver = "1.8"; +$ver = "1.9"; add_action('wp_enqueue_scripts', function () use ($ver) { wp_enqueue_style( 'awasqa', diff --git a/web/app/themes/awasqa/pre-script.js b/web/app/themes/awasqa/pre-script.js index 373c196..4900fab 100644 --- a/web/app/themes/awasqa/pre-script.js +++ b/web/app/themes/awasqa/pre-script.js @@ -5,3 +5,8 @@ const style = document.createElement("style") style.innerText = "body { visibility: hidden; }" document.head.appendChild(style) + + // Fallback in case of errors - display page after 5 seconds + setTimeout(() => { + document.head.removeChild(style); + }, 5000); \ No newline at end of file diff --git a/web/app/themes/awasqa/script.js b/web/app/themes/awasqa/script.js index d0920c8..45d07b4 100644 --- a/web/app/themes/awasqa/script.js +++ b/web/app/themes/awasqa/script.js @@ -153,5 +153,110 @@ document.querySelectorAll( query.previousElementSibling.style.display = "none" }) +// Set up infinite scroll +function isElementInViewport(el) { + const rect = el.getBoundingClientRect(); + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); +} + +/** + * Pass an element, and return the key and value of + * the ?query-N-page=M query parameter. Used for pagination. + */ +function getLinkPageParam(a) { + let href = a.getAttribute('href') + if (!href) { + return {} + } + if (!href.startsWith('http')) { + href = `${window.location.protocol}//${window.location.host}${href}` + } + const parsedHref = new URL(href) + const queryParams = parsedHref.searchParams + let pageParam = null; + for (const param of queryParams.keys()) { + if (param.match(/query-[0-9]+-page+/)) { + pageParam = param + } + } + if (!pageParam) { + return {} + } + let page = queryParams.get(pageParam) + return { + href: href, + param: pageParam, + value: page + } +} + +document.querySelectorAll('body.single .wp-block-query-pagination').forEach(pagination => { + const loading = document.createElement("div") + loading.setAttribute('class', 'awasqa-infinite-scroll-loading') + pagination.appendChild(loading) + pagination.querySelectorAll("*").forEach(el => { el.style.visibility = "hidden" }) + + const queryLoopWrapper = pagination.closest('.wp-block-query') + const queryLoop = queryLoopWrapper.querySelector('.wp-block-post-template') + const next = pagination.querySelector('.wp-block-query-pagination-next') + if (!next) { + return + } + + let { href: nextHref, param: paginationParam } = getLinkPageParam(next) + + let pagesFetched = [] + + function doInfiniteScroll() { + if (!nextHref) { + return + } + if (!isElementInViewport(pagination)) { + return + } + if (pagesFetched.includes(nextHref)) { + return + } + loading.style.visibility = "visible" + pagesFetched.push(nextHref) + window.fetch(nextHref).then(response => response.text()).then(html => { + let body = html.split(/]*>/)[1] + body = body.split('')[0] + const dummy = document.createElement('div') + dummy.innerHTML = body + dummy.querySelectorAll('.wp-block-query-pagination a').forEach(pageLink => { + const { param } = getLinkPageParam(pageLink) + let appended = false + if (!appended && param === paginationParam) { + const fetchedQueryLoop = pageLink.closest('.wp-block-query') + fetchedQueryLoop.querySelectorAll('.wp-block-post').forEach(post => { + queryLoop.appendChild(post) + }) + const next = fetchedQueryLoop.querySelector('.wp-block-query-pagination-next') + if (next) { + nextHref = getLinkPageParam(next).href + } else { + nextHref = null + window.removeEventListener('scroll', doInfiniteScroll) + } + appended = true + } + }) + loading.style.visibility = "hidden" + // In case the pagination is still visible after load, load again + doInfiniteScroll() + }) + } + + window.addEventListener('scroll', doInfiniteScroll) + + doInfiniteScroll() +}) + // Display content (hidden by pre-script.js) document.body.style.visibility = "visible" diff --git a/web/app/themes/awasqa/style.css b/web/app/themes/awasqa/style.css index 3e7870d..2efc845 100644 --- a/web/app/themes/awasqa/style.css +++ b/web/app/themes/awasqa/style.css @@ -202,6 +202,21 @@ h6::after { border-top: 1px solid var(--color-orange); flex-grow: 1; } +.awasqa-infinite-scroll-loading { + animation: spin 1s linear infinite; + height: 25px; + border: 2px solid var(--color-green); + border-left: 0; + border-top: 0; + border-radius: 100%; + visibility: visible; + width: 25px; +} +@keyframes spin { + 100% { + transform: rotate(360deg); + } +} .page-join-us-steps ol { counter-reset: li; list-style: none; diff --git a/web/app/themes/awasqa/styles/awasqa.css b/web/app/themes/awasqa/styles/awasqa.css index 7124366..9442db1 100644 --- a/web/app/themes/awasqa/styles/awasqa.css +++ b/web/app/themes/awasqa/styles/awasqa.css @@ -6,6 +6,7 @@ @import "gravity-forms.css"; @import "header.css"; @import "headings.css"; +@import "infinite-scroll.css"; @import "join-us.css"; @import "util.css"; @import "wp.css"; diff --git a/web/app/themes/awasqa/styles/infinite-scroll.css b/web/app/themes/awasqa/styles/infinite-scroll.css new file mode 100644 index 0000000..6e93a36 --- /dev/null +++ b/web/app/themes/awasqa/styles/infinite-scroll.css @@ -0,0 +1,16 @@ +.awasqa-infinite-scroll-loading { + animation: spin 1s linear infinite; + height: 25px; + border: 2px solid var(--color-green); + border-left: 0; + border-top: 0; + border-radius: 100%; + visibility: visible; + width: 25px; +} + +@keyframes spin { + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file