PageSourceSearch

https://restaurantmoon.nl/wp-content/plugins/video-background-wpbakery/assets/js/fgvb.js?ver=1.1.3

js restaurantmoon.nl collected 2026-10-05 07:32:39 UTC 6,346 bytes, 216 lines download raw bytes

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.