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.