Created
March 13, 2019 15:52
-
-
Save betancourtl/0ea4e94c28eaf0d6d78087381e9b2558 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* jshint latedef:false */ | |
/* global googletag */ | |
/*! | |
* jQuery DFP v2.4.2 | |
* http://github.com/coop182/jquery.dfp.js | |
* | |
* Copyright 2016 Matt Cooper | |
* Released under the MIT license | |
*/ | |
/* | |
* Modified for our own purposes | |
*/ | |
import latencyUtil from '../util/latency'; | |
var | |
// Save Scope | |
dfpScript = this || {}; | |
var | |
// DFP account ID | |
dfpID = '', | |
// Init counters | |
count = 0, | |
rendered = 0, | |
// Default DFP selector | |
dfpSelector = '.adunit', | |
adsCouldNeverBeInitilized = false, | |
eventListenersAdded = false, | |
// Keep track of if we've already tried to load gpt.js before | |
dfpIsLoaded = false, | |
// Store adunit on div as: | |
storeAs = 'googleAdUnit', | |
/** | |
* Init function sets required params and loads Google's DFP script | |
* @param String id The DFP account ID | |
* @param String selector The adunit selector | |
* @param Object options Custom options to apply | |
*/ | |
init = function (id, selector, options, dfpAds) { | |
var $adCollection; | |
// Reset counters on each call | |
count = 0; | |
rendered = 0; | |
dfpID = id; | |
$adCollection = $(selector); | |
/** | |
* @returns {boolean} | |
*/ | |
dfpScript.shouldCheckForAdBlockers = function () { | |
return options ? typeof options.afterAdBlocked === 'function' : false; | |
}; | |
// explicitly wait for loader to be completed, otherwise the googletag might not be available | |
dfpLoader(options, $adCollection).then(function () { | |
options = setOptions(options); | |
dfpScript.dfpOptions = options; | |
createAds(options, $adCollection, dfpAds); | |
displayAds(options, $adCollection); | |
}); | |
}, | |
/** | |
* Set the options for DFP | |
* @param Object options Custom options to apply | |
* @return Object extended options | |
*/ | |
setOptions = function (options) { | |
// Set default options | |
var dfpOptions = { | |
setTargeting: {}, | |
setCategoryExclusion: '', | |
setLocation: '', | |
enableSingleRequest: true, | |
collapseEmptyDivs: 'original', | |
refreshExisting: true, | |
disablePublisherConsole: false, | |
disableInitialLoad: false, | |
setCentering: false, | |
newPage: false, | |
noFetch: false, | |
namespace: undefined, | |
sizeMapping: {} | |
}; | |
if (typeof options.setUrlTargeting === 'undefined' || options.setUrlTargeting) { | |
// Get URL Targeting | |
var urlTargeting = getUrlTargeting(options.url); | |
$.extend(true, dfpOptions.setTargeting, { | |
UrlHost: urlTargeting.Host, | |
UrlPath: urlTargeting.Path, | |
UrlQuery: urlTargeting.Query | |
}); | |
} | |
// Merge options objects | |
$.extend(true, dfpOptions, options); | |
// If a custom googletag is specified, use it. | |
if (dfpOptions.googletag) { | |
window.googletag.cmd.push(function () { | |
$.extend(true, window.googletag, dfpOptions.googletag); | |
}); | |
} | |
return dfpOptions; | |
}, | |
/** | |
* Find and create all Ads | |
* @param Object dfpOptions options related to ad instantiation | |
* @param jQuery $adCollection collection of ads | |
* @return Array an array of ad units that have been created. | |
*/ | |
createAds = function (dfpOptions, $adCollection, dfpAds) { | |
var googletag = window.googletag; | |
// Loops through on page Ad units and gets ads for them. | |
if (dfpOptions.newPage) googletag.destroySlots(); | |
$adCollection.each(function (i) { | |
var $adUnit = $(this); | |
let thisDfpAd = dfpAds[i]; | |
count++; | |
// adUnit name | |
var slotName = thisDfpAd[0]; | |
// adUnit id - this will use an existing id | |
var adUnitID = thisDfpAd[2]; | |
// get dimensions of the adUnit | |
var dimensions = thisDfpAd[1]; | |
// wipe html clean ready for ad and set the default display class. | |
// $adUnit.data('existingContent', $adUnit.html()); | |
// $adUnit.html('').addClass('displayAd-none'); | |
// Push commands to DFP to create ads | |
googletag.cmd.push(function () { | |
if (dfpOptions.newPage) { | |
$adUnit.removeData(storeAs); | |
$adUnit.html(''); | |
} | |
var googleAdUnit, | |
$adUnitData = $adUnit.data(storeAs); | |
if ($adUnitData) { | |
// Get existing ad unit | |
googleAdUnit = $adUnitData; | |
} else { | |
// Create the ad - out of page or normal | |
if (dimensions[0] === false) { | |
googleAdUnit = googletag.defineOutOfPageSlot(slotName, adUnitID); | |
} else { | |
googleAdUnit = googletag.defineSlot(slotName, dimensions, adUnitID); | |
if ($adUnit.data('companion')) { | |
googleAdUnit = googleAdUnit.addService(googletag.companionAds()); | |
} | |
} | |
googleAdUnit = googleAdUnit.addService(googletag.pubads()); | |
} | |
// Sets custom targeting for just THIS ad unit if it has been specified | |
var targeting = thisDfpAd[3];//$adUnit.data('targeting'); | |
if (targeting) { | |
$.each(targeting, function (k, v) { | |
googleAdUnit.setTargeting(k, v); | |
}); | |
} | |
// Store googleAdUnit reference | |
$adUnit.data(storeAs, googleAdUnit); | |
}); | |
}); | |
// Push DFP config options | |
googletag.cmd.push(function () { | |
var pubadsService = googletag.pubads(); | |
if (dfpOptions.enableSingleRequest) pubadsService.enableSingleRequest(); | |
$.each(dfpOptions.setTargeting, function (k, v) { | |
pubadsService.setTargeting(k, v); | |
}); | |
// var setLocation = dfpOptions.setLocation; | |
// if (typeof setLocation === 'object') { | |
// if (typeof setLocation.latitude === 'number' && typeof setLocation.longitude === 'number' && | |
// typeof setLocation.precision === 'number') { | |
// pubadsService.setLocation(setLocation.latitude, setLocation.longitude, setLocation.precision); | |
// } else if (typeof setLocation.latitude === 'number' && typeof setLocation.longitude === 'number') { | |
// pubadsService.setLocation(setLocation.latitude, setLocation.longitude); | |
// } | |
// } | |
// $.each(exclusionsGroup, function (k, v) { | |
// valueTrimmed = $.trim(v); | |
// if (valueTrimmed.length > 0) { | |
// pubadsService.setCategoryExclusion(valueTrimmed); | |
// } | |
// }); | |
// if (dfpOptions.collapseEmptyDivs) pubadsService.collapseEmptyDivs(); | |
// if (dfpOptions.disablePublisherConsole) pubadsService.disablePublisherConsole(); | |
if (dfpOptions.companionAds) { | |
googletag.companionAds().setRefreshUnfilledSlots(true); | |
if (!dfpOptions.disableInitialLoad) { | |
pubadsService.enableVideoAds(); | |
} | |
} | |
if (dfpOptions.disableInitialLoad) { | |
pubadsService.disableInitialLoad(); | |
} | |
if (dfpOptions.noFetch) { | |
pubadsService.noFetch(); | |
} | |
// if (dfpOptions.setCentering) pubadsService.setCentering(true); | |
// Setup event listener to listen for renderEnded event and fire callbacks. | |
if (!eventListenersAdded) { | |
pubadsService.addEventListener('slotRenderEnded', function (event) { | |
rendered++; | |
var $adUnit = $('#' + event.slot.getSlotId().getDomId()); | |
var display = event.isEmpty ? 'none' : 'block'; | |
$adUnit.removeClass('displayAd-none').addClass('displayAd-' + display); | |
dfpOptions.afterEachAdLoaded.call(this, $adUnit, event); | |
if (rendered === count) { | |
dfpOptions.afterAllAdsLoaded.call(this, $adCollection); | |
} | |
}); | |
pubadsService.addEventListener('impressionViewable', function (e) { | |
dfpOptions.checkLatency(e.slot.getSlotElementId() + " viewable"); | |
}); | |
pubadsService.addEventListener('slotOnload', function (e) { | |
dfpOptions.checkLatency(e.slot.getSlotElementId() + " creative loaded"); | |
}); | |
eventListenersAdded = true; | |
} | |
// this will work with AdblockPlus | |
if (dfpScript.shouldCheckForAdBlockers() && !googletag._adBlocked_) { | |
setTimeout(function () { | |
var slots = pubadsService.getSlots ? pubadsService.getSlots() : []; | |
if (slots.length > 0) { | |
$.get(slots[0].getContentUrl()).always(function (r) { | |
if (r.status !== 200) { | |
$.each(slots, function () { | |
var $adUnit = $('#' + this.getSlotId().getDomId()); | |
dfpOptions.afterAdBlocked.call(dfpScript, $adUnit, this); | |
}); | |
} | |
}); | |
} | |
}, 0); | |
} | |
googletag.enableServices(); | |
}); | |
}, | |
/** | |
* Display all created Ads | |
* @param {Object} dfpOptions options related to ad instantiation | |
* @param {jQuery} $adCollection collection of ads | |
*/ | |
displayAds = function (dfpOptions, $adCollection) { | |
var googletag = window.googletag; | |
var pbjs = window.pbjs; | |
// Check if google adLoader can be loaded, this will work with AdBlock | |
if (dfpScript.shouldCheckForAdBlockers() && !googletag._adBlocked_) { | |
if (googletag.getVersion) { | |
var script = '//partner.googleadservices.com/gpt/pubads_impl_' + | |
googletag.getVersion() + '.js'; | |
$.getScript(script).always(function (r) { | |
if (r && r.statusText === 'error') { | |
$.each($adCollection, function () { | |
dfpOptions.afterAdBlocked.call(dfpScript, $(this)); | |
}); | |
} | |
}); | |
} | |
} | |
googletag.cmd.push(() => { | |
var refreshArray = []; | |
var ids = []; | |
$adCollection.each(function () { | |
var $adUnit = $(this), | |
$adUnitData = $adUnit.data(storeAs); | |
ids.push($adUnit.attr('id')); | |
if (googletag._adBlocked_) { | |
if (dfpScript.shouldCheckForAdBlockers()) { | |
dfpOptions.afterAdBlocked.call(dfpScript, $adUnit); | |
} | |
} | |
if (dfpOptions.refreshExisting && $adUnitData && $adUnit.hasClass('displayAd-block')) { | |
refreshArray.push($adUnitData); | |
} else { | |
googletag.cmd.push(function () { googletag.display($adUnit.attr('id')); }); | |
if (dfpOptions.disableInitialLoad) { | |
refreshArray.push($adUnitData); | |
} | |
} | |
}); | |
latencyUtil.log('DFP Ad Request', $adCollection.length, null, true); | |
const refreshAds = () => { | |
googletag.cmd.push(function () { | |
googletag.pubads().refresh(refreshArray, { changeCorrelator: false }); | |
}); | |
}; | |
if (refreshArray.length) { | |
// prebid slot targeting | |
googletag.cmd.push(function () { | |
pbjs.que.push(function () { | |
pbjs.setTargetingForGPTAsync(ids); | |
refreshAds(); | |
}); | |
}); | |
} | |
}); | |
}, | |
/** | |
* Create an array of paths so that we can target DFP ads to Page URI's | |
* @return Array an array of URL parts that can be targeted. | |
*/ | |
getUrlTargeting = function (url) { | |
// Get the url and parse it to its component parts using regex from RFC2396 Appendix-B (https://tools.ietf.org/html/rfc2396#appendix-B) | |
var urlMatches = (url || window.location.toString()).match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/); | |
var matchedAuthority = urlMatches[4] || ''; | |
var matchedPath = (urlMatches[5] || '').replace(/(.)\/$/, '$1'); | |
var matchedQuery = urlMatches[7] || ''; | |
// Get the query params for targeting against | |
var params = matchedQuery.replace(/\=/ig, ':').split('&'); | |
return { | |
Host: matchedAuthority, | |
Path: matchedPath, | |
Query: params | |
}; | |
}, | |
/** | |
* Get the dimensions of the ad unit using the container div dimensions or | |
* check for the optional attribute data-dimensions | |
* @param Object $adUnit The adunit to work with | |
* @return Array The dimensions of the adunit (width, height) | |
*/ | |
// getDimensions = function ($adUnit) { | |
// var dimensions = [], | |
// dimensionsData = $adUnit.data('dimensions'); | |
// // Check if data-dimensions are specified. If they aren't, use the dimensions of the ad unit div. | |
// if (dimensionsData) { | |
// var dimensionGroups = dimensionsData.split(','); | |
// $.each(dimensionGroups, function (k, v) { | |
// var dimensionSet = v.split('x'); | |
// dimensions.push([parseInt(dimensionSet[0], 10), parseInt(dimensionSet[1], 10)]); | |
// }); | |
// } else { | |
// dimensions.push([$adUnit.width(), $adUnit.height()]); | |
// } | |
// return dimensions; | |
// }, | |
/** | |
* Call the google DFP script - there is a little bit of error detection in here to detect | |
* if the dfp script has failed to load either through an error or it being blocked by an ad | |
* blocker... if it does not load we execute a dummy script to replace the real DFP. | |
* | |
* @param {Object} options | |
* @param {Array} $adCollection | |
*/ | |
dfpLoader = function (options, $adCollection) { | |
function execBlockEvents() { | |
if (dfpScript.shouldCheckForAdBlockers()) { | |
$.each($adCollection, function () { | |
options.afterAdBlocked.call(dfpScript, $(this)); | |
}); | |
} | |
} | |
// make sure we don't load gpt.js multiple times | |
dfpIsLoaded = dfpIsLoaded || $('script[src*="googletagservices.com/tag/js/gpt.js"]').length; | |
if (dfpIsLoaded) { | |
if (adsCouldNeverBeInitilized) { | |
execBlockEvents(); | |
} | |
return $.Deferred().resolve(); | |
} | |
var loaded = $.Deferred(); | |
window.googletag = window.googletag || {}; | |
window.googletag.cmd = window.googletag.cmd || []; | |
var gads = document.createElement('script'); | |
gads.async = true; | |
gads.type = 'text/javascript'; | |
// Adblock blocks the load of Ad scripts... so we check for that | |
gads.onerror = function () { | |
dfpBlocked(); | |
loaded.resolve(); | |
adsCouldNeverBeInitilized = true; | |
execBlockEvents(); | |
}; | |
gads.onload = function () { | |
// this will work with ghostery: | |
if (!googletag._loadStarted_) { | |
googletag._adBlocked_ = true; | |
execBlockEvents(); | |
} | |
loaded.resolve(); | |
}; | |
var useSSL = 'https:' === document.location.protocol; | |
gads.src = (useSSL ? 'https:' : 'http:') + | |
'//www.googletagservices.com/tag/js/gpt.js'; | |
var node = document.getElementsByTagName('script')[0]; | |
node.parentNode.insertBefore(gads, node); | |
// Adblock plus seems to hide blocked scripts... so we check for that | |
if (gads.style.display === 'none') { | |
dfpBlocked(); | |
} | |
return loaded; | |
}, | |
/** | |
* This function gets called if DFP has been blocked by an adblocker | |
* it implements a dummy version of the dfp object and allows the script to excute its callbacks | |
* regardless of whether DFP is actually loaded or not... it is basically only useful for situations | |
* where you are laying DFP over existing content and need to init things like slide shows after the loading | |
* is completed. | |
*/ | |
dfpBlocked = function () { | |
var googletag = window.googletag; | |
// Get the stored dfp commands | |
var commands = googletag.cmd; | |
var _defineSlot = function (name, dimensions, id) { | |
// Removed a mysterious, unused 4th argument - this is a reminder that it was there | |
googletag.ads.push(id); | |
googletag.ads[id] = { | |
renderEnded: function () { }, | |
addService: function () { return this; } | |
}; | |
return googletag.ads[id]; | |
}; | |
// overwrite the dfp object - replacing the command array with a function and defining missing functions | |
googletag = { | |
cmd: { | |
push: function (callback) { | |
callback.call(dfpScript); | |
} | |
}, | |
ads: [], | |
pubads: function () { return this; }, | |
noFetch: function () { return this; }, | |
disableInitialLoad: function () { return this; }, | |
disablePublisherConsole: function () { return this; }, | |
enableSingleRequest: function () { return this; }, | |
setTargeting: function () { return this; }, | |
collapseEmptyDivs: function () { return this; }, | |
enableServices: function () { return this; }, | |
defineSlot: function (name, dimensions, id) { | |
// return _defineSlot(name, dimensions, id, false); | |
return _defineSlot(name, dimensions, id); | |
}, | |
defineOutOfPageSlot: function (name, id) { | |
// return _defineSlot(name, [], id, true); | |
return _defineSlot(name, [], id); | |
}, | |
display: function (id) { | |
googletag.ads[id].renderEnded.call(dfpScript); | |
return this; | |
} | |
}; | |
// Execute any stored commands | |
$.each(commands, function (k, v) { | |
googletag.cmd.push(v); | |
}); | |
}; | |
/** | |
* Add function to the jQuery / Zepto namespace | |
* @param String id (Optional) The DFP account ID | |
* @param Object options (Optional) Custom options to apply | |
*/ | |
$.dfp = $.fn.dfp = function (dfpAds, id, options) { | |
options = options || {}; | |
if (id === undefined) { | |
id = dfpID; | |
} | |
if (typeof id === 'object') { | |
options = id; | |
id = options.dfpID || dfpID; | |
} | |
var selector = this; | |
if (typeof this === 'function') { | |
selector = dfpSelector; | |
} | |
init(id, selector, options, dfpAds); | |
return this; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment