Add CSS, JS and asset files (without videos)
Dieser Commit ist enthalten in:
209
js/hero-videos.js
Normale Datei
209
js/hero-videos.js
Normale Datei
@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Hero Video Rotation System
|
||||
* Manages rotating background videos in hero section
|
||||
*/
|
||||
|
||||
const HeroVideoRotation = {
|
||||
videos: [],
|
||||
currentIndex: 0,
|
||||
rotationInterval: null,
|
||||
isTransitioning: false,
|
||||
|
||||
/**
|
||||
* Initialize the video rotation system
|
||||
*/
|
||||
init() {
|
||||
// Get all video elements
|
||||
this.videos = document.querySelectorAll('.hero-video');
|
||||
|
||||
if (!this.videos.length) return;
|
||||
|
||||
// Setup event listeners
|
||||
this.setupEventListeners();
|
||||
|
||||
// Start rotation
|
||||
this.startRotation();
|
||||
|
||||
// Ensure first video is playing
|
||||
this.playVideo(0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup event listeners for videos
|
||||
*/
|
||||
setupEventListeners() {
|
||||
// Indicators removed - no click handlers needed
|
||||
|
||||
// Pause rotation on hover (optional)
|
||||
const heroSection = document.querySelector('.hero');
|
||||
if (heroSection) {
|
||||
heroSection.addEventListener('mouseenter', () => {
|
||||
// Optional: pause rotation on hover
|
||||
// this.stopRotation();
|
||||
});
|
||||
|
||||
heroSection.addEventListener('mouseleave', () => {
|
||||
// Optional: resume rotation
|
||||
// this.startRotation();
|
||||
});
|
||||
}
|
||||
|
||||
// Handle video load errors gracefully
|
||||
this.videos.forEach((video, index) => {
|
||||
video.addEventListener('error', () => {
|
||||
console.warn(`Video ${index} failed to load, skipping...`);
|
||||
// If current video fails, move to next
|
||||
if (index === this.currentIndex) {
|
||||
this.nextVideo();
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure videos are ready to play
|
||||
video.addEventListener('loadeddata', () => {
|
||||
console.log(`Video ${index} loaded successfully`);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Start automatic rotation
|
||||
*/
|
||||
startRotation() {
|
||||
// Clear any existing interval
|
||||
this.stopRotation();
|
||||
|
||||
// Set new interval
|
||||
this.rotationInterval = setInterval(() => {
|
||||
this.nextVideo();
|
||||
}, CONFIG.HERO_VIDEOS.ROTATION_INTERVAL);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stop automatic rotation
|
||||
*/
|
||||
stopRotation() {
|
||||
if (this.rotationInterval) {
|
||||
clearInterval(this.rotationInterval);
|
||||
this.rotationInterval = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Switch to next video
|
||||
*/
|
||||
nextVideo() {
|
||||
const nextIndex = (this.currentIndex + 1) % this.videos.length;
|
||||
this.switchToVideo(nextIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Switch to previous video
|
||||
*/
|
||||
previousVideo() {
|
||||
const prevIndex = (this.currentIndex - 1 + this.videos.length) % this.videos.length;
|
||||
this.switchToVideo(prevIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Switch to specific video by index
|
||||
* @param {number} index - Video index to switch to
|
||||
*/
|
||||
switchToVideo(index) {
|
||||
if (this.isTransitioning || index === this.currentIndex) return;
|
||||
|
||||
this.isTransitioning = true;
|
||||
|
||||
const currentVideo = this.videos[this.currentIndex];
|
||||
const nextVideo = this.videos[index];
|
||||
|
||||
// Indicators removed - no update needed
|
||||
|
||||
// Prepare next video
|
||||
this.prepareVideo(nextVideo);
|
||||
|
||||
// Fade out current video
|
||||
currentVideo.classList.add('fading-out');
|
||||
|
||||
// After half the fade duration, start fading in the next video
|
||||
setTimeout(() => {
|
||||
nextVideo.classList.add('active');
|
||||
nextVideo.classList.remove('fading-out');
|
||||
|
||||
// Play next video
|
||||
this.playVideo(index);
|
||||
}, CONFIG.HERO_VIDEOS.FADE_DURATION / 2);
|
||||
|
||||
// Complete transition
|
||||
setTimeout(() => {
|
||||
currentVideo.classList.remove('active', 'fading-out');
|
||||
this.currentIndex = index;
|
||||
this.isTransitioning = false;
|
||||
}, CONFIG.HERO_VIDEOS.FADE_DURATION);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Prepare video for playback
|
||||
* @param {HTMLVideoElement} video - Video element to prepare
|
||||
*/
|
||||
prepareVideo(video) {
|
||||
// Reset video to beginning
|
||||
video.currentTime = 0;
|
||||
|
||||
// Ensure video is ready to play
|
||||
const playPromise = video.play();
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(error => {
|
||||
console.warn('Video autoplay was prevented:', error);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Play specific video
|
||||
* @param {number} index - Index of video to play
|
||||
*/
|
||||
playVideo(index) {
|
||||
const video = this.videos[index];
|
||||
if (video) {
|
||||
const playPromise = video.play();
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(error => {
|
||||
console.warn(`Could not play video ${index}:`, error);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Pause all videos
|
||||
*/
|
||||
pauseAllVideos() {
|
||||
this.videos.forEach(video => {
|
||||
video.pause();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle page visibility change (pause when tab is not visible)
|
||||
*/
|
||||
handleVisibilityChange() {
|
||||
if (document.hidden) {
|
||||
this.stopRotation();
|
||||
this.pauseAllVideos();
|
||||
} else {
|
||||
this.playVideo(this.currentIndex);
|
||||
this.startRotation();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
HeroVideoRotation.init();
|
||||
});
|
||||
|
||||
// Handle page visibility API
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
HeroVideoRotation.handleVisibilityChange();
|
||||
});
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren