UNPKG

@astro-eco/dynamic-ads

Version:

> This library helps to create ads placeholder and render ads dynamically in the DOM.

991 lines (866 loc) 32.6 kB
window.pbjs = window.pbjs || { cmd: [] }; window.googletag = window.googletag || { cmd: [] }; window.__ADS_CONFIG_ENDPOINT__ = window.__ADS_CONFIG_ENDPOINT__; window.__USERID__ = window.__USERID__; window.adSlots = []; window.__DA_CONFIG__ = { missedAds: [], ads: [], pageAds: [], global: {} } let adTargets = null; const TIMEOUT = 5000; const breakPointMobile = window.__BREAK_POINT_MOBILE__ || '600px'; const breakPointTablet = window.__BREAK_POINT_TABLET__ || '960px'; const FAILSAFE_TIMEOUT = 3500; const dynamicads = (() => { // Public Method const _init = async () => { const searchParams = new URLSearchParams(window.location.search); const disableDynamicAds = searchParams.get('disableDynamicAds'); const fallbackAds = searchParams.get('fallbackAds'); const enableDynamicAds = searchParams.get('enableDynamicAds'); if ((disableDynamicAds && disableDynamicAds === 'true') || (fallbackAds && fallbackAds ==='true')) { return; } const configEndpoint = __ADS_CONFIG_ENDPOINT__; if (!configEndpoint) return; const { ads, global } = await _getConfiguration(configEndpoint); if (global && global.disableDynamicAdsLibrary) { if(!enableDynamicAds) { return; } } if (!ads) { return; } if (ads && ads.length === 0) { return; } __DA_CONFIG__.ads = ads; __DA_CONFIG__.global = global; const pageAds = _getPageAds(); __DA_CONFIG__.pageAds = pageAds; _renderAds(); const dynamicAdsConsole = searchParams.get('dynamicAdsConsole'); if (dynamicAdsConsole && dynamicAdsConsole === 'true') { _openConsole(); } }; const _openConsole = () => { const consoleWrapper = _createElement('div'); consoleWrapper.id = 'ad-console-wrapper'; consoleWrapper.setAttribute('style', 'background: black; position: fixed; top: 10px; right: 10px; z-index: 9999; width: 25%; height: 500px; overflow: auto;'); const consoleBar = _createElement('div'); consoleBar.id = 'ad-console-wrapper-bar'; consoleBar.setAttribute('style', 'position: fixed; width: 24%;background: #cfcfcf;padding: 0 0 0 10px;color: #fff;display: flex;'); const consoleTitle = _createElement('div'); consoleTitle.id = 'ad-console-wrapper-title'; consoleTitle.innerHTML = 'Ad Console'; consoleTitle.setAttribute('style', 'flex: 1'); const consoleClose = _createElement('a'); consoleClose.id = 'ad-console-wrapper-close'; consoleClose.innerHTML = 'close'; consoleClose.setAttribute('style', 'flex: 1;text-align: end;cursor: pointer;flex-grow: 0;'); consoleClose.addEventListener('click', () =>{ const wrapper = document.getElementById('ad-console-wrapper') if (wrapper && wrapper.remove) { wrapper.remove(); } }); const consoleContent = _createElement('div'); consoleContent.id = 'ad-console-wrapper-content'; consoleContent.setAttribute('style', 'color: #cfcfcf; padding: 10px'); consoleBar.appendChild(consoleTitle); consoleBar.appendChild(consoleClose); consoleWrapper.appendChild(consoleBar); consoleWrapper.appendChild(consoleContent); document.body.appendChild(consoleWrapper); } const _insertElement = ( referenceNode, insertBefore, insertAfter, insertInside, adConfig, isOutOfPageSlot = false ) => { let elementInserted = false; if (!referenceNode || !adConfig) { return elementInserted; } const { beforeEl, afterEl, insideEl } = _createNewElement( adConfig, isOutOfPageSlot ); const parentElement = referenceNode.parentNode; const eleIndex = Array.prototype.indexOf.call( parentElement.children, referenceNode, ); if (insertBefore) { parentElement.insertBefore(beforeEl, parentElement.children[eleIndex]); elementInserted = true; } if (insertAfter) { parentElement.insertBefore( afterEl, parentElement.children[eleIndex].nextSibling, ); elementInserted = true; } if (insertInside) { referenceNode.appendChild(insideEl); elementInserted = true; } return elementInserted; }; const _createElement = type => document.createElement(type).cloneNode(true); const _getInterstitialWrapper = closeBtnTitle => { const interstitialWrapper = _createElement('div'); interstitialWrapper.id = 'interstitial-popup'; interstitialWrapper.classList.add(`interstitial-popup`); interstitialWrapper.setAttribute('style', 'display: none;'); const interstitialButton = _createElement('button'); interstitialButton.classList.add(`interstitial-button`); interstitialButton.innerHTML = closeBtnTitle || 'Close'; interstitialButton.onclick = () => { const interstitialAd = document.querySelector('.interstitial-popup'); if (interstitialAd && interstitialAd.remove) { interstitialAd.remove(); } }; interstitialWrapper.appendChild(interstitialButton); return interstitialWrapper; }; const _getOutOfPageElement = (divId, type) => { const ele = _createElement('div'); ele.id = divId; ele.classList.add(`ad-slot-oop`); ele.setAttribute('data-dynamic-ad', 'ADOOPSLOT'); ele.setAttribute('data-ad-type', type); return ele; }; const _createOutOfPageElement = adConfig => { const { divId, type, closeBtnTitle } = adConfig; let ele = null; if (type === 'interstitial') { ele = _getInterstitialWrapper(closeBtnTitle); const oopEle = _getOutOfPageElement(divId, type); ele.appendChild(oopEle); } else { ele = _getOutOfPageElement(divId, type); } const adContainer = _createAdContainer(); adContainer.setAttribute('data-dynamic-ad', 'ADCONTAINER'); adContainer.setAttribute('data-dynamic-ad-type', type); adContainer.appendChild(ele); document.body.appendChild(adContainer); return true; }; const _createNewElement = (adConfig, isOutOfPageSlot) => { const { containerStyles: adContainerStyles, divId, adsTitle } = adConfig; const { containerStyles, defaultAdsTitle } = __DA_CONFIG__.global; let styles = {}; if(!isOutOfPageSlot) { const { isMobileScreen, isTabletScreen, isDesktopScreen } = _getLayout(); const { desktop = {}, mobile = {}, tablet = {} } = adContainerStyles ? adContainerStyles : containerStyles; styles = { ...styles, ...(isMobileScreen && mobile), ...(isTabletScreen && tablet), ...(isDesktopScreen && desktop), }; } let adTitle = null; if(!isOutOfPageSlot) { adTitle = _createElement('div'); adTitle.classList.add(`ad-container-title`); adTitle.innerHTML = adsTitle ? adsTitle : defaultAdsTitle; } const beforeAdContainer = _createAdContainer(); beforeAdContainer.classList.add(`ad-container-before`); if (Object.keys(styles).length) { beforeAdContainer.setAttribute( 'style', Object.keys(styles) .map(key => `${key}:${styles[key]}`) .join(';'), ); } beforeAdContainer.setAttribute('data-dynamic-ad', 'ADCONTAINER'); const afterAdContainer = _createAdContainer(); afterAdContainer.classList.add(`ad-container-after`); if (Object.keys(styles).length) { afterAdContainer.setAttribute( 'style', Object.keys(styles) .map(key => `${key}:${styles[key]}`) .join(';'), ); } afterAdContainer.setAttribute('data-dynamic-ad', 'ADCONTAINER'); const insideAdContainer = _createAdContainer(); insideAdContainer.classList.add(`ad-container-inside`); if (Object.keys(styles).length) { insideAdContainer.setAttribute( 'style', Object.keys(styles) .map(key => `${key}:${styles[key]}`) .join(';'), ); } afterAdContainer.setAttribute('data-dynamic-ad', 'ADCONTAINER'); const beforeEle = _createElement('div'); beforeEle.id = divId; beforeEle.classList.add(`ad-slot-before`); beforeEle.setAttribute('data-dynamic-ad', 'ADSLOT'); if(adTitle) beforeAdContainer.appendChild(adTitle.cloneNode(true)); beforeAdContainer.appendChild(beforeEle); const afterEle = _createElement('div'); afterEle.id = divId; afterEle.classList.add(`ad-slot-after`); afterEle.setAttribute('data-dynamic-ad', 'ADSLOT'); if(adTitle) afterAdContainer.appendChild(adTitle.cloneNode(true)); afterAdContainer.appendChild(afterEle); const insideEle = _createElement('div'); insideEle.id = divId; insideEle.classList.add(`ad-slot-inside`); insideEle.setAttribute('data-dynamic-ad', 'ADSLOT'); if(adTitle) insideAdContainer.appendChild(adTitle.cloneNode(true)); insideAdContainer.appendChild(insideEle); return { beforeEl: beforeAdContainer, afterEl: afterAdContainer, insideEl: insideAdContainer }; }; const _createAdContainer = () => { const adsContainer = _createElement('div'); adsContainer.classList.add('ads-container'); return adsContainer.cloneNode(true); }; const _transformConfig = config => { const obj = {}; config.forEach(i => { const { key, value } = i; obj[key] = value; }); return obj; }; const _getConfiguration = async configEndpoint => { const response = await fetch(configEndpoint); const data = await response.json(); return _transformConfig(data.response.config); }; const _renderAds = (pageAdsConfig = null) => { const pageAds = pageAdsConfig ? pageAdsConfig : __DA_CONFIG__.pageAds; if(pageAds && pageAds.length === 0) { return; } const { lazyLoading, collapseEmptyDiv, setTargeting, demandManager } = __DA_CONFIG__.global; googletag.cmd.push(() => { // key value targetting if(setTargeting) { _addPageLeveltargets(); } if(demandManager) { googletag.pubads().disableInitialLoad(); } let slot = ''; const headerBiddingSlots = []; pageAds.forEach(adItem => { const { pageLinkPlaceholder, divId, isOutOfPageSlot, type } = adItem; if (_isSlotAlreadyExist(divId)) { return null; } const { isMobileScreen, isDesktopScreen } = _getLayout(); const { selector: eleSelector, insertBefore: eleInsertBefore, insertAfter: eleInsertAfter, insertInside: eleInsertInside, mobile, desktop } = pageLinkPlaceholder; let selector = null; let insertBefore, insertAfter, insertInside; insertBefore = insertAfter = insertInside = false; if(!eleSelector) { if(mobile && isMobileScreen) { selector = mobile.selector; insertBefore = mobile.insertBefore; insertAfter = mobile.insertAfter; insertInside = mobile.insertInside; } else if(desktop && isDesktopScreen) { selector = desktop.selector; insertBefore = desktop.insertBefore; insertAfter = desktop.insertAfter; insertInside = desktop.insertInside; } } else { selector = eleSelector; insertBefore = eleInsertBefore; insertAfter = eleInsertAfter; insertInside = eleInsertInside; if(mobile && isMobileScreen) { selector = mobile.selector; insertBefore = mobile.insertBefore; insertAfter = mobile.insertAfter; insertInside = mobile.insertInside; } else if(desktop && isDesktopScreen) { selector = desktop.selector; insertBefore = desktop.insertBefore; insertAfter = desktop.insertAfter; insertInside = desktop.insertInside; } } const selectedElement = document.querySelector(selector); let slotInserted = false; if (isOutOfPageSlot) { if (selector) { slotInserted = _insertElement( selectedElement, insertBefore, insertAfter, insertInside, adItem, isOutOfPageSlot ); } else { slotInserted = _createOutOfPageElement(adItem); } } else { slotInserted = _insertElement( selectedElement, insertBefore, insertAfter, insertInside, adItem, ); } if(!selectedElement && !slotInserted) { if(__DA_CONFIG__.missedAds.findIndex(ele => ele.divId === adItem.divId) === -1) { __DA_CONFIG__.missedAds.push(adItem); } return; } if (slotInserted) { let adsDefinedSizeMapping = []; let adSizes = []; if (adItem.adSizeMapping) { adsDefinedSizeMapping = _getDefinedSizeMapping( adItem.adSizeMapping, ); } else { adSizes = _getAdSizes(adItem.sizeMapping); } const slotId = `Slot - ${divId}`; if ( isOutOfPageSlot && (!adItem.sizeMapping && !adItem.adSizeMapping) ) { slot = googletag.defineOutOfPageSlot(adItem.adUnitId, divId); } else { slot = googletag.defineSlot( adItem.adUnitId, adItem.adSizeMapping ? adsDefinedSizeMapping : adSizes.reduce((acc, item) => { acc = acc.concat(item[1]); return acc; }, []), divId, ); } if (slot) { if (isOutOfPageSlot || adItem.adSizeMapping) { slot.addService(googletag.pubads()); } else { slot.defineSizeMapping(adSizes).addService(googletag.pubads()); } } window.adSlots[slotId] = slot; headerBiddingSlots.push(slot); _adEvents(divId, adItem.adUnitId, type); if(type === 'interstitial') { googletag.pubads().addEventListener('slotRenderEnded', event => { const slotId = event.slot.getSlotElementId(); if (!event.isEmpty && type === 'interstitial' && slotId === divId) { const interstitialPopup = document.querySelector( '.interstitial-popup', ); interstitialPopup.setAttribute('style', 'display: block;'); } }); } } }); if (lazyLoading && lazyLoading.enable) { const { params } = lazyLoading; googletag.pubads().enableLazyLoad(params); } if(collapseEmptyDiv) { googletag.pubads().collapseEmptyDivs(); } // // Enable SRA and services. googletag.pubads().enableSingleRequest(); googletag.enableServices(); if(demandManager) { // group any header bidding slots in an array // make a request to DM to start header bidding _demandManagerRequest(headerBiddingSlots); } googletag.display(slot); }); }; const _adEvents = (divId, path, type) => { const USERID = window.__USERID__ || ''; const { isMobileScreen, isTabletScreen } = _getLayout(); let deviceScreen; if (isMobileScreen) { deviceScreen = 'Mobile'; } else if (isTabletScreen) { deviceScreen = 'Tablet'; } else { deviceScreen = 'Desktop'; } const timestamp = Date.now().toString(); if (googletag && googletag.apiReady) { // This listener will be called when an impression is considered viewable. googletag.pubads().addEventListener('impressionViewable', event => { const slotId = event.slot.getSlotElementId(); if (slotId === divId) { window && window.dataLayer && window.dataLayer.push({ event: 'GA_ADS', adUnit: path, divId, device: deviceScreen, timestamp, userId: USERID, adEventListener: 'impressionViewable', adEventMessage: `Impression has become viewable for slot : ${slotId}`, }); const consoleContentContainer = document.getElementById('ad-console-wrapper-content'); if(consoleContentContainer) { const paragraph = _createElement("p"); paragraph.textContent = `Impression has become viewable for ${slotId}`; consoleContentContainer.appendChild(paragraph); } } }); // This listener will be called when a slot's creative iframe load event // fires. googletag.pubads().addEventListener('slotOnload', event => { const slotId = event.slot.getSlotElementId(); if (slotId === divId) { window && window.dataLayer && window.dataLayer.push({ event: 'GA_ADS', adUnit: path, divId, device: deviceScreen, timestamp, userId: USERID, adEventListener: 'slotOnload', adEventMessage: `Creative iframe load event has fired : ${slotId}`, }); _updateLazyLoadSlotStatus(slotId, "rendered"); const consoleContentContainer = document.getElementById('ad-console-wrapper-content') if(consoleContentContainer) { const paragraph = _createElement("p"); paragraph.textContent = `Creative iframe load event has fired ${slotId}`; consoleContentContainer.appendChild(paragraph); } } }); // This listener will be called when a slot has finished rendering. googletag.pubads().addEventListener('slotRenderEnded', event => { const slotId = event.slot.getSlotElementId(); if (slotId === divId) { // Record details of the rendered ad. const details = { 'Advertiser ID': event.advertiserId, 'Campaign ID': event.campaignId, 'Company IDs': event.companyIds, 'Creative ID': event.creativeId, 'Creative Template ID': event.creativeId, 'Is backfill?': event.isBackfill, 'Is empty?': event.isEmpty, 'Label IDs': event.labelIds, 'Line Item ID': event.lineItemId, Size: event.size, 'Slot content changed?': event.slotContentChanged, 'Source Agnostic Creative ID': event.sourceAgnosticCreativeId, 'Source Agnostic Line Item ID': event.sourceAgnosticLineItemId, 'Yield Group IDs': event.yieldGroupIds, }; window && window.dataLayer && window.dataLayer.push({ event: 'GA_ADS', adUnit: path, divId, device: deviceScreen, timestamp, userId: USERID, adEventListener: 'slotRenderEnded', adEventMessage: `Slot has finished rendering : ${slotId}`, adEventDetails: details, }); const consoleContentContainer = document.getElementById('ad-console-wrapper-content') if(consoleContentContainer) { const paragraph = _createElement("p"); paragraph.textContent = `Slot has finished rendering ${slotId}`; consoleContentContainer.appendChild(paragraph); const pre = _createElement("pre"); const data_stringified = JSON.stringify(details, null, 2); pre.innerHTML = data_stringified; consoleContentContainer.appendChild(pre); } } }); // This listener will be called when the specified service actually // sets an ad request for a slot. Each slot will fire this event, even // though they may be batched together in a single request if single // request architecture (SRA) is enabled. googletag.pubads().addEventListener('slotRequested', event => { const slotId = event.slot.getSlotElementId(); if (slotId === divId) { window && window.dataLayer && window.dataLayer.push({ event: 'GA_ADS', adUnit: path, divId, device: deviceScreen, timestamp, userId: USERID, adEventListener: 'slotRequested', adEventMessage: `Slot has been requested : ${slotId}`, }); _updateLazyLoadSlotStatus(slotId, "fetched"); const consoleContentContainer = document.getElementById('ad-console-wrapper-content') if(consoleContentContainer) { const paragraph = _createElement("p"); paragraph.textContent = `Slot has been requested ${slotId}`; consoleContentContainer.appendChild(paragraph); } } }); // This listener will be called when an ad response has been received for // a slot. googletag.pubads().addEventListener('slotResponseReceived', event => { const slotId = event.slot.getSlotElementId(); if (slotId === divId) { window && window.dataLayer && window.dataLayer.push({ event: 'GA_ADS', adUnit: path, divId, device: deviceScreen, timestamp, userId: USERID, adEventListener: 'slotResponseReceived', adEventMessage: `Ad response has been received : ${slotId}`, }); const consoleContentContainer = document.getElementById('ad-console-wrapper-content') if(consoleContentContainer) { const paragraph = _createElement("p"); paragraph.textContent = `Ad response has been received ${slotId}`; consoleContentContainer.appendChild(paragraph); } } }); } }; const _destroyAllSlots = () => { if (googletag.pubadsReady) { googletag.cmd.push(() => { googletag.destroySlots(); window.adSlots = []; }); } // additionally remove all the ad slots from the dom const ALL_AD_SLOTS = document.querySelectorAll( '[data-dynamic-ad="ADCONTAINER"]', ); ALL_AD_SLOTS.forEach(e => { e.remove(); }); const interstitialAd = document.querySelector('.interstitial-popup'); if (interstitialAd && interstitialAd.remove) { interstitialAd.remove(); } }; const _getPageAds = () => { const path = window.location.pathname; const pathName = path && path.toLowerCase(); const AdvertisementConfigs = []; if (__DA_CONFIG__.ads && Array.isArray(__DA_CONFIG__.ads)) { __DA_CONFIG__.ads.forEach(item => { if (item.enabled) { const { isMobileScreen, isDesktopScreen } = _getLayout(); const { showOnMobile, showOnDesktop } = item; if ( (!showOnDesktop && !showOnMobile) || showOnMobile === isMobileScreen || showOnDesktop === isDesktopScreen ) { item.routes.forEach(lp => { const { link } = lp; if (link && Array.isArray(link)) { if(link.includes(pathName)) { AdvertisementConfigs.push({ ...item, pageLinkPlaceholder: lp }); } } else { const pattern = new RegExp(`${link}$`); if (pattern.test(pathName)) { AdvertisementConfigs.push({ ...item, pageLinkPlaceholder: lp }); } } }); } } }); } return AdvertisementConfigs; }; const _getAdSizes = sizeMapping => { let definedMapping = []; const allSizes = []; if (sizeMapping && googletag.sizeMapping) { /* eslint-disable array-callback-return */ // mapping = googletag.sizeMapping(); definedMapping = googletag.sizeMapping(); const mobileSizeAdSizes = []; const tabletSizeAdSizes = []; const desktopSizeAdSizes = []; Object.keys(sizeMapping).map(keys => { const width = parseInt(sizeMapping[keys].split(',')[0], 10); const height = parseInt(sizeMapping[keys].split(',')[1], 10); if (keys < 600 && window.innerWidth >= width) { mobileSizeAdSizes.push([width, height]); } else if (keys < 960 && window.innerWidth >= width) { tabletSizeAdSizes.push([width, height]); } else if (window.innerWidth >= width) { desktopSizeAdSizes.push([width, height]); } allSizes.push({ width, height }); // mapping.addSize([parseInt(keys, 10), height], [width, height]); }); // size mapping will be only 3 dimensions // 0 - 599, 600 - 959, 960 - infinity // as a specific range will accept mutiple dimension options // so it can cover more advertisement impressions if (mobileSizeAdSizes.length) { definedMapping.addSize( // 0 - 599 [0, 10], mobileSizeAdSizes, ); } else { definedMapping.addSize( // 0 - 599 [0, 10], _getFallbackSizeMaping(allSizes), ); } if (tabletSizeAdSizes.length) { definedMapping.addSize( // 600 - 959 [599, 10], tabletSizeAdSizes, ); } else { definedMapping.addSize( // 0 - 599 [599, 10], _getFallbackSizeMaping(allSizes), ); } if (desktopSizeAdSizes.length) { definedMapping.addSize( // 960 - infinity [959, 10], desktopSizeAdSizes, ); } else { definedMapping.addSize( // 0 - 599 [959, 10], _getFallbackSizeMaping(allSizes), ); } definedMapping = definedMapping.build(); // mapping = mapping.build(); // console.log('mapping', definedMapping); } return definedMapping; }; const _getDefinedSizeMapping = sizeMapping => { let definedMapping = []; if (sizeMapping) { const { isMobileScreen, isTabletScreen, isDesktopScreen } = _getLayout(); if (isMobileScreen) { const { mobile } = sizeMapping; definedMapping = _getParsedSize(mobile); } else if (isTabletScreen) { const { tablet } = sizeMapping; definedMapping = _getParsedSize(tablet); } else if (isDesktopScreen) { const { desktop } = sizeMapping; definedMapping = _getParsedSize(desktop); } } return definedMapping; }; const _getParsedSize = sizes => sizes.map(item => { let temp = null; if (item) { const x = parseInt(item.split(',')[0], 10); const y = parseInt(item.split(',')[1], 10); temp = [x, y]; } return temp; }); const _getFallbackSizeMaping = allSizes => allSizes.reduce((acc, { width, height }) => { if (window.innerWidth > width) { acc.push([width, height]); } return acc; }, []); const _getLayout = () => { const isMobileScreen = window.matchMedia(`(max-width: ${breakPointMobile})`) .matches; const isTabletScreen = window.matchMedia( `(min-width: calc(${breakPointMobile} + 1px)) and (max-width: ${breakPointTablet})`, ).matches; const isMobileAndTabletScreen = isMobileScreen || isTabletScreen; const isDesktopScreen = window.matchMedia( `(min-width: calc(${breakPointTablet} + 1px))`, ).matches; return { isMobileScreen, isTabletScreen, isMobileAndTabletScreen, isDesktopScreen, }; }; const _setTargetting = targets => { adTargets = targets; }; // action which refreshes all slots const _refreshAllSlots = () => { if (googletag.pubadsReady) { googletag.cmd.push(() => { googletag.pubads().refresh(); }); } }; // Note: calling clear() removes any currently displayed ads // and replaces them with blank content, leaving the slots intact so they // can be repopulated later. const _clearAllSlots = () => { if (googletag.pubadsReady) { googletag.cmd.push(() => { googletag.pubads().clear(); }); } }; const _updateLazyLoadSlotStatus = (slotId, state) => { const searchParams = new URLSearchParams(window.location.search); const lazyDebug = searchParams.get('lazy_debug'); if(lazyDebug && lazyDebug === 'true') { console.info('SlotId: ', slotId, '|| Lazy load status:', state) } } const _isSlotAlreadyExist = divId => { let isExist = false; if (googletag.pubadsReady) { googletag.cmd.push(() => { const existingSlots = googletag.pubads().getSlots(); const existingAd = existingSlots.find(ad => { const adId = ad && ad.getSlotElementId ? ad.getSlotElementId() : ''; return adId === divId; }); if (existingAd) { isExist = true; } }); } return isExist; }; const _demandManagerRequest = (slots) => { // provide failsafeHandler with callback function to fire when we want to make // the ad server request, as well as headerBiddingSlots to use in case of failsafe const sendAdServerRequest = failsafeHandler(slotsToRefresh => { googletag.pubads().refresh(slotsToRefresh); }, slots); // request bids when PBJS is ready pbjs.que.push(() => { pbjs.rp.requestBids({ callback: sendAdServerRequest, gptSlotObjects: slots, }); }); // start the failsafe timeout setTimeout(sendAdServerRequest, FAILSAFE_TIMEOUT); // function that handles the failsafe using boolean logic per auction function failsafeHandler(callback, initialSlots) { let adserverRequestSent = false; return bidsBackSlots => { if (adserverRequestSent) return; adserverRequestSent = true; callback(bidsBackSlots || initialSlots); }; } } const _addPageLeveltargets = () => { if (googletag.apiReady) { if (adTargets && adTargets.length) { adTargets.forEach(target => { if (target) { googletag .pubads() .setTargeting( target.key, target.value && target.value.toLowerCase(), ); } }); } } } return { _init, _getConfiguration, _destroyAllSlots, _setTargetting, _refreshAllSlots, _clearAllSlots, _renderAds, _getPageAds, }; })(); if (typeof window !== 'undefined') { window.addEventListener('load', () => { __DA_CONFIG__.missedAds = __DA_CONFIG__.ads = __DA_CONFIG__.global = __DA_CONFIG__.pageAds = []; dynamicads._init(); }); document.addEventListener('__ON_ROUTE_CHANGE__', () => { dynamicads._destroyAllSlots(); __DA_CONFIG__.missedAds = []; setTimeout(() => { const pageAds = dynamicads._getPageAds(); __DA_CONFIG__.pageAds = pageAds; dynamicads._renderAds(pageAds); }, TIMEOUT); }); document.addEventListener('__ON_LAYOUT_CHANGE__', () => { dynamicads._renderAds(__DA_CONFIG__.missedAds); }); } else { console.log('Oops, `window` is not defined'); } export default dynamicads;