More Featured
Webinars, Podcasts & Videos
Latest Products & Services
5 min read

Why Long-Term Rental Power Deserves A Closer Look

Caterpillar Rental Power Solutions
Reliable power plays a critical role in business continuity, but the energy requirements of the enterprise are continually evolving.
3 min read

Verified Mapping Data Bridges Emergency Response, Daily Operations

life-safety data
Critical Response Group’s new Map Builder turns field-verified life-safety data into customizable maps to support continuity planning, emergency response, and day-to-day operational readiness.
3 min read

New Dashboard Measures Cybersecurity Progress

cyber risk management
CTG’s new cyber resilience scoring dashboard helps organizations quantify risk, prioritize remediation, and track measurable improvement over time.
Subscribe To ENews
Submit a Press Release
Webinars & Podcasts
Job Board

Receive the latest articles in your inbox

`; if (isWallpaper) { container.classList.remove('is-active'); iframe.addEventListener('load', () => { requestAnimationFrame(() => { container.classList.add('is-active'); }); }, { once: true }); } renderTarget.appendChild(iframe); container.setAttribute('data-active-id', String(spot.id)); // Avoid inline display:block overriding .gcm-sponsored-by.is-filled // (whose flex layout centers the two rows). container.style.display = isSponsoredBy ? '' : 'block'; if (!isWallpaper) { requestAnimationFrame(() => { container.classList.add('is-active'); }); } } function clearSlot(container) { const activeId = container.getAttribute('data-active-id'); if (activeId) { loadedAdKeys.delete(container.id + ':' + activeId); } clearRefreshTimer(container.id); container.classList.remove('is-active'); container.style.display = 'none'; container.setAttribute('data-active-id', ''); if (container.id === 'aje_gcm_sb_ads') { const holder = container.querySelector('.gcm-sponsored-by__creative'); if (holder) holder.innerHTML = ''; container.classList.remove('is-filled'); container.setAttribute('aria-hidden', 'true'); container.dataset.gcmSponsorStatus = 'waiting'; delete container.dataset.gcmSponsorStarted; } else { container.innerHTML = ''; } } function startRefreshTimer(slot, spot) { clearRefreshTimer(slot.containerId); const timer = setInterval(() => { if (!canRefreshAds()) return; const container = document.getElementById(slot.containerId); if (!container) { clearRefreshTimer(slot.containerId); return; } if (!window.matchMedia(spot.query).matches) { clearRefreshTimer(slot.containerId); clearSlot(container); return; } injectIframeAd(container, spot, { force: true }); }, REFRESH_MS); refreshTimers.set(slot.containerId, timer); } function processSlot(slot) { const container = document.getElementById(slot.containerId); if (!container) return; if (slot.containerId === 'aje_gcm_sb_ads' && !IS_SINGLE_POST) return; const match = slot.responsive.find( res => res.id && window.matchMedia(res.query).matches ); if (match) { injectIframeAd(container, match); // Sponsored By only becomes visible after a real creative is found. if (slot.containerId !== 'aje_gcm_sb_ads') { container.style.display = 'block'; } else { container.style.display = ''; } if (REFRESH_SLOT_IDS.has(slot.containerId)) { startRefreshTimer(slot, match); } else { clearRefreshTimer(slot.containerId); } } else { clearSlot(container); } } function checkSlots(mode = 'all') { adSlots.forEach(slot => { const isCritical = CRITICAL_SLOT_IDS.has(slot.containerId); const isScrollBound = SCROLL_SLOT_IDS.has(slot.containerId); if (mode === 'critical') { if (!isCritical) return; } else if (mode === 'delayed') { if (isCritical || isScrollBound) return; } else if (mode === 'scroll') { if (!isScrollBound) return; } processSlot(slot); }); } function debounce(fn, wait) { let t; return function() { clearTimeout(t); t = setTimeout(fn, wait); }; } /** * Handle viewport / breakpoint changes. * * Only process: * - critical slots * - scroll slots that have already activated * - delayed slots that IntersectionObserver already activated * * This prevents resize/orientation events from loading * every below-fold advertisement. */ const handleChange = debounce(() => { adSlots.forEach(slot => { const isCritical = CRITICAL_SLOT_IDS.has(slot.containerId); const isScrollBound = SCROLL_SLOT_IDS.has(slot.containerId); const isActivatedDelayed = activatedDelayedSlots.has(slot.containerId); /** * Critical ads may always react to * responsive breakpoint changes. */ if (isCritical) { processSlot(slot); return; } /** * Adhesion / scroll-bound placements should * only react after they have been activated. */ if (isScrollBound) { if (scrollStarted) { processSlot(slot); } return; } /** * Below-fold delayed ads should only react * after IntersectionObserver activates * that specific placement. */ if (isActivatedDelayed) { processSlot(slot); } }); }, 150); /** * Watch responsive breakpoints. */ function bindMediaListeners() { const allQueries = [ ...new Set( adSlots.flatMap( slot => slot.responsive.map( res => res.query ) ) ) ]; allQueries.forEach(query => { const mql = window.matchMedia(query); if ( typeof mql.addEventListener === 'function' ) { mql.addEventListener( 'change', handleChange ); } else if ( typeof mql.addListener === 'function' ) { mql.addListener( handleChange ); } }); window.addEventListener( 'resize', handleChange, { passive: true } ); window.addEventListener( 'orientationchange', handleChange, { passive: true } ); } /** * Observe non-critical, non-adhesion ads. * * Ads begin loading when they come within * approximately 800px of the viewport. */ function setupDelayedAds() { const delayedSlots = adSlots.filter(slot => { return ( !CRITICAL_SLOT_IDS.has( slot.containerId ) && !SCROLL_SLOT_IDS.has( slot.containerId ) ); }); if (!delayedSlots.length) { return; } /** * Fallback for browsers without * IntersectionObserver. */ if (!('IntersectionObserver' in window)) { setTimeout(() => { delayedSlots.forEach(slot => { activatedDelayedSlots.add( slot.containerId ); processSlot(slot); }); }, DELAY_MS); return; } const observer = new IntersectionObserver( entries => { entries.forEach(entry => { if (!entry.isIntersecting) { return; } // For a collapsed Sponsored By wrapper the observer // watches a 1x1 sentinel with a pointer to its slot. const target = entry.target; const containerId = target.dataset.gcmSlotContainer || target.id; const container = document.getElementById(containerId); const slot = delayedSlots.find( item => item.containerId === containerId ); if (!slot || !container) { observer.unobserve(target); return; } /** * Record that this specific * placement is now allowed * to load and respond to * breakpoint changes. */ activatedDelayedSlots.add( slot.containerId ); processSlot(slot); /** * Only trigger this placement * once. */ observer.unobserve(target); if (target !== container) target.remove(); }); }, { /** * Begin requesting the ad before * it actually enters the viewport. */ rootMargin: '800px 0px', threshold: 0 } ); delayedSlots.forEach(slot => { const container = document.getElementById( slot.containerId ); if (container) { if (slot.containerId === 'aje_gcm_sb_ads') { // The unit must occupy no space on no-fill, but a zero-height // box isn't a reliable IntersectionObserver target. const sentinel = document.createElement('span'); sentinel.dataset.gcmSlotContainer = container.id; sentinel.setAttribute('aria-hidden', 'true'); sentinel.style.cssText = 'position:absolute;top:0;left:0;width:1px;height:1px;opacity:0;pointer-events:none;'; container.appendChild(sentinel); container.dataset.gcmSponsorStatus = 'waiting'; observer.observe(sentinel); } else { observer.observe(container); } } }); } /** * Activate adhesion ads after the * visitor begins scrolling. */ function startScrollAds() { if (scrollStarted) { return; } scrollStarted = true; checkSlots('scroll'); } /** * Trigger adhesion inventory after * 200px of page scroll. */ function setupScrollTrigger() { const handleScroll = () => { if (window.scrollY >= 200) { startScrollAds(); window.removeEventListener( 'scroll', handleScroll ); } }; window.addEventListener( 'scroll', handleScroll, { passive: true } ); } /** * Pause adhesion refresh while the * page is hidden or does not have focus. */ function setupFocusVisibilityRefresh() { document.addEventListener( 'visibilitychange', () => { pageHasFocus = document.hasFocus(); if (!canRefreshAds()) { REFRESH_SLOT_IDS.forEach( clearRefreshTimer ); return; } adSlots.forEach(slot => { if ( !REFRESH_SLOT_IDS.has( slot.containerId ) ) { return; } processSlot(slot); }); } ); window.addEventListener( 'focus', () => { pageHasFocus = true; adSlots.forEach(slot => { if ( !REFRESH_SLOT_IDS.has( slot.containerId ) ) { return; } processSlot(slot); }); } ); window.addEventListener( 'blur', () => { pageHasFocus = false; REFRESH_SLOT_IDS.forEach( clearRefreshTimer ); } ); } /** * Normalize Sponsored By shortcode output before slot discovery. * * Existing sites may still have the original shortcode markup using * aje_gcm_sponsored_by. Migrate that legacy ID to aje_gcm_sb_ads so the * NEW standard ad slot works without editing the article-layout call. * Recommended long-term: update shortcode registration in functions.php. */ function normalizeSponsoredByContainer() { if (!IS_SINGLE_POST) return; let container = document.getElementById('aje_gcm_sb_ads'); if (!container) { container = document.getElementById('aje_gcm_sponsored_by'); if (container) container.id = 'aje_gcm_sb_ads'; } if (!container) return; container.classList.add('gcm-sponsored-by'); container.setAttribute('aria-hidden', 'true'); if (!container.querySelector('.gcm-sponsored-by__label')) { const label = document.createElement('span'); label.className = 'gcm-sponsored-by__label'; label.textContent = 'Sponsored By'; container.prepend(label); } if (!container.querySelector('.gcm-sponsored-by__creative')) { const holder = document.createElement('div'); holder.className = 'gcm-sponsored-by__creative'; container.appendChild(holder); } } /** * Initialize NUI advertisements. */ function init() { normalizeSponsoredByContainer(); bindMediaListeners(); setupFocusVisibilityRefresh(); /** * Revenue-critical / above-fold inventory. */ checkSlots('critical'); /** * Adhesion inventory activates after * the visitor scrolls 200px. */ setupScrollTrigger(); /** * All remaining advertisements activate * only as they approach the viewport. */ if ( document.visibilityState === 'visible' ) { setupDelayedAds(); } else { document.addEventListener( 'visibilitychange', function onVisible() { if ( document.visibilityState !== 'visible' ) { return; } document.removeEventListener( 'visibilitychange', onVisible ); setupDelayedAds(); } ); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init, { once: true }); } else { init(); } })();