1/** 2 * Video Magnifier - Click-to-zoom functionality for videos 3 * Similar to image magnifier but handles video elements 4 */ 5 6class VideoMagnifier { 7 constructor() { 8 this.modal = null; 9 this.init(); 10 } 11 12 init() { 13 // Wait for DOM to be ready and videos to be loaded 14 if (document.readyState === 'loading') { 15 document.addEventListener('DOMContentLoaded', () => { 16 // Give videos time to initialize 17 setTimeout(() => this.setup(), 100); 18 }); 19 } else { 20 // Give videos time to initialize 21 setTimeout(() => this.setup(), 100); 22 } 23 } 24 25 setup() { 26 this.createModal(); 27 this.setupVideos(); 28 this.bindEvents(); 29 } 30 31 createModal() { 32 // Create modal elements 33 this.modal = document.createElement('div'); 34 this.modal.className = 'video-magnify-modal'; 35 36 const closeBtn = document.createElement('div'); 37 closeBtn.className = 'video-magnify-close'; 38 closeBtn.innerHTML = 'Ã'; 39 closeBtn.setAttribute('title', 'Close (Press Esc)'); 40 41 const video = document.createElement('video'); 42 video.className = 'video-magnify-video'; 43 video.controls = true; 44 video.autoplay = true; 45 video.loop = true; 46 video.muted = true; 47 video.playsInline = true; 48 49 const caption = document.createElement('div'); 50 caption.className = 'video-magnify-caption'; 51 52 this.modal.appendChild(closeBtn); 53 this.modal.appendChild(video); 54 this.modal.appendChild(caption); 55 56 document.body.appendChild(this.modal); 57 } 58 59 setupVideos() { 60 // Find all videos that should be magnifiable 61 const videos = document.querySelectorAll('video'); 62 63 videos.forEach(video => { 64 // Skip if already processed 65 if (video.hasAttribute('data-magnify-enabled')) { 66 return; 67 } 68 69 console.log('Setting up video magnifier for:', video.src || video.querySelector('source')?.src); 70 console.log('Video loop attribute:', video.hasAttribute('loop')); 71 console.log('Video autoplay attribute:', video.hasAttribute('autoplay')); 72 console.log('Video paused state:', video.paused); 73 74 // Mark as processed 75 video.setAttribute('data-magnify-enabled', 'true'); 76 77 // Add click handler only - no DOM manipulation 78 video.addEventListener('click', (e) => { 79 e.preventDefault(); 80 e.stopPropagation(); 81 this.showMagnified(e, video); 82 }); 83 84 console.log('Video magnifier enabled - video should continue natural behavior'); 85 }); 86 } 87 88 wrapVideo(video) { 89 const container = document.createElement('div'); 90 container.className = 'video-magnify-container'; 91 92 const overlay = document.createElement('div'); 93 overlay.className = 'video-magnify-overlay'; 94 95 // Insert container before video 96 video.parentNode.insertBefore(container, video); 97 98 // Move video into container 99 container.appendChild(video); 100 container.appendChild(overlay); 101 } 102 103 showMagnified(event, video) { 104 event.preventDefault(); 105 event.stopPropagation(); 106 107 const modalVideo = this.modal.querySelector('.video-magnify-video'); 108 const caption = this.modal.querySelector('.video-magnify-caption'); 109 110 // Copy video source 111 modalVideo.innerHTML = video.innerHTML; 112 113 // Set caption from video title or alt attribute 114 const captionText = video.getAttribute('title') || video.getAttribute('alt') || 'Video preview'; 115 caption.textContent = captionText; 116 117 // Show modal 118 this.modal.classList.add('active'); 119 document.body.style.overflow = 'hidden'; 120 121 // Start playing the modal video 122 modalVideo.load(); 123 modalVideo.play().catch(e => { 124 console.log('Video autoplay prevented:', e); 125 }); 126 127 // Focus for keyboard accessibility 128 this.modal.focus(); 129 } 130 131 hideMagnified() { 132 const modalVideo = this.modal.querySelector('.video-magnify-video'); 133 134 // Pause the modal video 135 modalVideo.pause(); 136 137 this.modal.classList.remove('active'); 138 document.body.style.overflow = ''; 139 } 140 141 bindEvents() { 142 // Close button click 143 this.modal.querySelector('.video-magnify-close').addEventListener('click', () => { 144 this.hideMagnified(); 145 }); 146 147 // Modal background click 148 this.modal.addEventListener('click', (e) => { 149 if (e.target === this.modal) { 150 this.hideMagnified(); 151 } 152 }); 153 154 // Escape key 155 document.addEventListener('keydown', (e) => { 156 if (e.key === 'Escape' && this.modal.classList.contains('active')) { 157 this.hideMagnified(); 158 } 159 }); 160 } 161} 162 163// Initialize when script loads 164new VideoMagnifier();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.