2024-07-14 02:46:48 +02:00
|
|
|
var users = [];
|
|
|
|
var posts = {};
|
|
|
|
|
2024-07-17 01:08:03 +02:00
|
|
|
const blockContainer = document.getElementById("block-container");
|
2024-07-11 22:19:51 +02:00
|
|
|
const postCountElem = document.getElementById("post-count");
|
|
|
|
const postTotalElem = document.getElementById("post-total");
|
2024-07-11 21:13:17 +02:00
|
|
|
const loader = document.getElementById("loader");
|
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
// define a variable for how many posts we want to increase the page by
|
2024-07-11 22:19:51 +02:00
|
|
|
const postIncrease = 9;
|
2024-07-11 21:13:17 +02:00
|
|
|
// and define a value to determine which page we're on
|
|
|
|
let currentPage = 1;
|
|
|
|
|
2024-07-20 13:55:10 +02:00
|
|
|
// how many times can we increase the content until we reach the max limit?
|
|
|
|
function getPageCount() {
|
|
|
|
return Math.ceil(Object.keys(posts).length / postIncrease);
|
|
|
|
}
|
2024-07-11 21:13:17 +02:00
|
|
|
|
|
|
|
function getRandomColor() {
|
|
|
|
const h = Math.floor(Math.random() * 360);
|
|
|
|
return `hsl(${h}deg, 90%, 85%)`;
|
|
|
|
}
|
|
|
|
|
2024-07-11 22:19:51 +02:00
|
|
|
class Post {
|
2024-07-25 00:35:30 +02:00
|
|
|
// JSON post data
|
2024-07-14 02:46:48 +02:00
|
|
|
constructor(data) {
|
|
|
|
this.id = data.id;
|
|
|
|
this.username = data.associatedUser;
|
|
|
|
this.content = data.body;
|
|
|
|
this.replyTo = data.replyTo;
|
2024-07-25 00:35:30 +02:00
|
|
|
this.parentPost = null;
|
2024-07-14 02:46:48 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
this.replies = [];
|
2024-07-14 02:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
getIsReply() {
|
|
|
|
return this.replyTo != "";
|
|
|
|
}
|
|
|
|
|
|
|
|
addReply(reply) {
|
|
|
|
this.replies.push(reply);
|
2024-07-25 00:35:30 +02:00
|
|
|
reply.parentPost = this;
|
2024-07-11 22:19:51 +02:00
|
|
|
}
|
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
getPostLevel() {
|
|
|
|
let p = this.parentPost;
|
|
|
|
let depth = 0;
|
|
|
|
while (p != null) {
|
|
|
|
p = p.parentPost;
|
|
|
|
depth++;
|
|
|
|
}
|
|
|
|
return depth;
|
|
|
|
}
|
2024-07-13 02:45:55 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
getHeaderTag() {
|
|
|
|
const level = this.getPostLevel();
|
|
|
|
switch (level) {
|
|
|
|
case 0: return "h1";
|
|
|
|
case 1: return "h2";
|
|
|
|
case 2: return "h3";
|
|
|
|
case 3: return "h4";
|
|
|
|
default:
|
|
|
|
console.error(`${level} is not a supported post level`);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2024-07-13 02:45:55 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
getHeaderElement() {
|
|
|
|
const headerElem = document.createElement(this.getHeaderTag());
|
|
|
|
headerElem.innerHTML = this.username;
|
2024-07-13 02:45:55 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
const elem = document.createElement("a");
|
|
|
|
elem.setAttribute("href", "#");
|
|
|
|
elem.addEventListener("click", () => updateUserProfile(this.username));
|
|
|
|
elem.appendChild(headerElem);
|
2024-07-14 02:46:48 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
return elem;
|
|
|
|
}
|
2024-07-14 02:46:48 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
getContentElement() {
|
|
|
|
const elem = document.createElement("p");
|
|
|
|
elem.innerHTML = this.content;
|
|
|
|
return elem;
|
|
|
|
}
|
2024-07-14 02:46:48 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
getElement() {
|
|
|
|
const elem = document.createElement("div");
|
2024-07-14 02:46:48 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
// display root posts as blocks, and comments as attached to their posts
|
|
|
|
if (this.getPostLevel() == 0) {
|
|
|
|
elem.className = "block post";
|
|
|
|
}
|
|
|
|
elem.style.backgroundColor = getRandomColor();
|
|
|
|
elem.appendChild(this.getHeaderElement());
|
|
|
|
elem.appendChild(this.getContentElement());
|
2024-07-14 02:46:48 +02:00
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
for (let i = 0; i < this.replies.length; i++) {
|
|
|
|
const reply = this.replies[i];
|
|
|
|
elem.appendChild(reply.getElement());
|
2024-07-13 02:45:55 +02:00
|
|
|
}
|
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
return elem;
|
2024-07-11 22:19:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-14 02:46:48 +02:00
|
|
|
function getRootPosts() {
|
|
|
|
let result = [];
|
|
|
|
for (var id in posts) {
|
|
|
|
const post = posts[id];
|
|
|
|
if (post.getIsReply())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
result.push(post);
|
|
|
|
}
|
|
|
|
return result;
|
2024-07-11 21:13:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-11 22:19:51 +02:00
|
|
|
function addPosts(pageIdx) {
|
2024-07-11 21:13:17 +02:00
|
|
|
currentPage = pageIdx;
|
|
|
|
|
2024-07-11 22:19:51 +02:00
|
|
|
const startRange = (pageIdx - 1) * postIncrease;
|
2024-07-20 13:55:10 +02:00
|
|
|
const endRange = currentPage == getPageCount()
|
|
|
|
? posts.length
|
2024-07-11 22:19:51 +02:00
|
|
|
: pageIdx * postIncrease;
|
2024-07-11 21:13:17 +02:00
|
|
|
|
2024-07-11 22:19:51 +02:00
|
|
|
postCountElem.innerHTML = endRange;
|
2024-07-11 21:13:17 +02:00
|
|
|
|
2024-07-14 02:46:48 +02:00
|
|
|
const rootPosts = getRootPosts();
|
|
|
|
|
2024-07-11 21:13:17 +02:00
|
|
|
for (let i = startRange + 1; i <= endRange; i++) {
|
2024-07-25 00:35:30 +02:00
|
|
|
const post = rootPosts[i];
|
|
|
|
const elem = post.getElement();
|
|
|
|
blockContainer.appendChild(elem);
|
2024-07-11 21:13:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleInfiniteScroll() {
|
|
|
|
throttle(() => {
|
|
|
|
const endOfPage = window.innerHeight + window.pageYOffset >= document.body.offsetHeight;
|
|
|
|
|
|
|
|
if (endOfPage) {
|
2024-07-11 22:19:51 +02:00
|
|
|
addPosts(currentPage + 1);
|
2024-07-11 21:13:17 +02:00
|
|
|
}
|
|
|
|
|
2024-07-20 13:55:10 +02:00
|
|
|
if (currentPage === getPageCount()) {
|
2024-07-11 21:13:17 +02:00
|
|
|
removeInfiniteScroll();
|
|
|
|
}
|
|
|
|
}, 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-11 22:19:51 +02:00
|
|
|
// limit how often we try to load new posts to maintain browser performance
|
2024-07-11 21:13:17 +02:00
|
|
|
var throttleTimer;
|
|
|
|
function throttle(callback, time) {
|
|
|
|
if (throttleTimer) return;
|
|
|
|
|
|
|
|
throttleTimer = true;
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
callback();
|
|
|
|
throttleTimer = false;
|
|
|
|
}, time);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function removeInfiniteScroll() {
|
|
|
|
loader.remove();
|
|
|
|
window.removeEventListener("scroll", handleInfiniteScroll);
|
|
|
|
}
|
|
|
|
|
2024-07-20 14:40:54 +02:00
|
|
|
function getTopPost() {
|
|
|
|
// find the first post
|
|
|
|
const children = blockContainer.childNodes;
|
|
|
|
let firstPost = null;
|
|
|
|
for (let i = 0; i < children.length; i++) {
|
|
|
|
const child = children[i];
|
|
|
|
const classes = child.className.split(" ");
|
|
|
|
if (classes.some(c => c == "post")) {
|
|
|
|
firstPost = child;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-07-18 02:16:52 +02:00
|
|
|
|
2024-07-20 14:40:54 +02:00
|
|
|
return firstPost;
|
|
|
|
}
|
|
|
|
|
|
|
|
function makePostFromJson(json) {
|
|
|
|
return new Post({
|
|
|
|
id: json.id,
|
|
|
|
associatedUser: json.associatedUser,
|
|
|
|
body: json.body
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCurrentUser() {
|
|
|
|
return {
|
|
|
|
"user": "theChief",
|
|
|
|
"interests": [
|
|
|
|
"gen-ai",
|
|
|
|
"blockchain",
|
|
|
|
"nfts"
|
|
|
|
],
|
|
|
|
"posting_style": "just the most truly inane takes"
|
|
|
|
};
|
|
|
|
}
|
2024-07-18 02:16:52 +02:00
|
|
|
|
2024-07-20 14:40:54 +02:00
|
|
|
function writePost() {
|
|
|
|
const request = {
|
2024-07-18 02:16:52 +02:00
|
|
|
method: "POST",
|
|
|
|
mode: "cors",
|
2024-07-20 14:40:54 +02:00
|
|
|
body: JSON.stringify(getCurrentUser()),
|
2024-07-18 02:16:52 +02:00
|
|
|
headers: {
|
|
|
|
"Content-type": "application/json; charset=UTF-8"
|
|
|
|
}
|
2024-07-20 14:40:54 +02:00
|
|
|
};
|
2024-07-18 02:16:52 +02:00
|
|
|
|
2024-07-20 14:40:54 +02:00
|
|
|
fetch("https://api.wayfarer.games/singularity/generate-posts.php", request)
|
|
|
|
.then(response => response.json())
|
|
|
|
.then(makePostFromJson)
|
|
|
|
.then(post => blockContainer.insertBefore(post.getElement(), getTopPost()));
|
2024-07-18 02:16:52 +02:00
|
|
|
}
|
|
|
|
|
2024-07-17 01:08:55 +02:00
|
|
|
function addWritePostBlock() {
|
|
|
|
const blockElem = document.createElement("div");
|
|
|
|
blockElem.className = "block";
|
|
|
|
blockElem.style.backgroundColor = "red";
|
|
|
|
|
|
|
|
const buttonElem = document.createElement("a");
|
|
|
|
buttonElem.setAttribute("href", "#");
|
|
|
|
buttonElem.innerHTML = "Write something interesting for me!";
|
2024-07-18 02:16:52 +02:00
|
|
|
buttonElem.addEventListener("click", writePost);
|
2024-07-17 01:08:55 +02:00
|
|
|
blockElem.append(buttonElem);
|
|
|
|
|
|
|
|
blockContainer.append(blockElem)
|
|
|
|
}
|
|
|
|
|
2024-07-14 02:46:48 +02:00
|
|
|
function init() {
|
|
|
|
if (posts == undefined)
|
|
|
|
{
|
|
|
|
console.log("resource loading failed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// need to load all the resources first
|
2024-07-17 01:08:55 +02:00
|
|
|
const postCount = Object.keys(posts).length;
|
|
|
|
if (users.length == 0 || postCount == 0)
|
2024-07-14 02:46:48 +02:00
|
|
|
return;
|
|
|
|
|
2024-07-17 01:08:55 +02:00
|
|
|
console.log(`loaded ${users.length} users and ${postCount} posts`);
|
|
|
|
|
2024-07-25 00:35:30 +02:00
|
|
|
// TODO: add user bio above write post button
|
2024-07-17 01:08:55 +02:00
|
|
|
addWritePostBlock();
|
2024-07-14 02:46:48 +02:00
|
|
|
|
|
|
|
addPosts(currentPage);
|
|
|
|
window.addEventListener("scroll", handleInfiniteScroll);
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadDataFromEndpoint(endpoint, callback) {
|
|
|
|
fetch(endpoint)
|
|
|
|
.then(response => response.json())
|
|
|
|
.then(json => {
|
|
|
|
callback(json);
|
|
|
|
init();
|
|
|
|
});
|
|
|
|
}
|
2024-07-11 21:13:17 +02:00
|
|
|
|
2024-07-16 20:56:34 +02:00
|
|
|
loadDataFromEndpoint("https://api.wayfarer.games/singularity/users.json", json => { users = json.users; });
|
|
|
|
loadDataFromEndpoint("https://api.wayfarer.games/singularity/posts.json", json => {
|
2024-07-14 02:46:48 +02:00
|
|
|
// first pass to instantiate all the posts
|
|
|
|
for (let i = 0; i < json.content.length; i++) {
|
|
|
|
const post = new Post(json.content[i]);
|
|
|
|
posts[post.id] = post;
|
|
|
|
}
|
|
|
|
|
|
|
|
// second pass to link each reply to the appropriate parent
|
|
|
|
for (const id in posts) {
|
|
|
|
const post = posts[id];
|
|
|
|
if (!post.getIsReply())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const parent = posts[post.replyTo];
|
|
|
|
parent.addReply(post);
|
|
|
|
}
|
2024-07-20 13:55:10 +02:00
|
|
|
|
|
|
|
postTotalElem.innerHTML = Object.keys(posts).length;
|
2024-07-14 02:46:48 +02:00
|
|
|
});
|