mirror of
https://github.com/Xevion/glance.git
synced 2025-12-07 22:07:12 -06:00
Refactor
Delay showing page content until JS has finished setting up page elements That then allows the following: Leave relative time to be rendered on the client Leave collapsible lists to be rendered on the client Which massively simplfies the backend templates which were error prone
This commit is contained in:
@@ -21,7 +21,7 @@ function throttledDebounce(callback, maxDebounceTimes, debounceDelay) {
|
||||
};
|
||||
|
||||
|
||||
async function fetchPageContents (pageSlug) {
|
||||
async function fetchPageContent(pageSlug) {
|
||||
// TODO: handle non 200 status codes/time outs
|
||||
// TODO: add retries
|
||||
const response = await fetch(`/api/pages/${pageSlug}/content/`);
|
||||
@@ -33,6 +33,10 @@ async function fetchPageContents (pageSlug) {
|
||||
function setupCarousels() {
|
||||
const carouselElements = document.getElementsByClassName("carousel-container");
|
||||
|
||||
if (carouselElements.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < carouselElements.length; i++) {
|
||||
const carousel = carouselElements[i];
|
||||
carousel.classList.add("show-right-cutoff");
|
||||
@@ -57,7 +61,7 @@ function setupCarousels() {
|
||||
itemsContainer.addEventListener("scroll", determineSideCutoffsRateLimited);
|
||||
document.addEventListener("resize", determineSideCutoffsRateLimited);
|
||||
|
||||
determineSideCutoffs();
|
||||
setTimeout(determineSideCutoffs, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +112,8 @@ function setupDynamicRelativeTime() {
|
||||
const updateInterval = 60 * 1000;
|
||||
let lastUpdateTime = Date.now();
|
||||
|
||||
updateRelativeTimeForElements(elements);
|
||||
|
||||
const updateElementsAndTimestamp = () => {
|
||||
updateRelativeTimeForElements(elements);
|
||||
lastUpdateTime = Date.now();
|
||||
@@ -154,35 +160,101 @@ function setupLazyImages() {
|
||||
image.classList.add("finished-transition");
|
||||
}
|
||||
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
const image = images[i];
|
||||
setTimeout(() => {
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
const image = images[i];
|
||||
|
||||
if (image.complete) {
|
||||
image.classList.add("cached");
|
||||
setTimeout(() => imageFinishedTransition(image), 5);
|
||||
} else {
|
||||
// TODO: also handle error event
|
||||
image.addEventListener("load", () => {
|
||||
image.classList.add("loaded");
|
||||
setTimeout(() => imageFinishedTransition(image), 500);
|
||||
});
|
||||
if (image.complete) {
|
||||
image.classList.add("cached");
|
||||
setTimeout(() => imageFinishedTransition(image), 5);
|
||||
} else {
|
||||
// TODO: also handle error event
|
||||
image.addEventListener("load", () => {
|
||||
image.classList.add("loaded");
|
||||
setTimeout(() => imageFinishedTransition(image), 500);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 5);
|
||||
}
|
||||
|
||||
function setupCollapsibleLists() {
|
||||
const collapsibleListElements = document.getElementsByClassName("list-collapsible");
|
||||
|
||||
if (collapsibleListElements.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const showMoreText = "Show more";
|
||||
const showLessText = "Show less";
|
||||
|
||||
const attachExpandToggleButton = (listElement) => {
|
||||
let expanded = false;
|
||||
const button = document.createElement("button");
|
||||
const arrowElement = document.createElement("span");
|
||||
arrowElement.classList.add("list-collapsible-label-icon");
|
||||
const textNode = document.createTextNode(showMoreText);
|
||||
button.classList.add("list-collapsible-label");
|
||||
button.append(textNode, arrowElement);
|
||||
button.addEventListener("click", () => {
|
||||
if (expanded) {
|
||||
listElement.classList.remove("list-collapsible-expanded");
|
||||
button.classList.remove("list-collapsible-label-expanded");
|
||||
textNode.nodeValue = showMoreText;
|
||||
} else {
|
||||
listElement.classList.add("list-collapsible-expanded");
|
||||
button.classList.add("list-collapsible-label-expanded");
|
||||
textNode.nodeValue = showLessText;
|
||||
}
|
||||
|
||||
expanded = !expanded;
|
||||
});
|
||||
|
||||
listElement.after(button);
|
||||
};
|
||||
|
||||
for (let i = 0; i < collapsibleListElements.length; i++) {
|
||||
const listElement = collapsibleListElements[i];
|
||||
|
||||
if (listElement.dataset.collapseAfter === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const collapseAfter = parseInt(listElement.dataset.collapseAfter);
|
||||
|
||||
if (listElement.children.length <= collapseAfter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
attachExpandToggleButton(listElement);
|
||||
|
||||
for (let c = collapseAfter; c < listElement.children.length; c++) {
|
||||
const child = listElement.children[c];
|
||||
child.classList.add("list-collapsible-item");
|
||||
child.style.animationDelay = ((c - collapseAfter) * 20).toString() + "ms";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function setupPage() {
|
||||
const pageElement = document.getElementById("page");
|
||||
const pageContents = await fetchPageContents(pageData.slug);
|
||||
const pageContentElement = document.getElementById("page-content");
|
||||
const pageContent = await fetchPageContent(pageData.slug);
|
||||
|
||||
pageElement.innerHTML = pageContents;
|
||||
pageContentElement.innerHTML = pageContent;
|
||||
|
||||
setTimeout(() => {
|
||||
document.body.classList.add("animate-element-transition");
|
||||
}, 200);
|
||||
|
||||
setTimeout(setupLazyImages, 5);
|
||||
setupCarousels();
|
||||
setupDynamicRelativeTime();
|
||||
try {
|
||||
setupLazyImages();
|
||||
setupCarousels();
|
||||
setupCollapsibleLists();
|
||||
setupDynamicRelativeTime();
|
||||
} finally {
|
||||
pageElement.classList.add("content-ready");
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
|
||||
Reference in New Issue
Block a user