1// ------------------------------------------------------------------------------------------- 2// 3// AVIA VIDEO API - make sure that youtube, vimeo and html 5 use the same interface 4// 5// requires froogaloop vimeo library and youtube iframe api (yt can be loaded async) 6// 7// ------------------------------------------------------------------------------------------- 8 9 10(function($) 11{ 12 "use strict"; 13 14 $.AviaVideoAPI = function(options, video, option_container) 15 { 16 this.videoElement = video; 17 18 // actual video element. either iframe or video 19 this.$video = $( video ); 20 21 // container where the AviaVideoAPI object will be stored as data, and that can receive events like play, pause etc 22 // also the container that allows to overwrite javacript options by adding html data- attributes 23 this.$option_container = option_container ? $( option_container ) : this.$video; 24 25 // button to click to actually start the loading process of the video 26 this.load_btn = this.$option_container.find('.av-click-to-play-overlay'); 27 28 // contains video list 29 this.video_wrapper = this.$video.parents('ul').eq(0); 30 31 //check if we should load immediately or on click 32 this.lazy_load = this.video_wrapper.hasClass('av-show-video-on-click') ? true : false; 33 34 //mobile device? 35 this.isMobile = $.avia_utilities.isMobile; 36 37 //iamge fallback use 38 this.fallback = this.isMobile ? this.$option_container.is('.av-mobile-fallback-image') : false; 39 40 if( this.fallback ) 41 { 42 return; 43 } 44 45 // set up the whole api object 46 this._init( options ); 47 }; 48 49 $.AviaVideoAPI.defaults = { 50 51 loop: false, 52 mute: false, 53 controls: false, 54 events: 'play pause mute unmute loop toggle reset unload' 55 56 }; 57 58 $.AviaVideoAPI.apiFiles = 59 { 60 youtube : {loaded: false, src: 'https://www.youtube.com/iframe_api' } 61 }; 62 63 $.AviaVideoAPI.players = 64 { 65 66 }; 67 68 $.AviaVideoAPI.prototype = 69 { 70 _init: function( options ) 71 { 72 // set slider options 73 this.options = this._setOptions(options); 74 75 // info which video service we are using: html5, vimeo or youtube 76 this.type = this._getPlayerType(); 77 78 this.player = false; 79 80 // store the player object to the this.player variable created by one of the APIs (mediaelement, youtube, vimeo) 81 this._bind_player(); 82 83 // set to true once the events are bound so it doesnt happen a second time by accident or racing condition 84 this.eventsBound = false; 85 86 // info if the video is playing 87 this.playing = false; 88 89 //set css class that video is currently not playing 90 this.$option_container.addClass('av-video-paused'); 91 92 //play pause indicator 93 this.pp = $.avia_utilities.playpause(this.$option_container); 94 }, 95 96 97 //set the video options by first merging the default options and the passed options, then checking the video element if any data attributes overwrite the option set 98 _setOptions: function(options) 99 { 100 var newOptions = $.extend( true, {}, $.AviaVideoAPI.defaults, options ), 101 htmlData = this.$option_container.data(), 102 i = ""; 103 104 //overwritte passed option set with any data properties on the html element 105 for( i in htmlData ) 106 { 107 if( htmlData.hasOwnProperty(i) && (typeof htmlData[i] === "string" || typeof htmlData[i] === "number" || typeof htmlData[i] === "boolean") ) 108 { 109 newOptions[i] = htmlData[i]; 110 } 111 } 112 113 return newOptions; 114 }, 115 116 //get the player type 117 _getPlayerType: function() 118 { 119 var vid_src = this.$video.get(0).src || this.$video.data('src'); 120 121 if( this.$video.is('video') ) 122 { 123 return 'html5'; 124 } 125 126 if( this.$video.is('.av_youtube_frame') ) 127 { 128 return 'youtube'; 129 } 130 131 if( vid_src.indexOf('vimeo.com') != -1 ) 132 { 133 return 'vimeo'; 134 } 135 if( vid_src.indexOf('youtube.com') != -1) 136 { 137 return 'youtube'; 138 } 139 }, 140 141 _bind_player: function() 142 { 143 var _self = this; 144 145 // check if videos are disabled by user setting via cookie - or user must opt in. 146 var cookie_check = $('html').hasClass('av-cookies-needs-opt-in') || $('html').hasClass('av-cookies-can-opt-out'); 147 var allow_continue = true;
148 var silent_accept_cookie = $('html').hasClass('av-cookies-user-silent-accept'); 149 var self_hosted = 'html5' == this.type; 150 151 if( cookie_check && ! silent_accept_cookie && ! self_hosted ) 152 { 153 if( ! document.cookie.match(/aviaCookieConsent/) || $('html').hasClass('av-cookies-session-refused') ) 154 { 155 allow_continue = false; 156 } 157 else 158 { 159 if( ! document.cookie.match(/aviaPrivacyRefuseCookiesHideBar/) ) 160 { 161 allow_continue = false; 162 } 163 else if( ! document.cookie.match(/aviaPrivacyEssentialCookiesEnabled/) ) 164 { 165 allow_continue = false; 166 } 167 else if( document.cookie.match(/aviaPrivacyVideoEmbedsDisabled/) ) 168 { 169 allow_continue = false; 170 } 171 } 172 } 173 174 // allow 3-rd party plugins to hook (see enfold\config-cookiebot\cookiebot.js) 175 if( window['wp'] && wp.hooks ) 176 { 177 allow_continue = wp.hooks.applyFilters( 'aviaCookieConsent_allow_continue', allow_continue ); 178 } 179 180 if( ! allow_continue ) 181 { 182 this._use_external_link(); 183 return; 184 } 185 186 if(this.lazy_load && this.load_btn.length && this.type != "html5") 187 { 188 this.$option_container.addClass('av-video-lazyload'); 189 190 this.load_btn.on('click', function() 191 { 192 _self.load_btn.remove(); 193 _self._setPlayer(); 194 }); 195 } 196 else 197 { 198 this.lazy_load = false; 199 this._setPlayer(); 200 } 201 }, 202 203 //if the user has disabled video slides via cookie a click event will open the video externally 204 _use_external_link: function() 205 { 206 //display the play button no matter what 207 this.$option_container.addClass('av-video-lazyload'); 208 209 this.load_btn.on('click', function(e) 210 { 211 if (e.originalEvent === undefined) return; //human click only 212 213 var src_url = $(this).parents('.avia-slide-wrap').find('div[data-original_url]').data('original_url');
214 if( src_url ) window.open(src_url , '_blank'); 215 }); 216 }, 217 218 //get the player object 219 _setPlayer: function() 220 { 221 var _self = this; 222 223 switch( this.type ) 224 { 225 case "html5": 226 227 this.player = this.$video.data('mediaelementplayer'); 228 229 //apply fallback. sometimes needed for safari 230 if( ! this.player ) 231 { 232 this.$video.data('mediaelementplayer', $.AviaVideoAPI.players[ this.$video.attr('id').replace(/_html5/,'') ] ); 233 this.player = this.$video.data('mediaelementplayer'); 234 } 235 236 this._playerReady(); 237 break; 238 239 case "vimeo": 240 241 //we need to create an iframe and append it to the html first 242 var ifrm = document.createElement("iframe"); 243 var $ifrm = $( ifrm ); 244 245 //note: unmuted vimeo videos in chrome do often times not work due to chrome blocking them 246 ifrm.onload = function() 247 { 248 _self.player = Froogaloop( ifrm ); 249 _self._playerReady(); 250 _self.$option_container.trigger('av-video-loaded'); 251 }; 252 253 ifrm.setAttribute("src", this.$video.data('src') ); 254 255 //we replace the old html structure with the iframe 256 $ifrm.insertAfter( this.$video ); 257 this.$video.remove(); 258 this.$video = ifrm; 259 break; 260 261 case "youtube": 262 263 this._getAPI(this.type); 264 $('body').on('av-youtube-iframe-api-loaded', function(){ _self._playerReady(); }); 265 break; 266 } 267 }, 268 269 _getAPI: function( api ) 270 { 271 //make sure the api file is loaded only once 272 if($.AviaVideoAPI.apiFiles[api].loaded === false) 273 { 274 $.AviaVideoAPI.apiFiles[api].loaded = true; 275 //load the file async 276 var tag = document.createElement('script'), 277 first = document.getElementsByTagName('script')[0]; 278 279 tag.src = $.AviaVideoAPI.apiFiles[api].src; 280 first.parentNode.insertBefore(tag, first); 281 } 282 }, 283 284 //wait for player to be ready, then bind events 285 _playerReady: function() 286 { 287 var _self = this; 288 289 this.$option_container.on('av-video-loaded', function(){ _self._bindEvents(); }); 290 291 switch(this.type) 292 { 293 case "html5": 294 this.$video.on( 'av-mediajs-loaded', function(){ _self.$option_container.trigger('av-video-loaded'); } ); 295 this.$video.on( 'av-mediajs-ended' , function(){ _self.$option_container.trigger('av-video-ended'); } ); 296 break; 297 case "vimeo": 298 //finish event must be applied after ready event for firefox 299 _self.player.addEvent('ready', function() 300 { 301 _self.$option_container.trigger('av-video-loaded'); 302 _self.player.addEvent('finish', function(){ _self.$option_container.trigger('av-video-ended'); }); 303 }); 304 break; 305 306 case "youtube": 307 308 var params = _self.$video.data(); 309 310 if( _self._supports_video() ) 311 { 312 params.html5 = 1; 313 } 314 315 _self.player = new YT.Player(_self.$video.attr('id'), 316 { 317 videoId: params.videoid, 318 height: _self.$video.attr('height'), 319 width: _self.$video.attr('width'), 320 playerVars: params, 321 events: { 322 'onReady': function(){ _self.$option_container.trigger('av-video-loaded'); }, 323 'onError': function(player){ $.avia_utilities.log('YOUTUBE ERROR:', 'error', player); }, 324 'onStateChange': function(event){ 325 if (event.data === YT.PlayerState.ENDED) 326 { 327 var command = _self.options.loop != false ? 'loop' : 'av-video-ended'; 328 _self.$option_container.trigger(command); 329 } 330 } 331 } 332 }); 333 break; 334 } 335 336 //fallback always trigger after 2 seconds 337 setTimeout(function() 338 { 339 if(_self.eventsBound == true || typeof _self.eventsBound == 'undefined' || _self.type == 'youtube' ) 340 { 341 return; 342 } 343 344 $.avia_utilities.log('Fallback Video Trigger "' + _self.type + '":', 'log', _self ); 345 346 _self.$option_container.trigger('av-video-loaded'); 347 348 }, 2000 ); 349 }, 350 351 //bind events we should listen to, to the player 352 _bindEvents: function() 353 { 354 if( this.eventsBound == true || typeof this.eventsBound == 'undefined') 355 { 356 return; 357 } 358 359 var _self = this, volume = 'unmute'; 360 361 this.eventsBound = true; 362 363 this.$option_container.on(this.options.events, function(e) 364 { 365 _self.api(e.type); 366 }); 367 368 if( !_self.isMobile ) 369 { 370 //set up initial options 371 if( this.options.mute != false ) 372 { 373 volume = "mute"; 374 } 375 376 if( this.options.loop != false ) 377 { 378 _self.api('loop'); 379 } 380 381 _self.api(volume); 382 } 383 384 //set timeout to prevent racing conditions with other scripts 385 setTimeout( function() 386 {
387 _self.$option_container.trigger('av-video-events-bound').addClass('av-video-events-bound'); 388 }, 50 ); 389 }, 390 391 392 _supports_video: function() 393 { 394 return !!document.createElement('video').canPlayType; 395 }, 396 397 398 /************************************************************************ 399 PUBLIC Methods 400 *************************************************************************/ 401 402 403 api: function( action ) 404 { 405 //commands on mobile can not be executed if the player was not started manually 406 if(this.isMobile && !this.was_started()) return; 407 408 // prevent calling of unbound function 409 if(this.options.events.indexOf(action) === -1) return; 410 411 // broadcast that the command was executed 412 this.$option_container.trigger('av-video-'+action+'-executed'); 413 414 // console.log("video player api action: " + action); 415 416 // calls the function based on action. eg: _html5_play() 417 if(typeof this[ '_' + this.type + '_' + action] == 'function') 418 { 419 this[ '_' + this.type + '_' + action].call(this); 420 } 421 422 //call generic function eg: _toggle() or _play() 423 if(typeof this[ '_' + action] == 'function') 424 { 425 this[ '_' + action].call(this); 426 } 427 }, 428 429 was_started: function() 430 { 431 if(!this.player) return false; 432 433 switch(this.type) 434 { 435 case "html5": 436 if( this.player.getCurrentTime() > 0 ) 437 { 438 return true; 439 } 440 break; 441 442 case "vimeo": 443 if( this.player.api('getCurrentTime') > 0 ) 444 { 445 return true; 446 } 447 break; 448 449 case "youtube": 450 if( this.player.getPlayerState() !== -1 ) 451 { 452 return true; 453 } 454 break; 455 } 456 457 return false; 458 }, 459 460 /************************************************************************ 461 Generic Methods, are always executed and usually set variables 462 *************************************************************************/ 463 _play: function() 464 { 465 this.playing = true; 466 this.$option_container.addClass('av-video-playing').removeClass('av-video-paused'); 467 }, 468 469 _pause: function() 470 { 471 this.playing = false; 472 this.$option_container.removeClass('av-video-playing').addClass('av-video-paused'); 473 }, 474 475 _loop: function() 476 { 477 this.options.loop = true; 478 }, 479 480 _toggle: function( ) 481 { 482 var command = this.playing == true ? 'pause' : 'play'; 483 484 this.api(command); 485 this.pp.set(command); 486 }, 487 488 489 /************************************************************************ 490 VIMEO Methods 491 *************************************************************************/ 492 493 _vimeo_play: function( ) 494 { 495 this.player.api('play'); 496 }, 497 498 _vimeo_pause: function( ) 499 { 500 this.player.api('pause'); 501 }, 502 503 _vimeo_mute: function( ) 504 { 505 this.player.api('setVolume', 0); 506 }, 507 508 _vimeo_unmute: function( ) 509 { 510 this.player.api('setVolume', 0.7); 511 }, 512 513 _vimeo_loop: function( ) 514 { 515 // currently throws error, must be set in iframe 516 // this.player.api('setLoop', true); 517 }, 518 519 _vimeo_reset: function( ) 520 { 521 this.player.api('seekTo',0); 522 }, 523 524 _vimeo_unload: function() 525 { 526 this.player.api('unload'); 527 }, 528 529 /************************************************************************ 530 YOUTUBE Methods 531 *************************************************************************/ 532 533 _youtube_play: function( ) 534 { 535 this.player.playVideo(); 536 }, 537 538 _youtube_pause: function( ) 539 { 540 this.player.pauseVideo(); 541 }, 542 543 _youtube_mute: function( ) 544 { 545 this.player.mute(); 546 }, 547 548 _youtube_unmute: function( ) 549 { 550 this.player.unMute(); 551 }, 552 553 _youtube_loop: function( ) 554 { 555 // does not work properly with iframe api. needs to manual loop on "end" event 556 // this.player.setLoop(true); 557 if(this.playing == true) this.player.seekTo(0); 558 }, 559 560 _youtube_reset: function( ) 561 { 562 this.player.stopVideo(); 563 }, 564 565 _youtube_unload: function() 566 { 567 this.player.clearVideo(); 568 }, 569 570 /************************************************************************ 571 HTML5 Methods 572 *************************************************************************/ 573 574 _html5_play: function( ) 575 { 576 //disable stoping of other videos in case the user wants to run section bgs 577 if(this.player) 578 { 579 this.player.options.pauseOtherPlayers = false;
580 this.player.play(); 581 } 582 583 }, 584 585 _html5_pause: function( ) 586 { 587 if(this.player) this.player.pause(); 588 }, 589 590 _html5_mute: function( ) 591 { 592 if(this.player) this.player.setMuted(true); 593 }, 594 595 _html5_unmute: function( ) 596 { 597 if(this.player) this.player.setVolume(0.7); 598 }, 599 600 _html5_loop: function( ) 601 { 602 if(this.player) this.player.options.loop = true; 603 }, 604 605 _html5_reset: function( ) 606 { 607 if(this.player) this.player.setCurrentTime(0); 608 }, 609 610 _html5_unload: function() 611 { 612 this._html5_pause(); 613 this._html5_reset(); 614 } 615 }; 616 617 //simple wrapper to call the api. makes sure that the api data is not applied twice 618 $.fn.aviaVideoApi = function( options , apply_to_parent) 619 { 620 return this.each( function() 621 { 622 // by default save the object as data to the initial video. 623 // in the case of slideshows its more benefitial to save it to a parent element (eg: the slide) 624 var applyTo = this; 625 626 if( apply_to_parent ) 627 { 628 applyTo = $(this).parents(apply_to_parent).get(0); 629 } 630 631 var self = $.data( applyTo, 'aviaVideoApi' ); 632 633 if( ! self ) 634 { 635 self = $.data( applyTo, 'aviaVideoApi', new $.AviaVideoAPI( options, this, applyTo ) ); 636 } 637 }); 638 }; 639 640})( jQuery ); 641 642window.onYouTubeIframeAPIReady = function(){ jQuery('body').trigger('av-youtube-iframe-api-loaded'); }; 643 644 645// Init style shamelessly stolen from jQuery http://jquery.com 646// min version: https://f.vimeocdn.com/js/froogaloop2.min.js 647var Froogaloop = (function(){ 648 // Define a local copy of Froogaloop 649 function Froogaloop(iframe) { 650 // The Froogaloop object is actually just the init constructor 651 return new Froogaloop.fn.init(iframe); 652 } 653 654 var eventCallbacks = {}, 655 hasWindowEvent = false, 656 isReady = false, 657 slice = Array.prototype.slice, 658 playerOrigin = '*'; 659 660 Froogaloop.fn = Froogaloop.prototype = { 661 element: null, 662 663 init: function(iframe) { 664 if (typeof iframe === "string") { 665 iframe = document.getElementById(iframe); 666 } 667 668 this.element = iframe; 669 670 return this; 671 }, 672 673 /* 674 * Calls a function to act upon the player. 675 * 676 * @param {string} method The name of the Javascript API method to call. Eg: 'play'. 677 * @param {Array|Function} valueOrCallback params Array of parameters to pass when calling an API method 678 * or callback function when the method returns a value. 679 */ 680 api: function(method, valueOrCallback) { 681 if (!this.element || !method) { 682 return false; 683 } 684 685 var self = this, 686 element = self.element, 687 target_id = element.id !== '' ? element.id : null, 688 params = !isFunction(valueOrCallback) ? valueOrCallback : null, 689 callback = isFunction(valueOrCallback) ? valueOrCallback : null; 690 691 // Store the callback for get functions 692 if (callback) { 693 storeCallback(method, callback, target_id); 694 } 695 696 postMessage(method, params, element); 697 return self; 698 }, 699 700 /* 701 * Registers an event listener and a callback function that gets called when the event fires. 702 * 703 * @param eventName (String): Name of the event to listen for. 704 * @param callback (Function): Function that should be called when the event fires. 705 */ 706 addEvent: function(eventName, callback) { 707 if (!this.element) { 708 return false; 709 } 710 711 var self = this, 712 element = self.element, 713 target_id = element.id !== '' ? element.id : null; 714 715 716 storeCallback(eventName, callback, target_id); 717 718 // The ready event is not registered via postMessage. It fires regardless. 719 if (eventName != 'ready') { 720 postMessage('addEventListener', eventName, element); 721 } 722 else if (eventName == 'ready' && isReady) { 723 callback.call(null, target_id); 724 } 725 726 return self; 727 }, 728 729 /* 730 * Unregisters an event listener that gets called when the event fires. 731 * 732 * @param eventName (String): Name of the event to stop listening for. 733 */ 734 removeEvent: function(eventName) { 735 if (!this.element) { 736 return false;
737 } 738 739 var self = this, 740 element = self.element, 741 target_id = element.id !== '' ? element.id : null, 742 removed = removeCallback(eventName, target_id); 743 744 // The ready event is not registered 745 if (eventName != 'ready' && removed) { 746 postMessage('removeEventListener', eventName, element); 747 } 748 } 749 }; 750 751 /** 752 * Handles posting a message to the parent window. 753 * 754 * @param method (String): name of the method to call inside the player. For api calls 755 * this is the name of the api method (api_play or api_pause) while for events this method 756 * is api_addEventListener. 757 * @param params (Object or Array): List of parameters to submit to the method. Can be either 758 * a single param or an array list of parameters. 759 * @param target (HTMLElement): Target iframe to post the message to. 760 */ 761 function postMessage(method, params, target) { 762 if (!target.contentWindow.postMessage) { 763 return false; 764 } 765 766 var data = JSON.stringify({ 767 method: method, 768 value: params 769 }); 770 771 target.contentWindow.postMessage(data, playerOrigin); 772 } 773 774 /** 775 * Event that fires whenever the window receives a message from its parent 776 * via window.postMessage. 777 */ 778 function onMessageReceived(event) 779 { 780 781 var data, method; 782 783 try { 784 data = JSON.parse(event.data); 785 method = data.event || data.method; 786 } 787 catch(e) { 788 //fail silently... like a ninja! 789 } 790 791 if (method == 'ready' && !isReady) { 792 isReady = true; 793 } 794 795 // Handles messages from the vimeo player only 796 if (!(/^https?:\/\/player.vimeo.com/).test(event.origin)) { 797 return false; 798 } 799 800 if (playerOrigin === '*') { 801 playerOrigin = event.origin; 802 } 803 var value = data.value, 804 eventData = data.data, 805 target_id = target_id === '' ? null : data.player_id, 806 807 callback = getCallback(method, target_id), 808 params = []; 809 810 if (!callback) { 811 return false; 812 } 813 814 if (value !== undefined) { 815 params.push(value); 816 } 817 818 if (eventData) { 819 params.push(eventData); 820 } 821 822 if (target_id) { 823 params.push(target_id); 824 } 825 826 return params.length > 0 ? callback.apply(null, params) : callback.call(); 827 } 828 829 830 /** 831 * Stores submitted callbacks for each iframe being tracked and each 832 * event for that iframe. 833 * 834 * @param eventName (String): Name of the event. Eg. api_onPlay 835 * @param callback (Function): Function that should get executed when the 836 * event is fired. 837 * @param target_id (String) [Optional]: If handling more than one iframe then 838 * it stores the different callbacks for different iframes based on the iframe's 839 * id. 840 */ 841 function storeCallback(eventName, callback, target_id) { 842 if (target_id) { 843 if (!eventCallbacks[target_id]) { 844 eventCallbacks[target_id] = {}; 845 } 846 eventCallbacks[target_id][eventName] = callback; 847 } 848 else { 849 eventCallbacks[eventName] = callback; 850 } 851 } 852 853 /** 854 * Retrieves stored callbacks. 855 */ 856 function getCallback(eventName, target_id) { 857 858 /*modified by kriesi - removing this will result in a js error. */ 859 if (target_id && eventCallbacks[target_id] && eventCallbacks[target_id][eventName]) 860 { 861 return eventCallbacks[target_id][eventName]; 862 } 863 else 864 { 865 return eventCallbacks[eventName]; 866 } 867 } 868 869 function removeCallback(eventName, target_id) { 870 if (target_id && eventCallbacks[target_id]) { 871 if (!eventCallbacks[target_id][eventName]) { 872 return false; 873 } 874 eventCallbacks[target_id][eventName] = null; 875 } 876 else { 877 if (!eventCallbacks[eventName]) { 878 return false;
879 } 880 eventCallbacks[eventName] = null; 881 } 882 883 return true; 884 } 885 886 function isFunction(obj) { 887 return !!(obj && obj.constructor && obj.call && obj.apply); 888 } 889 890 function isArray(obj) { 891 return toString.call(obj) === '[object Array]'; 892 } 893 894 // Give the init function the Froogaloop prototype for later instantiation 895 Froogaloop.fn.init.prototype = Froogaloop.fn; 896 897 // Listens for the message event. 898 // W3C 899 if (window.addEventListener) { 900 window.addEventListener('message', onMessageReceived, false); 901 } 902 // IE 903 else { 904 window.attachEvent('onmessage', onMessageReceived); 905 } 906 907 // Expose froogaloop to the global object 908 return (window.Froogaloop = window.$f = Froogaloop); 909 910})();
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.