PageSourceSearch

https://www.zivipf.com/WebRoot/StoreTypes/7.119.0/Strato/SF/vilkascontentelement.video.js?cacheversion=

js zivipf.com collected 2026-10-04 06:21:13 UTC 8,131 bytes, 206 lines download raw bytes

1/**
2 * Click to load videos for FI_GAGAR::ContentElements Video elements.
3 *
4 * The storefront renders a preview image inside a real <button>. Nothing is requested from
5 * the video service until the visitor presses it, which keeps the visitor's data out of the
6 * video service (GDPR) and keeps the page light.
7 *
8 * One delegated listener handles every video on the page, so a page with many videos costs
9 * no more than a page with one.
10 */
11(function () {
12    'use strict';
13
14    var FACADE_SELECTOR = 'button.VilkasContentElementVideoFacade';
15    var IFRAME_ALLOW = 'accelerometer; autoplay; clipboard-write; encrypted-media; ' +
16                       'gyroscope; picture-in-picture; web-share';
17
18    // WCAG 2.2.2: the visitor asked to watch a video, so stop rotating the slider it sits in.
19    function stopSurroundingSlider(node) {
20        var slider = node.closest('.VilkasContentElementImageSlider');
21        if (slider && slider.swiper && slider.swiper.autoplay) {
22            slider.swiper.autoplay.stop();
23        }
24    }
25
26    function announce(message) {
27        if (!message) {
28            return;
29        }
30        var existing = document.getElementById('VilkasContentElementVideoAnnouncer');
31        if (existing) {
32            existing.remove();
33        }
34        var announcer = document.createElement('div');
35        announcer.id = 'VilkasContentElementVideoAnnouncer';
36        announcer.className = 'VilkasSrOnly';
37        announcer.setAttribute('role', 'status');
38        announcer.setAttribute('aria-live', 'polite');
39        announcer.setAttribute('aria-atomic', 'true');
40        announcer.textContent = message;
41        document.body.appendChild(announcer);
42    }
43
44    function loadVideo(button) {
45        var wrapper = button.parentNode;
46        var announcement = button.getAttribute('data-vilkas-video-announcement');
47
48        // A video file is already sitting behind the button with preload none, so there is
49        // nothing to inject: take the button away and play what is there.
50        var file = wrapper.querySelector('video');
51        if (file) {
52            stopSurroundingSlider(button);
53            button.remove();
54            var playing = file.play();
55            if (playing && playing.catch) {
56                playing.catch(function () { /* the browser declined, controls are still there */ });
57            }
58            if (file.focus) {
59                file.focus();
60            }
61            announce(announcement);
62            return;
63        }
64
65        var source = button.getAttribute('data-vilkas-video-src');
66        if (!source) {
67            return;
68        }
69
70        // The click is the user gesture that permits playback, so autoplay is safe to add
71        // here. It is deliberately not stored in the address, so that nothing autoplays
72        // when click to load is switched off.
73        var separator = source.indexOf('?') === -1 ? '?' : '&';
74        var iframe = document.createElement('iframe');
75        iframe.className = 'VilkasContentElementVideoPlayer';
76        iframe.setAttribute('src', source + separator + 'autoplay=1');
77        iframe.setAttribute('title', button.getAttribute('data-vilkas-video-title') || '');
78        iframe.setAttribute('loading', 'eager');
79        iframe.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');
80        iframe.setAttribute('allow', IFRAME_ALLOW);
81        iframe.setAttribute('allowfullscreen', 'allowfullscreen');
82
83        stopSurroundingSlider(button);
84        button.remove();
85        wrapper.appendChild(iframe);
86        // Keyboard users must not lose their place in the page.
87        iframe.focus();
88        announce(announcement);
89    }
90
91    document.addEventListener('click', function (event) {
92        if (!event.target || !event.target.closest) {
93            return;
94        }
95        var button = event.target.closest(FACADE_SELECTOR);
96        if (!button) {
97            return;
98        }
99        event.preventDefault();
100        loadVideo(button);
101    });
102
103    // The play event does not bubble, so it has to be caught in the capture phase.
104    document.addEventListener('play', function (event) {
105        var video = event.target;
106        if (!video || !video.matches || !video.matches('video.VilkasContentElementVideoPlayer')) {
107            return;
108        }
109        stopSurroundingSlider(video);
110    }, true);
111
112    /**
113     * Video files on a slide of an image slider.
114     *
115     * These are not given the autoplay attribute, because that would start every slide's
116     * video while the slider is still out of sight. Instead the video of the slide the
117     * visitor is actually looking at is started here, and the slider is held still until
118     * the video ends. Only the merchant's own video files get this treatment: a video
119     * service is never contacted before the visitor clicks its play button.
120     */
121    var AUTOPLAY_SLIDE_SELECTOR = 'video[data-vilkas-video-autoplay-in-slider]';
122
123    function slideOf(video) {
124        return video.closest('.swiper-slide');
125    }
126
127
128    function syncSliderVideos(slider, isVisible) {
129        var videos = slider.querySelectorAll(AUTOPLAY_SLIDE_SELECTOR);
130        Array.prototype.forEach.call(videos, function (video) {
131            var slide = slideOf(video);
132            var isActive = isVisible && slide && slide.classList.contains('swiper-slide-active');
133            if (isActive) {
134                // Muted is required, otherwise the browser refuses to start it.
135                video.muted = true;
136                var started = video.play();
137                if (started && started.catch) {
138                    started.catch(function () { /* the browser declined, leave the poster up */ });
139                }
140            } else if (!video.paused) {
141                video.pause();
142                video.currentTime = 0;
143            }
144        });
145    }
146
147    function initSlider(slider) {
148        if (slider.dataset.vilkasVideoSliderBound) {
149            return;
150        }
151        if (!slider.querySelector(AUTOPLAY_SLIDE_SELECTOR)) {
152            return;
153        }
154        slider.dataset.vilkasVideoSliderBound = '1';
155
156        var onScreen = true;
157        if (typeof IntersectionObserver === 'function') {
158            onScreen = false;
159            new IntersectionObserver(function (entries) {
160                entries.forEach(function (entry) {
161                    onScreen = entry.isIntersecting;
162                    syncSliderVideos(slider, onScreen);
163                });
164            }, {threshold: 0.25}).observe(slider);
165        }
166
167        // Swiper is created by an inline script that may run after this file, so hooking
168        // swiper.on() here would silently do nothing. The active slide is marked with a
169        // class either way, so watch the class instead of the Swiper API.
170        var pending = null;
171        new MutationObserver(function () {
172            if (pending) {
173                return;
174            }
175            pending = setTimeout(function () {
176                pending = null;
177                syncSliderVideos(slider, onScreen);
178            }, 50);
179        }).observe(slider, {subtree: true, attributes: true, attributeFilter: ['class']});
180
181        // Let the slider move on once the video has had its turn.
182        slider.addEventListener('ended', function (event) {
183            if (!event.target.matches || !event.target.matches(AUTOPLAY_SLIDE_SELECTOR)) {
184                return;
185            }
186            if (slider.swiper && slider.swiper.autoplay && slider.swiper.params.autoplay) {
187                slider.swiper.autoplay.start();
188            }
189        }, true);
190
191        syncSliderVideos(slider, onScreen);
192    }
193
194    function initAllSliders() {
195        var sliders = document.querySelectorAll('.VilkasContentElementImageSlider');
196        Array.prototype.forEach.call(sliders, initSlider);
197    }
198
199    if (document.readyState === 'loading') {
200        document.addEventListener('DOMContentLoaded', initAllSliders);
201    } else {
202        initAllSliders();
203    }
204    // Swiper is initialised from an inline script per slider, which may run after this file.
205    window.addEventListener('load', initAllSliders);
206}());

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.