(function() { 'use strict'; const AIOVGTemplate = document.createElement( 'template' ); AIOVGTemplate.innerHTML = `
`; class AIOVGBaseElement extends HTMLElement { /** * Element created. */ constructor() { super(); // Attach Shadow DOM to the component const shadowDom = this.attachShadow({ mode: 'open' }); this.shadowRoot.appendChild( AIOVGTemplate.content.cloneNode( true ) ); // Set references to the DOM elements from the component's template this.$root = shadowDom.querySelector( '#root' ); this.$posterImage = shadowDom.querySelector( '#posterimage' ); this.$playButton = shadowDom.querySelector( '#playbutton' ); this.$cookieConsentButton = shadowDom.querySelector( '#cookieconsent-button' ); this.$emailCaptureModal = shadowDom.querySelector( '#email-capture-modal' ); // Set references to the private properties used by the component this._isRendered = false; this._ajaxUrl = aiovg_embed.ajax_url; this._ajaxNonce = aiovg_embed.ajax_nonce; this._isCookieConsentLoaded = false; this._isEmailCaptureLoaded = false; this._isPosterImageLoaded = false; this._isIframeLoaded = false; this._forceIframeElement = navigator.vendor.includes( 'Apple' ) || navigator.userAgent.includes( 'Mobi' ); this._intersectionObserver = null; this._isInViewport = false; } /** * Browser calls this method when the element is added to the document. * (can be called many times if an element is repeatedly added/removed) */ connectedCallback() { if ( ! this.src ) return false; if ( ! this.lazyLoading ) { this._forceIframeElement = true; } if ( ! this.poster ) { this._forceIframeElement = true; } if ( ! this._forceIframeElement ) { const url = new URL( this.src ); const query = new URLSearchParams( url.search ); const autoplayRequested = query.has( 'autoplay' ) && ( query.get( 'autoplay' ) == 1 || query.get( 'autoplay' ) == true ); if ( autoplayRequested ) this._forceIframeElement = true; } this._render(); this.addEventListener( 'pointerover', () => this._warmConnections(), { once: true, } ); this.addEventListener( 'click', () => this._addIframe( true ) ); } /** * Browser calls this method when the element is removed from the document. * (can be called many times if an element is repeatedly added/removed) */ disconnectedCallback() { // TODO } /** * Array of attribute names to monitor for changes. */ static get observedAttributes() { return [ 'title', 'ratio' ]; } /** * Called when one of the observed attributes listed above is modified. */ attributeChangedCallback( name, oldValue, newValue ) { if ( oldValue == newValue ) return false; switch ( name ) { case 'title': // Set attributes for accessibility if ( newValue ) { this.$posterImage.setAttribute( 'alt', newValue ); } else { this.$posterImage.setAttribute( 'alt', '' ); } break; case 'ratio': if ( newValue ) { this.$root.style.paddingBottom = `${parseFloat(newValue)}%`; } break; } } /** * Define getters and setters for attributes. */ get title() { return this.getAttribute( 'title' ) || ''; } get src() { const value = this.getAttribute( 'src' ) || ''; return AIOVGBaseElement.isValidUrl( value ) ? value : ''; } get poster() { const value = this.getAttribute( 'poster' ) || ''; return AIOVGBaseElement.isValidUrl( value ) ? value : ''; } get postId() { return parseInt( this.getAttribute( 'post_id' ) || 0 ); } get postType() { return this.getAttribute( 'post_type' ) || ''; } get lazyLoading() { return this.hasAttribute( 'lazyloading' ); } get statistics() { return this.hasAttribute( 'statistics' ); } get cookieConsent() { return this.hasAttribute( 'cookieconsent' ); } set cookieConsent( value ) { const isEnabled = Boolean( value ); if ( isEnabled ) { this.setAttribute( 'cookieconsent', '' ); } else { this.removeAttribute( 'cookieconsent' ); } } get emailCapture() { return this.hasAttribute( 'email-capture' ); } set emailCapture( value ) { const isEnabled = Boolean( value ); if ( isEnabled ) { this.setAttribute( 'email-capture', '' ); } else { this.removeAttribute( 'email-capture' ); } } /** * Define private methods. */ _render() { if ( this._isRendered ) return false; if ( this.lazyLoading && ! this._isInViewport ) { this._initIntersectionObserver(); return false; } if ( this.emailCapture ) { this._addEmailCapture(); return false; } if ( this.cookieConsent ) { this._addCookieConsent(); return false; } this._isRendered = true; if ( this._forceIframeElement ) { this._warmConnections(); this._addIframe(); } else { this._addPosterImage(); } } _addCookieConsent() { if ( this._isCookieConsentLoaded ) return false; this._isCookieConsentLoaded = true; this._addPosterImage(); this._addClass( 'cookieconsent' ); this.$cookieConsentButton.addEventListener( 'click', () => this._onCookieConsent() ); } _onCookieConsent() { this._isRendered = true; this._removeClass( 'cookieconsent' ); this.cookieConsent = false; this._warmConnections(); this._addIframe( true ); this._setCookie(); // Remove cookieconsent from other players const videos = document.querySelectorAll( '.aiovg-player-element' ); for ( let i = 0; i < videos.length; i++ ) { videos[ i ].removeCookieConsent(); } window.postMessage({ message: 'aiovg-cookie-consent' }, window.location.origin ); } _addEmailCapture() { if ( this._isEmailCaptureLoaded ) return false; this._isEmailCaptureLoaded = true; // Read template from light DOM child placed by PHP const templateEl = this.querySelector( 'template.aiovg-player-template' ); if ( ! templateEl ) return false; // Clone HTML from template into shadow DOM const emailCaptureEl = templateEl.content.querySelector( '.email-capture' ); if ( ! emailCaptureEl ) return false; // Move all children of email capture block into the email capture modal container in the shadow DOM this.$emailCaptureModal.appendChild( emailCaptureEl.cloneNode( true ) ); // Add poster image if available and enable the email capture modal by adding the corresponding class to the root element this._addPosterImage(); this._addClass( 'email-capture' ); // Focus the first input for better accessibility const firstInput = this.$emailCaptureModal.querySelector( 'input' ); if ( firstInput ) { firstInput.focus(); } // Submit handler const submitBtn = this.$emailCaptureModal.querySelector( '.email-capture-submit' ); if ( submitBtn ) { submitBtn.addEventListener( 'click', () => { const emailField = this.$emailCaptureModal.querySelector( '.email-capture-email' ); const errorSpan = this.$emailCaptureModal.querySelector( '.email-capture-error' ); const email = emailField ? emailField.value.trim() : ''; const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if ( ! email || ! regex.test( email ) ) { if ( errorSpan ) { const errorMessage = errorSpan.getAttribute( 'data-invalid_email' ) || 'Please enter a valid email address.'; errorSpan.textContent = errorMessage; errorSpan.style.display = 'block'; } if ( emailField ) { emailField.classList.add( 'is-invalid' ); emailField.setAttribute( 'aria-invalid', 'true' ); } return false; } if ( errorSpan ) { errorSpan.style.display = 'none'; } if ( emailField ) { emailField.classList.remove( 'is-invalid' ); emailField.removeAttribute( 'aria-invalid' ); } let params = 'email=' + encodeURIComponent( email ); const nameField = this.$emailCaptureModal.querySelector( '.email-capture-name' ); if ( nameField && nameField.value.trim() ) { params += '&name=' + encodeURIComponent( nameField.value.trim() ); } const phoneField = this.$emailCaptureModal.querySelector( '.email-capture-phone' ); if ( phoneField && phoneField.value.trim() ) { params += '&phone=' + encodeURIComponent( phoneField.value.trim() ); } if ( 'aiovg_videos' === this.postType && this.postId ) { params += '&video_id=' + encodeURIComponent( this.postId ); } else { params += '&video_id=0'; if ( this.src ) { params += '&video_url=' + encodeURIComponent( this.src ); } } params += '&page_url=' + encodeURIComponent( window.location.href ); this._onEmailCapture( params ); } ); } // Skip handler const skipLink = this.$emailCaptureModal.querySelector( '.email-capture-skip' ); if ( skipLink ) { const doSkip = () => { this._onEmailCapture( 'skipped=1' ); }; skipLink.addEventListener( 'click', doSkip ); skipLink.addEventListener( 'keydown', ( event ) => { if ( 13 === event.keyCode || 32 === event.keyCode ) { event.preventDefault(); doSkip(); } } ); } } _onEmailCapture( data ) { if ( this.$emailCaptureModal.classList.contains( 'is-loading' ) ) return false; // Prevent multiple submissions this.$emailCaptureModal.classList.add( 'is-loading' ); const xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = () => { if ( 4 == xmlhttp.readyState ) { let response = null; if ( 200 == xmlhttp.status && xmlhttp.responseText ) { try { response = JSON.parse( xmlhttp.responseText ); } catch ( e ) {} } if ( response && response.success ) { // Email captured successfully, proceed to load the video and remove the email capture gate this._isRendered = true; this._removeClass( 'email-capture' ); this.emailCapture = false; this._warmConnections(); this._addIframe( true ); // Email submission implies consent — remove both gates from other players const videos = document.querySelectorAll( '.aiovg-player-element' ); for ( let i = 0; i < videos.length; i++ ) { videos[ i ].removeCookieConsent(); videos[ i ].removeEmailCapture(); } window.postMessage({ message: 'aiovg-email-captured' }, window.location.origin ); } else { // Show error message const errorSpan = this.$emailCaptureModal.querySelector( '.email-capture-error' ); if ( errorSpan ) { errorSpan.textContent = ( response && response.data && typeof response.data === 'string' ) ? response.data : errorSpan.getAttribute( 'data-error_generic' ); errorSpan.style.display = 'block'; } // Restore the form so the user can retry. this.$emailCaptureModal.classList.remove( 'is-loading' ); } } }; xmlhttp.open( 'POST', this._ajaxUrl + '?action=aiovg_save_email_lead&security=' + this._ajaxNonce, true ); xmlhttp.setRequestHeader( 'Content-type', 'application/x-www-form-urlencoded' ); xmlhttp.send( data ); } _addPosterImage() { if ( this._isPosterImageLoaded ) return false; this._isPosterImageLoaded = true; if ( this.poster ) { this.$posterImage.src = this.poster; } } _addIframe( autoplayRequested = false ) { if ( this._isIframeLoaded || this.emailCapture || this.cookieConsent ) return false; this._isIframeLoaded = true; const iframeEl = document.createElement( 'iframe' ); iframeEl.width = 560; iframeEl.height = 315; iframeEl.title = this.title; iframeEl.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'; iframeEl.allowFullscreen = true; if ( /youtube\.com|youtu\.be/.test( this.src ) ) { iframeEl.referrerPolicy = 'strict-origin-when-cross-origin'; } if ( autoplayRequested ) { const url = new URL( this.src ); let searchParams = url.searchParams; searchParams.set( 'autoplay', 1 ); url.search = searchParams.toString(); iframeEl.src = url.toString(); } else { iframeEl.src = this.src; } this.$root.append( iframeEl ); this._onIframeAdded( iframeEl ); this._addClass( 'initialized' ); this._updateViewsCount(); } _initIntersectionObserver() { if ( this._intersectionObserver ) return false; const options = { root: null, rootMargin: '0px', threshold: 0, }; this._intersectionObserver = new IntersectionObserver(( entries, observer ) => { entries.forEach(entry => { if ( entry.isIntersecting ) { this._isInViewport = true; this._render(); if ( this._isRendered ) observer.unobserve( this ); } else { this._isInViewport = false; } }); }, options); this._intersectionObserver.observe( this ); } _hasClass( className ) { return this.$root.classList.contains( className ); } _addClass( className ) { this.$root.classList.add( className ); } _removeClass( className ) { this.$root.classList.remove( className ); } /** * Define private async methods. */ async _updateViewsCount() { if ( this.statistics && this.postType == 'aiovg_videos' ) { let formData = new FormData(); formData.append( 'action', 'aiovg_update_views_count' ); formData.append( 'post_id', this.postId ); formData.append( 'security', this._ajaxNonce ); fetch( this._ajaxUrl, { method: 'POST', body: formData } ); } } async _setCookie() { let formData = new FormData(); formData.append( 'action', 'aiovg_set_cookie' ); formData.append( 'security', this._ajaxNonce ); fetch( this._ajaxUrl, { method: 'POST', body: formData } ); } /** * Define public methods. */ _warmConnections() { // Always overridden by the child classes } _onIframeAdded() { // Always overridden by the child classes } /** * Define public static methods. */ static isValidUrl( url ) { if ( url == '' ) return false; try { new URL( url ); return true; } catch ( error ) { return false; } } static addPrefetch( kind, url ) { const linkElem = document.createElement( 'link' ); linkElem.rel = kind; linkElem.href = url; linkElem.crossOrigin = 'true'; document.head.append( linkElem ); } /** * Define API methods. */ removeCookieConsent() { if ( this._isRendered ) return false; this._removeClass( 'cookieconsent' ); this.cookieConsent = false; this._render(); } removeEmailCapture() { if ( this._isRendered ) return false; this._removeClass( 'email-capture' ); this.emailCapture = false; this._render(); } play() { // Always overridden by the child classes } pause() { // Always overridden by the child classes } seekTo( seconds ) { // Always overridden by the child classes } } class AIOVGYouTubeElement extends AIOVGBaseElement { constructor() { super(); this._addClass( 'youtube' ); // Set references to the private properties used by the component this._player = null; } /** * Browser calls this method when the element is removed from the document. * (can be called many times if an element is repeatedly added/removed) */ disconnectedCallback() { if ( this._player && this._player.destroy ) { this._player.destroy(); } this._player = null; if ( super.disconnectedCallback ) { super.disconnectedCallback(); } } /** * Define public methods. */ _warmConnections() { if ( window.AIOVGYouTubeIsPreconnected ) return false; AIOVGBaseElement.addPrefetch( 'preconnect', 'https://i.ytimg.com' ); AIOVGBaseElement.addPrefetch( 'preconnect', 'https://s.ytimg.com' ); AIOVGBaseElement.addPrefetch( 'preconnect', 'https://yt3.ggpht.com' ); if ( this.src.indexOf( 'www.youtube-nocookie.com' ) > -1 ) { AIOVGBaseElement.addPrefetch( 'preconnect', 'https://www.youtube-nocookie.com' ); } else { AIOVGBaseElement.addPrefetch( 'preconnect', 'https://www.youtube.com' ); } AIOVGBaseElement.addPrefetch( 'preconnect', 'https://www.google.com' ); AIOVGBaseElement.addPrefetch( 'preconnect', 'https://googleads.g.doubleclick.net' ); AIOVGBaseElement.addPrefetch( 'preconnect', 'https://static.doubleclick.net' ); window.AIOVGYouTubeIsPreconnected = true; } _onIframeAdded( iframeEl ) { this._loadApi().then(() => { const player = new YT.Player( iframeEl, { events: { 'onReady': () => { this._player = player; }, 'onStateChange': ( event ) => { if ( 1 == event.data ) { // Playing // Pause other players const videos = document.querySelectorAll( '.aiovg-player-element' ); for ( let i = 0; i < videos.length; i++ ) { if ( videos[ i ] != this ) { videos[ i ].pause(); } } window.postMessage({ message: 'aiovg-video-playing' }, window.location.origin ); } } } }); }); } /** * Define private methods. */ _loadApi() { return new Promise(( resolve ) => { if ( typeof window.YT === 'undefined' && typeof AIOVGYouTubeElement.isApiLoaded === 'undefined' ) { AIOVGYouTubeElement.isApiLoaded = true; const tag = document.createElement( 'script' ); tag.src = 'https://www.youtube.com/iframe_api'; const firstScriptTag = document.getElementsByTagName( 'script' )[0]; firstScriptTag.parentNode.insertBefore( tag, firstScriptTag ); } if ( typeof window.YT !== 'undefined' && window.YT.Player ) { resolve(); } else { let intervalHandler = setInterval(function() { if ( typeof window.YT !== 'undefined' && window.YT.Player ) { clearInterval( intervalHandler ); resolve(); } }, 100 ); } }); } /** * Define API methods. */ play() { if ( this._player && this._player.playVideo ) { this._player.playVideo(); } } pause() { if ( this._player && this._player.pauseVideo ) { this._player.pauseVideo(); } } seekTo( seconds ) { if ( this._player && this._player.seekTo ) { this._player.seekTo( seconds, true ); } } } class AIOVGVimeoElement extends AIOVGBaseElement { constructor() { super(); this._addClass( 'vimeo' ); // Set references to the private properties used by the component this._player = null; } /** * Browser calls this method when the element is removed from the document. * (can be called many times if an element is repeatedly added/removed) */ disconnectedCallback() { if ( this._player && this._player.destroy ) { this._player.destroy(); } this._player = null; if ( super.disconnectedCallback ) { super.disconnectedCallback(); } } /** * Define public methods. */ _warmConnections() { if ( window.AIOVGVimeoIsPreconnected ) return false; AIOVGBaseElement.addPrefetch( 'preconnect', 'https://i.vimeocdn.com' ); AIOVGBaseElement.addPrefetch( 'preconnect', 'https://player.vimeo.com' ); window.AIOVGVimeoIsPreconnected = true; } _onIframeAdded( iframeEl ) { this._loadApi().then(() => { const player = new Vimeo.Player( iframeEl ); player.ready().then(() => { this._player = player; }); player.on( 'play', ( data ) => { // Pause other players const videos = document.querySelectorAll( '.aiovg-player-element' ); for ( let i = 0; i < videos.length; i++ ) { if ( videos[ i ] != this ) { videos[ i ].pause(); } } window.postMessage({ message: 'aiovg-video-playing' }, window.location.origin ); }); }); } /** * Define private methods. */ _loadApi() { return new Promise(( resolve ) => { if ( typeof window.Vimeo === 'undefined' && typeof AIOVGVimeoElement.isApiLoaded === 'undefined' ) { AIOVGVimeoElement.isApiLoaded = true; const tag = document.createElement( 'script' ); tag.src = 'https://player.vimeo.com/api/player.js'; const firstScriptTag = document.getElementsByTagName( 'script' )[0]; firstScriptTag.parentNode.insertBefore( tag, firstScriptTag ); } if ( typeof window.Vimeo !== 'undefined' && window.Vimeo.Player ) { resolve(); } else { let intervalHandler = setInterval(function() { if ( typeof window.Vimeo !== 'undefined' && window.Vimeo.Player ) { clearInterval( intervalHandler ); resolve(); } }, 100 ); } }); } /** * Define API methods. */ play() { if ( this._player && this._player.play ) { this._player.play(); } } pause() { if ( this._player && this._player.pause ) { this._player.pause(); } } seekTo( seconds ) { if ( this._player && this._player.setCurrentTime ) { this._player.setCurrentTime( seconds ); } } } class AIOVGDailymotionElement extends AIOVGBaseElement { constructor() { super(); this._addClass( 'dailymotion' ); } _warmConnections() { if ( window.AIOVGDailymotionIsPreconnected ) return false; AIOVGBaseElement.addPrefetch( 'preconnect', 'https://s1.dmcdn.net' ); AIOVGBaseElement.addPrefetch( 'preconnect', 'https://s2.dmcdn.net' ); AIOVGBaseElement.addPrefetch( 'preconnect', 'https://www.dailymotion.com' ); window.AIOVGDailymotionIsPreconnected = true; } } class AIOVGIframeElement extends AIOVGBaseElement { constructor() { super(); this._forceIframeElement = true; } } window.AIOVGYouTubeIsPreconnected = false; window.AIOVGVimeoIsPreconnected = false; window.AIOVGDailymotionIsPreconnected = false; /** * Called when the page has loaded. */ document.addEventListener( 'DOMContentLoaded', function() { // Register custom elements if ( ! customElements.get( 'aiovg-youtube' ) ) { customElements.define( 'aiovg-youtube', AIOVGYouTubeElement ); } if ( ! customElements.get( 'aiovg-vimeo' ) ) { customElements.define( 'aiovg-vimeo', AIOVGVimeoElement ); } if ( ! customElements.get( 'aiovg-dailymotion' ) ) { customElements.define( 'aiovg-dailymotion', AIOVGDailymotionElement ); } if ( ! customElements.get( 'aiovg-embed' ) ) { customElements.define( 'aiovg-embed', AIOVGIframeElement ); } // Update views count for the non-iframe embeds const videos = document.querySelectorAll( '.aiovg-player-raw' ); for ( let i = 0; i < videos.length; i++ ) { const elem = videos[ i ]; const post_id = parseInt( elem.dataset.post_id ); const statistics = parseInt( elem.dataset.statistics ); if ( statistics ) { let formData = new FormData(); formData.append( 'action', 'aiovg_update_views_count' ); formData.append( 'post_id', post_id ); formData.append( 'security', aiovg_embed.ajax_nonce ); fetch( aiovg_embed.ajax_url, { method: 'POST', body: formData } ); } } // Listen to the iframe player events window.addEventListener( 'message', function( event ) { if ( event.origin != window.location.origin ) { return false; } if ( ! event.data.hasOwnProperty( 'context' ) || event.data.context != 'iframe' ) { return false; } if ( ! event.data.hasOwnProperty( 'message' ) ) { return false; } if ( event.data.message == 'aiovg-cookie-consent' ) { const videos = document.querySelectorAll( '.aiovg-player-element' ); for ( let i = 0; i < videos.length; i++ ) { videos[ i ].removeCookieConsent(); } } if ( event.data.message == 'aiovg-email-captured' ) { const videos = document.querySelectorAll( '.aiovg-player-element' ); for ( let i = 0; i < videos.length; i++ ) { videos[ i ].removeEmailCapture(); } } if ( event.data.message == 'aiovg-video-playing' ) { const videos = document.querySelectorAll( '.aiovg-player-element' ); for ( let i = 0; i < videos.length; i++ ) { videos[ i ].pause(); } } }); }); })();