263 lines
9.3 KiB
JavaScript
263 lines
9.3 KiB
JavaScript
// Client-side comic navigation using the API
|
|
(function() {
|
|
'use strict';
|
|
|
|
let totalComics = 0;
|
|
|
|
// Fetch and display a comic
|
|
async function loadComic(comicId) {
|
|
try {
|
|
const response = await fetch(`/api/comics/${comicId}`);
|
|
|
|
if (!response.ok) {
|
|
if (response.status === 404) {
|
|
window.location.href = '/404';
|
|
return;
|
|
}
|
|
throw new Error('Failed to load comic');
|
|
}
|
|
|
|
const comic = response.json ? await response.json() : comic;
|
|
displayComic(comic);
|
|
|
|
} catch (error) {
|
|
console.error('Error loading comic:', error);
|
|
}
|
|
}
|
|
|
|
// Update the page with comic data
|
|
function displayComic(comic) {
|
|
const title = comic.title || `#${comic.number}`;
|
|
|
|
// Update container class for full-width option
|
|
const container = document.querySelector('.comic-container');
|
|
if (comic.full_width) {
|
|
container.classList.add('comic-container-fullwidth');
|
|
} else {
|
|
container.classList.remove('comic-container-fullwidth');
|
|
}
|
|
|
|
// Update container class for plain mode
|
|
if (comic.plain) {
|
|
container.classList.add('comic-container-plain');
|
|
} else {
|
|
container.classList.remove('comic-container-plain');
|
|
}
|
|
|
|
// Show/hide header based on plain mode
|
|
const header = document.querySelector('.comic-header');
|
|
if (comic.plain) {
|
|
if (header) {
|
|
header.style.display = 'none';
|
|
}
|
|
} else {
|
|
if (header) {
|
|
header.style.display = 'block';
|
|
} else {
|
|
// Create header if it doesn't exist
|
|
const newHeader = document.createElement('div');
|
|
newHeader.className = 'comic-header';
|
|
newHeader.innerHTML = '<h1></h1><p class="comic-date"></p>';
|
|
container.insertBefore(newHeader, container.firstChild);
|
|
}
|
|
// Update title and date
|
|
document.querySelector('.comic-header h1').textContent = title;
|
|
document.querySelector('.comic-date').textContent = comic.date;
|
|
}
|
|
|
|
// Update image and its link
|
|
const comicImageDiv = document.querySelector('.comic-image');
|
|
updateComicImage(comicImageDiv, comic, title);
|
|
|
|
// Update or create/remove the link wrapper
|
|
updateComicImageLink(comic.number);
|
|
|
|
// Update author note
|
|
const transcriptDiv = document.querySelector('.comic-transcript');
|
|
if (comic.author_note) {
|
|
if (!transcriptDiv) {
|
|
const container = document.querySelector('.comic-container');
|
|
const newDiv = document.createElement('div');
|
|
newDiv.className = 'comic-transcript';
|
|
newDiv.innerHTML = '<h3>Author Note</h3>';
|
|
container.appendChild(newDiv);
|
|
}
|
|
|
|
// Clear existing content after the h3
|
|
const h3 = transcriptDiv.querySelector('h3');
|
|
while (h3.nextSibling) {
|
|
h3.nextSibling.remove();
|
|
}
|
|
|
|
// Add content based on whether it's HTML or plain text
|
|
if (comic.author_note_is_html) {
|
|
const contentDiv = document.createElement('div');
|
|
contentDiv.innerHTML = comic.author_note;
|
|
transcriptDiv.appendChild(contentDiv);
|
|
} else {
|
|
const contentP = document.createElement('p');
|
|
contentP.textContent = comic.author_note;
|
|
transcriptDiv.appendChild(contentP);
|
|
}
|
|
|
|
transcriptDiv.style.display = 'block';
|
|
} else if (transcriptDiv) {
|
|
transcriptDiv.style.display = 'none';
|
|
}
|
|
|
|
// Update navigation buttons
|
|
updateNavButtons(comic.number, comic.formatted_date);
|
|
|
|
// Update page title
|
|
document.title = `${title} - Sunday Comics`;
|
|
|
|
// Update URL without reload
|
|
history.pushState({ comicId: comic.number }, '', `/comic/${comic.number}`);
|
|
}
|
|
|
|
// Update or create comic image with optional mobile version
|
|
function updateComicImage(comicImageDiv, comic, title) {
|
|
// Clear all existing content
|
|
comicImageDiv.innerHTML = '';
|
|
|
|
// Create new image element(s)
|
|
if (comic.mobile_filename) {
|
|
// Create picture element with mobile source
|
|
const picture = document.createElement('picture');
|
|
|
|
const source = document.createElement('source');
|
|
source.media = '(max-width: 768px)';
|
|
source.srcset = `/static/images/comics/${comic.mobile_filename}`;
|
|
|
|
const img = document.createElement('img');
|
|
img.src = `/static/images/comics/${comic.filename}`;
|
|
img.alt = title;
|
|
img.title = comic.alt_text;
|
|
|
|
picture.appendChild(source);
|
|
picture.appendChild(img);
|
|
comicImageDiv.appendChild(picture);
|
|
} else {
|
|
// Create regular img element
|
|
const img = document.createElement('img');
|
|
img.src = `/static/images/comics/${comic.filename}`;
|
|
img.alt = title;
|
|
img.title = comic.alt_text;
|
|
comicImageDiv.appendChild(img);
|
|
}
|
|
}
|
|
|
|
// Update comic image link for click navigation
|
|
function updateComicImageLink(currentNumber) {
|
|
const comicImageDiv = document.querySelector('.comic-image');
|
|
const imgOrPicture = comicImageDiv.querySelector('picture') || comicImageDiv.querySelector('img');
|
|
|
|
// Remove existing link if present
|
|
const existingLink = comicImageDiv.querySelector('a');
|
|
if (existingLink) {
|
|
existingLink.replaceWith(imgOrPicture);
|
|
}
|
|
|
|
// Add link if there's a next comic
|
|
if (currentNumber < totalComics) {
|
|
const link = document.createElement('a');
|
|
link.href = `/comic/${currentNumber + 1}`;
|
|
link.onclick = (e) => {
|
|
e.preventDefault();
|
|
loadComic(currentNumber + 1);
|
|
};
|
|
imgOrPicture.parentNode.insertBefore(link, imgOrPicture);
|
|
link.appendChild(imgOrPicture);
|
|
}
|
|
}
|
|
|
|
// Update navigation button states
|
|
function updateNavButtons(currentNumber, formattedDate) {
|
|
const navButtons = document.querySelector('.nav-buttons');
|
|
|
|
// First button
|
|
const firstBtn = navButtons.children[0];
|
|
if (currentNumber > 1) {
|
|
firstBtn.className = 'btn btn-nav';
|
|
firstBtn.onclick = (e) => { e.preventDefault(); loadComic(1); };
|
|
} else {
|
|
firstBtn.className = 'btn btn-nav btn-disabled';
|
|
firstBtn.onclick = null;
|
|
}
|
|
|
|
// Previous button
|
|
const prevBtn = navButtons.children[1];
|
|
if (currentNumber > 1) {
|
|
prevBtn.className = 'btn btn-nav';
|
|
prevBtn.onclick = (e) => { e.preventDefault(); loadComic(currentNumber - 1); };
|
|
} else {
|
|
prevBtn.className = 'btn btn-nav btn-disabled';
|
|
prevBtn.onclick = null;
|
|
}
|
|
|
|
// Comic date display
|
|
if (formattedDate) {
|
|
navButtons.children[2].textContent = formattedDate;
|
|
}
|
|
|
|
// Next button
|
|
const nextBtn = navButtons.children[3];
|
|
if (currentNumber < totalComics) {
|
|
nextBtn.className = 'btn btn-nav';
|
|
nextBtn.onclick = (e) => { e.preventDefault(); loadComic(currentNumber + 1); };
|
|
} else {
|
|
nextBtn.className = 'btn btn-nav btn-disabled';
|
|
nextBtn.onclick = null;
|
|
}
|
|
|
|
// Latest button
|
|
const latestBtn = navButtons.children[4];
|
|
if (currentNumber < totalComics) {
|
|
latestBtn.className = 'btn btn-nav';
|
|
latestBtn.onclick = (e) => { e.preventDefault(); loadComic(totalComics); };
|
|
} else {
|
|
latestBtn.className = 'btn btn-nav btn-disabled';
|
|
latestBtn.onclick = null;
|
|
}
|
|
}
|
|
|
|
// Initialize on page load
|
|
async function init() {
|
|
// Only run on comic pages
|
|
if (!document.querySelector('.comic-container')) {
|
|
return;
|
|
}
|
|
|
|
// Get total comics count from the page
|
|
totalComics = parseInt(document.querySelector('.comic-container').dataset.totalComics || 0);
|
|
|
|
// Get current comic number
|
|
const currentNumber = parseInt(document.querySelector('.comic-container').dataset.comicNumber || 0);
|
|
|
|
if (currentNumber && totalComics) {
|
|
// Get the formatted date from the DOM (already rendered by server)
|
|
const dateDisplay = document.querySelector('.comic-date-display');
|
|
const formattedDate = dateDisplay ? dateDisplay.textContent : null;
|
|
updateNavButtons(currentNumber, formattedDate);
|
|
updateComicImageLink(currentNumber);
|
|
}
|
|
|
|
// Handle browser back/forward
|
|
window.addEventListener('popstate', (event) => {
|
|
if (event.state && event.state.comicId) {
|
|
loadComic(event.state.comicId);
|
|
}
|
|
});
|
|
|
|
// Set initial state
|
|
history.replaceState({ comicId: currentNumber }, '', window.location.pathname);
|
|
}
|
|
|
|
// Run when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|