Files
agent0_homepage/docs/assets/js/slideshow.js
T
2025-05-28 12:18:20 +02:00

222 lines
6.8 KiB
JavaScript

// Slideshow functionality for FAQ answers - OPTIMIZED VERSION
document.addEventListener('DOMContentLoaded', initSlideshows);
document.addEventListener('DOMContentSwap', initSlideshows);
document.addEventListener('mdContentChanged', initSlideshows);
// Track initialized slideshows to prevent double-initialization
const initializedSlideshows = new Set();
// Function to initialize all slideshows on the page
function initSlideshows() {
const slideshows = document.querySelectorAll('.faq-slideshow');
if (slideshows.length === 0) {
return;
}
console.log('Slideshows found:', slideshows.length);
slideshows.forEach((slideshow, slideshowIndex) => {
// Create unique ID for this slideshow
const slideshowId = `slideshow-${slideshowIndex}`;
// Skip if already initialized
if (initializedSlideshows.has(slideshowId)) {
return;
}
slideshow.setAttribute('id', slideshowId);
initializedSlideshows.add(slideshowId);
// Get slideshow elements
const container = slideshow.querySelector('.faq-slideshow-container');
const slides = slideshow.querySelectorAll('.faq-slide');
const prevBtn = slideshow.querySelector('button.faq-slideshow-prev');
const nextBtn = slideshow.querySelector('button.faq-slideshow-next');
const dotsContainer = slideshow.querySelector('.faq-slideshow-dots');
console.log('Slideshow elements found:', {
container: !!container,
slides: slides.length,
prevBtn: !!prevBtn,
nextBtn: !!nextBtn,
dotsContainer: !!dotsContainer
});
if (!container || slides.length === 0) {
return;
}
// Current slide index
let currentSlide = 0;
// Function to go to a specific slide
function goToSlide(index) {
console.log(`goToSlide called for slideshow ${slideshowId} with index ${index}`);
// Handle wrapping around
if (index < 0) {
index = slides.length - 1;
console.log(`Wrapped to last slide: ${index}`);
} else if (index >= slides.length) {
index = 0;
console.log(`Wrapped to first slide: ${index}`);
}
// Update current slide index
const previousSlide = currentSlide;
currentSlide = index;
console.log(`Changing slide from ${previousSlide} to ${currentSlide}`);
// Move the container to show the current slide (OPTIMIZED)
const transformValue = `translateX(-${currentSlide * 100}%)`;
console.log(`Setting transform to: ${transformValue}`);
container.style.transform = transformValue;
// Update active dot (OPTIMIZED)
if (dotsContainer) {
const dots = dotsContainer.querySelectorAll('.faq-slideshow-dot');
const activeDot = dotsContainer.querySelector('.faq-slideshow-dot.active');
const newActiveDot = dots[currentSlide];
if (activeDot && activeDot !== newActiveDot) {
activeDot.classList.remove('active');
}
if (newActiveDot && !newActiveDot.classList.contains('active')) {
newActiveDot.classList.add('active');
}
console.log(`Updated active dot to index ${currentSlide}`);
}
}
// Create dots if they don't exist
if (dotsContainer && dotsContainer.children.length === 0) {
for (let i = 0; i < slides.length; i++) {
const dot = document.createElement('div');
dot.className = 'faq-slideshow-dot';
if (i === 0) {
dot.classList.add('active');
}
dot.addEventListener('click', () => {
goToSlide(i);
});
dotsContainer.appendChild(dot);
}
}
// FIXED: Only use addEventListener (remove onclick to prevent double execution)
if (prevBtn) {
console.log('Adding click event listener to prev button for slideshow', slideshowId);
// Remove any existing handlers
prevBtn.onclick = null;
// Add single event listener
prevBtn.addEventListener('click', (e) => {
console.log('Prev button clicked for slideshow', slideshowId);
e.stopPropagation();
e.preventDefault();
goToSlide(currentSlide - 1);
}, { once: false, passive: false });
prevBtn.style.cursor = 'pointer';
}
if (nextBtn) {
console.log('Adding click event listener to next button for slideshow', slideshowId);
// Remove any existing handlers
nextBtn.onclick = null;
// Add single event listener
nextBtn.addEventListener('click', (e) => {
console.log('Next button clicked for slideshow', slideshowId);
e.stopPropagation();
e.preventDefault();
goToSlide(currentSlide + 1);
}, { once: false, passive: false });
nextBtn.style.cursor = 'pointer';
}
// Initialize the first slide
goToSlide(0);
// Add keyboard navigation when slideshow is in focus
slideshow.tabIndex = 0;
slideshow.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
goToSlide(currentSlide - 1);
} else if (e.key === 'ArrowRight') {
goToSlide(currentSlide + 1);
}
});
// Add optimized swipe support for touch devices
let touchStartX = 0;
let touchEndX = 0;
slideshow.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
}, { passive: true });
slideshow.addEventListener('touchend', (e) => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
}, { passive: true });
function handleSwipe() {
const swipeThreshold = 50;
if (touchEndX < touchStartX - swipeThreshold) {
goToSlide(currentSlide + 1);
} else if (touchEndX > touchStartX + swipeThreshold) {
goToSlide(currentSlide - 1);
}
}
});
}
// MutationObserver to detect when new slideshows are added to the DOM
// FIXED: Renamed to avoid conflicts and added throttling
const slideshowObserver = new MutationObserver((mutations) => {
let hasRelevantMutation = false;
mutations.forEach((mutation) => {
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
for (let i = 0; i < mutation.addedNodes.length; i++) {
const node = mutation.addedNodes[i];
if (node.nodeType === 1 && (node.classList?.contains('faq-slideshow') ||
node.querySelector?.('.faq-slideshow'))) {
hasRelevantMutation = true;
break;
}
}
}
});
if (hasRelevantMutation) {
setTimeout(initSlideshows, 100);
}
});
// Start observing the document
slideshowObserver.observe(document.body, {
childList: true,
subtree: true
});
// Additional event listener for dynamically loaded content
window.addEventListener('load', function() {
setTimeout(initSlideshows, 500);
});
// For Material for MkDocs specific events
if (typeof document$.subscribe === 'function') {
document$.subscribe(function() {
setTimeout(initSlideshows, 100);
});
}