var fluidPlayerScriptLocation = function () { var currentSrc = ''; if (document.currentScript) { currentSrc = document.currentScript.src; } else { //IE currentSrc = (function () { var scripts = document.getElementsByTagName('script'), script = scripts[scripts.length - 1]; if (script.getAttribute.length !== undefined) { return script.src; } return script.getAttribute('src', -1) }()); } if (currentSrc) { return currentSrc.substring(0, currentSrc.lastIndexOf('/')); } return ''; }(); //Object.assign polyfill if (typeof Object.assign != 'function') { // Must be writable: true, enumerable: false, configurable: true Object.defineProperty(Object, "assign", { value: function assign(target, varArgs) { // .length of function is 2 'use strict'; if (target == null) { // TypeError if undefined or null throw new TypeError('Cannot convert undefined or null to object'); } var to = Object(target); for (var index = 1; index < arguments.length; index++) { var nextSource = arguments[index]; if (nextSource != null) { // Skip over if undefined or null for (var nextKey in nextSource) { // Avoid bugs when hasOwnProperty is shadowed if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }, writable: true, configurable: true }); } //CustomEvent polyfill (function () { if ( typeof window.CustomEvent === "function" ) return false; function CustomEvent ( event, params ) { params = params || { bubbles: false, cancelable: false, detail: undefined }; var evt = document.createEvent( 'CustomEvent' ); evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); return evt; } CustomEvent.prototype = window.Event.prototype; window.CustomEvent = CustomEvent; })(); //remove() polyfill (function (arr) { arr.forEach(function (item) { if (item.hasOwnProperty('remove')) { return; } Object.defineProperty(item, 'remove', { configurable: true, enumerable: true, writable: true, value: function remove() { if (this.parentNode === null) { return; } this.parentNode.removeChild(this); } }); }); })([Element.prototype, CharacterData.prototype, DocumentType.prototype]); fluidPlayer = function (idVideoPlayer, options) { var inArray = function (needle, haystack) { var length = haystack.length; for (var i = 0; i < length; i++) { if (haystack[i] == needle) { return true; } } return false; }; var copy = fluidPlayerClass.constructor(); for (var attr in fluidPlayerClass) { if (fluidPlayerClass.hasOwnProperty(attr) && !inArray(attr, fluidPlayerClass.notCloned)) { copy[attr] = fluidPlayerClass[attr]; } } fluidPlayerClass.instances.push(copy); copy.init(idVideoPlayer, options); return copy; }; var fluidPlayerClass = { hlsJsScript: '/scripts/hls.min.js', dashJsScript: '/scripts/dash.min.js', vttParserScript: '/scripts/webvtt.min.js', subtitlesParseScript: '/scripts/vtt.js', panolensScript: '/scripts/panolens.min.js', threeJsScript: '/scripts/three.min.js', instances: [], notCloned: ['notCloned', 'vttParserScript', 'instances', 'getInstanceById', 'requestStylesheet', 'reqiestScript', 'isTouchDevice', 'vastOptions', 'displayOptions', 'getEventOffsetX', 'getEventOffsetY', 'getTranslateX', 'toggleElementText', 'getMobileOs', 'findClosestParent', 'activeVideoPlayerId', 'getInstanceIdByWrapperId', 'timer', 'timerPool', 'adList', 'adPool', 'isUserActive', 'isCurrentlyPlayingAd', 'initialAnimationSet'], version: '2.4.10', vpaidVer: '2.0', homepage: 'https://www.fluidplayer.com/', activeVideoPlayerId: null, getInstanceById: function (playerId) { for (var i = 0; i < this.instances.length; i++) { if (this.instances[i].videoPlayerId === playerId) { return this.instances[i]; } } return null; }, getInstanceIdByWrapperId: function (wrapperId) { return typeof wrapperId != "undefined" ? wrapperId.replace('fluid_video_wrapper_', '') : null; }, requestStylesheet: function (cssId, url) { if (!document.getElementById(cssId)) { var head = document.getElementsByTagName('head')[0]; var link = document.createElement('link'); link.id = cssId; link.rel = 'stylesheet'; link.type = 'text/css'; link.href = url; link.media = 'all'; head.appendChild(link); } }, requestScript: function (url, callback) { // Adding the script tag to the head var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; script.src = url; // Then bind the event to the callback function. // There are several events for cross browser compatibility. script.onreadystatechange = callback; script.onload = callback; // Fire the loading head.appendChild(script); }, isTouchDevice: function () { return !!('ontouchstart' in window // works on most browsers || navigator.maxTouchPoints); // works on IE10/11 and Surface }, /** * Distinguishes iOS from Android devices and the OS version. * * @returns object */ getMobileOs: function () { var ua = navigator.userAgent; var uaindex; var result = {device: false, userOs: false, userOsVer: false, userOsMajor: false}; // determine OS if (ua.match(/iPad/i)) { result.device = 'iPad'; result.userOs = 'iOS'; uaindex = ua.indexOf('OS '); } else if (ua.match(/iPhone/i)) { result.device = 'iPhone'; result.userOs = 'iOS'; uaindex = ua.indexOf('OS '); } else if (ua.match(/Android/i)) { result.userOs = 'Android'; uaindex = ua.indexOf('Android '); } else { result.userOs = false; } // determine version if (result.userOs === 'iOS' && (uaindex > -1)) { var userOsTemp = ua.substr(uaindex + 3); var indexOfEndOfVersion = userOsTemp.indexOf(' '); if (indexOfEndOfVersion !== -1) { result.userOsVer = userOsTemp.substring(0, userOsTemp.indexOf(' ')).replace(/_/g, '.'); result.userOsMajor = parseInt(result.userOsVer); } } else if (result.userOs === 'Android' && (uaindex > -1)) { result.userOsVer = ua.substr(uaindex + 8, 3); } else { result.userOsVer = false; } return result; }, /** * Browser detection * * @returns object */ getBrowserVersion: function () { var ua = navigator.userAgent; var result = {browserName: false, fullVersion: false, majorVersion: false, userOsMajor: false}; var idx, uaindex; try { result.browserName = navigator.appName; if ((idx = ua.indexOf("OPR/")) != -1) { result.browserName = "Opera"; result.fullVersion = ua.substring(idx + 4); } else if ((idx = ua.indexOf("Opera")) != -1) { result.browserName = "Opera"; result.fullVersion = ua.substring(idx + 6); if ((idx = ua.indexOf("Version")) != -1) result.fullVersion = ua.substring(idx + 8); } else if ((idx = ua.indexOf("MSIE")) != -1) { result.browserName = "Microsoft Internet Explorer"; result.fullVersion = ua.substring(idx + 5); } else if ((idx = ua.indexOf("Chrome")) != -1) { result.browserName = "Google Chrome"; result.fullVersion = ua.substring(idx + 7); } else if ((idx = ua.indexOf("Safari")) != -1) { result.browserName = "Safari"; result.fullVersion = ua.substring(idx + 7); if ((idx = ua.indexOf("Version")) != -1) result.fullVersion = ua.substring(idx + 8); } else if ((idx = ua.indexOf("Firefox")) != -1) { result.browserName = "Mozilla Firefox"; result.fullVersion = ua.substring(idx + 8); } // Others "name/version" is at the end of userAgent else if ((uaindex = ua.lastIndexOf(' ') + 1) < (idx = ua.lastIndexOf('/'))) { result.browserName = ua.substring(uaindex, idx); result.fullVersion = ua.substring(idx + 1); if (result.browserName.toLowerCase() == result.browserName.toUpperCase()) { result.browserName = navigator.appName; } } // trim the fullVersion string at semicolon/space if present if ((uaindex = result.fullVersion.indexOf(';')) != -1) { result.fullVersion = result.fullVersion.substring(0, uaindex); } if ((uaindex = result.fullVersion.indexOf(' ')) != -1) { result.fullVersion = result.fullVersion.substring(0, uaindex); } result.majorVersion = parseInt('' + result.fullVersion, 10); if (isNaN(result.majorVersion)) { result.fullVersion = '' + parseFloat(navigator.appVersion); result.majorVersion = parseInt(navigator.appVersion, 10); } } catch (e) { //Return default obj. } return result; }, getCurrentVideoDuration: function () { var videoPlayerTag = document.getElementById(this.videoPlayerId); if (videoPlayerTag) { return videoPlayerTag.duration; } return 0; }, getClickThroughUrlFromLinear: function (linear) { var videoClicks = linear.getElementsByTagName('VideoClicks'); if (videoClicks.length) {//There should be exactly 1 node var clickThroughs = videoClicks[0].getElementsByTagName('ClickThrough'); if (clickThroughs.length) { return this.extractNodeData(clickThroughs[0]); } } return false; }, getVastAdTagUriFromWrapper: function (xmlResponse) { var wrapper = xmlResponse.getElementsByTagName('Wrapper'); if (typeof wrapper !== 'undefined' && wrapper.length) { var vastAdTagURI = wrapper[0].getElementsByTagName('VASTAdTagURI'); if (vastAdTagURI.length) { return this.extractNodeData(vastAdTagURI[0]); } } return false; }, hasInLine: function (xmlResponse) { var inLine = xmlResponse.getElementsByTagName('InLine'); return ((typeof inLine !== 'undefined') && inLine.length); }, hasVastAdTagUri: function (xmlResponse) { var vastAdTagURI = xmlResponse.getElementsByTagName('VASTAdTagURI'); return ((typeof vastAdTagURI !== 'undefined') && vastAdTagURI.length); }, getClickThroughUrlFromNonLinear: function (nonLinear) { var result = ''; var nonLinears = nonLinear.getElementsByTagName('NonLinear'); if (nonLinears.length) {//There should be exactly 1 node var nonLinearClickThrough = nonLinear.getElementsByTagName('NonLinearClickThrough'); if (nonLinearClickThrough.length) { result = this.extractNodeData(nonLinearClickThrough[0]); } } return result; }, getTrackingFromLinear: function (linear) { var trackingEvents = linear.getElementsByTagName('TrackingEvents'); if (trackingEvents.length) {//There should be no more than one node return trackingEvents[0].getElementsByTagName('Tracking'); } return []; }, getDurationFromLinear: function (linear) { var duration = linear.getElementsByTagName('Duration'); if (duration.length && (typeof duration[0].childNodes[0] !== 'undefined')) { var nodeDuration = this.extractNodeData(duration[0]); return this.convertTimeStringToSeconds(nodeDuration); } return false; }, getDurationFromNonLinear: function (tag) { var result = 0; var nonLinear = tag.getElementsByTagName('NonLinear'); if (nonLinear.length && (typeof nonLinear[0].getAttribute('minSuggestedDuration') !== 'undefined')) { result = this.convertTimeStringToSeconds(nonLinear[0].getAttribute('minSuggestedDuration')); } return result; }, getDimensionFromNonLinear: function (tag) { var result = {'width': null, 'height': null}; var nonLinear = tag.getElementsByTagName('NonLinear'); if (nonLinear.length) { if (typeof nonLinear[0].getAttribute('width') !== 'undefined') { result.width = nonLinear[0].getAttribute('width'); } if (typeof nonLinear[0].getAttribute('height') !== 'undefined') { result.height = nonLinear[0].getAttribute('height'); } } return result; }, getCreativeTypeFromStaticResources: function (tag) { var result = ''; var nonLinears = tag.getElementsByTagName('NonLinear'); if (nonLinears.length && (typeof nonLinears[0].childNodes[0] !== 'undefined')) {//There should be exactly 1 StaticResource node result = nonLinears[0].getElementsByTagName('StaticResource')[0].getAttribute('creativeType'); } return result.toLowerCase(); }, getMediaFilesFromLinear: function (linear) { var mediaFiles = linear.getElementsByTagName('MediaFiles'); if (mediaFiles.length) {//There should be exactly 1 MediaFiles node return mediaFiles[0].getElementsByTagName('MediaFile'); } return []; }, getStaticResourcesFromNonLinear: function (linear) { var result = []; var nonLinears = linear.getElementsByTagName('NonLinear'); if (nonLinears.length) {//There should be exactly 1 StaticResource node result = nonLinears[0].getElementsByTagName('StaticResource'); } return result; }, extractNodeData: function (parentNode) { var contentAsString = ""; for(var n = 0; n < parentNode.childNodes.length; n ++) { var child = parentNode.childNodes[n]; if (child.nodeType === 8 || (child.nodeType === 3 && /^\s*$/.test(child.nodeValue))) { // Comments or text with no content } else { contentAsString += child.nodeValue; } } var tidyString = contentAsString.replace(/(^\s+|\s+$)/g,''); return tidyString; }, getAdParametersFromLinear: function(linear){ var adParameters = linear.getElementsByTagName('AdParameters'); var adParametersData = null; if (adParameters.length) { adParametersData = this.extractNodeData(adParameters[0]); } return adParametersData; }, getMediaFileListFromLinear: function (linear) { var mediaFileList = []; var mediaFiles = this.getMediaFilesFromLinear(linear); if (mediaFiles.length) { for (var n = 0; n < mediaFiles.length; n++) { var mediaType = mediaFiles[n].getAttribute('mediaType'); if(!mediaType){ // if there is no mediaType attribute then the video is 2D mediaType = '2D'; } // get all the attributes of media file mediaFileList.push({ 'src': this.extractNodeData(mediaFiles[n]), 'type': mediaFiles[n].getAttribute('type'), 'apiFramework': mediaFiles[n].getAttribute('apiFramework'), 'codec': mediaFiles[n].getAttribute('codec'), 'id': mediaFiles[n].getAttribute('codec'), 'fileSize': mediaFiles[n].getAttribute('fileSize'), 'delivery': mediaFiles[n].getAttribute('delivery'), 'width': mediaFiles[n].getAttribute('width'), 'height': mediaFiles[n].getAttribute('height'), 'mediaType': mediaType.toLowerCase() }); } } return mediaFileList; }, getIconClickThroughFromLinear: function (linear) { var iconClickThrough = linear.getElementsByTagName('IconClickThrough'); if (iconClickThrough.length) { return this.extractNodeData(iconClickThrough[0]); } return ''; }, getStaticResourceFromNonLinear: function (linear) { var fallbackStaticResource; var staticResources = this.getStaticResourcesFromNonLinear(linear); for (var i = 0; i < staticResources.length; i++) { if (!staticResources[i].getAttribute('type')) { fallbackStaticResource = this.extractNodeData(staticResources[i]); } if (staticResources[i].getAttribute('type') === this.displayOptions.staticResource) { return this.extractNodeData(staticResources[i]); } } return fallbackStaticResource; }, registerTrackingEvents: function (creativeLinear, tmpOptions) { var trackingEvents = this.getTrackingFromLinear(creativeLinear); var eventType = ''; var oneEventOffset = 0; for (var i = 0; i < trackingEvents.length; i++) { eventType = trackingEvents[i].getAttribute('event'); switch (eventType) { case 'start': case 'firstQuartile': case 'midpoint': case 'thirdQuartile': case 'complete': if (typeof tmpOptions.tracking[eventType] === 'undefined') { tmpOptions.tracking[eventType] = []; } if (typeof tmpOptions.stopTracking[eventType] === 'undefined') { tmpOptions.stopTracking[eventType] = []; } tmpOptions.tracking[eventType].push(trackingEvents[i].childNodes[0].nodeValue); tmpOptions.stopTracking[eventType] = false; break; case 'progress': if (typeof tmpOptions.tracking[eventType] === 'undefined') { tmpOptions.tracking[eventType] = []; } oneEventOffset = this.convertTimeStringToSeconds(trackingEvents[i].getAttribute('offset')); if (typeof tmpOptions.tracking[eventType][oneEventOffset] === 'undefined') { tmpOptions.tracking[eventType][oneEventOffset] = { elements: [], stopTracking: false }; } tmpOptions.tracking[eventType][oneEventOffset].elements.push(trackingEvents[i].childNodes[0].nodeValue); break; default: break; } } }, registerClickTracking: function (clickTrackingTag, tmpOptions) { if (clickTrackingTag.length) { for (var i = 0; i < clickTrackingTag.length; i++) { if (clickTrackingTag[i] != '') { tmpOptions.clicktracking.push(clickTrackingTag[i]); } } } }, registerImpressionEvents: function (impressionTags, tmpOptions) { if (impressionTags.length) { for (var i = 0; i < impressionTags.length; i++) { var impressionEvent = this.extractNodeData(impressionTags[i]); tmpOptions.impression.push(impressionEvent); } } }, registerErrorEvents: function (errorTags, tmpOptions) { if ( (typeof errorTags !== 'undefined') && (errorTags !== null) && (errorTags.length === 1) && //Only 1 Error tag is expected (errorTags[0].childNodes.length === 1) ) { tmpOptions.errorUrl = errorTags[0].childNodes[0].nodeValue; } }, announceError: function (code) { if ( (typeof this.vastOptions.errorUrl === 'undefined') || !this.vastOptions.errorUrl ) { return; } if (typeof(code) !== 'undefined') { code = parseInt(code); } else { //Set a default code (900 Unidentified error) code = 900; } var errorUrl = this.vastOptions.errorUrl.replace('[ERRORCODE]' , code); //Send the error request this.callUris([errorUrl]); }, announceLocalError: function (code, msg) { if (typeof(code) !== 'undefined') { code = parseInt(code); } else { //Set a default code (900 Unidentified error) code = 900; } message = '[Error] (' + code + '): '; message += (!msg) ? 'Failed to load Vast' : msg; console.log(message); }, getClickTrackingEvents: function (linear) { var result = []; var videoClicks = linear.getElementsByTagName('VideoClicks'); if (videoClicks.length) {//There should be exactly 1 node var clickTracking = videoClicks[0].getElementsByTagName('ClickTracking'); if (clickTracking.length) { for (var i = 0; i < clickTracking.length; i++) { var clickTrackingEvent = this.extractNodeData(clickTracking[i]); result.push(clickTrackingEvent); } } } return result; }, getNonLinearClickTrackingEvents: function (nonLinear) { var result = []; var nonLinears = nonLinear.getElementsByTagName('NonLinear'); if (nonLinears.length) { var clickTracking = nonLinear.getElementsByTagName('NonLinearClickTracking'); if (clickTracking.length) { for (var i = 0; i < clickTracking.length; i++) { var NonLinearClickTracking = this.extractNodeData(clickTracking[i]); result.push(NonLinearClickTracking); } } } return result; }, callUris: function (uris) { for (var i = 0; i < uris.length; i++) { new Image().src = uris[i]; } }, recalculateAdDimensions: function (idVideoPlayer) { if ((!idVideoPlayer) && (typeof this.videoPlayerId !== 'undefined')) { var idVideoPlayer = this.videoPlayerId; } var videoPlayer = document.getElementById(idVideoPlayer); var divClickThrough = document.getElementById('vast_clickthrough_layer_' + idVideoPlayer); if (divClickThrough) { divClickThrough.style.width = videoPlayer.offsetWidth + 'px'; divClickThrough.style.height = videoPlayer.offsetHeight + 'px'; } var requestFullscreenFunctionNames = this.checkFullscreenSupport('fluid_video_wrapper_' + idVideoPlayer); var fullscreenButton = document.getElementById(idVideoPlayer + '_fluid_control_fullscreen'); var menuOptionFullscreen = document.getElementById(idVideoPlayer + 'context_option_fullscreen'); if (requestFullscreenFunctionNames) { // this will go other way around because we alredy exited full screen if (document[requestFullscreenFunctionNames.isFullscreen] === null) { // Exit fullscreen this.fullscreenOff(fullscreenButton, menuOptionFullscreen); } else { // Go fullscreen this.fullscreenOn(fullscreenButton, menuOptionFullscreen); } } else { //The browser does not support the Fullscreen API, so a pseudo-fullscreen implementation is used if (fullscreenTag.className.search(/\bpseudo_fullscreen\b/g) !== -1) { fullscreenTag.className += ' pseudo_fullscreen'; this.fullscreenOn(fullscreenButton, menuOptionFullscreen); } else { fullscreenTag.className = fullscreenTag.className.replace(/\bpseudo_fullscreen\b/g, ''); this.fullscreenOff(fullscreenButton, menuOptionFullscreen); } } }, prepareVast: function (roll) { var player = this; var videoPlayerTag = document.getElementById(this.videoPlayerId); var list = []; list.length = 0; list = player.findRoll(roll); for (var i = 0; i < list.length; i++) { var adListId = list[i]; if (player.adList[adListId].vastLoaded !== true && player.adList[adListId].error !== true) { player.processVastWithRetries(player.adList[adListId]); videoPlayerTag.addEventListener('adId_' + adListId, player[roll]); } } }, toggleLoader: function (showLoader) { var player = this; if (showLoader) { player.isLoading = true; } else { player.isLoading = false; } var loaderDiv = document.getElementById('vast_video_loading_' + this.videoPlayerId); if (showLoader) { loaderDiv.style.display = 'table'; } else { loaderDiv.style.display = 'none'; } }, sendRequest: function (url, withCredentials, timeout, functionReadyStateChange) { var xmlHttpReq = new XMLHttpRequest(); xmlHttpReq.onreadystatechange = functionReadyStateChange; xmlHttpReq.open('GET', url, true); xmlHttpReq.withCredentials = withCredentials; xmlHttpReq.timeout = timeout; xmlHttpReq.send(); }, playMainVideoWhenVpaidFails: function (errorCode) { var player = this; var videoPlayerTag = document.getElementById(player.videoPlayerId); var vpaidSlot = document.getElementById(player.videoPlayerId +"_fluid_vpaid_slot"); if (vpaidSlot){ vpaidSlot.remove(); } clearInterval(player.getVPAIDAdInterval); player.playMainVideoWhenVastFails(errorCode); }, playMainVideoWhenVastFails: function (errorCode) { var player = this; player.debugMessage('playMainVideoWhenVastFails called'); var videoPlayerTag = document.getElementById(player.videoPlayerId); videoPlayerTag.removeEventListener('loadedmetadata', player.switchPlayerToVastMode); videoPlayerTag.pause(); player.toggleLoader(false); player.displayOptions.vastOptions.vastAdvanced.noVastVideoCallback(); if (!player.vastOptions || typeof this.vastOptions.errorUrl === 'undefined') { player.announceLocalError(errorCode); } else { player.announceError(errorCode); } player.switchToMainVideo(); }, switchPlayerToVastMode: function () {}, switchPlayerToVpaidMode: function() {}, /** * Process the XML response * * @param xmlResponse * @param adListId * @param tmpOptions */ processVastXml: function (xmlResponse, tmpOptions, callBack) { var player = this; if (!xmlResponse) { callBack(false); return; } //Get impression tag var impression = xmlResponse.getElementsByTagName('Impression'); if (impression !== null) { player.registerImpressionEvents(impression, tmpOptions); } //Get the error tag, if any var errorTags = xmlResponse.getElementsByTagName('Error'); if (errorTags !== null) { player.registerErrorEvents(errorTags, tmpOptions); } //Get Creative var creative = xmlResponse.getElementsByTagName('Creative'); //Currently only 1 creative and 1 linear is supported if ((typeof creative !== 'undefined') && creative.length) { var arrayCreativeLinears = creative[0].getElementsByTagName('Linear'); if ((typeof arrayCreativeLinears !== 'undefined') && (arrayCreativeLinears !== null) && arrayCreativeLinears.length) { var creativeLinear = arrayCreativeLinears[0]; player.registerTrackingEvents(creativeLinear, tmpOptions); var clickTracks = player.getClickTrackingEvents(creativeLinear); player.registerClickTracking(clickTracks, tmpOptions); //Extract the Ad data if it is actually the Ad (!wrapper) if (!player.hasVastAdTagUri(xmlResponse) && player.hasInLine(xmlResponse)) { //Set initial values tmpOptions.adFinished = false; tmpOptions.adType = 'linear'; tmpOptions.vpaid = false; //Extract the necessary data from the Linear node tmpOptions.skipoffset = player.convertTimeStringToSeconds(creativeLinear.getAttribute('skipoffset')); tmpOptions.clickthroughUrl = player.getClickThroughUrlFromLinear(creativeLinear); tmpOptions.duration = player.getDurationFromLinear(creativeLinear); tmpOptions.mediaFileList = player.getMediaFileListFromLinear(creativeLinear); tmpOptions.adParameters = player.getAdParametersFromLinear(creativeLinear); tmpOptions.iconClick = player.getIconClickThroughFromLinear(creativeLinear); if (tmpOptions.adParameters) { tmpOptions.vpaid = true; } } } var arrayCreativeNonLinears = creative[0].getElementsByTagName('NonLinearAds'); if ((typeof arrayCreativeNonLinears !== 'undefined') && (arrayCreativeNonLinears !== null) && arrayCreativeNonLinears.length) { var creativeNonLinear = arrayCreativeNonLinears[0]; player.registerTrackingEvents(creativeNonLinear, tmpOptions); var clickTracks = player.getNonLinearClickTrackingEvents(creativeNonLinear); player.registerClickTracking(clickTracks, tmpOptions); //Extract the Ad data if it is actually the Ad (!wrapper) if (!player.hasVastAdTagUri(xmlResponse) && player.hasInLine(xmlResponse)) { //Set initial values tmpOptions.adType = 'nonLinear'; tmpOptions.vpaid = false; //Extract the necessary data from the NonLinear node tmpOptions.clickthroughUrl = player.getClickThroughUrlFromNonLinear(creativeNonLinear); tmpOptions.duration = player.getDurationFromNonLinear(creativeNonLinear); // VAST version < 4.0 tmpOptions.dimension = player.getDimensionFromNonLinear(creativeNonLinear); // VAST version < 4.0 tmpOptions.staticResource = player.getStaticResourceFromNonLinear(creativeNonLinear); tmpOptions.creativeType = player.getCreativeTypeFromStaticResources(creativeNonLinear); tmpOptions.adParameters = player.getAdParametersFromLinear(creativeNonLinear); if (tmpOptions.adParameters) { tmpOptions.vpaid = true; } } } //Extract the Ad data if it is actually the Ad (!wrapper) if (!player.hasVastAdTagUri(xmlResponse) && player.hasInLine(xmlResponse)) { if (typeof tmpOptions.mediaFileList !== 'undefined' || typeof tmpOptions.staticResource !== 'undefined') { callBack(true, tmpOptions); } else { callBack(false); } } } else { callBack(false); } }, /** * Parse the VAST Tag * * @param vastTag * @param adListId */ processVastWithRetries: function (vastObj) { var player = this; var vastTag = vastObj.vastTag; var adListId = vastObj.id; var handleVastResult = function (pass, tmpOptions) { if (pass && typeof tmpOptions !== 'undefined' && tmpOptions.vpaid && !player.displayOptions.vastOptions.allowVPAID) { pass = false; player.announceLocalError('103', 'VPAID not allowed, so skipping this VAST tag.') } if (pass) { // ok if (tmpOptions.adType === 'linear') { if ((typeof tmpOptions.iconClick !== 'undefined') && (tmpOptions.iconClick !== null) && tmpOptions.iconClick.length) { player.adList[adListId].landingPage = tmpOptions.iconClick; } var selectedMediaFile = player.getSupportedMediaFileObject(tmpOptions.mediaFileList); if (selectedMediaFile) { player.adList[adListId].mediaType = selectedMediaFile.mediaType; } } player.adList[adListId].adType = tmpOptions.adType ? tmpOptions.adType : 'unknown'; player.adList[adListId].vastLoaded = true; player.adPool[adListId] = Object.assign({}, tmpOptions); var event = document.createEvent('Event'); event.initEvent('adId_' + adListId, false, true); document.getElementById(player.videoPlayerId).dispatchEvent(event); player.displayOptions.vastOptions.vastAdvanced.vastLoadedCallback(); if (player.hasTitle()) { var title = document.getElementById(player.videoPlayerId + '_title'); title.style.display = 'none'; } } else { // when vast failed player.reportError('101'); if (vastObj.hasOwnProperty('fallbackVastTags') && vastObj.fallbackVastTags.length > 0) { vastTag = vastObj.fallbackVastTags.shift(); player.processUrl(vastTag, handleVastResult); } else { if (vastObj.roll === 'preRoll') { player.preRollFail(vastObj); } player.adList[adListId].error = true; } } }; player.processUrl(vastTag, handleVastResult); }, processUrl: function (vastTag, callBack) { var player = this; var numberOfRedirects = 0; //var adListId = adListId; var tmpOptions = { tracking: [], stopTracking: [], impression: [], clicktracking: [], vastLoaded: false }; player.resolveVastTag( vastTag, numberOfRedirects, tmpOptions, callBack ); }, resolveVastTag: function (vastTag, numberOfRedirects, tmpOptions, callBack) { var player = this; if (!vastTag || vastTag == '') { callBack(false); return; } var handleXmlHttpReq = function () { var xmlHttpReq = this; if (xmlHttpReq.readyState === 4 && xmlHttpReq.status === 404) { callBack(false); return; } if (xmlHttpReq.readyState === 4 && xmlHttpReq.status === 0) { callBack(false); //Most likely that Ad Blocker exists return; } if (!((xmlHttpReq.readyState === 4) && (xmlHttpReq.status === 200))) { return; } if ((xmlHttpReq.readyState === 4) && (xmlHttpReq.status !== 200)) { callBack(false); return; } try { var xmlResponse = xmlHttpReq.responseXML; } catch (e) { callBack(false); return; } if (!xmlResponse) { callBack(false); return; } player.inLineFound = player.hasInLine(xmlResponse); if (!player.inLineFound && player.hasVastAdTagUri(xmlResponse)) { var vastAdTagUri = player.getVastAdTagUriFromWrapper(xmlResponse); if (vastAdTagUri) { player.resolveVastTag(vastAdTagUri, numberOfRedirects, tmpOptions, callBack); } else { callBack(false); return; } } if (numberOfRedirects > player.displayOptions.vastOptions.maxAllowedVastTagRedirects && !player.inLineFound) { callBack(false); return; } player.processVastXml(xmlResponse, tmpOptions, callBack); }; if (numberOfRedirects <= player.displayOptions.vastOptions.maxAllowedVastTagRedirects) { player.sendRequest( vastTag, true, player.displayOptions.vastOptions.vastTimeout, handleXmlHttpReq ); } numberOfRedirects++; }, /** * Helper function to stop processing * * @param adListId */ reportError: function (errorCode) { var player = this; player.announceLocalError(errorCode); }, backupMainVideoContentTime: function (adListId) { var player = this; var videoPlayerTag = document.getElementById(player.videoPlayerId); var roll = player.adList[adListId].roll; //spec configs by roll switch (roll) { case 'midRoll': videoPlayerTag.mainVideoCurrentTime = videoPlayerTag.currentTime - 1; break; case 'postRoll': videoPlayerTag.mainVideoCurrentTime = player.mainVideoDuration; player.autoplayAfterAd = false; videoPlayerTag.currentTime = player.mainVideoDuration; break; case 'preRoll': if (videoPlayerTag.currentTime > 0) { videoPlayerTag.mainVideoCurrentTime = videoPlayerTag.currentTime - 1; } break; } }, checkVPAIDInterface: function(vpaidAdUnit) { var VPAIDCreative = vpaidAdUnit; // checks if all the mandatory params present if ( VPAIDCreative.handshakeVersion && typeof VPAIDCreative.handshakeVersion == "function" && VPAIDCreative.initAd && typeof VPAIDCreative.initAd == "function" && VPAIDCreative.startAd && typeof VPAIDCreative.startAd == "function" && VPAIDCreative.stopAd && typeof VPAIDCreative.stopAd == "function" && VPAIDCreative.skipAd && typeof VPAIDCreative.skipAd == "function" && VPAIDCreative.resizeAd && typeof VPAIDCreative.resizeAd == "function" && VPAIDCreative.pauseAd && typeof VPAIDCreative.pauseAd == "function" && VPAIDCreative.resumeAd && typeof VPAIDCreative.resumeAd == "function" && VPAIDCreative.expandAd && typeof VPAIDCreative.expandAd == "function" && VPAIDCreative.collapseAd && typeof VPAIDCreative.collapseAd == "function" && VPAIDCreative.subscribe && typeof VPAIDCreative.subscribe == "function" && VPAIDCreative.unsubscribe && typeof VPAIDCreative.unsubscribe == "function" ) { return true; } return false; }, debugMessage: function (msg) { var player = this; if (player.displayOptions.debug) { console.log(msg); } }, // Callback for AdPaused onVpaidAdPaused: function() { var player = this; player.vpaidTimeoutTimerClear(); player.debugMessage("onAdPaused"); }, // Callback for AdPlaying onVpaidAdPlaying: function() { var player = this; player.vpaidTimeoutTimerClear(); player.debugMessage("onAdPlaying"); }, // Callback for AdError onVpaidAdError: function(message) { var player = this; player.debugMessage("onAdError: " + message); player.vpaidTimeoutTimerClear(); player.onVpaidEnded(); }, // Callback for AdLog onVpaidAdLog: function(message) { var player = this; player.debugMessage("onAdLog: " + message); }, // Callback for AdUserAcceptInvitation onVpaidAdUserAcceptInvitation: function() { var player = this; player.debugMessage("onAdUserAcceptInvitation"); }, // Callback for AdUserMinimize onVpaidAdUserMinimize: function() { var player = this; player.debugMessage("onAdUserMinimize"); }, // Callback for AdUserClose onVpaidAdUserClose: function() { var player = this; player.debugMessage("onAdUserClose"); }, // Callback for AdUserClose onVpaidAdSkippableStateChange: function() { var player = this; if (!player.vpaidAdUnit) { return; } player.debugMessage("Ad Skippable State Changed to: " + player.vpaidAdUnit.getAdSkippableState()); }, // Callback for AdUserClose onVpaidAdExpandedChange: function() { var player = this; if (!player.vpaidAdUnit) { return; } player.debugMessage("Ad Expanded Changed to: " + player.vpaidAdUnit.getAdExpanded()); }, // Pass through for getAdExpanded getVpaidAdExpanded: function() { var player = this; player.debugMessage("getAdExpanded"); if (!player.vpaidAdUnit) { return; } return player.vpaidAdUnit.getAdExpanded(); }, // Pass through for getAdSkippableState getVpaidAdSkippableState: function() { var player = this; player.debugMessage("getAdSkippableState"); if (!player.vpaidAdUnit) { return; } return player.vpaidAdUnit.getAdSkippableState(); }, // Callback for AdSizeChange onVpaidAdSizeChange: function() { var player = this; if (!player.vpaidAdUnit) { return; } player.debugMessage("Ad size changed to: w=" + player.vpaidAdUnit.getAdWidth() + " h=" + player.vpaidAdUnit.getAdHeight()); }, // Callback for AdDurationChange onVpaidAdDurationChange: function() { var player = this; if (!player.vpaidAdUnit) { return; } player.debugMessage("Ad Duration Changed to: " + player.vpaidAdUnit.getAdDuration()); }, // Callback for AdRemainingTimeChange onVpaidAdRemainingTimeChange: function() { var player = this; if (!player.vpaidAdUnit) { return; } player.debugMessage("Ad Remaining Time Changed to: " + player.vpaidAdUnit.getAdRemainingTime()); }, // Pass through for getAdRemainingTime getVpaidAdRemainingTime: function() { var player = this; player.debugMessage("getAdRemainingTime"); if (!player.vpaidAdUnit) { return; } return player.vpaidAdUnit.getAdRemainingTime(); }, // Callback for AdImpression onVpaidAdImpression: function() { var player = this; player.debugMessage("Ad Impression"); //Announce the impressions player.trackSingleEvent('impression'); }, // Callback for AdClickThru onVpaidAdClickThru: function(url, id, playerHandles) { var player = this; player.debugMessage("Clickthrough portion of the ad was clicked"); // if playerHandles flag is set to true // then player need to open click thorough url in new window if (playerHandles) { window.open(player.vastOptions.clickthroughUrl); } player.pauseVpaidAd(); // fire click tracking player.callUris(player.vastOptions.clicktracking); }, // Callback for AdInteraction onVpaidAdInteraction: function(id) { var player = this; player.debugMessage("A non-clickthrough event has occured"); }, // Callback for AdVideoStart onVpaidAdVideoStart: function() { var player = this; player.debugMessage("Video 0% completed"); player.trackSingleEvent('start'); }, // Callback for AdUserClose onVpaidAdVideoFirstQuartile: function() { var player = this; player.debugMessage("Video 25% completed"); player.trackSingleEvent('firstQuartile'); }, // Callback for AdUserClose onVpaidAdVideoMidpoint: function() { var player = this; player.debugMessage("Video 50% completed"); player.trackSingleEvent('midpoint'); }, // Callback for AdUserClose onVpaidAdVideoThirdQuartile: function() { var player = this; player.debugMessage("Video 75% completed"); player.trackSingleEvent('thirdQuartile'); }, // Callback for AdVideoComplete onVpaidAdVideoComplete: function() { var player = this; player.debugMessage("Video 100% completed"); player.trackSingleEvent('complete'); }, // Callback for AdLinearChange onVpaidAdLinearChange: function() { var player = this; var videoPlayerTag = document.getElementById(player.videoPlayerId); var vpaidNonLinearSlot = document.getElementsByClassName("fluid_vpaidNonLinear_ad")[0]; var closeBtn = document.getElementById('close_button_' + player.videoPlayerId); var adListId = vpaidNonLinearSlot.getAttribute('adlistid'); player.debugMessage("Ad linear has changed: " + player.vpaidAdUnit.getAdLinear()); if (player.vpaidAdUnit.getAdLinear()) { player.backupMainVideoContentTime(adListId); player.isCurrentlyPlayingAd = true; if (closeBtn) { closeBtn.remove(); } vpaidNonLinearSlot.className = 'fluid_vpaid_slot'; vpaidNonLinearSlot.id = player.videoPlayerId +"_fluid_vpaid_slot"; videoPlayerTag.loop = false; videoPlayerTag.removeAttribute('controls'); //Remove the default Controls var progressbarContainer = videoPlayerTag.parentNode.getElementsByClassName('fluid_controls_currentprogress'); for (var i = 0; i < progressbarContainer.length; i++) { progressbarContainer[i].style.backgroundColor = player.displayOptions.layoutControls.adProgressColor; } player.toggleLoader(false); } }, // Pass through for getAdLinear getVpaidAdLinear: function() { var player = this; player.debugMessage("getAdLinear"); return player.vpaidAdUnit.getAdLinear(); }, // Pass through for startAd() startVpaidAd: function() { var player = this; player.debugMessage("startAd"); player.vpaidTimeoutTimerStart(); player.vpaidAdUnit.startAd(); }, // Callback for AdLoaded onVpaidAdLoaded: function() { var player = this; player.debugMessage("ad has been loaded"); // start the video play as vpaid is loaded successfully player.vpaidTimeoutTimerClear(); player.startVpaidAd(); }, // Callback for StartAd() onStartVpaidAd: function() { var player = this; player.debugMessage("Ad has started"); player.vpaidTimeoutTimerClear(); }, // Pass through for stopAd() stopVpaidAd: function() { var player = this; player.vpaidTimeoutTimerStart(); player.vpaidAdUnit.stopAd(); }, // Hard Pass through for stopAd() excluding deleteOtherVpaidAdsApart hardStopVpaidAd: function(deleteOtherVpaidAdsApart) { // this is hard stop of vpaid ads // we delete all the vpaid assets so the new one can be loaded // delete all assets apart from the ad from deleteOtherVpaidAdsApart var player = this; if (player.vpaidAdUnit) { player.vpaidAdUnit.stopAd(); player.vpaidAdUnit = null; } var vpaidIframes = document.getElementsByClassName("fluid_vpaid_iframe"); var vpaidSlots = document.getElementsByClassName("fluid_vpaid_slot"); var vpaidNonLinearSlots = document.getElementsByClassName("fluid_vpaidNonLinear_ad"); for (var i = 0; i< vpaidIframes.length; i++){ if (vpaidIframes[i].getAttribute('adListId') !== deleteOtherVpaidAdsApart) { vpaidIframes[i].remove(); } } for (var j = 0; j< vpaidSlots.length; j++){ if (vpaidSlots[j].getAttribute('adListId') !== deleteOtherVpaidAdsApart) { vpaidSlots[j].remove(); } } for (var k = 0; k< vpaidNonLinearSlots.length; k++){ if (vpaidNonLinearSlots[k].getAttribute('adListId') !== deleteOtherVpaidAdsApart) { vpaidNonLinearSlots[k].remove(); } } }, // Callback for AdUserClose onStopVpaidAd: function() { var player = this; player.debugMessage("Ad has stopped"); player.vpaidTimeoutTimerClear(); player.onVpaidEnded(); }, // Callback for AdUserClose onSkipVpaidAd: function() { var player = this; player.debugMessage("Ad was skipped"); player.vpaidTimeoutTimerClear(); player.onVpaidEnded(); }, // Passthrough for skipAd skipVpaidAd: function() { var player = this; player.vpaidTimeoutTimerStart(); if (!player.vpaidAdUnit) { return; } player.vpaidAdUnit.skipAd(); }, // Passthrough for setAdVolume setVpaidAdVolume: function(val) { var player = this; if (!player.vpaidAdUnit) { return; } player.vpaidAdUnit.setAdVolume(val); }, // Passthrough for getAdVolume getVpaidAdVolume: function() { var player = this; if (!player.vpaidAdUnit) { return; } return player.vpaidAdUnit.getAdVolume(); }, // Callback for AdVolumeChange onVpaidAdVolumeChange: function() { var player = this; if (!player.vpaidAdUnit) { return; } player.debugMessage("Ad Volume has changed to - " + player.vpaidAdUnit.getAdVolume()); }, resizeVpaidAuto: function () { var player = this; if (player.vastOptions !== null && player.vastOptions.vpaid && player.vastOptions.linear) { var adWidth = videoPlayer.offsetWidth; var adHeight = videoPlayer.offsetHeight; var mode = (player.fullscreenMode ? 'fullscreen' : 'normal'); this.resizeVpaidAd(adWidth, adHeight, mode); } }, //Passthrough for resizeAd resizeVpaidAd: function(width, height, viewMode) { var player = this; if (!player.vpaidAdUnit) { return; } player.vpaidAdUnit.resizeAd(width, height, viewMode); }, // Passthrough for pauseAd() pauseVpaidAd: function() { var player = this; player.vpaidTimeoutTimerStart(); if (!player.vpaidAdUnit) { return; } player.vpaidAdUnit.pauseAd(); }, // Passthrough for resumeAd() resumeVpaidAd: function() { var player = this; player.vpaidTimeoutTimerStart(); if (!player.vpaidAdUnit) { return; } player.vpaidAdUnit.resumeAd(); }, //Passthrough for expandAd() expandVpaidAd: function() { var player = this; if (!player.vpaidAdUnit) { return; } player.vpaidAdUnit.expandAd(); }, //Passthrough for collapseAd() collapseVpaidAd: function() { var player = this; if (!player.vpaidAdUnit) { return; } player.vpaidAdUnit.collapseAd(); }, vpaidTimeoutTimerClear: function () { var player = this; if (player.vpaidTimer) { clearTimeout(player.vpaidTimer); } }, // placeholder for timer function vpaidTimeoutTimerStart: function () { var player = this; // clear previous timer if any player.vpaidTimeoutTimerClear(); player.vpaidTimer = setTimeout(function() { player.reportError('901'); player.onVpaidEnded(); },player.displayOptions.vastOptions.vpaidTimeout); }, vpaidCallbackListenersAttach: function() { var player = this; //The key of the object is the event name and the value is a reference to the callback function that is registered with the creative var callbacks = { AdStarted : player.onStartVpaidAd, AdStopped : player.onStopVpaidAd, AdSkipped : player.onSkipVpaidAd, AdLoaded : player.onVpaidAdLoaded, AdLinearChange : player.onVpaidAdLinearChange, AdSizeChange : player.onVpaidAdSizeChange, AdExpandedChange : player.onVpaidAdExpandedChange, AdSkippableStateChange : player.onVpaidAdSkippableStateChange, AdDurationChange : player.onVpaidAdDurationChange, AdRemainingTimeChange : player.onVpaidAdRemainingTimeChange, AdVolumeChange : player.onVpaidAdVolumeChange, AdImpression : player.onVpaidAdImpression, AdClickThru : player.onVpaidAdClickThru, AdInteraction : player.onVpaidAdInteraction, AdVideoStart : player.onVpaidAdVideoStart, AdVideoFirstQuartile : player.onVpaidAdVideoFirstQuartile, AdVideoMidpoint : player.onVpaidAdVideoMidpoint, AdVideoThirdQuartile : player.onVpaidAdVideoThirdQuartile, AdVideoComplete : player.onVpaidAdVideoComplete, AdUserAcceptInvitation : player.onVpaidAdUserAcceptInvitation, AdUserMinimize : player.onVpaidAdUserMinimize, AdUserClose : player.onVpaidAdUserClose, AdPaused : player.onVpaidAdPaused, AdPlaying : player.onVpaidAdPlaying, AdError : player.onVpaidAdError, AdLog : player.onVpaidAdLog }; // Looping through the object and registering each of the callbacks with the creative for ( var eventName in callbacks) { player.vpaidAdUnit.subscribe(callbacks[eventName], eventName, player); } }, loadVpaid: function (adListId, vpaidJsUrl) { var player = this; var videoPlayerTag = document.getElementById(player.videoPlayerId); var vpaidIframe = document.createElement('iframe'); vpaidIframe.id = player.videoPlayerId + "_" + adListId + "_fluid_vpaid_iframe"; vpaidIframe.className = 'fluid_vpaid_iframe'; vpaidIframe.setAttribute('adListId', adListId); vpaidIframe.setAttribute('frameborder', '0'); videoPlayerTag.parentNode.insertBefore(vpaidIframe, videoPlayerTag.nextSibling); vpaidIframe.contentWindow.document.write('