PageSourceSearch

https://boka.tekniskamuseet.se/modules/custom/common/youtube_background/js/jquery.youtubebackground.js?tlv36y

js tekniskamuseet.se collected 2026-09-24 20:27:30 UTC 18,042 bytes, 492 lines download raw bytes

1/*
2 * YoutubeBackground - A wrapper for the Youtube API - Great for fullscreen background videos or just regular videos.
3 *
4 * Licensed under the MIT license:
5 *   http://www.opensource.org/licenses/mit-license.php
6 *
7 *
8 * Version:  1.0.5
9 *
10 */
11
12/* Updates made by Sara 2019-12-19 */
13
14// Chain of Responsibility pattern. Creates base class that can be overridden.
15if (typeof Object.create !== "function") {
16    Object.create = function (obj) {
17        function F() {
18        }
19
20        F.prototype = obj;
21        return new F();
22    };
23}
24
25(function ($, window, document) {
26    var
27        loadAPI = function loadAPI(callback) {
28
29            // Load Youtube API
30            var tag = document.createElement('script'),
31                head = document.getElementsByTagName('head')[0];
32
33            if (window.location.origin == 'file://') {
34                tag.src = 'http://www.youtube.com/iframe_api';
35            } else {
36                tag.src = 'https://www.youtube.com/iframe_api';
37            }
38
39            head.appendChild(tag);
40
41            // Clean up Tags.
42            head = null;
43            tag = null;
44
45            iframeIsReady(callback);
46        },
47
48        iframeIsReady = function iframeIsReady(callback) {
49            // Listen for Gobal YT player callback
50            if (typeof YT === 'undefined' && typeof window.loadingPlayer === 'undefined') {
51                // Prevents Ready Event from being called twice
52                window.loadingPlayer = true;
53
54                // Creates deferred so, other players know when to wait.
55                window.dfd = $.Deferred();
56                window.onYouTubeIframeAPIReady = function () {
57                    window.onYouTubeIframeAPIReady = null;
58                    window.dfd.resolve("done");
59                    callback();
60                };
61            } else if (typeof YT === 'object') {
62                callback();
63            } else {
64                window.dfd.done(function (name) {
65                    callback();
66                });
67            }
68        };
69
70    // YTPlayer Object
71    YTPlayer = {
72        player: null,
73
74        // Defaults
75        defaults: {
76            ratio: 16 / 9,
77            host: 'https://www.youtube-nocookie.com',
78            videoId: 'LSmgKRx5pBo',
79            repeat: true,
80            width: $(window).width(),
81            playButtonClass: 'YTPlayer-play',
82            pauseButtonClass: 'YTPlayer-pause',
83            muteButtonClass: 'YTPlayer-mute',
84            volumeUpClass: 'YTPlayer-volume-up',
85            volumeDownClass: 'YTPlayer-volume-down',
86            start: 0,
87            pauseOnScroll: false,
88            fitToBackground: true,
89            playerVars: {
90                iv_load_policy: 3,
91                autoplay: 1,
92                controls: 0,
93                loop: 1,
94                mute: 1,
95                rel: 0,
96                playsinline: 1,
97                origin: window.location.origin,
98            },
99          events: {
100            'onReady': this.onPlayerReady,
101          }
102        },
103
104        /**
105         * @function init
106         * Intializes YTPlayer object
107         */
108        init: function init(node, userOptions) {
109            var self = this;
110
111            userOptions.playerVars = {};
112            userOptions.playerVars.autoplay = userOptions.autoplay;
113            userOptions.playerVars.mute = userOptions.mute;
114            userOptions.playerVars.controls = userOptions.controls;
115            userOptions.playerVars.origin = window.location.origin;
116
117            self.userOptions = userOptions;
118
119            self.$body = $('body'),
120                self.$node = $(node),
121                self.$window = $(window);
122
123            // Setup event defaults with the reference to this
124            self.defaults.events = {
125                'onReady': function (e) {
126                    self.onPlayerReady(e);
127
128                    // setup up pause on scroll
129                    if (self.options.pauseOnScroll) {
130                        self.pauseOnScroll();
131                    }
132
133                    // Callback for when finished
134                    if (typeof self.options.callback == 'function') {
135                        self.options.callback.call(this);
136                    }
137                },
138                'onStateChange': function (e) {
139                    if (e.data === 1) { // playing
140                        self.$node.addClass('loaded playing');
141                        self.$node.removeClass('paused');
142                    } else if (e.data === 2) { // paused
143                        self.$node.removeClass('playing');
144                        self.$node.addClass('paused');
145                    } else if (e.data === 0 && self.options.repeat) { // video ended and repeat option is set true
146                        self.player.seekTo(self.options.start);
147                    }
148                }
149            }
150
151            self.options = $.extend(true, {}, self.defaults, self.userOptions);
152            self.options.height = Math.ceil(self.options.width / self.options.ratio);
153            self.ID = (new Date()).getTime();
154            self.holderID = 'YTPlayer-ID-' + self.ID;
155
156            if (self.options.fitToBackground) {
157                self.createBackgroundVideo();
158            } else {
159                self.createContainerVideo();
160            }
161            // Listen for Resize Event
162            self.$window.on('resize.YTplayer' + self.ID, function () {
163                self.resize(self);
164            });
165
166            loadAPI(self.onYouTubeIframeAPIReady.bind(self));
167
168            self.resize(self);
169
170            self.$node.find('.YTPlayer-play').click(function (e) {
171                self.player.playVideo();
172                self.$node.addClass('playing');
173                self.$node.removeClass('paused');
174
175                self.$node.find('.' + self.options.pauseButtonClass).show().addClass('visible');
176                self.$node.find('.' + self.options.playButtonClass).hide();
177
178                // Handle iframe tabindex for native controls with image overlay
179                var hasImageOverlay = self.$node.hasClass('puasedImageRendered');
180                var iframe = self.$node.find('iframe')[0];
181                if (iframe && hasImageOverlay) {
182                    iframe.removeAttribute('tabindex');
183                }
184
185                // Only focus for keyboard interactions (Enter/Space key)
186                if (e.originalEvent && (e.originalEvent.detail === 0 || e.originalEvent.type === 'keydown')) {
187                    self.$node.find('.YTPlayer-pause').focus();
188                }
189            });
190
191            self.$node.find('.YTPlayer-pause').click(function (e) {
192                self.player.pauseVideo();
193                self.$node.removeClass('playing');
194                self.$node.addClass('paused');
195
196                self.$node.find('.' + self.options.pauseButtonClass).hide().removeClass('visible');
197                self.$node.find('.' + self.options.playButtonClass).show();
198
199                // Handle iframe tabindex for native controls with image overlay
200                var hasImageOverlay = self.$node.hasClass('puasedImageRendered');
201                var iframe = self.$node.find('iframe')[0];
202                if (iframe && hasImageOverlay) {
203                    iframe.setAttribute('tabindex', '-1');
204                }
205
206                // Only focus for keyboard interactions (Enter/Space key)
207                if (e.originalEvent && (e.originalEvent.detail === 0 || e.originalEvent.type === 'keydown')) {
208                    self.$node.find('.YTPlayer-play').focus();
209                }
210            });
211
212            function toggleMute(self, isKeyboardEvent) {
213              if (self.player.isMuted()) {
214                self.player.unMute();
215                self.$node.find('.YTPlayer-mute').show();
216                self.$node.find('.YTPlayer-unmute').hide();
217                // Only focus for keyboard interactions
218                if (isKeyboardEvent) {
219                    self.$node.find('.YTPlayer-mute').focus();
220                }
221              } else {
222                self.player.mute();
223                self.$node.find('.YTPlayer-mute').hide();
224                self.$node.find('.YTPlayer-unmute').show();
225                // Only focus for keyboard interactions
226                if (isKeyboardEvent) {
227                    self.$node.find('.YTPlayer-unmute').focus();
228                }
229              }
230            }
231
232            self.$node.find('.YTPlayer-mute').click(function (e) {
233              const isKeyboardEvent = e.originalEvent && (e.originalEvent.detail === 0 || e.originalEvent.type === 'keydown');
234              toggleMute(self, isKeyboardEvent);
235            });
236
237            self.$node.find('.YTPlayer-unmute').click(function (e) {
238              const isKeyboardEvent = e.originalEvent && (e.originalEvent.detail === 0 || e.originalEvent.type === 'keydown');
239              toggleMute(self, isKeyboardEvent);
240            });
241
242            return self;
243        },
244
245        /**
246         * @function pauseOnScroll
247         * Adds window events to pause video on scroll.
248         */
249        pauseOnScroll: function pauseOnScroll() {
250            var self = this;
251            self.$window.on('scroll.YTplayer' + self.ID, function () {
252                var state = self.player.getPlayerState();
253                if (state === 1) {
254                    self.player.pauseVideo();
255                    self.$node.removeClass('playing');
256                    self.$node.addClass('paused');
257                }
258            });
259            self.$window.scrollStopped(function () {
260                var state = self.player.getPlayerState();
261                if (state === 2) {
262                    self.player.playVideo();
263                    self.$node.addClass('playing');
264                    self.$node.removeClass('paused');
265                }
266            });
267        },
268        /**
269         * @function pauseInMobile
270         * Adds window events to pause video in mobile
271         */
272        pauseInMobile: function pauseInMobile() {
273            var self = this;
274            var state = self.player.getPlayerState();
275
276            if(self.options.width < 630){
277              if (state === 1) { // it plays
278                self.player.pauseVideo();
279                self.$node.removeClass('playing');
280                self.$node.addClass('paused');
281              }
282            }else{
283              if (state === 2) {
284                self.player.playVideo();
285                self.$node.addClass('playing');
286                self.$node.removeClass('paused');
287              }
288            }
289        },
290        /**
291         * @function createContainerVideo
292         * Adds HTML for video in a container
293         */
294        createContainerVideo: function createContainerVideo() {
295            var self = this;
296
297            /*jshint multistr: true */
298            var $YTPlayerString = $('<div id="ytplayer-container' + self.ID + '" >\
299                                    <div id="' + self.holderID + '" class="ytplayer-player-inline"></div> \
300                                    </div> \
301                                    <div id="ytplayer-shield" class="ytplayer-shield"></div>');
302
303            self.$node.append($YTPlayerString);
304            self.$YTPlayerString = $YTPlayerString;
305            $YTPlayerString = null;
306        },
307
308        /**
309         * @function createBackgroundVideo
310         * Adds HTML for video background
311         */
312        createBackgroundVideo: function createBackgroundVideo() {
313            /*jshint multistr: true */
314            var self = this,
315                $YTPlayerString = $('<div id="ytplayer-container' + self.ID + '" class="ytplayer-container background">\
316                                    <div id="' + self.holderID + '" class="ytplayer-player"></div>\
317                                    </div>\
318                                    <div id="ytplayer-shield" class="ytplayer-shield"></div>');
319
320            self.$node.append($YTPlayerString);
321            self.$YTPlayerString = $YTPlayerString;
322            $YTPlayerString = null;
323        },
324
325        /**
326         * @function resize
327         * Resize event to change video size
328         */
329        resize: function resize(self) {
330
331            var container = $('#ytplayer-container' + self.ID).parent();
332
333            if (!self.options.fitToBackground) {
334                container = self.$node;
335            }
336
337            if(self.player){
338              var state = self.player.getPlayerState();
339            }
340
341            var width = container.width(),
342                pWidth, // player width, to be defined
343                height = container.height(),
344                pHeight, // player height, tbd
345                $YTPlayerPlayer = $('#' + self.holderID);
346
347            // when screen aspect ratio differs from video, video must center and underlay one dimension
348            if (width / self.options.ratio < height) {
349                pWidth = Math.ceil(height * self.options.ratio); // get new player width
350                $YTPlayerPlayer.width(pWidth).height(height).css({
351                  left: parseFloat(width) > 0 &&  parseFloat(pWidth) > 0 ? (width - pWidth) / 2 : 0,
352                  top: 0,
353                }); // player width is greater, offset left; reset top
354            } else { // new video width < window width (gap to right)
355                pHeight = Math.ceil(width / self.options.ratio); // get new player height
356                $YTPlayerPlayer.width(width).height(pHeight).css({
357                    left: 0,
358                    top: parseFloat(height) > 0 &&  parseFloat(pHeight) > 0 ? (height - pHeight) / 2 : 0,
359                }); // player height is greater, offset top; reset left
360            }
361
362            /*
363            if(width < 630){
364              if (state === 1) { // it plays, pause video
365                self.player.pauseVideo();
366                self.$node.removeClass('playing');
367                self.$node.addClass('paused');
368              }
369
370            }else{
371              if (state === 2) {
372                self.player.playVideo();
373                self.$node.addClass('playing');
374                self.$node.removeClass('paused');
375              }
376            }*/
377
378            $YTPlayerPlayer = null;
379            container = null;
380        },
381
382        /**
383         * @function onYouTubeIframeAPIReady
384         * @ params {object} YTPlayer object for access to options
385         * Youtube API calls this function when the player is ready.
386         */
387        onYouTubeIframeAPIReady: function onYouTubeIframeAPIReady() {
388            var self = this;
389            self.player = new window.YT.Player(self.holderID, self.options);
390        },
391
392        /**
393         * @function onPlayerReady
394         * @ params {event} window event from youtube player
395         */
396        onPlayerReady: function onPlayerReady(e) {
397            let isPlay = false;
398            var self = this;
399            var hasImageOverlay = self.$node.hasClass('puasedImageRendered');
400
401            if (this.options.mute) {
402                e.target.mute();
403            }
404
405            if (this.options.autoplay) {
406              e.target.mute(); // Set to mute as autoplay could be disabled by the browser e.g Chrome autoplay policies '...Muted autoplay is always allowed...'( Source: https://developer.chrome.com/blog/autoplay )
407              isPlay = true;
408            }
409
410            // Get the iframe element for tabindex management
411            var iframe = self.$node.find('iframe')[0];
412
413            if (isPlay) {
414              e.target.playVideo();
415              this.$node.addClass('playing');
416              this.$node.removeClass('paused');
417              this.$node.find('.' + this.options.pauseButtonClass).show().addClass('visible');
418              this.$node.find('.' + this.options.playButtonClass).hide();
419
420              // Make iframe focusable when playing
421              if (iframe && hasImageOverlay) {
422                iframe.removeAttribute('tabindex');
423              }
424            } else {
425              e.target.pauseVideo();
426              this.$node.addClass('paused');
427              this.$node.removeClass('playing');
428              this.$node.find('.' + this.options.pauseButtonClass).hide().removeClass('visible');
429              this.$node.find('.' + this.options.playButtonClass).show();
430
431              // Make iframe non-focusable when paused with image overlay and native controls
432              if (iframe && hasImageOverlay) {
433                iframe.setAttribute('tabindex', '-1');
434              }
435            }
436        },        /**
437         * @function getPlayer
438         * returns youtube player
439         */
440        getPlayer: function getPlayer() {
441            return this.player;
442        },
443
444        /**
445         * @function destroy
446         * destroys all!
447         */
448        destroy: function destroy() {
449            var self = this;
450
451            self.$node
452                .removeData('yt-init')
453                .removeData('ytPlayer')
454                .removeClass('loaded');
455
456            self.$YTPlayerString.remove();
457
458            $(window).off('resize.YTplayer' + self.ID);
459            $(window).off('scroll.YTplayer' + self.ID);
460            self.$body = null;
461            self.$node = null;
462            self.$YTPlayerString = null;
463            self.player.destroy();
464            self.player = null;
465        }
466    };
467
468    // Scroll Stopped event.
469    $.fn.scrollStopped = function (callback) {
470        var $this = $(this), self = this;
471        $this.scroll(function () {
472            if ($this.data('scrollTimeout')) {
473                clearTimeout($this.data('scrollTimeout'));
474            }
475            $this.data('scrollTimeout', setTimeout(callback, 250, self));
476        });
477    };
478
479    // Create plugin
480    $.fn.YTPlayer = function (options) {
481
482        return this.each(function () {
483            var el = this;
484
485            $(el).data("yt-init", true);
486            var player = Object.create(YTPlayer);
487            player.init(el, options);
488            $.data(el, "ytPlayer", player);
489        });
490    };
491
492})(jQuery, window, document);

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.