PageSourceSearch

https://www.potucky-obec.cz/wrs_frontend/js/iframemanager/iframemanager.js

js potucky-obec.cz collected 2026-10-02 19:24:07 UTC 24,125 bytes, 666 lines download raw bytes

1/*!
2 * iframemanager v1.0
3 * Author Orest Bida
4 * Released under the MIT License
5 */
6(function(){
7    'use strict';
8
9    var module = {
10        iframes : {},
11        preconnects : [],
12        preloads: [],
13        iframeObserver : null,
14        currLang : null,
15        services : null,
16        serviceNames : null,
17
18        _getVideoProp : function(_div){
19            return {
20                _id: _div.dataset.id,
21                _title: _div.dataset.title,
22                thumbnail: _div.dataset['thumbnail'],
23                params: _div.dataset['params'],
24                thumbnailPreload: _div.hasAttribute('data-thumbnailpreload'),
25                div: _div,
26                backgroundDiv: null,
27                hasIframe: false,
28                hasNotice: false,
29                showNotice : true
30            }
31        },
32
33        /**
34         * Lazy load all thumbnails of the iframes relative to specified service
35         * @param {String} service_name
36         * @param {String} thumbnail_url
37         */
38        _lazyLoadThumnails : function(service_name, thumbnail_url){
39
40            var videos = this.iframes[service_name];
41            var length = videos.length;
42
43            if ("IntersectionObserver" in window) {
44                var thumbnailObserver = new IntersectionObserver(function(entries) {
45                    entries.forEach(function(entry){
46                        if(entry.isIntersecting){
47                            // true index of the video in the array relative to current service
48                            var _index = entry.target.dataset.index;
49                            module._loadThumbnail(thumbnail_url, videos[_index]);
50                            thumbnailObserver.unobserve(entry.target);
51                        }
52                    });
53                });
54
55                for(var i=0; i<length; i++){
56                    thumbnailObserver.observe(videos[i].div);
57                }
58            }else{
59                // Fallback for old browsers
60                for(var i=0; i<length; i++){
61                    module._loadThumbnail(thumbnail_url, videos[i]);
62                }
63            }
64        },
65
66        /**
67         * 1. Set cookie (if not alredy set)
68         * 2. show iframes (relative to the specified service)
69         * @param {String} service_name
70         */
71        acceptService : function(service_name){
72            if(service_name === 'all'){
73                var length = this.serviceNames.length;
74                for(var i=0; i<length; i++){
75                    var service_name = this.serviceNames[i];
76                    _acceptService(service_name, this.services[service_name]);
77                }
78            }else{
79                if(this.serviceNames.indexOf(service_name) > -1){
80                    _acceptService(service_name, this.services[service_name]);
81                }
82            }
83
84            function _acceptService(service_name, service){
85                if(!module._getCookie(service['cookie']['name'])){
86                    module._setCookie(service['cookie']);
87                }
88                module._hideAllNotices(service_name, service);
89            }
90        },
91
92        /**
93         * 1. set cookie
94         * 2. hide all notices
95         * 3. how iframes (relative to the specified service)
96         * @param {String} service_name
97         */
98         rejectService : function(service_name){
99            if(service_name === 'all'){
100                this.iframeObserver = null;
101                var length = this.serviceNames.length;
102                for(var i=0; i<length; i++){
103                    var service_name = this.serviceNames[i];
104                    _rejectService(service_name, this.services[service_name]);
105                }
106            }else{
107                if(this.serviceNames.indexOf(service_name) > -1){
108                    _rejectService(service_name, this.services[service_name]);
109                }
110            }
111
112            function _rejectService(service_name, service){
113                if(module._getCookie(service['cookie']['name'])){
114                    module._eraseCookie(service['cookie']);
115                }
116                module._showAllNotices(service_name, service);
117            }
118        },
119
120        /**
121         * Set image as background
122         * @param {String} url
123         * @param {Object} video
124         */
125        _loadThumbnail: function(url, video){
126
127            // Set custom thumbnail if provided
128            if(typeof video.thumbnail === 'string'){
129                video.thumbnailPreload && this._thumbnailPreload(video.thumbnail);
130                video.thumbnail !== "" && _loadBackgroundImage(video.thumbnail);
131            }else{
132
133                if(typeof url === "function"){
134
135                    url(video._id, function(src){
136                        module._preconnect(src);
137                        video.thumbnailPreload && this._thumbnailPreload(src);
138                        _loadBackgroundImage(src);
139                    });
140
141                }else if(typeof url === "string"){
142                    var src = url.replace('{data-id}', video._id);
143                    this._preconnect(src);
144                    video.thumbnailPreload && this._thumbnailPreload(src);
145                    _loadBackgroundImage(src);
146                }
147            }
148
149            function _loadBackgroundImage(src){
150                video.backgroundDiv.style.backgroundImage = "url('"+src+"')";
151
152                var img = new Image();
153                img.onload = function(){
154                    video.backgroundDiv.classList.add('loaded');
155                }
156
157                img.src = src;
158            }
159        },
160
161        /**
162         * Create iframe and append it into the specified div
163         * @param {Object} video
164         * @param {Object} service
165         */
166        _createIframe: function(video, service) {
167
168            // Create iframe only if doesn't alredy have one
169            if(video.hasIframe) return;
170
171            video.iframe = this._createNode('iframe');
172            var iframeParams = video.params || (service['iframe'] && service['iframe']['params']);
173
174            // Replace data-id with valid resource id
175            var src = service['embedUrl'].replace('{data-id}', video._id);
176
177            video.iframe['loading'] = 'lazy';
178            video._title && (video.iframe.title = video._title);
179
180            // Add allow attribute to iframe
181            if(service['iframe'] && service['iframe']['allow']){
182                video.iframe.allow = service['iframe']['allow'];
183            }
184
185            // Add parameters to src
186            if(iframeParams){
187                if (iframeParams.substring(0, 3) === "ap:"){
188                    src += iframeParams.substring(3);
189                }else{
190                    src += "?" + iframeParams
191                }
192            }
193
194            video.iframe.src = encodeURI(src);
195
196            // When iframe is loaded => hide background image
197            video.iframe.onload = function(){
198                video.div.classList.add('c-h-b');
199                video.iframe.onload = undefined;
200                service['iframe'] && typeof service['iframe']['onload'] === 'function' && service['iframe']['onload'](video._id, this);
201            }
202
203            video.hasIframe = true;
204            video.div.appendChild(video.iframe);
205        },
206
207        /**
208         * Remove iframe HTMLElement from div
209         * @param {Object} video
210         */
211        _removeIframe: function(video){
212            video.iframe.parentNode.removeChild(video.iframe);
213            video.hasIframe = false;
214        },
215
216        /**
217         * Remove necessary classes to hide notice
218         * @param {Object} video
219         */
220        _hideNotice : function(video){
221            if(video.showNotice){
222                video.div.classList.add('c-h-n');
223                video.showNotice = false;
224            }
225        },
226
227        /**
228         * Add necessary classes to show notice
229         * @param {Object} video
230         */
231        _showNotice : function(video){
232            if(!video.showNotice){
233                video.div.classList.remove('c-h-n', 'c-h-b');
234                video.showNotice = true;
235            }
236        },
237
238        /**
239         * Get cookie by name
240         * @param {String} a cookie name
241         * @returns {String} cookie value
242         */
243        _getCookie : function(a) {
244            return (a = document.cookie.match("(^|;)\\s*" + a + "\\s*=\\s*([^;]+)")) ? a.pop() : "";
245        },
246
247        /**
248         * Set cookie based on given object
249         * @param {Object} cookie
250         */
251        _setCookie : function(cookie) {
252
253            var date = new Date();
254            var path = cookie['path'] || "/";
255            var expiration = cookie['expiration'] || 182;
256            var sameSite = cookie['sameSite'] || "Lax";
257            var domain = cookie['domain'] || location.hostname;
258
259            date.setTime(date.getTime() + (1000 * ( expiration * 24 * 60 * 60)));
260            var expires = " expires=" + date.toUTCString();
261
262            var cookieStr = cookie.name + "=1;" + expires + "; Path=" + path + ";";
263            cookieStr += " SameSite=" + sameSite + ";";
264
265            // assures cookie works with localhost (=> don't specify domain if on localhost)
266            if(domain.indexOf(".") > -1){
267                cookieStr += " Domain=" + domain + ";";
268            }
269
270            if(location.protocol === "https:") {
271                cookieStr += " Secure;";
272            }
273
274            document.cookie = cookieStr;
275        },
276
277        /**
278         * Delete cookie by name & path
279         * @param {Array} cookies
280         * @param {String} custom_path
281         */
282         _eraseCookie : function(cookie) {
283            var path = cookie['path'] || "/";
284            var domain = cookie['domain'] || location.hostname;
285            var expires = 'Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
286
287            document.cookie = cookie['name'] +'=; Path='+ path +'; Domain=' + domain + '; ' + expires;
288        },
289
290        /**
291         * Get all prop. keys defined inside object
292         * @param {Object} obj
293         */
294        _getKeys : function(obj){
295            if(typeof obj === "object"){
296                var keys = [], i = 0;
297                for (keys[i++] in obj) {};
298                return keys;
299            }
300        },
301
302        /**
303         * Add link rel="preconnect"
304         * @param {String} url
305         */
306        _preconnect: function(url){
307            var url = url.split("://");
308            var protocol = url[0];
309
310            // if valid protocol
311            if(
312                protocol == 'http' ||
313                protocol == 'https'
314            ){
315                var domain = (url[1] && url[1].split("/")[0]) || false;
316
317                // if not current domain
318                if(domain && domain !== location.hostname){
319                    if(this.preconnects.indexOf(domain) === -1){
320                        var l = this._createNode('link');
321                        l.rel = 'preconnect';
322                        l.href = protocol + "://" + domain;
323                        document.head.appendChild(l);
324                        this.preconnects.push(domain);
325                    }
326                }
327            }
328        },
329
330        /**
331         * Add link rel="preload"
332         * @param {String} url
333         */
334        _thumbnailPreload : function(url){
335            if(url && this.preloads.indexOf(url) === -1){
336                var l = this._createNode('link');
337                l.rel = 'preload';
338                l.as = 'image';
339                l.href = url;
340                document.head.appendChild(l);
341                this.preloads.push(url);
342            }
343        },
344
345        /**
346         * Create and return HTMLElement based on specified type
347         * @param {String} type
348         * @returns {HTMLElement}
349         */
350        _createNode : function(type){
351            return document.createElement(type);
352        },
353
354        /**
355         * Create all notices relative to the specified service
356         * @param {String} service_name
357         * @param {Object} service
358         * @param {Boolean} hidden
359         */
360        _createAllNotices : function(service_name, service, hidden){
361
362            // get number of iframes of current service
363            var iframes = this.iframes[service_name];
364            var n_iframes = iframes.length;
365
366            // for each iframe
367            for(var i=0; i<n_iframes; i++){
368                (function(i){
369
370                    var video = iframes[i];
371
372                    if(!video.hasNotice){
373
374                        var loadBtnText = service['languages'][module.currLang]['loadBtn'];
375                        var noticeText = service['languages'][module.currLang]['notice'];
376                        var loadAllBtnText = service['languages'][module.currLang]['loadAllBtn'];
377
378                        var fragment = document.createDocumentFragment();
379                        var notice = module._createNode('div');
380                        var span = module._createNode('span');
381                        var innerDiv = module._createNode('p');
382                        var load_button = module._createNode('button');
383                        var load_all_button = module._createNode('button');
384
385                        var notice_text = module._createNode('span');
386                        var ytVideoBackground = module._createNode('div');
387                        var loaderBg = module._createNode('div');
388                        var ytVideoBackgroundInner = module._createNode('div');
389                        var notice_text_container = module._createNode('div');
390                        var buttons = module._createNode('div');
391
392                        load_button.type = load_all_button.type = 'button';
393                        notice_text.className = 'cc-text';
394                        load_button.type = load_all_button.type = 'button';
395                        notice_text.className = 'cc-text';
396
397                        ytVideoBackgroundInner.className = 'c-bg-i';
398                        video.backgroundDiv = ytVideoBackgroundInner;
399                        loaderBg.className = 'c-ld';
400
401                        if(typeof video.thumbnail !== 'string' || video.thumbnail !== ""){
402                            ytVideoBackground.className = 'c-bg';
403                        }
404
405
406                        var iframeTitle = video._title;
407                        var fragment_2 = document.createDocumentFragment();
408
409                        if(iframeTitle) {
410                            var title_span = module._createNode('span');
411                            title_span.className = 'c-tl';
412                            title_span.insertAdjacentHTML('beforeend', iframeTitle);
413                            fragment_2.appendChild(title_span);
414                        }
415
416                        load_button.textContent = loadBtnText;
417                        load_all_button.textContent = loadAllBtnText;
418
419                        notice_text.appendChild(fragment_2);
420                        notice && notice_text.insertAdjacentHTML('beforeend', noticeText || "");
421                        span.appendChild(notice_text);
422
423
424                        notice_text_container.className = 'c-t-cn';
425                        span.className = 'c-n-t';
426                        innerDiv.className = 'c-n-c';
427                        notice.className = 'c-nt';
428
429                        buttons.className =  'c-n-a';
430                        load_button.className = 'c-l-b';
431                        load_all_button.className = 'c-la-b';
432
433                        buttons.appendChild(load_button);
434                        buttons.appendChild(load_all_button);
435
436                        notice_text_container.appendChild(span);
437                        notice_text_container.appendChild(buttons);
438
439                        innerDiv.appendChild(notice_text_container);
440                        notice.appendChild(innerDiv);
441
442                        function showVideo(){
443                            module._hideNotice(video);
444                            module._createIframe(video, service);
445                        }
446
447                        load_button.addEventListener('click', function(){
448                            showVideo();
449                        });
450
451                        load_all_button.addEventListener('click', function(){
452                            showVideo();
453                            module.acceptService(service_name);
454                        });
455
456                        ytVideoBackground.appendChild(ytVideoBackgroundInner);
457                        fragment.appendChild(notice);
458                        (service['thumbnailUrl'] || video.thumbnail) && fragment.appendChild(ytVideoBackground);
459                        fragment.appendChild(loaderBg);
460
461                        hidden && video.div.classList.add('c-h-n');
462
463                        // Avoid reflow with fragment (only 1 appendChild)
464                        video.div.appendChild(fragment);
465                        video.hasNotice = true;
466                    }
467                })(i);
468            }
469        },
470
471        /**
472         * Hides all notices relative to the specified service
473         * and creates iframe with the video
474         * @param {String} service_name
475         * @param {Object} service
476         */
477        _hideAllNotices : function(service_name, service){
478
479            // get number of iframes of current service
480            var videos = this.iframes[service_name];
481            var n_iframes = videos.length;
482
483            if ("IntersectionObserver" in window) {
484                this.iframeObserver = new IntersectionObserver(function(entries) {
485                    for(var i=0; i<entries.length; ++i){
486                        if(module.iframeObserver === null){
487                            return;
488                        }
489                        if(entries[i].isIntersecting){
490                            (function(_index){
491                                setTimeout(function(){
492                                    var index = entries[_index].target.dataset.index;
493                                    module._createIframe(videos[index], service);
494                                    module._hideNotice(videos[index]);
495                                }, _index*50);
496                                module.iframeObserver.unobserve(entries[_index].target);
497                            })(i);
498                        }
499                    }
500                });
501
502                for(var i=0; i<n_iframes; i++){
503                    if(!videos[i].hasIframe){
504                        this.iframeObserver.observe(videos[i].div);
505                    }
506                }
507            }else{
508                for(var i=0; i<n_iframes; i++){
509                    (function(index){
510                        module._createIframe(videos[i], service);
511                        module._hideNotice(videos[index])
512                    })(i);
513                }
514            }
515        },
516
517
518        /**
519         * Show all notices relative to the specified service
520         * and hides iframe with the video
521         * @param {String} service_name
522         * @param {Object} service
523         */
524        _showAllNotices : function(service_name, service){
525
526            // get number of iframes of current service
527            var videos = this.iframes[service_name];
528            var n_iframes = videos.length;
529
530            for(var i=0; i<n_iframes; i++){
531                (function(index){
532                    // if doesn't have iframe => create it
533                    if(!videos[i].showNotice){
534                        if(videos[i].hasIframe){
535                            module._removeIframe(videos[i]);
536                        }
537                        module._showNotice(videos[index]);
538                    }
539                })(i);
540            }
541        },
542
543        /**
544         * Validate language (make sure it exists)
545         * @param {String} lang
546         * @param {Object} all_languages
547         * @returns {String} language
548         */
549        _getValidatedLanguage : function(lang, all_languages){
550            if(all_languages.hasOwnProperty(lang)){
551                return lang;
552            }else if(this._getKeys(all_languages).length > 0){
553                if(all_languages.hasOwnProperty(this.currLang)){
554                    return this.currLang ;
555                }else{
556                    return this._getKeys(all_languages)[0];
557                }
558            }
559        },
560
561        /**
562         * Get current client's browser language
563         * @returns {String} browser language
564         */
565        _getBrowserLang : function(){
566            var browser_lang = navigator.language || navigator.browserLanguage;
567            browser_lang.length > 2 && (browser_lang = browser_lang[0]+browser_lang[1]);
568            return browser_lang.toLowerCase()
569        },
570
571        run : function(_config) {
572            /**
573             * Object with all services config.
574             */
575            var services = _config['services'];
576            this.services = services;
577
578            /**
579             * Array containing the names of all services
580             */
581            var service_names = this._getKeys(services);
582            this.serviceNames = service_names;
583
584            /**
585             * Number of services
586             */
587            var n_services = service_names.length;
588
589            // if there are no services => don't do anything
590            if(n_services === 0){
591                return;
592            }
593
594            // Set curr lang
595            this.currLang = _config['currLang'];
596            var languages = services[service_names[0]]['languages'];
597
598            if(_config['autoLang'] === true){
599                this.currLang = this._getValidatedLanguage(this._getBrowserLang(), languages);
600            }else{
601                if(typeof _config['currLang'] === "string"){
602                    this.currLang = this._getValidatedLanguage(_config['currLang'], languages);
603                }
604            }
605
606            // for each service
607            for(var i=0; i<n_services; i++){
608
609                /**
610                 * Name of current service
611                 */
612                var service_name = service_names[i];
613
614                // add new empty array of videos (with current service name as property)
615                this.iframes[service_name] = [];
616
617                /**
618                 * iframes/divs in the dom that have data-service value as current service name
619                 */
620                var found_iframes = document.querySelectorAll('div[data-service="' + service_name + '"]');
621
622                /**
623                 * number of iframes with current service
624                 */
625                var n_iframes = found_iframes.length;
626
627                // if no iframes found =>
627 go to next service
628                if(n_iframes === 0){
629                    continue;
630                }
631
632                // add each iframe to array of iframes of the current service
633                for(var j=0; j<n_iframes; j++){
634                    found_iframes[j].dataset.index = j;
635                    this.iframes[service_name].push(this._getVideoProp(found_iframes[j]));
636                }
637
638                var curr_service = services[service_name];
639
640                // check if cookie for current service is set
641                var cookie_name = curr_service['cookie']['name'];
642
643                // get current service's cookie value
644                var cookie = this._getCookie(cookie_name);
645
646                // if cookie is not set => show notice
647                if(cookie){
648                    this._createAllNotices(service_name, curr_service, true);
649                    this._hideAllNotices(service_name, curr_service);
650                }else{
651                    this._createAllNotices(service_name, curr_service, false);
652                }
653
654                this._lazyLoadThumnails(service_name, curr_service['thumbnailUrl']);
655            }
656        }
657    };
658
659    var fn_name = 'iframemanager';
660
661    window[fn_name] = function(){
662        window[fn_name] = undefined;
663        return module;
664    };
665
666})();

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.