From 997f62ba52e5fdb398794d593ee011b345c8eff6 Mon Sep 17 00:00:00 2001 From: Kuba Suder Date: Thu, 16 May 2024 23:19:51 +0200 Subject: [PATCH] added pagination to quotes and hashtags --- api.js | 26 ++++++--- skythread.js | 161 +++++++++++++++++++++++++-------------------------- 2 files changed, 96 insertions(+), 91 deletions(-) diff --git a/api.js b/api.js index 8b990eb..1c6721f 100644 --- a/api.js +++ b/api.js @@ -204,22 +204,32 @@ class BlueskyAPI extends Minisky { return json.quoteCount; } - /** @param {string} url, @returns {Promise} */ + /** @param {string} url, @param {string | undefined} cursor, @returns {Promise} */ - async getQuotes(url) { + async getQuotes(url, cursor = undefined) { let [handle, postId] = BlueskyAPI.parsePostURL(url); let did = handle.startsWith('did:') ? handle : await appView.resolveHandle(handle); let postURI = `at://${did}/app.bsky.feed.post/${postId}`; - let json = await this.getRequest('eu.mackuba.private.getPostQuotes', { uri: postURI }); - return json; + let params = { uri: postURI }; + + if (cursor) { + params['cursor'] = cursor; + } + + return await this.getRequest('eu.mackuba.private.getPostQuotes', params); } - /** @param {string} hashtag, @returns {Promise} */ + /** @param {string} hashtag, @param {string | undefined} cursor, @returns {Promise} */ + + async getHashtagFeed(hashtag, cursor = undefined) { + let params = { tag: hashtag }; + + if (cursor) { + params['cursor'] = cursor; + } - async getHashtagFeed(hashtag) { - let json = await this.getRequest('eu.mackuba.private.getHashtagFeed', { tag: hashtag }); - return json.feed; + return await this.getRequest('eu.mackuba.private.getHashtagFeed', params); } /** @param {string} postURI, @returns {Promise} */ diff --git a/skythread.js b/skythread.js index d492b8e..db394c6 100644 --- a/skythread.js +++ b/skythread.js @@ -278,116 +278,111 @@ function loadHashtagPage(hashtag) { hashtag = hashtag.replace(/^\#/, ''); document.title = `#${hashtag} - Skythread`; - blue.getHashtagFeed(hashtag).then(uris => { - let loading = true; - let footerAdded = false; + let isLoading = false; + let firstPageLoaded = false; + let cursor; - loadPostsInBatches(uris, jsons => { - let posts = jsons.map(j => new Post(j)); + loadInPages(() => { + if (isLoading) { return; } + isLoading = true; - if (loading) { - loading = false; - hideLoader(); + blue.getHashtagFeed(hashtag, cursor).then(data => { + api.loadPosts(data.feed).then(jsons => { + let posts = jsons.map(j => new Post(j)); - let header = $tag('header'); - header.append($tag('h2', { text: 'Posts tagged: #' + hashtag })); - $id('thread').appendChild(header); - $id('thread').classList.add('hashtag'); - } + if (!firstPageLoaded) { + hideLoader(); - for (let post of posts) { - let postView = new PostComponent(post).buildElement('feed'); - $id('thread').appendChild(postView); - } + let header = $tag('header'); + header.append($tag('h2', { text: 'Posts tagged: #' + hashtag })); + $id('thread').appendChild(header); + $id('thread').classList.add('hashtag'); + } - if (!footerAdded) { - let footer = $tag('p.note', { - text: "Note: at the moment, Skythread can show at most 100 recent posts and only from the last 30 days." - }); + for (let post of posts) { + let postView = new PostComponent(post).buildElement('feed'); + $id('thread').appendChild(postView); + } - $id('thread').after(footer); - footerAdded = true; - } + isLoading = false; + firstPageLoaded = true; + cursor = data.cursor; + }).catch(error => { + hideLoader(); + console.log(error); + isLoading = false; + }); }).catch(error => { hideLoader(); console.log(error); - }) - }).catch(error => { - hideLoader(); - console.log(error); + isLoading = false; + }); }); } /** @param {string} url */ function loadQuotesPage(url) { - blue.getQuotes(url).then(data => { - let uris = data.posts; - let loading = true; - let footerAdded = false; - - loadPostsInBatches(uris, jsons => { - let posts = jsons.map(j => new Post(j)); - - if (loading) { - loading = false; - hideLoader(); - - let header = $tag('header'); - let h2; - - if (data.quoteCount > 1) { - h2 = $tag('h2', { text: `${data.quoteCount} quotes:` }); - } else if (data.quoteCount == 1) { - h2 = $tag('h2', { text: '1 quote:' }); - } else { - h2 = $tag('h2', { text: 'No quotes found' }); + let isLoading = false; + let firstPageLoaded = false; + let cursor; + + loadInPages(() => { + if (isLoading) { return; } + isLoading = true; + + blue.getQuotes(url, cursor).then(data => { + api.loadPosts(data.posts).then(jsons => { + let posts = jsons.map(j => new Post(j)); + + if (!firstPageLoaded) { + hideLoader(); + + let header = $tag('header'); + let h2; + + if (data.quoteCount > 1) { + h2 = $tag('h2', { text: `${data.quoteCount} quotes:` }); + } else if (data.quoteCount == 1) { + h2 = $tag('h2', { text: '1 quote:' }); + } else { + h2 = $tag('h2', { text: 'No quotes found' }); + } + + header.append(h2); + $id('thread').appendChild(header); + $id('thread').classList.add('quotes'); } - header.append(h2); - $id('thread').appendChild(header); - $id('thread').classList.add('quotes'); - } - - for (let post of posts) { - let postView = new PostComponent(post).buildElement('quotes'); - $id('thread').appendChild(postView); - } - - if (!footerAdded) { - let text; - - if (data.quoteCount >= 100) { - text = "Note: at the moment, Skythread can show at most 100 recent quotes and only from the last 30 days."; - } else { - text = "Note: at the moment, Skythread can only show quotes from the last 30 days."; + for (let post of posts) { + let postView = new PostComponent(post).buildElement('quotes'); + $id('thread').appendChild(postView); } - let footer = $tag('p.note', { text }); - $id('thread').after(footer); - footerAdded = true; - } + isLoading = false; + firstPageLoaded = true; + cursor = data.cursor; + }).catch(error => { + hideLoader(); + console.log(error); + isLoading = false; + }) }).catch(error => { hideLoader(); console.log(error); - }) - }).catch(error => { - hideLoader(); - console.log(error); + isLoading = false; + }); }); } -/** @param {string[]} uris, @param {(p: object[]) => void} callback, @returns Promise */ +function loadInPages(callback) { + callback(); -async function loadPostsInBatches(uris, callback) { - if (uris.length > 0) { - for (let i = 0; i < uris.length; i += 25) { - let batch = await api.loadPosts(uris.slice(i, i + 25)); - callback(batch); + document.addEventListener('scroll', (e) => { + if (window.pageYOffset + window.innerHeight > document.body.offsetHeight - 200) { + callback(); } - } else { - callback([]); - } + }); } /** @param {string} url, @param {string} [postId], @param {AnyElement} [nodeToUpdate] */ -- 2.51.2