1/* jquery.youtube-background v1.0.7 | Nikola Stamatovic <@stamat> | MIT */ 2 3var tag = document.createElement('script'); 4tag.src = "https://www.youtube.com/player_api"; 5var firstScriptTag = document.getElementsByTagName('script')[0]; 6firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 7 8 9//native addClass, removeClass, hasClass and toggleClass 10if (!window.hasOwnProperty('d0')) { 11 window.d0 = {}; 12 13 d0.hasClass = function(element, className) { 14 if (element.classList) { 15 return element.classList.contains(className); 16 } 17 return new RegExp('\\b'+ className+'\\b').test(element.className); 18 }; 19 20 d0.addClass = function(element, className) { 21 if (element.classList) { 22 element.classList.add(className); 23 return; 24 } 25 26 if (!d0.hasClass(element, className)) { 27 element.className += ' ' + className; 28 } 29 }; 30 31 d0.removeClass = function(element, className) { 32 if (element.classList) { 33 element.classList.remove(className); 34 return; 35 } 36 37 element.className = element.className.replace(new RegExp('\\b'+ className+'\\b', 'g'), ''); 38 }; 39 40 d0.toogleClass = function(element, className) { 41 if (d0.hasClass(element, className)) { 42 d0.removeClass(element, className); 43 } else { 44 d0.addClass(element, className); 45 } 46 }; 47} 48 49function YoutubeBackground(elem, params, id, uid) { 50 this.is_mobile = this.isMobile(); 51 52 this.element = elem; 53 this.ytid = id; 54 this.uid = uid; 55 this.player = null; 56 this.buttons = {}; 57 58 this.state = {}; 59 this.state.play = false; 60 this.state.mute = false; 61 62 this.params = {}; 63 64 this.defaults = { 65 'fitToBackground': true, 66 'pause': false, //deprecated 67 'play-button': false, 68 'mute-button': false, 69 'autoplay': true, 70 'muted': true, 71 'loop': true, 72 'mobile': false, 73 'load-background': true, 74 'resolution': '16:9', 75 'offset': 200 76 }; 77 78 this.__init__ = function () { 79 if (!this.ytid) { 80 return; 81 } 82 83 this.parseProperties(params); 84 this.params.resolution_mod = this.parseResolutionString(this.params.resolution); 85 this.state.playing = this.params.autoplay; 86 this.state.muted = this.params.muted; 87 88 this.buildHTML(); 89 this.injectIFrame(); 90 91 92 if (this.params['play-button']) { 93 this.generateActionButton({ 94 name: 'play', 95 className: 'play-toggle', 96 innerHtml: '<i class="fa"></i>', 97 initialState: false, 98 stateClassName: 'paused', 99 condition_parameter: 'autoplay', 100 stateChildClassNames: ['fa-pause-circle', 'fa-play-circle'], 101 actions: ['play', 'pause'] 102 }); 103 } 104 105 if (this.params['mute-button']) { 106 this.generateActionButton({ 107 name: 'mute', 108 className: 'mute-toggle', 109 innerHtml: '<i class="fa"></i>', 110 initialState: true, 111 stateClassName: 'muted', 112 condition_parameter: 'muted', 113 stateChildClassNames: ['fa-volume-up', 'fa-volume-mute'], 114 actions: ['unmute', 'mute'] 115 }); 116 } 117 } 118 119 this.__init__(); 120} 121 122YoutubeBackground.prototype.initYTPlayer = function () { 123 var self = this; 124 125 if (window.hasOwnProperty('YT')) { 126 this.player = new YT.Player(this.uid, { 127 events: { 128 'onReady': function(event) { 129 self.onVideoPlayerReady(event); 130 }, 131 'onStateChange': function(event) { 132 self.onVideoStateChange(event); 133 }, 134 'onError' : function(event) { 135 //console.error('player_api', event); 136 } 137 } 138 }); 139 } 140}; 141 142YoutubeBackground.prototype.onVideoPlayerReady = function (event) { 143 if (this.params.autoplay) { 144 event.target.playVideo(); 145 } 146}; 147 148YoutubeBackground.prototype.onVideoStateChange = function (event) { 149 if (event.data === 0 && this.params.loop) { 150 event.target.playVideo(); 151 } 152 153 if (event.data === -1 && this.params.autoplay) { 154 event.target.playVideo(); 155 } 156 157 if (event.data === 1) { 158 this.iframe.style.opacity = 1; 159 } 160}; 161 162YoutubeBackground.prototype.parseProperties = function (params) { 163 if (!params) { 164 this.params = this.defaults; 165 } else { 166 //load in defaults 167 for (var k in this.defaults) { 168 if (!this.params.hasOwnProperty(k)) { 169 this.params[k] = this.defaults[k]; 170 } 171 } 172 } 173 174 // load params from data attributes 175 for (var k in this.params) { 176 var data = this.element.getAttribute('data-ytbg-'+k);
177 178 if (data !== undefined && data !== null) { 179 switch (data) { 180 case data === 'false': 181 data = false; 182 break; 183 case data === 'true': 184 data = true; 185 break; 186 } 187 188 this.params[k] = data; 189 } 190 } 191 192 //pause deprecated 193 if (this.params.pause) { 194 this.params['play-button'] = this.params.pause; 195 } 196}; 197 198YoutubeBackground.prototype.injectIFrame = function () { 199 this.iframe = document.createElement('iframe'); 200 this.iframe.setAttribute('frameborder', 0); 201 this.iframe.setAttribute('title', 'Video Background'); 202 this.iframe.setAttribute('allow', ['autoplay; mute']); 203 var src = 'https://www.youtube.com/embed/'+this.ytid+'?enablejsapi=1&disablekb=1&controls=0&rel=0&iv_load_policy=3&cc_load_policy=0&playsinline=1&showinfo=0&modestbranding=1&fs=0&origin='+window.location.origin; 204 205 if (this.params.muted) { 206 src += '&mute=1'; 207 } 208 209 if (this.params.autoplay) { 210 src += '&autoplay=1'; 211 } 212 213 if (this.params.loop) { 214 src += '&loop=1'; 215 } 216 217 this.iframe.src = src; 218 219 if (this.uid) { 220 this.iframe.id = this.uid; 221 } 222 223 this.iframe.style.top = '50%'; 224 this.iframe.style.left = '50%'; 225 this.iframe.style.transform = 'translateX(-50%) translateY(-50%)'; 226 this.iframe.style.position = 'absolute'; 227 this.iframe.style.opacity = 0; 228 229 this.element.parentNode.appendChild(this.iframe); 230 this.iframe.parentNode.removeChild(this.element); 231 232 var self = this; 233 234 function onResize() { 235 var h = self.iframe.parentNode.offsetHeight + self.params.offset; // since showinfo is deprecated and ignored after September 25, 2018. we add +200 to hide it in the overflow 236 var w = self.iframe.parentNode.offsetWidth + self.params.offset; 237 var res = self.params.resolution_mod; 238 239 if (res > w/h) { 240 self.iframe.style.width = h*res + 'px'; 241 self.iframe.style.height = h + 'px'; 242 } else { 243 self.iframe.style.width = w + 'px'; 244 self.iframe.style.height = w/res + 'px'; 245 } 246 } 247 248 window.addEventListener('resize', onResize); 249 onResize(); 250}; 251 252YoutubeBackground.prototype.buildHTML = function () { 253 var parent = this.element.parentNode; 254 // wrap 255 var wrapper = document.createElement('div'); 256 wrapper.className = 'youtube-background'; 257 parent.insertBefore(wrapper, this.element); 258 wrapper.appendChild(this.element); 259 var id = this.element.id; 260 this.element.id = ''; 261 wrapper.id = id; 262 263 //set css rules 264 var wrapper_styles = { 265 "height" : "100%", 266 "width" : "100%", 267 "z-index": "0", 268 "position": "absolute", 269 "overflow": "hidden", 270 "top": 0, // added by @insad 271 "left": 0, 272 "bottom": 0, 273 "right": 0 274 }; 275 276 if (!this.params['mute-button']) { 277 wrapper_styles["pointer-events"] = "none" // avoid right mouse click popup menu 278 } 279 280 if (this.params['load-background']) { 281 wrapper_styles['background-image'] = 'url(https://img.youtube.com/vi/'+this.ytid+'/maxresdefault.jpg)'; 282 wrapper_styles['background-size'] = 'cover'; 283 wrapper_styles['background-repeat'] = 'no-repeat'; 284 wrapper_styles['background-position'] = 'center'; 285 } 286 287 for (var property in wrapper_styles) { 288 wrapper.style[property] = wrapper_styles[property]; 289 } 290 291 wrapper.parentNode.style.position = 'relative'; 292 293 if (this.is_mobile && !this.params.mobile) { 294 return wrapper; 295 } 296 297 // set play/mute controls wrap 298 if (this.params['play-button'] || this.params['mute-button']) { 299 var controls = document.createElement('div'); 300 controls.className = 'video-background-controls'; 301 302 controls.style.position = 'absolute'; 303 controls.style.top = '10px'; 304 controls.style.right = '10px'; 305 controls.style['z-index'] = 2; 306 307 this.controls_element = controls; 308 wrapper.parentNode.appendChild(controls); 309 } 310 311 return wrapper; 312}; 313 314YoutubeBackground.prototype.play = function () { 315 if (this.buttons.hasOwnProperty('play')) { 316 var btn_obj = this.buttons.play; 317 d0.removeClass(btn_obj.element, btn_obj.button_properties.stateClassName); 318 d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0]) 319 d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]); 320 } 321 322 if (this.player) { 323 this.player.playVideo(); 324 } 325} 326
327YoutubeBackground.prototype.pause = function () { 328 if (this.buttons.hasOwnProperty('play')) { 329 var btn_obj = this.buttons.play; 330 d0.addClass(btn_obj.element, btn_obj.button_properties.stateClassName); 331 d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0]) 332 d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]); 333 } 334 335 if (this.player) { 336 this.player.pauseVideo(); 337 } 338} 339 340YoutubeBackground.prototype.unmute = function () { 341 if (this.buttons.hasOwnProperty('mute')) { 342 var btn_obj = this.buttons.mute; 343 d0.removeClass(btn_obj.element, btn_obj.button_properties.stateClassName); 344 d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0]) 345 d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]); 346 } 347 348 if (this.player) { 349 this.player.unMute(); 350 } 351} 352 353YoutubeBackground.prototype.mute = function () { 354 if (this.buttons.hasOwnProperty('mute')) { 355 var btn_obj = this.buttons.mute; 356 d0.addClass(btn_obj.element, btn_obj.button_properties.stateClassName); 357 d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0]) 358 d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]); 359 } 360 361 if (this.player) { 362 this.player.mute(); 363 } 364} 365 366//TODO: refactor states to be equal for all buttons 367YoutubeBackground.prototype.generateActionButton = function (obj) { 368 var btn = document.createElement('button'); 369 btn.className = obj.className; 370 btn.innerHTML = obj.innerHtml; 371 d0.addClass(btn.firstChild, obj.stateChildClassNames[0]); 372 373 if (this.params[obj.condition_parameter] == obj.initialState) { 374 d0.addClass(btn, obj.stateClassName); 375 d0.removeClass(btn.firstChild, obj.stateChildClassNames[0]); 376 d0.addClass(btn.firstChild, obj.stateChildClassNames[1]); 377 } 378 379 var self = this; 380 btn.addEventListener('click', function(e) { 381 if (d0.hasClass(this, obj.stateClassName)) { 382 self.state[obj.name] = false; 383 self[obj.actions[0]](); 384 } else { 385 self.state[obj.name] = true; 386 self[obj.actions[1]](); 387 } 388 }); 389 390 this.buttons[obj.name] = { 391 element: btn, 392 button_properties: obj 393 }; 394 395 this.controls_element.appendChild(btn); 396}; 397 398 399YoutubeBackground.prototype.parseResolutionString = function (res) { 400 var pts = res.split(/\s?:\s?/i); 401 if (pts.length < 2) { 402 return 16/9; 403 } 404 405 var w = parseInt(pts[0], 10); 406 var h = parseInt(pts[1], 10); 407 408 if (isNaN(w) || isNaN(h)) { 409 return 16/9; 410 } 411 412 return w/h; 413}; 414 415YoutubeBackground.prototype.isMobile = function (event) { 416 var is_mobile = false; 417 (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|
417sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) is_mobile = true;})(navigator.userAgent||navigator.vendor||window.opera); 418 419 return is_mobile; 420}; 421 422YoutubeBackground.prototype.error = function (message, value) { 423 if (window.hasOwnProperty('console') 424 && window.console.hasOwnProperty('error')) { 425 console.error(message, value); 426 } 427}; 428 429function ActivityMonitor(on_activity, on_inactivity, activity_timeout, inactivity_timeout, events) { 430 this.timer = null; 431 this.timeout = inactivity_timeout || 10000; 432 this.activity_timer = null; //for event throttling 433 this.activity_timeout = activity_timeout || 1000; 434 this.last_activity = null; 435 436 this.resetTimer = function() { 437 if (this.timer) { 438 clearTimeout(this.timer); 439 this.timer = null; 440 } 441 442 var self = this; 443 this.timer = setTimeout(function() { 444 if (self.last_activity + self.timeout + self.activity_timeout 445 >= new Date().getTime()) { 446 if (on_inactivity) { 447 on_inactivity(); 448 } 449 } 450 }, this.timeout); 451 }; 452 453 this.logActivity = function() { 454 this.last_activity = new Date().getTime(); 455 456 if (on_activity) { 457 on_activity(); 458 } 459 }; 460 461 this.onActivity = function() { 462 if (!this.activity_timer) { 463 var self = this; 464 this.activity_timer = setTimeout(function(){ 465 self.logActivity(); 466 self.resetTimer(); 467 468 clearTimeout(self.activity_timer); 469 self.activity_timer = null; 470 }, this.activity_timeout); 471 } 472 }; 473 474 this.__init__ = function() { 475 var self = this; 476 477 if (!events) { 478 events = ['click', 'mousemove', 'scroll']; 479 } else { 480 if (typeof events === 'string') { 481 events = [events]; 482 } 483 } 484 485 for (var i = 0; i < events.length; i++) { 486 document.addEventListener(events[i], function() { 487 self.onActivity(); 488 }); 489 } 490 }; 491 492 this.__init__(); 493} 494 495function VideoBackgrounds(selector, params) { 496 this.elements = selector; 497 498 if (typeof selector === 'string') { 499 this.elements = document.querySelectorAll(selector); 500 } 501 502 this.index = {}; 503 this.re = {}; 504 this.re.YOUTUBE = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i; 505 506 this.__init__ = function () { 507 for (var i = 0; i < this.elements.length; i++) { 508 var element = this.elements[i]; 509 510 var link = element.getAttribute('data-youtube'); 511 var ytid = this.getYTID(link); 512 var uid = this.generateUID(ytid); 513 514 var yb = new YoutubeBackground(element, params, ytid, uid); 515 516 if (!uid) { 517 continue; 518 } 519 520 this.index[uid] = yb; 521 } 522 523 var self = this; 524 525 this.initYTPlayers(function() { 526 //TODO: FIX! 527 if (params && 528 (params.hasOwnProperty('activity_timeout') 529 || params.hasOwnProperty('inactivity_timeout'))) { 530 this.activity_monitor = new ActivityMonitor(function () { 531 self.playVideos(); 532 }, function() { 533 self.pauseVideos(); 534 }, 535 params ? params.activity_timeout : null, 536 params ? params.inactivity_timeout : null, 537 ['mousemove', 'scroll'] 538 ); 539 } 540 }); 541 }; 542 543 this.__init__(); 544} 545 546VideoBackgrounds.prototype.getYTID = function (link) { 547 if (link !== undefined && link !== null) { 548 var pts = link.match(this.re.YOUTUBE); 549 if (pts && pts.length) { 550 this.re.YOUTUBE.lastIndex = 0; //regex needs a reset in for loops, I always forget this 551 return pts[1]; 552 } 553 } 554 return null; 555}; 556 557VideoBackgrounds.prototype.generateUID = function (pref) { 558 //index the instance 559 function getRandomIntInclusive(min, max) { 560 min = Math.ceil(min); 561 max = Math.floor(max); 562 return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive 563 } 564 565 var uid = pref +'-'+ getRandomIntInclusive(0, 9999); 566 while (this.index.hasOwnProperty(uid)) { 567 uid = pref +'-'+ getRandomIntInclusive(0, 9999); 568 } 569 570 return uid; 571}; 572
573VideoBackgrounds.prototype.pauseVideos = function () { 574 for (var k in this.index) { 575 this.index[k].pause(); 576 } 577}; 578 579VideoBackgrounds.prototype.playVideos = function () { 580 for (var k in this.index) { 581 this.index[k].play(); 582 } 583}; 584 585VideoBackgrounds.prototype.initYTPlayers = function (callback) { 586 var self = this; 587 588 window.onYouTubeIframeAPIReady = function () { 589 for (var k in self.index) { 590 self.index[k].initYTPlayer(); 591 } 592 593 if (callback) { 594 setTimeout(callback, 100); 595 } 596 }; 597 598 if (window.hasOwnProperty('YT') && window.YT.loaded) { 599 window.onYouTubeIframeAPIReady(); 600 } 601}; 602 603if (window.hasOwnProperty('jQuery')) { 604 (function ($) { 605 $.fn.youtube_background = function(params) { 606 var $this = $(this); 607 new VideoBackgrounds(this, params); 608 return $this; 609 }; 610 })(jQuery); 611}
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.