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 'pause': false, //deprecated 66 'play-button': false, 67 'mute-button': false, 68 'autoplay': true, 69 'muted': true, 70 'loop': true, 71 'mobile': false, 72 'load-background': true, 73 'resolution': '16:9', 74 'offset': 200 75 }; 76 77 this.__init__ = function () { 78 if (!this.ytid) { 79 return; 80 } 81 82 this.parseProperties(params); 83 this.params.resolution_mod = this.parseResolutionString(this.params.resolution); 84 this.state.playing = this.params.autoplay; 85 this.state.muted = this.params.muted; 86 87 this.buildHTML(); 88 this.injectIFrame(); 89 90 91 if (this.params['play-button']) { 92 this.generateActionButton({ 93 name: 'play', 94 className: 'play-toggle', 95 innerHtml: '<i class="fa"></i>', 96 initialState: false, 97 stateClassName: 'paused', 98 condition_parameter: 'autoplay', 99 stateChildClassNames: ['fa-pause-circle', 'fa-play-circle'], 100 actions: ['play', 'pause'] 101 }); 102 } 103 104 if (this.params['mute-button']) { 105 this.generateActionButton({ 106 name: 'mute', 107 className: 'mute-toggle', 108 innerHtml: '<i class="fa"></i>', 109 initialState: true, 110 stateClassName: 'muted', 111 condition_parameter: 'muted', 112 stateChildClassNames: ['fa-volume-up', 'fa-volume-mute'], 113 actions: ['unmute', 'mute'] 114 }); 115 } 116 } 117 118 this.__init__(); 119} 120 121YoutubeBackground.prototype.initYTPlayer = function () { 122 var self = this; 123 124 if (window.hasOwnProperty('YT')) { 125 this.player = new YT.Player(this.uid, { 126 events: { 127 'onReady': function(event) { 128 self.onVideoPlayerReady(event); 129 }, 130 'onStateChange': function(event) { 131 self.onVideoStateChange(event); 132 }, 133 'onError' : function(event) { 134 //console.error('player_api', event); 135 } 136 } 137 }); 138 } 139}; 140 141YoutubeBackground.prototype.onVideoPlayerReady = function (event) { 142 if (this.params.autoplay) { 143 event.target.playVideo(); 144 } 145}; 146 147YoutubeBackground.prototype.onVideoStateChange = function (event) { 148 if (event.data === 0 && this.params.loop) { 149 event.target.playVideo(); 150 } 151 152 if (event.data === -1 && this.params.autoplay) { 153 event.target.playVideo(); 154 } 155 156 if (event.data === 1) { 157 this.iframe.style.opacity = 1; 158 } 159}; 160 161YoutubeBackground.prototype.parseProperties = function (params) { 162 if (!params) { 163 this.params = this.defaults; 164 } else { 165 //load in defaults 166 for (var k in this.defaults) { 167 if (!this.params.hasOwnProperty(k)) { 168 this.params[k] = this.defaults[k]; 169 } 170 } 171 } 172 173 // load params from data attributes 174 for (var k in this.params) { 175 var data = this.element.getAttribute('data-ytbg-'+k); 176 177 if (data !== undefined && data !== null) { 178 switch (data) { 179 case data === 'false': 180 data = false;
181 break; 182 case data === 'true': 183 data = true; 184 break; 185 } 186 187 this.params[k] = data; 188 } 189 } 190 191 //pause deprecated 192 if (this.params.pause) { 193 this.params['play-button'] = this.params.pause; 194 } 195}; 196 197YoutubeBackground.prototype.injectIFrame = function () { 198 this.iframe = document.createElement('iframe'); 199 this.iframe.setAttribute('frameborder', 0); 200 this.iframe.setAttribute('allow', ['autoplay; mute']); 201 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; 202 203 if (this.params.muted) { 204 src += '&mute=1'; 205 } 206 207 if (this.params.autoplay) { 208 src += '&autoplay=1'; 209 } 210 211 if (this.params.loop) { 212 src += '&loop=1'; 213 } 214 215 this.iframe.src = src; 216 217 if (this.uid) { 218 this.iframe.id = this.uid; 219 } 220 221 this.iframe.style.top = '50%'; 222 this.iframe.style.left = '50%'; 223 this.iframe.style.transform = 'translateX(-50%) translateY(-50%)'; 224 this.iframe.style.position = 'absolute'; 225 this.iframe.style.opacity = 0; 226 227 this.element.parentNode.appendChild(this.iframe); 228 this.iframe.parentNode.removeChild(this.element); 229 230 var self = this; 231 232 function onResize() { 233 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 234 var w = self.iframe.parentNode.offsetWidth + self.params.offset; 235 var res = self.params.resolution_mod; 236 237 if (res > w/h) { 238 self.iframe.style.width = h*res + 'px'; 239 self.iframe.style.height = h + 'px'; 240 } else { 241 self.iframe.style.width = w + 'px'; 242 self.iframe.style.height = w/res + 'px'; 243 } 244 } 245 246 window.addEventListener('resize', onResize); 247 onResize(); 248}; 249 250YoutubeBackground.prototype.buildHTML = function () { 251 var parent = this.element.parentNode; 252 // wrap 253 var wrapper = document.createElement('div'); 254 wrapper.className = 'youtube-background'; 255 parent.insertBefore(wrapper, this.element); 256 wrapper.appendChild(this.element); 257 var id = this.element.id; 258 this.element.id = ''; 259 wrapper.id = id; 260 261 //set css rules 262 var wrapper_styles = { 263 "height" : "100%", 264 "width" : "100%", 265 "z-index": "0", 266 "position": "absolute", 267 "overflow": "hidden", 268 "top": 0, // added by @insad 269 "left": 0, 270 "bottom": 0, 271 "right": 0 272 }; 273 274 if (!this.params['mute-button']) { 275 wrapper_styles["pointer-events"] = "none" // avoid right mouse click popup menu 276 } 277 278 if (this.params['load-background']) { 279 wrapper_styles['background-image'] = 'url(https://img.youtube.com/vi/'+this.ytid+'/maxresdefault.jpg)'; 280 wrapper_styles['background-size'] = 'cover'; 281 wrapper_styles['background-repeat'] = 'no-repeat'; 282 wrapper_styles['background-position'] = 'center'; 283 } 284 285 for (var property in wrapper_styles) { 286 wrapper.style[property] = wrapper_styles[property]; 287 } 288 289 wrapper.parentNode.style.position = 'relative'; 290 291 if (this.is_mobile && !this.params.mobile) { 292 return wrapper; 293 } 294 295 // set play/mute controls wrap 296 if (this.params['play-button'] || this.params['mute-button']) { 297 var controls = document.createElement('div'); 298 controls.className = 'video-background-controls'; 299 300 controls.style.position = 'absolute'; 301 controls.style.top = '10px'; 302 controls.style.right = '10px'; 303 controls.style['z-index'] = 2; 304 305 this.controls_element = controls; 306 wrapper.parentNode.appendChild(controls); 307 } 308 309 return wrapper; 310}; 311 312YoutubeBackground.prototype.play = function () { 313 if (this.buttons.hasOwnProperty('play')) { 314 var btn_obj = this.buttons.play; 315 d0.removeClass(btn_obj.element, btn_obj.button_properties.stateClassName); 316 d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0]) 317 d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]); 318 } 319 320 if (this.player) { 321 this.player.playVideo(); 322 } 323} 324 325YoutubeBackground.prototype.pause = function () { 326 if (this.buttons.hasOwnProperty('play')) { 327 var btn_obj = this.buttons.play; 328 d0.addClass(btn_obj.element, btn_obj.button_properties.stateClassName); 329 d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0]) 330 d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]); 331 } 332 333 if (this.player) { 334 this.player.pauseVideo(); 335 } 336} 337
338YoutubeBackground.prototype.unmute = function () { 339 if (this.buttons.hasOwnProperty('mute')) { 340 var btn_obj = this.buttons.mute; 341 d0.removeClass(btn_obj.element, btn_obj.button_properties.stateClassName); 342 d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0]) 343 d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]); 344 } 345 346 if (this.player) { 347 this.player.unMute(); 348 } 349} 350 351YoutubeBackground.prototype.mute = function () { 352 if (this.buttons.hasOwnProperty('mute')) { 353 var btn_obj = this.buttons.mute; 354 d0.addClass(btn_obj.element, btn_obj.button_properties.stateClassName); 355 d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0]) 356 d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]); 357 } 358 359 if (this.player) { 360 this.player.mute(); 361 } 362} 363 364//TODO: refactor states to be equal for all buttons 365YoutubeBackground.prototype.generateActionButton = function (obj) { 366 var btn = document.createElement('button'); 367 btn.className = obj.className; 368 btn.innerHTML = obj.innerHtml; 369 d0.addClass(btn.firstChild, obj.stateChildClassNames[0]); 370 371 if (this.params[obj.condition_parameter] == obj.initialState) { 372 d0.addClass(btn, obj.stateClassName); 373 d0.removeClass(btn.firstChild, obj.stateChildClassNames[0]); 374 d0.addClass(btn.firstChild, obj.stateChildClassNames[1]); 375 } 376 377 var self = this; 378 btn.addEventListener('click', function(e) { 379 if (d0.hasClass(this, obj.stateClassName)) { 380 self.state[obj.name] = false; 381 self[obj.actions[0]](); 382 } else { 383 self.state[obj.name] = true; 384 self[obj.actions[1]](); 385 } 386 }); 387 388 this.buttons[obj.name] = { 389 element: btn, 390 button_properties: obj 391 }; 392 393 this.controls_element.appendChild(btn); 394}; 395 396 397YoutubeBackground.prototype.parseResolutionString = function (res) { 398 var pts = res.split(/\s?:\s?/i); 399 if (pts.length < 2) { 400 return 16/9; 401 } 402 403 var w = parseInt(pts[0], 10); 404 var h = parseInt(pts[1], 10); 405 406 if (isNaN(w) || isNaN(h)) { 407 return 16/9; 408 } 409 410 return w/h; 411}; 412 413YoutubeBackground.prototype.isMobile = function (event) { 414 var is_mobile = false; 415 (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 )|sy(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); 416 417 return is_mobile; 418}; 419
420YoutubeBackground.prototype.error = function (message, value) { 421 if (window.hasOwnProperty('console') 422 && window.console.hasOwnProperty('error')) { 423 console.error(message, value); 424 } 425}; 426 427function ActivityMonitor(on_activity, on_inactivity, activity_timeout, inactivity_timeout, events) { 428 this.timer = null; 429 this.timeout = inactivity_timeout || 10000; 430 this.activity_timer = null; //for event throttling 431 this.activity_timeout = activity_timeout || 1000; 432 this.last_activity = null; 433 434 this.resetTimer = function() { 435 if (this.timer) { 436 clearTimeout(this.timer); 437 this.timer = null; 438 } 439 440 var self = this; 441 this.timer = setTimeout(function() { 442 if (self.last_activity + self.timeout + self.activity_timeout 443 >= new Date().getTime()) { 444 if (on_inactivity) { 445 on_inactivity(); 446 } 447 } 448 }, this.timeout); 449 }; 450 451 this.logActivity = function() { 452 this.last_activity = new Date().getTime(); 453 454 if (on_activity) { 455 on_activity(); 456 } 457 }; 458 459 this.onActivity = function() { 460 if (!this.activity_timer) { 461 var self = this; 462 this.activity_timer = setTimeout(function(){ 463 self.logActivity(); 464 self.resetTimer(); 465 466 clearTimeout(self.activity_timer); 467 self.activity_timer = null; 468 }, this.activity_timeout); 469 } 470 }; 471 472 this.__init__ = function() { 473 var self = this; 474 475 if (!events) { 476 events = ['click', 'mousemove', 'scroll']; 477 } else { 478 if (typeof events === 'string') { 479 events = [events]; 480 } 481 } 482 483 for (var i = 0; i < events.length; i++) { 484 document.addEventListener(events[i], function() { 485 self.onActivity(); 486 }); 487 } 488 }; 489 490 this.__init__(); 491} 492 493function VideoBackgrounds(selector, params) { 494 this.elements = selector; 495 496 if (typeof selector === 'string') { 497 this.elements = document.querySelectorAll(selector); 498 } 499 500 this.index = {}; 501 this.re = {}; 502 this.re.YOUTUBE = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i; 503 504 this.__init__ = function () { 505 for (var i = 0; i < this.elements.length; i++) { 506 var element = this.elements[i]; 507 508 var link = element.getAttribute('data-youtube'); 509 var ytid = this.getYTID(link); 510 var uid = this.generateUID(ytid); 511 512 var yb = new YoutubeBackground(element, params, ytid, uid); 513 514 if (!uid) { 515 continue; 516 } 517 518 this.index[uid] = yb; 519 } 520 521 var self = this; 522 523 this.initYTPlayers(function() { 524 //TODO: FIX! 525 if (params && 526 (params.hasOwnProperty('activity_timeout') 527 || params.hasOwnProperty('inactivity_timeout'))) { 528 this.activity_monitor = new ActivityMonitor(function () { 529 self.playVideos(); 530 }, function() { 531 self.pauseVideos(); 532 }, 533 params ? params.activity_timeout : null, 534 params ? params.inactivity_timeout : null, 535 ['mousemove', 'scroll'] 536 ); 537 } 538 }); 539 }; 540 541 this.__init__(); 542} 543 544VideoBackgrounds.prototype.getYTID = function (link) { 545 if (link !== undefined && link !== null) { 546 var pts = link.match(this.re.YOUTUBE); 547 if (pts && pts.length) { 548 this.re.YOUTUBE.lastIndex = 0; //regex needs a reset in for loops, I always forget this 549 return pts[1]; 550 } 551 } 552 return null; 553}; 554 555VideoBackgrounds.prototype.generateUID = function (pref) { 556 //index the instance 557 function getRandomIntInclusive(min, max) { 558 min = Math.ceil(min); 559 max = Math.floor(max); 560 return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive 561 } 562 563 var uid = pref +'-'+ getRandomIntInclusive(0, 9999); 564 while (this.index.hasOwnProperty(uid)) { 565 uid = pref +'-'+ getRandomIntInclusive(0, 9999); 566 } 567 568 return uid; 569}; 570 571VideoBackgrounds.prototype.pauseVideos = function () { 572 for (var k in this.index) { 573 this.index[k].pause(); 574 } 575}; 576 577VideoBackgrounds.prototype.playVideos = function () { 578 for (var k in this.index) { 579 this.index[k].play(); 580 } 581}; 582 583VideoBackgrounds.prototype.initYTPlayers = function (callback) { 584 var self = this; 585 586 window.onYouTubeIframeAPIReady = function () { 587 for (var k in self.index) { 588 self.index[k].initYTPlayer(); 589 } 590 591 if (callback) { 592 setTimeout(callback, 100); 593 } 594 }; 595 596 if (window.hasOwnProperty('YT') && window.YT.loaded) { 597 window.onYouTubeIframeAPIReady(); 598 } 599}; 600 601if (window.hasOwnProperty('jQuery')) { 602 (function ($) { 603 $.fn.youtube_background = function(params) { 604 var $this = $(this);
605 new VideoBackgrounds(this, params); 606 return $this; 607 }; 608 })(jQuery); 609}
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.