diff options
| author | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2020-07-28 12:54:40 -0400 |
|---|---|---|
| committer | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2020-07-28 12:54:40 -0400 |
| commit | 03860ebc2e0624ecd0cf094498ac3bfc2df18183 (patch) | |
| tree | 6c4176402df1d218e8f03a4741bc0b164bee7111 /static | |
| parent | eca1cae812ba2b5ff84a9770c4b3bda84cc27fea (diff) | |
[kona-web] Implement infinite scroll.
Diffstat (limited to 'static')
| -rw-r--r-- | static/js/infinite_scroll.js | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/static/js/infinite_scroll.js b/static/js/infinite_scroll.js new file mode 100644 index 0000000..15df7ae --- /dev/null +++ b/static/js/infinite_scroll.js @@ -0,0 +1,91 @@ +// Copyright © 2020 Jakob L. Kreuze <zerodaysfordays@sdf.org> +// +// This file is part of Kona. +// +// Kona is free software; you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by +// the Free Software Foundation; either version 3 of the License, or (at +// your option) any later version. +// +// Kona is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public +// License for more details. +// +// You should have received a copy of the GNU Affero General Public +// License along with Kona. If not, see <http://www.gnu.org/licenses/>. + +let searchQuery = /query=[^\&]*/.exec(window.location)[0]; +let searchLast = 0; + +// Calculate the `last` parameter for the 'posts' endpoint from the images +// currently displayed. +function lastId() { + let children = document.getElementById("main").children; + + if (children.length === 0) { + return 0; + } + + let lastChild = children[children.length - 1]; + return parseInt(/image-([\d]*)/.exec(lastChild.id)[1]); +} + +function scrollHandler() { + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + // Remove ourselves so we don't get triggered while we're loading. + window.removeEventListener("scroll", scrollHandler); + + let xhr = new XMLHttpRequest(); + xhr.open("GET", searchQuery ? + `/api/posts?${searchQuery}&last=${searchLast}` : + `/api/posts?query=&last=${searchLast}`); + xhr.onload = () => { + let results = JSON.parse(xhr.response); + + // Add ourselves iff there's more to load. + if (results.length > 0) { + window.addEventListener("scroll", scrollHandler); + } + + results.forEach((image) => { + let div = document.createElement("div"); + div.id = `image-${image.id}`; + div.classList.add("image-container"); + + let a = document.createElement("a"); + a.href = `/posts/${image.id}`; + + let img = document.createElement("img"); + img.src = `/image/${image.thumb_filename}`; + + div.appendChild(a); + a.appendChild(img); + document.getElementById("main").appendChild(div); + }); + + // Update the `searchLast` global. + searchLast = lastId(); + }; + xhr.send(); + } +}; + +window.addEventListener("scroll", scrollHandler); + +window.addEventListener("load", () => { + // Remove the "next" link. + let main = document.getElementById("main"); + let lastChild = main.children[main.children.length - 1]; + if (lastChild && lastChild.nodeName === "P") { + main.removeChild(lastChild); + } + + // Initialize `searchLast'. + searchLast = lastId(); + + // Simulate a scroll if we have the space to load more images. + if (window.innerHeight >= document.body.offsetHeight) { + scrollHandler(); + } +}); |