/** * Complex TV Youtube Recommended * * @author Jonathan Crockett * @version 1.0.0 * @data 2/11/14 * @param {object} userOptions * { selector: '#youtube-player', (required) auotplayTimeout: 40000, (optional) channelSlug: 'music' (optional) }; @desecription Finds all the youtube iframe players specified in the selector and displays a Complex TV ooyala player widget over the video when it completes. Supports modern browsers desktop & mobile. IE9+ @usage: ytRecWidget({ selector: '#youtube-player', autoplayTimeout: 40000, channelSlug: 'music' }); @link git@gitlab.complexmedianetwork.com:jonathanc/youtube-overlay-widget.git */ var ytRecWidget = function (userOptions) { // No IE8 if (!window.addEventListener) { return false; } if (!userOptions.hasOwnProperty('selector')) { console.log('ytRecWidget error: No selector specified'); return false; } var ytIframeEmbeds, ooRecWidgets = [], options = {}, autoIdPrefix = 'yt-player-id-', videoAutoPlayed = false; var defaultOptions = { selector: '', autoplayTimeout: 8000, channelSlug: '' }; for (var x in defaultOptions) { options[x] = userOptions[x] ? userOptions[x] : defaultOptions[x]; } /** * Gets all the youtube iframe embeds on the page based on the selector. * Also adds wmode transparent which is need for the widget to display properly in IE. * @return {[type]} */ function getYTiFrameEmbeds() { var youtubeIframeEmbeds = document.querySelectorAll(options.selector), appendUrlParams; for (var x = 0; x < youtubeIframeEmbeds.length; x++) { appendUrlParams = ''; // Assigns ID to iframe if one does not exists. This is needed to hook in the youtube API. if (!youtubeIframeEmbeds[x].id) { youtubeIframeEmbeds[x].id = autoIdPrefix + x; } // Need to add this param for overlay on IE. if (!/mode=transparent/.test(youtubeIframeEmbeds[x].src)) { if (/\?/.test(youtubeIframeEmbeds[x].src)) { appendUrlParams += '&wmode=transparent'; } else { appendUrlParams += '?wmode=transparent'; } } // Need to add this param for overlay on IE. if (!/enablejsapi=1/.test(youtubeIframeEmbeds[x].src)) { if (/\?/.test(youtubeIframeEmbeds[x].src) || appendUrlParams) { appendUrlParams += '&enablejsapi=1'; } else { appendUrlParams += '?enablejsapi=1'; } } if (appendUrlParams) { youtubeIframeEmbeds[x].src += appendUrlParams; } } return youtubeIframeEmbeds; } /** * creates and returns the Oyalla recommended widget object exposing "show" method. * @param {HTML Iframe Element} youtubePlayer * @param {int} widgetIndex * @return {Object} */ function ooRecWidget(youtubePlayer, widgetIndex) { var overlayDiv, throttleTimeout, videoApiUrl, videoAutoPlayTimeout, videoAutoPlay = options.autoplayTimeout, widgetId = "ooyala-rec-widget-" + widgetIndex; /** * Resizes the overlay player div to fit the youtube embed. * @return {[type]} */ function resizeOverlayPlayerDiv() { if (!overlayDiv) { return; } overlayDiv.style.left = youtubePlayer.offsetLeft + 'px'; overlayDiv.style.top = youtubePlayer.offsetTop + 'px'; overlayDiv.style.width = youtubePlayer.offsetWidth + 'px'; overlayDiv.style.height = youtubePlayer.offsetHeight + 'px'; } /** * Creates the widget dif to overlay over the youtube player. * @return {[type]} [description] */ function createWidgetElement() { overlayDiv = document.createElement('div'); overlayDiv.id = widgetId; overlayDiv.className = "ooyala-rec-widget"; overlayDiv.style.position = 'absolute'; overlayDiv.style.zIndex = '1000000'; resizeOverlayPlayerDiv(); overlayDiv.style.backgroundColor = "#000"; overlayDiv.innerHTML = ''; youtubePlayer.parentNode.appendChild(overlayDiv); } /** * Retrieves and displays the ComplexTV vids from the API. */ function getOOVids() { var relatedVidsHTML = ''; if (options.channelSlug) { videoApiUrl = 'http://www.complex.com/tv/api/labels/original/latest_videos/' + options.channelSlug; } else { videoApiUrl = 'http://www.complex.com/tv/api/videos/original/latest'; } var oReq = createCORSRequest('GET', videoApiUrl); oReq.open("GET", videoApiUrl, true); oReq.responseType = "text"; oReq.onload = function (evt) { var response = JSON.parse(oReq.responseText), marker; // The latest_videos api link returns an object with a data prop. if (response.data) { response = response.data; } for (var x = 0; x < 2 && x < response.length; x++) { _gaq.push(['ComplexYouTubeOverlay._trackEvent', 'ComplexYouTubeOverlay', 'Thumbnail Load', response[x].name]); relatedVidsHTML += ''; } overlayDiv.innerHTML = '

Up Next on Complex TV

' + relatedVidsHTML; videoAutoPlayTimeout = setTimeout(function () { //user didn't click on thumbnail, video autoplays fired //_gaq.push(['ComplexYouTubeOverlay._trackEvent', 'ComplexYouTubeOverlay', 'AutoPlay', response[0].display_title]); loadAndPlayOyallaPlayer(response[0].embed_code, response[0].display_title, 'AutoPlay'); }, videoAutoPlay); marker = document.querySelectorAll('#' + widgetId + ' .cplx-related-vid-progress-mark')[0]; marker.parentNode.style.display = 'block'; // Need to wrap in timeout so that the dom has time to initialize for the css property. setTimeout(function() { var seconds = videoAutoPlay / 1000; marker.style.webkitTransition = "width " + seconds + "s linear"; marker.style.oTransition = "width " + seconds + "s linear"; marker.style.msTransition = "width " + seconds + "s linear"; marker.style.mozTransition = "width " + seconds + "s linear"; marker.style.transition = "width " + seconds + "s linear"; marker.style.width = "100%"; }, 100); document.getElementById(widgetId).addEventListener('click', videoClickCallback, false); }; oReq.send(); } /** * Creates the dom elements and displays the widget * @return {void} */ function show() { if (!overlayDiv) { createWidgetElement(); _gaq.push(['ComplexYouTubeOverlay._trackEvent', 'ComplexYouTubeOverlay', 'Load Complete', 'Overlay loaded']); getOOVids(); } else { overlayDiv.style.display = 'block'; } } /** * Creates the dom elements and displays the widget * @return {void} */ function hide() { if (overlayDiv) { overlayDiv.style.display = 'none'; } } /** * Plays the video * @param {clickEvent} evt * @return {void} */ function videoClickCallback(evt) { var parentElement = evt.target.parentNode.parentNode; var titleEl = parentElement.querySelector('h3'); var title = titleEl.innerHTML; //_gaq.push(['ComplexYouTubeOverlay._trackEvent', 'ComplexYouTubeOverlay', 'Click', title]); clearTimeout(videoAutoPlayTimeout); if (evt.target.className === 'cplx-related-vid') { loadAndPlayOyallaPlayer(evt.target.getAttribute('data-embedcode'), title, 'Click'); } else if (evt.target.parentNode.className === 'cplx-related-vid') { loadAndPlayOyallaPlayer(evt.target.parentNode.getAttribute('data-embedcode'), title, 'Click'); } else if (evt.target.parentNode.parentNode.className === 'cplx-related-vid') { loadAndPlayOyallaPlayer(evt.target.parentNode.parentNode.getAttribute('data-embedcode'), title, 'Click'); } } function loadAndPlayOyallaPlayer(oyallaId, title, eventType) { var player = OO.Player.create(widgetId, oyallaId); if(player.mb != undefined){ mesb = player.mb; mesb.subscribe(OO.EVENTS.PLAYING, 'ComplexYouTubeOverlay', function(eventName) { if(!videoAutoPlayed){ _gaq.push(['ComplexYouTubeOverlay._trackEvent', 'ComplexYouTubeOverlay', eventType, title]); videoAutoPlayed = true; } }); mesb.subscribe(OO.EVENTS.WILL_PLAY_ADS, 'ComplexYouTubeOverlay', function(eventName) { if(!videoAutoPlayed){ _gaq.push(['ComplexYouTubeOverlay._trackEvent', 'ComplexYouTubeOverlay', eventType, title]); videoAutoPlayed = true; } }); } player.play(); } /** * Cross browser AJAX request object * @param {[type]} method * @param {[type]} url * @return {[type]} */ function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // Check if the XMLHttpRequest object has a "withCredentials" property. // "withCredentials" only exists on XMLHTTPRequest2 objects. xhr.open(method, url, true); } else if (typeof XDomainRequest !== "undefined") { // Otherwise, check if XDomainRequest. // XDomainRequest only exists in IE, and is IE's way of making CORS requests. xhr = new XDomainRequest(); xhr.open(method, url); } else { // Otherwise, CORS is not supported by the browser. xhr = null; } return xhr; } window.addEventListener('resize', function () { clearTimeout(throttleTimeout); throttleTimeout = setTimeout(resizeOverlayPlayerDiv, 200); }, false); window.addEventListener('orientationchange', resizeOverlayPlayerDiv); return { show: show, hide: hide, }; } /** * Loads the dependancy scripts * @return {void} */ function loadScripts() { var oyallaScript, youtubeScript; if (typeof YT === 'undefined') { youtubeScript = document.createElement('script'); youtubeScript.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(youtubeScript, firstScriptTag); } if (typeof OO === 'undefined') { oyallaScript = document.createElement('script'); oyallaScript.setAttribute("type", "text/javascript"); oyallaScript.setAttribute("src", 'http://player.ooyala.com/v3/556f8260656c47a4ab49bf6f2dde85f3?platform=html5-fallback'); if (typeof oyallaScript !== "undefined") { document.getElementsByTagName("head")[0].appendChild(oyallaScript); } } } function youtubeVideoComplete(evt) { if (evt.data === YT.PlayerState.ENDED) { if (document.getElementById(evt.target.a.id).hasOwnProperty('ooRecWigetIndex')) { ooRecWidgets[document.getElementById(evt.target.a.id).ooRecWigetIndex].show(); } } } // Load script dependancies loadScripts(); ytIframeEmbeds = getYTiFrameEmbeds(); if (ytIframeEmbeds.length === 0) { return false; } // Creates Oyalla recommended widget objects and assigns widget index to iframe embeds. for (var y = 0; y < ytIframeEmbeds.length; y++) { ooRecWidgets.push(ooRecWidget(ytIframeEmbeds[y], y)); // Create pointer to rec windget index so it can be accessed within the yt event playback complete callback. ytIframeEmbeds[y].ooRecWigetIndex = y; } // Callback from youtube api window.onYouTubeIframeAPIReady = function (evt) { var players = []; // Iterates through the iframe yt players and assigns callbacks to load the OO rec widget. for (var x = 0; x < ytIframeEmbeds.length; x++) { players.push(new YT.Player(ytIframeEmbeds[x].id, { events: { 'onStateChange': youtubeVideoComplete } })); } }; };