UNPKG

react-dfp

Version:

A React implementation of the google [DFP](https://developers.google.com/doubleclick-gpt/reference "GPT Reference") API. This package is inspired in the awesome library [jquery.dfp](https://github.com/coop182/jquery.dfp.js), and aims to provide its same e

481 lines (430 loc) 13.8 kB
import { EventEmitter } from 'events'; import * as Utils from './utils'; let loadPromise = null; let googleGPTScriptLoadPromise = null; let singleRequestEnabled = true; let disableInitialLoadEnabled = false; let lazyLoadEnabled = false; let lazyLoadConfig = null; let servePersonalizedAds = true; let serveCookies = true; const registeredSlots = {}; let managerAlreadyInitialized = false; const globalTargetingArguments = {}; const globalAdSenseAttributes = {}; let limitedAds = false; const DFPManager = Object.assign(new EventEmitter().setMaxListeners(0), { singleRequestIsEnabled() { return singleRequestEnabled; }, configureSingleRequest(value) { singleRequestEnabled = !!value; }, disableInitialLoadIsEnabled() { return disableInitialLoadEnabled; }, configureDisableInitialLoad(value) { disableInitialLoadEnabled = !!value; }, configureLazyLoad(enable = true, config = null) { let conf = null; if (config !== null && typeof config === 'object') { conf = { ...config }; } lazyLoadEnabled = !!enable; lazyLoadConfig = conf; }, lazyLoadIsEnabled() { return lazyLoadEnabled; }, limitedAdsIsEnabled() { return limitedAds; }, configureLimitedAds(value) { limitedAds = !!value; }, getLazyLoadConfig() { return lazyLoadConfig; }, getAdSenseAttribute(key) { return globalAdSenseAttributes[key]; }, configurePersonalizedAds(value) { servePersonalizedAds = value; }, configureCookieOption(value) { serveCookies = value; }, personalizedAdsEnabled() { return servePersonalizedAds; }, cookiesEnabled() { return serveCookies; }, setAdSenseAttribute(key, value) { this.setAdSenseAttributes({ [key]: value }); }, getAdSenseAttributes() { return { ...globalAdSenseAttributes }; }, setAdSenseAttributes(attrs) { Object.assign(globalAdSenseAttributes, attrs); if (managerAlreadyInitialized === true) { this.getGoogletag().then((googletag) => { googletag.cmd.push(() => { const pubadsService = googletag.pubads(); Object.keys(globalAdSenseAttributes).forEach( (key) => { pubadsService.set(key, globalTargetingArguments[key]); }, ); }); }); } }, setTargetingArguments(data) { Object.assign(globalTargetingArguments, data); const availableKeys = Object.keys(registeredSlots); availableKeys.forEach((slotId) => { registeredSlots[slotId].targetingArguments = data; }); if (managerAlreadyInitialized === true) { this.getGoogletag().then((googletag) => { googletag.cmd.push(() => { const pubadsService = googletag.pubads(); Object.keys(globalTargetingArguments).forEach((varName) => { if (pubadsService) { pubadsService.setTargeting(varName, globalTargetingArguments[varName]); } }); }); }); } }, getTargetingArguments() { return { ...globalTargetingArguments }; }, getSlotProperty(slotId, propName) { const slot = this.getRegisteredSlots()[slotId]; let ret = null; if (slot !== undefined) { ret = slot[propName] || ret; } return ret; }, getSlotTargetingArguments(slotId) { const propValue = this.getSlotProperty(slotId, 'targetingArguments'); return propValue ? { ...propValue } : null; }, getSlotAdSenseAttributes(slotId) { const propValue = this.getSlotProperty(slotId, 'adSenseAttributes'); return propValue ? { ...propValue } : null; }, init() { if (managerAlreadyInitialized === false) { managerAlreadyInitialized = true; this.getGoogletag().then((googletag) => { googletag.cmd.push(() => { const pubadsService = googletag.pubads(); pubadsService.addEventListener('slotRenderEnded', (event) => { const slotId = event.slot.getSlotElementId(); this.emit('slotRenderEnded', { slotId, event }); }); pubadsService.addEventListener('impressionViewable', (event) => { const slotId = event.slot.getSlotElementId(); this.emit('impressionViewable', { slotId, event }); }); pubadsService.addEventListener('slotVisibilityChanged', (event) => { const slotId = event.slot.getSlotElementId(); this.emit('slotVisibilityChanged', { slotId, event }); }); pubadsService.setRequestNonPersonalizedAds( this.personalizedAdsEnabled() ? 0 : 1, ); pubadsService.setCookieOptions( this.cookiesEnabled() ? 0 : 1, ); }); }); } }, getGoogletag() { if (googleGPTScriptLoadPromise === null) { googleGPTScriptLoadPromise = Utils.loadGPTScript(limitedAds); } return googleGPTScriptLoadPromise; }, setCollapseEmptyDivs(collapse) { this.collapseEmptyDivs = collapse; }, load(...slots) { if (loadPromise === null) { loadPromise = this.doLoad(...slots); } else { loadPromise = loadPromise.then( () => this.doLoad(...slots), ); } }, doLoad(...slots) { this.init(); let availableSlots = {}; if (slots.length > 0) { availableSlots = slots.filter( slotId => Object.prototype.hasOwnProperty.call(registeredSlots, slotId), ); } else { availableSlots = Object.keys(registeredSlots); } availableSlots = availableSlots.filter( id => !registeredSlots[id].loading && !registeredSlots[id].gptSlot, ); availableSlots.forEach((slotId) => { registeredSlots[slotId].loading = true; }); return this.gptLoadAds(availableSlots); }, gptLoadAds(slotsToInitialize) { return new Promise((resolve) => { this.getGoogletag().then((googletag) => { this.configureInitialOptions(googletag); slotsToInitialize.forEach((currentSlotId) => { registeredSlots[currentSlotId].loading = false; googletag.cmd.push(() => { const slot = registeredSlots[currentSlotId]; let gptSlot; const adUnit = `${slot.dfpNetworkId}/${slot.adUnit}`; if (slot.renderOutOfThePage === true) { gptSlot = googletag.defineOutOfPageSlot(adUnit, currentSlotId); } else { gptSlot = googletag.defineSlot(adUnit, slot.sizes, currentSlotId); } if (gptSlot !== null) { slot.gptSlot = gptSlot; const slotTargetingArguments = this.getSlotTargetingArguments(currentSlotId); if (slotTargetingArguments !== null) { Object.keys(slotTargetingArguments).forEach((varName) => { if (slot && slot.gptSlot) { slot.gptSlot.setTargeting(varName, slotTargetingArguments[varName]); } }); } const slotAdSenseAttributes = this.getSlotAdSenseAttributes(currentSlotId); if (slotAdSenseAttributes !== null) { Object.keys(slotAdSenseAttributes).forEach((varName) => { slot.gptSlot.set(varName, slotAdSenseAttributes[varName]); }); } slot.gptSlot.addService(googletag.pubads()); if (slot.sizeMapping) { let smbuilder = googletag.sizeMapping(); slot.sizeMapping.forEach((mapping) => { smbuilder = smbuilder.addSize(mapping.viewport, mapping.sizes); }); slot.gptSlot.defineSizeMapping(smbuilder.build()); } } }); }); this.configureOptions(googletag); googletag.cmd.push(() => { googletag.enableServices(); slotsToInitialize.forEach((theSlotId) => { googletag.display(theSlotId); }); resolve(); }); }); }); }, // configure those gpt parameters that need to be set before pubsads service // initialization. configureInitialOptions(googletag) { googletag.cmd.push(() => { if (this.disableInitialLoadIsEnabled()) { googletag.pubads().disableInitialLoad(); } }); }, configureOptions(googletag) { googletag.cmd.push(() => { const pubadsService = googletag.pubads(); pubadsService.setRequestNonPersonalizedAds( this.personalizedAdsEnabled() ? 0 : 1, ); pubadsService.setCookieOptions( this.cookiesEnabled() ? 0 : 1, ); const targetingArguments = this.getTargetingArguments(); // set global targetting arguments Object.keys(targetingArguments).forEach((varName) => { if (pubadsService) { pubadsService.setTargeting(varName, targetingArguments[varName]); } }); // set global adSense attributes const adSenseAttributes = this.getAdSenseAttributes(); Object.keys(adSenseAttributes).forEach((key) => { pubadsService.set(key, adSenseAttributes[key]); }); if (this.lazyLoadIsEnabled()) { const config = this.getLazyLoadConfig(); if (config) { pubadsService.enableLazyLoad(config); } else { pubadsService.enableLazyLoad(); } } if (this.singleRequestIsEnabled()) { pubadsService.enableSingleRequest(); } if (this.collapseEmptyDivs === true || this.collapseEmptyDivs === false) { pubadsService.collapseEmptyDivs(this.collapseEmptyDivs); } }); }, getRefreshableSlots(...slotsArray) { const slots = {}; if (slotsArray.length === 0) { const slotsToRefresh = Object.keys(registeredSlots) .map(k => registeredSlots[k]); return slotsToRefresh.reduce((last, slot) => { if (slot.slotShouldRefresh() === true) { slots[slot.slotId] = slot; } return slots; }, slots); } return slotsArray.reduce((last, slotId) => { const slot = registeredSlots[slotId]; if (typeof slot !== 'undefined') { slots[slotId] = slot; } return slots; }, slots); }, refresh(...slots) { if (loadPromise === null) { this.load(); } else { loadPromise.then(() => { this.gptRefreshAds( Object.keys( this.getRefreshableSlots(...slots), ), ); }); } }, gptRefreshAds(slots) { return this.getGoogletag().then((googletag) => { this.configureOptions(googletag); googletag.cmd.push(() => { const pubadsService = googletag.pubads(); const slotsToRefreshArray = slots.map(slotId => registeredSlots[slotId].slotId); pubadsService.refresh(slotsToRefreshArray); }); }); }, reload(...slots) { return this.destroyGPTSlots(...slots).then(() => this.load()); }, destroyGPTSlots(...slotsToDestroy) { if (slotsToDestroy.length === 0) { // eslint-disable-next-line no-param-reassign slotsToDestroy = Object.keys(registeredSlots); } return new Promise((resolve) => { const slots = []; // eslint-disable-next-line guard-for-in,no-restricted-syntax for (const idx in slotsToDestroy) { const slotId = slotsToDestroy[idx]; const slot = registeredSlots[slotId]; slots.push(slot); } this.getGoogletag() .then((googletag) => { googletag.cmd.push(() => { if (managerAlreadyInitialized === true) { if (slotsToDestroy.length > 0) { // eslint-disable-next-line guard-for-in,no-restricted-syntax for (const idx in slots) { const slot = slots[idx]; slots.push(slot.gptSlot); delete slot.gptSlot; } googletag.destroySlots(slots); } else { googletag.destroySlots(); } } resolve(slotsToDestroy); }); }); }); }, registerSlot({ slotId, dfpNetworkId, adUnit, sizes, renderOutOfThePage, sizeMapping, adSenseAttributes, targetingArguments, slotShouldRefresh, }, autoLoad = true) { if (!Object.prototype.hasOwnProperty.call(registeredSlots, slotId)) { registeredSlots[slotId] = { slotId, sizes, renderOutOfThePage, dfpNetworkId, adUnit, adSenseAttributes, targetingArguments, sizeMapping, slotShouldRefresh, loading: false, }; this.emit('slotRegistered', { slotId }); if (autoLoad === true && loadPromise !== null) { loadPromise = loadPromise.catch().then(() => { const slot = registeredSlots[slotId]; if (typeof slot !== 'undefined') { const { loading, gptSlot } = slot; if (loading === false && !gptSlot) { this.load(slotId); } } }); } } }, unregisterSlot({ slotId }) { this.destroyGPTSlots(slotId); delete registeredSlots[slotId]; }, getRegisteredSlots() { return registeredSlots; }, attachSlotRenderEnded(cb) { this.on('slotRenderEnded', cb); }, detachSlotRenderEnded(cb) { this.removeListener('slotRenderEnded', cb); }, attachSlotVisibilityChanged(cb) { this.on('slotVisibilityChanged', cb); }, detachSlotVisibilityChanged(cb) { this.removeListener('slotVisibilityChanged', cb); }, attachSlotIsViewable(cb) { this.on('impressionViewable', cb); }, detachSlotIsViewable(cb) { this.removeListener('impressionViewable', cb); }, }); export default DFPManager;