Created
July 7, 2024 13:57
-
-
Save webuilder240/5993e7f01f941dc5a3d5c5471bd69669 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
| export async function requestGet(url) { | |
| const response = await fetch(url) | |
| return await response.text() | |
| } | |
| export function nextFrame() { | |
| return new Promise(requestAnimationFrame) | |
| } | |
| export function delay(ms) { | |
| return new Promise(resolve => setTimeout(resolve, ms)) | |
| } |
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
| <p style="color: green"><%= notice %></p> | |
| <h1>Users</h1> | |
| <infinite-scroll-pagination data-manual-load="false" data-root-margin="40px"> | |
| <% @users.each do |user| %> | |
| <div> | |
| <%= render user %> | |
| <p> | |
| <%= link_to "Show this user", user %> | |
| </p> | |
| </div> | |
| <% end %> | |
| <%= link_to("relead more", users_path(page: @users.next_page), class: "pagination-link", data: { preload: @users.first_page? }) unless @users.last_page? %> | |
| </infinite-scroll-pagination> | |
| <%= link_to "New user", new_user_path %> |
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
| import { delay, nextFrame, requestGet } from "../helper"; | |
| class InfiniteScrollPagination extends HTMLElement { | |
| constructor() { | |
| super(); | |
| this.nextPageLink = null; | |
| this.manualLoad = this.getAttribute('data-manual-load') === 'true'; | |
| this.rootMargin = this.getAttribute('data-root-margin') || '0px'; | |
| } | |
| connectedCallback() { | |
| this.observeNextPageLink(); | |
| } | |
| async loadNextPage(event) { | |
| event?.preventDefault(); | |
| this.setAttribute("aria-busy", "true"); | |
| const html = await this.loadNextPageHTML(); | |
| await nextFrame(); | |
| this.setAttribute("aria-busy", "false"); | |
| this.nextPageLink.outerHTML = html; | |
| await delay(500); | |
| this.observeNextPageLink(); | |
| } | |
| async observeNextPageLink() { | |
| if (this.manualLoad) return; | |
| await nextFrame(); | |
| const nextPageLink = this.querySelector('.pagination-link'); | |
| if (!nextPageLink) return; | |
| this.nextPageLink = nextPageLink; | |
| if (nextPageLink.dataset.preload === "true") { | |
| this.loadNextPage(); | |
| } else { | |
| await this.nextIntersection(nextPageLink, this.intersectionOptions); | |
| this.loadNextPage(); | |
| } | |
| } | |
| async loadNextPageHTML() { | |
| const html = await requestGet(this.nextPageLink.href); | |
| const doc = new DOMParser().parseFromString(html, "text/html"); | |
| const element = doc.querySelector('infinite-scroll-pagination'); | |
| return element ? element.innerHTML.trim() : ""; | |
| } | |
| get intersectionOptions() { | |
| const root = this.scrollableOffsetParent; | |
| return { | |
| root: root, | |
| rootMargin: this.rootMargin | |
| }; | |
| } | |
| get scrollableOffsetParent() { | |
| const root = this.offsetParent; | |
| return root && root.scrollHeight > root.clientHeight ? root : null; | |
| } | |
| nextIntersection(element, options = {}) { | |
| return new Promise(resolve => { | |
| new IntersectionObserver(([entry], observer) => { | |
| if (!entry.isIntersecting) return; | |
| observer.disconnect(); | |
| resolve(); | |
| }, options).observe(element); | |
| }); | |
| } | |
| } | |
| customElements.define('infinite-scroll-pagination', InfiniteScrollPagination); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment