More Featured
Webinars, Podcasts & Videos
From The Magazine
4 min read

Colorado Attracts Business Growth Through Innovation, Advanced Industries

Denver, Colorado
The Centennial State builds on innovation, talent, and advanced manufacturing.
5 min read

Rural Broadband Gains Ground

rural broadband
With federal funds expanding rural broadband, connectivity, site selection may take the long view.
5 min read

Texas’ Expanding Industry Base Offers New Location Opportunities

Fort Worth Texas
Through established ecosystems and new opportunities, the Lone Star State economy continues to diversify.
Request Product Info
Submit a Press Release
Business Facilities Site Seekers' Guide
Site Seekers’ Guide
Business Facilities LiveXchange Events
Events
`; if (isWallpaper) { container.classList.remove('is-active'); iframe.addEventListener('load', () => { requestAnimationFrame(() => { container.classList.add('is-active'); }); }, { once: true }); } container.appendChild(iframe); container.setAttribute('data-active-id', String(spot.id)); container.style.display = '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', ''); 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; const match = slot.responsive.find( res => res.id && window.matchMedia(res.query).matches ); if (match) { injectIframeAd(container, match); container.style.display = 'block'; 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; } const container = entry.target; const slot = delayedSlots.find( item => item.containerId === container.id ); if (!slot) { observer.unobserve( container ); 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( container ); }); }, { /** * 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) { 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 ); } ); } /** * Initialize NUI advertisements. */ function init() { 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(); } })();