1/** 2 * Video Background voor WPBakery 3 * 4 * De videobronnen staan in data-src; dit script besluit per achtergrond 5 * of er geladen wordt (mobiel gedrag, prefers-reduced-motion, Save-Data) 6 * en regelt autoplay, loop/fragment-loop, snelheid en pauzeren buiten beeld. 7 */ 8(function () { 9 'use strict'; 10 11 // Toont automatisch het eerste frame van de video als "poster", ook als 12 // de video niet (auto)speelt. Een minieme sprong dwingt browsers (o.a. 13 // iOS Safari) het frame echt te renderen i.p.v. een leeg/zwart vlak. 14 function showFirstFrame(video) { 15 var nudged = false; 16 function nudge() { 17 if (nudged) { return; } 18 nudged = true; 19 try { 20 if (video.paused && video.currentTime < 0.05) { 21 video.currentTime = 0.05; 22 } 23 } catch (e) { /* noop */ } 24 } 25 video.addEventListener('loadeddata', nudge, { once: true }); 26 if (video.getAttribute('preload') === 'none') { 27 video.preload = 'metadata'; 28 } 29 video.load(); 30 } 31 32 function setup(el) { 33 el.setAttribute('data-fgvb-init', '1'); 34 35 var video = el.querySelector('video.fgvb-video'); 36 if (!video) { 37 return; 38 } 39 40 var d = el.dataset; 41 var breakpoint = parseInt(d.breakpoint, 10) || 768; 42 43 // Viewport-selectie: bij een aparte desktop-/mobiele video bepaalt CSS 44 // (een inline media-query) welke laag zichtbaar is. Hier zorgen we er 45 // alleen voor dat de video van de NIET-zichtbare laag niet laadt. 46 if (d.only) { 47 var isMobileViewport = window.matchMedia && 48 window.matchMedia('(max-width: ' + breakpoint + 'px)').matches; 49 var wantMobile = d.only === 'mobile'; 50 if (wantMobile !== isMobileViewport) { 51 if (video.parentNode) { 52 video.parentNode.removeChild(video); 53 } 54 return; // laag is via CSS verborgen; video niet laden 55 } 56 } 57 58 var hasPoster = !!el.querySelector('.fgvb-poster'); 59 60 // Bronnen activeren (data-src -> src) zodat de video kan laden. 61 var sources = video.querySelectorAll('source[data-src]'); 62 for (var i = 0; i < sources.length; i++) { 63 sources[i].src = sources[i].getAttribute('data-src'); 64 } 65 // preload="metadata": laadt een eerste frame zodat dat getoond kan 66 // worden als autoplay (nog) niet lukt, i.p.v. een leeg vlak. 67 if (video.getAttribute('preload') === 'none') { 68 video.preload = 'metadata'; 69 } 70 71 // "Verminderde beweging" en "databesparing" tonen een stilstaand beeld 72 // in plaats van bewegende video. Is er een poster-afbeelding, dan tonen 73 // we die; anders tonen we automatisch het eerste frame van de video. 74 // Let op: iOS Low Power Mode zet prefers-reduced-motion automatisch aan. 75 var reducedMotion = d.rm === '1' && 76 window.matchMedia && 77 window.matchMedia('(prefers-reduced-motion: reduce)').matches; 78 79 var saveData = d.sd === '1' && 80 navigator.connection && 81 navigator.connection.saveData; 82 83 var mobilePoster = d.mobile === 'poster' && 84 window.matchMedia && 85 window.matchMedia('(max-width: ' + breakpoint + 'px)').matches; 86 87 if (reducedMotion || saveData || mobilePoster) { 88 el.classList.add('fgvb-poster-only'); 89 if (hasPoster) { 90 // Poster-afbeelding aanwezig: video-element kan weg. 91 if (video.parentNode) { 92 video.parentNode.removeChild(video); 93 } 94 } else { 95 // Geen poster: eerste frame als automatische poster, niet spelen. 96 video.loop = false; 97 video.removeAttribute('loop'); 98 showFirstFrame(video); 99 } 100 return; 101 } 102 103 var loop = d.loop !== '0'; 104 var rate = parseFloat(d.rate); 105 var start = parseFloat(d.start) || 0; 106 var end = parseFloat(d.end) || 0; 107 var fragmentLoop = start > 0 || (end > 0 && end > start); 108 109 if (d.muted !== '0') { 110 video.muted = true; 111 video.setAttribute('muted', ''); 112 } 113 if (loop && !fragmentLoop) { 114 video.loop = true; 115 } 116 117 video.load(); 118 119 video.addEventListener('loadedmetadata', function () { 120 if (rate && rate > 0 && rate !== 1) { 121 video.playbackRate = rate; 122 } 123 if (start > 0) { 124 try { video.currentTime = start; } catch (e) { /* noop */ } 125 } 126 }); 127 128 // Fragment-loop: alleen tussen start- en eindtijd afspelen. 129 if (fragmentLoop) { 130 video.addEventListener('timeupdate', function () { 131 if (end > start && video.currentTime >
131= end) { 132 if (loop) { 133 video.currentTime = start; 134 } else { 135 video.pause(); 136 } 137 } 138 }); 139 video.addEventListener('ended', function () { 140 if (loop) { 141 video.currentTime = start; 142 play(); 143 } 144 }); 145 } 146 147 var wantAutoplay = d.autoplay !== '0'; 148 149 function play() { 150 var p = video.play(); 151 if (p && typeof p.catch === 'function') { 152 p.catch(function () { 153 // Autoplay geblokkeerd (bv. iOS Low Power Mode): toon het 154 // eerste frame zodat er geen leeg vlak staat tot interactie. 155 el.classList.add('fgvb-blocked'); 156 try { 157 if (video.paused && video.currentTime < 0.05) { 158 video.currentTime = 0.05; 159 } 160 } catch (e) { /* noop */ } 161 }); 162 } 163 } 164 165 video.addEventListener('playing', function () { 166 el.classList.add('fgvb-playing'); 167 el.classList.remove('fgvb-blocked'); 168 }); 169 170 // Pauzeren zodra de sectie uit beeld scrollt (CPU/batterij). 171 if (wantAutoplay && d.pause === '1' && 'IntersectionObserver' in window) { 172 var io = new IntersectionObserver(function (entries) { 173 for (var j = 0; j < entries.length; j++) { 174 if (entries[j].isIntersecting) { 175 play(); 176 } else { 177 video.pause(); 178 } 179 } 180 }, { threshold: 0.05 }); 181 io.observe(el); 182 } else if (wantAutoplay) { 183 play(); 184 } 185 186 // Als autoplay werd geblokkeerd: opnieuw proberen bij eerste interactie. 187 function retry() { 188 if (wantAutoplay && el.classList.contains('fgvb-blocked')) { 189 play(); 190 } 191 } 192 window.addEventListener('click', retry, { once: true }); 193 window.addEventListener('touchstart', retry, { once: true, passive: true }); 194 } 195 196 function init(root) { 197 var items = (root || document).querySelectorAll('.fgvb-bg[data-fgvb]:not([data-fgvb-init])'); 198 for (var i = 0; i < items.length; i++) { 199 setup(items[i]); 200 } 201 } 202 203 if (document.readyState === 'loading') { 204 document.addEventListener('DOMContentLoaded', function () { init(); }); 205 } else { 206 init(); 207 } 208 209 // WPBakery frontend-editor: opnieuw initialiseren na een reload van de inhoud. 210 if (window.jQuery) { 211 window.jQuery(window).on('vc_reload', function () { init(); }); 212 } 213 214 // Publieke API, o.a. voor dynamisch toegevoegde content (AJAX). 215 window.FGVB = { init: init }; 216})();
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.