1var mediaContainer = document.getElementById('media-container'); 2var volume = document.getElementById('volume-control'); 3var mediaImage = document.getElementById('media-image'); 4var mediaList = document.getElementById('media-list').getElementsByTagName('li'); 5document.getElementById('media-list').setAttribute('role', 'group'); 6document.getElementById('media-list').setAttribute('aria-label', 'Kies een zender'); 7function updateVolumeLabel() { 8 if (volume) volume.setAttribute('aria-valuetext', Math.round(Number(volume.value) * 100) + ' procent'); 9} 10volume?.addEventListener('input', updateVolumeLabel); 11var autoStartDone = false; 12var autoPlayEnabled = document.body.dataset.autoplay === 'true'; 13if (document.body.classList.contains('player-popup')) { 14 var requestedVolume = new URLSearchParams(location.search).get('volume'); 15 if (requestedVolume !== null && Number.isFinite(Number(requestedVolume)) && Number(requestedVolume) >= 0 && Number(requestedVolume) <= 1) volume.value = requestedVolume; 16} 17var currentMedia; 18updateVolumeLabel(); 19var playerControlWindow = null; 20var handoffMedia = null; 21var handoffWaiting = false; 22var handoffAnnounced = false; 23function announcePopupPlayback() { 24 if (handoffAnnounced || new URLSearchParams(location.search).get('handoff') !== '1' || !window.opener) return; 25 handoffAnnounced = true; 26 window.opener.postMessage({ kind: 'nieuwsned-player-started' }, location.origin); 27} 28window.addEventListener('message', function (event) { 29 if (event.origin !== location.origin || event.source !== playerControlWindow || event.data?.kind !== 'nieuwsned-player-started' || !handoffWaiting) return; 30 handoffWaiting = false; 31 // Only pause the stream that was handed over, not a subsequently selected station. 32 if (currentMedia === handoffMedia) pauseMedia(); 33}); 34for (var i = 0; i < mediaList.length; i++) { 35 mediaList[i].setAttribute('role', 'button'); 36 mediaList[i].tabIndex = 0; 37 mediaList[i].setAttribute('aria-pressed', String(mediaList[i].classList.contains('active'))); 38 mediaList[i].querySelectorAll('i').forEach(icon => icon.setAttribute('aria-hidden', 'true')); 39 if (!mediaList[i].hasAttribute('onkeydown')) { 40 mediaList[i].addEventListener('keydown', function (event) { 41 if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); this.click(); } 42 }); 43 } 44 mediaList[i].addEventListener('click', function() { 45 var url = this.getAttribute('data-url'); 46 var type = this.getAttribute('data-type'); 47 var image = this.getAttribute('data-image'); 48 //document.title = this.innerText; 49 //alert(this.innerText); 50 updateActiveMedia(this); 51 if ((type === 'audio') && (image != "")) { 52 mediaImage.src = image; 53 mediaImage.style.display = 'block'; 54 mediaContainer.innerHTML = ''; // clear the container if switching from video to audio 55 mediaContainer.appendChild(mediaImage); 56 } else { 57 mediaImage.style.display = 'none'; 58 } 59 loadMedia(url, type); 60 }); 61} 62 63function popupPlayer() { 64 var activeElement = document.querySelector('.media-list li.active'); 65 if (!activeElement) { 66 activeElement = document.querySelector('.media-list li'); 67 } 68 if (!activeElement) return; 69 var item = activeElement.innerText.trim().replaceAll(" ", "_"); 70 var width = Math.min(500, window.screen.availWidth || 500); 71 var height = Math.min(Math.ceil(width * 9 / 16 + mediaList.length * 48 + 100), (window.screen.availHeight || 800) - 80); 72 handoffMedia = currentMedia; 73 handoffWaiting = true; 74 playerControlWindow = window.open('/player/' + encodeURIComponent(item) + '/popup?handoff=1&volume=' + encodeURIComponent(volume.value), '_player', 'width=' + width + ',height=' + height + ',resizable=yes,scrollbars=yes'); 75 if (!playerControlWindow) handoffWaiting = false; 76} 77 78// Measure the rendered station names (including wrapping), not a fixed row count. 79function resizePopup() { 80 if (!document.body.classList.contains('player-popup')) return; 81 var container = document.querySelector('.player-popup .container'); 82 if (!container) return; 83 var controlsHeight = container.scrollHeight; 84 var chromeHeight = Math.max(0, window.outerHeight - window.innerHeight); 85 var available = window.screen.availHeight || window.outerHeight; 86 var visualHeight = Math.round(document.documentElement.clientWidth * 9 / 16);
87 var target = Math.min(available, Math.ceil(controlsHeight + visualHeight + chromeHeight)); 88 if (window.opener && Math.abs(window.outerHeight - target) > 2) { 89 try { window.resizeTo(window.outerWidth, target); } catch (_) {} 90 } 91 // Browsers may refuse window resizing. Prioritise stations over the artwork. 92 requestAnimationFrame(function () { 93 var space = Math.max(0, window.innerHeight - controlsHeight); 94 mediaContainer.style.setProperty('--popup-media-height', Math.min(visualHeight, space) + 'px'); 95 }); 96} 97if (document.body.classList.contains('player-popup')) { 98 window.addEventListener('load', resizePopup); 99 window.addEventListener('resize', resizePopup); 100 if (document.fonts) document.fonts.ready.then(resizePopup); 101 new ResizeObserver(resizePopup).observe(document.getElementById('media-list')); 102} 103 104function toggleFullScreen() { 105 if (!document.fullscreenElement) { 106 mediaContainer.classList.add('fullscreen'); 107 mediaContainer.requestFullscreen().catch(err => { 108 mediaContainer.classList.remove('fullscreen'); 109 alert(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`); 110 }); 111 112 } else { 113 if (document.exitFullscreen) { 114 document.exitFullscreen(); 115 mediaContainer.classList.remove('fullscreen'); 116 } 117 } 118} 119 120 121function updateActiveMedia(activeElement) { 122 for (var j = 0; j < mediaList.length; j++) { 123 mediaList[j].classList.remove('active'); 124 mediaList[j].setAttribute('aria-pressed', 'false'); 125 } 126 activeElement.classList.add('active'); 127 activeElement.setAttribute('aria-pressed', 'true'); 128} 129function loadMedia(url, type) { 130 var isPlaying = false; 131 if (currentMedia) { 132 isPlaying = !currentMedia.paused; 133 // Remove event listeners 134 currentMedia.setAttribute('preload', 'none'); 135 currentMedia.removeEventListener('play', updatePlayPauseButton); 136 currentMedia.removeEventListener('pause', updatePlayPauseButton); 137 currentMedia.pause(); 138 currentMedia.currentTime = 0; 139 updatePlayPauseButton(); 140 currentMedia.removeAttribute('src'); 141 //currentMedia.load(); 142 // Remove the media element from the DOM 143 if (currentMedia.parentNode) { 144 currentMedia.parentNode.removeChild(currentMedia); 145 } 146 } 147 148 // Set preload to none to prevent preloading 149 // currentMedia.setAttribute('preload', 'none'); 150 151 if (type === 'audio') { 152 currentMedia = document.createElement('audio'); 153 } else { 154 currentMedia = document.createElement('video'); 155 //currentMedia.setAttribute('controls', 'controls'); 156 } 157 158 mediaContainer.appendChild(currentMedia); 159 160 if (type === 'audio') { 161 currentMedia.src = url; 162 currentMedia.type = 'audio/mp3'; 163 } else { 164 if (Hls.isSupported()) { 165 var hls = new Hls(); 166 hls.loadSource(url); 167 hls.attachMedia(currentMedia); 168 } else if (currentMedia.canPlayType('application/vnd.apple.mpegurl')) { 169 currentMedia.src = url; 170 } 171 } 172 173 currentMedia.addEventListener('play', updatePlayPauseButton); 174 currentMedia.addEventListener('playing', announcePopupPlayback); 175 currentMedia.addEventListener('pause', updatePlayPauseButton); 176 177 currentMedia.addEventListener('error', function(e) { 178 console.error('Stream Error:', e); 179 }); 180 181 // currentMedia.load(); 182 currentMedia.volume = volume.value; 183 184 if (isPlaying || autoPlayEnabled) { 185 playMedia(); 186 } 187 188 if (typeof resizePopup === 'function') { 189 setTimeout(resizePopup, 1000); 190 setTimeout(resizePopup, 5000); 191 } 192} 193 194async function playMedia() { 195try { 196if (currentMedia) await currentMedia.play(); 197 // Media has started playing 198 } catch (error) { 199 console.error('Error playing media:', error); 200 } 201} 202 203function playMediax() { 204 if (currentMedia) currentMedia.play(); 205} 206 207function pauseMedia() { 208 if (currentMedia) currentMedia.pause(); 209} 210 211function togglePlayPause() { 212 if (currentMedia) { 213 if (currentMedia.paused) { 214 currentMedia.play(); 215 } else { 216 currentMedia.pause(); 217 } 218 updatePlayPauseButton(); // Update the play/pause button icon 219 } 220} 221 222function updatePlayPauseButton() { 223 var playPauseButton = document.getElementById('play-pause-button'); 224 if (currentMedia && playPauseButton) { 225 if (currentMedia.paused) { 226 playPauseButton.setAttribute('aria-label', 'Afspelen'); 227 playPauseButton.innerHTML = '<i class="fas fa-play"></i>'; // Show play icon 228 } else { 229 playPauseButton.setAttribute('aria-label', 'Pauzeren'); 230 playPauseButton.innerHTML = '<i class="fas fa-pause"></i>'; // Show pause icon 231 } 232 } 233} 234 235function prevMedia() { 236 var currentIndex = Array.from(mediaList).indexOf(document.querySelector('.media-list li.active')); 237 if (currentIndex > 0) { 238 mediaList[currentIndex - 1].click(); 239 } 240} 241 242function nextMedia() { 243 var currentIndex = Array.from(mediaList).indexOf(document.querySelector('.media-list li.active')); 244 if (currentIndex < mediaList.length - 1) { 245 mediaList[currentIndex + 1].click(); 246 } 247} 248 249function setVolume(value) { 250 if (currentMedia) currentMedia.volume = value; 251} 252 253// Load the default media when the page loads 254window.addEventListener('DOMContentLoaded', (event) => { 255 if (autoPlayEnabled && !autoStartDone) { 256 var activeElement = document.querySelector('.media-list li.active'); 257 if (!activeElement) { 258 activeElement = document.querySelector('.media-list li'); 259 } 260 if (activeElement) { 261 activeElement.click(); 262 autoStartDone = true; 263 } 264 } 265});
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.