// 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 = '

'; 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 = '

Author Note

'; 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'); // Detect if using icon navigation const isIconNav = navButtons.children[0].classList.contains('btn-icon-nav'); // First button const firstBtn = navButtons.children[0]; if (currentNumber > 1) { firstBtn.className = isIconNav ? 'btn-icon-nav' : 'btn btn-nav'; firstBtn.onclick = (e) => { e.preventDefault(); loadComic(1); }; } else { firstBtn.className = isIconNav ? 'btn-icon-nav btn-icon-disabled' : 'btn btn-nav btn-disabled'; firstBtn.onclick = null; } // Previous button const prevBtn = navButtons.children[1]; if (currentNumber > 1) { prevBtn.className = isIconNav ? 'btn-icon-nav' : 'btn btn-nav'; prevBtn.onclick = (e) => { e.preventDefault(); loadComic(currentNumber - 1); }; } else { prevBtn.className = isIconNav ? 'btn-icon-nav btn-icon-disabled' : '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 = isIconNav ? 'btn-icon-nav' : 'btn btn-nav'; nextBtn.onclick = (e) => { e.preventDefault(); loadComic(currentNumber + 1); }; } else { nextBtn.className = isIconNav ? 'btn-icon-nav btn-icon-disabled' : 'btn btn-nav btn-disabled'; nextBtn.onclick = null; } // Latest button const latestBtn = navButtons.children[4]; if (currentNumber < totalComics) { latestBtn.className = isIconNav ? 'btn-icon-nav' : 'btn btn-nav'; latestBtn.onclick = (e) => { e.preventDefault(); loadComic(totalComics); }; } else { latestBtn.className = isIconNav ? 'btn-icon-nav btn-icon-disabled' : '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(); } })();