1/** 2 * AdSense Width Fix for Maritime Executive 3 * 4 * Fixes "No slot size for availableWidth=0" errors by ensuring 5 * AdSense containers have proper dimensions before initialization 6 */ 7 8(function () { 9 'use strict'; 10 11 // Configuration 12 const config = { 13 minWidth: 300, // Minimum container width 14 retryAttempts: 5, // Number of retry attempts 15 retryDelay: 500, // Delay between retries (ms) 16 observeTimeout: 10000, // Maximum time to wait for container sizing 17 debugMode: true // Enable debug logging 18 }; 19 20 // Track processed ads to prevent duplicates 21 const processedAds = new Set(); 22 const pendingAds = new Map(); 23 24 function debugLog(message, data = null) { 25 if (config.debugMode) { 26 console.log('[AdSense Width Fix]', message, data || ''); 27 } 28 } 29 30 /** 31 * Check if a container has sufficient width 32 */ 33 function hasValidWidth(element) { 34 const rect = element.getBoundingClientRect(); 35 const computedStyle = window.getComputedStyle(element); 36 const width = rect.width || parseFloat(computedStyle.width) || 0; 37 38 debugLog('Checking width for element:', { 39 element: element, 40 width: width, 41 minRequired: config.minWidth 42 }); 43 44 return width >= config.minWidth; 45 } 46 47 /** 48 * Check if element is visible in viewport or layout 49 */ 50 function isElementVisible(element) { 51 const rect = element.getBoundingClientRect(); 52 const style = window.getComputedStyle(element); 53 54 return ( 55 style.display !== 'none' && 56 style.visibility !== 'hidden' && 57 style.opacity !== '0' && 58 rect.width > 0 && 59 rect.height > 0 60 ); 61 } 62 63 /** 64 * Wait for container to have valid width 65 */ 66 function waitForValidWidth(element, callback, attempts = 0) { 67 if (attempts >= config.retryAttempts) { 68 debugLog('Max attempts reached, forcing initialization:', element); 69 // Force minimum dimensions if still no width 70 if (!hasValidWidth(element)) { 71 element.style.minWidth = config.minWidth + 'px'; 72 element.style.minHeight = '250px'; 73 } 74 callback(); 75 return; 76 } 77 78 if (hasValidWidth(element) && isElementVisible(element)) { 79 debugLog('Valid width found, initializing:', element); 80 callback(); 81 return; 82 } 83 84 debugLog(`Waiting for valid width, attempt ${attempts + 1}:`, element); 85 setTimeout(() => { 86 waitForValidWidth(element, callback, attempts + 1); 87 }, config.retryDelay); 88 } 89 90 /** 91 * Use ResizeObserver to watch for width changes 92 */ 93 function observeElementWidth(element, callback) { 94 if (!window.ResizeObserver) { 95 // Fallback to polling for older browsers 96 waitForValidWidth(element, callback); 97 return; 98 } 99 100 const observer = new ResizeObserver((entries) => { 101 for (const entry of entries) { 102 if (hasValidWidth(entry.target)) { 103 debugLog('ResizeObserver detected valid width:', entry.target); 104 observer.disconnect(); 105 callback(); 106 return; 107 } 108 } 109 }); 110 111 observer.observe(element); 112 113 // Set timeout to prevent infinite waiting 114 setTimeout(() => { 115 observer.disconnect(); 116 debugLog('ResizeObserver timeout, forcing callback:', element); 117 callback(); 118 }, config.observeTimeout); 119 } 120 121 /** 122 * Force container sizing for AdSense slots 123 */ 124 function forceContainerSizing(element) { 125 if (!element) return false; 126 127 // Get container and any parent elements 128 const container = element.closest('.add, .sidebar-ad-slot, [id*="div-gpt-ad"]') || element; 129 130 // Set explicit dimensions if not already set 131 const style = window.getComputedStyle(container); 132 const hasWidth = parseFloat(style.width) > 0; 133 const hasHeight = parseFloat(style.height) > 0; 134 135 if (!hasWidth || !hasHeight) { 136 debugLog('Forcing container dimensions for:', element); 137 138 // Set minimum dimensions for AdSense 139 if (!hasWidth) { 140 container.style.width = '300px'; 141 container.style.minWidth = '300px'; 142 } 143 if (!hasHeight) { 144 container.style.height = '250px'; 145 container.style.minHeight = '250px'; 146 } 147 148 // Ensure container is visible 149 container.style.display = container.style.display || 'block'; 150 container.style.visibility = 'visible'; 151 container.style.overflow = 'hidden'; 152 153 // Force layout recalculation 154 container.offsetHeight; 155 156 debugLog('Container forced to:', { 157 width: container.style.width, 158 height: container.style.height, 159 computed: { 160 width: window.getComputedStyle(container).width, 161 height: window.getComputedStyle(container).height 162 } 163 }); 164 165 return true; 166 } 167 168 return false;
169 } 170 171 /** 172 * Initialize AdSense ad safely 173 */ 174 function initializeAdSenseAd(insElement) { 175 const adId = insElement.dataset.adSlot || 'unknown'; 176 177 // Check if already processed or if element already has ads 178 if (processedAds.has(adId) || insElement.dataset.adsbygoogleStatus) { 179 debugLog('Ad already processed:', adId); 180 return; 181 } 182 183 // Mark as being processed 184 insElement.dataset.adsbygoogleStatus = 'processing'; 185 debugLog('Processing AdSense ad:', adId); 186 processedAds.add(adId); 187 188 const container = insElement.closest('.add') || insElement.parentElement; 189 190 if (!container) { 191 debugLog('No container found for ad:', adId); 192 return; 193 } 194 195 // Check if already has valid width 196 if (hasValidWidth(container) && isElementVisible(container)) { 197 debugLog('Container already has valid width:', adId); 198 triggerAdSenseLoad(insElement); 199 return; 200 } 201 202 // Wait for valid width before loading 203 debugLog('Waiting for container to have valid width:', adId); 204 observeElementWidth(container, () => { 205 triggerAdSenseLoad(insElement); 206 }); 207 } 208 209 /** 210 * Trigger AdSense ad loading 211 */ 212 function triggerAdSenseLoad(insElement) { 213 try { 214 // Double-check this element hasn't been processed already 215 if (insElement.dataset.adsbygoogleStatus === 'loaded') { 216 debugLog('Element already loaded, skipping:', insElement.dataset.adSlot); 217 return; 218 } 219 220 // Ensure the adsbygoogle array exists 221 if (!window.adsbygoogle) { 222 window.adsbygoogle = []; 223 } 224 225 // Mark as loaded before pushing to prevent duplicates 226 insElement.dataset.adsbygoogleStatus = 'loaded'; 227 228 // Push the ad to AdSense 229 window.adsbygoogle.push({}); 230 231 debugLog('AdSense ad loaded successfully:', insElement.dataset.adSlot); 232 } catch (error) { 233 debugLog('Error loading AdSense ad:', { 234 error: error.message, 235 element: insElement 236 }); 237 // Mark as failed 238 insElement.dataset.adsbygoogleStatus = 'failed'; 239 } 240 } 241 242 /** 243 * Override adsbygoogle.push to intercept and fix width issues 244 */ 245 function patchAdsByGooglePush() { 246 // Patching disabled to prevent conflicts with multiple initialization attempts 247 debugLog('AdsByGoogle push patching disabled to prevent conflicts'); 248 249 // Just ensure the array exists 250 if (!window.adsbygoogle) { 251 window.adsbygoogle = []; 252 } 253 } 254 255 /** 256 * Process existing AdSense ads on page 257 */ 258 function processExistingAds() { 259 const insElements = document.querySelectorAll('ins.adsbygoogle:not([data-adsbygoogle-status])'); 260 261 debugLog(`Found ${insElements.length} unprocessed AdSense ads`); 262 263 insElements.forEach((ins, index) => { 264 // Add delay to prevent all ads from loading simultaneously 265 setTimeout(() => { 266 initializeAdSenseAd(ins); 267 }, index * 100); 268 }); 269 } 270 271 /** 272 * Watch for new AdSense ads added to the DOM 273 */ 274 function watchForNewAds() { 275 if (!window.MutationObserver) { 276 return; 277 } 278 279 const observer = new MutationObserver((mutations) => { 280 mutations.forEach((mutation) => { 281 mutation.addedNodes.forEach((node) => { 282 if (node.nodeType === Node.ELEMENT_NODE) { 283 // Check if the node itself is an AdSense ad 284 if (node.classList && node.classList.contains('adsbygoogle')) { 285 initializeAdSenseAd(node); 286 } 287 288 // Check for AdSense ads within the added node 289 const insElements = node.querySelectorAll && node.querySelectorAll('ins.adsbygoogle:not([data-adsbygoogle-status])'); 290 if (insElements) {
291 insElements.forEach(ins => initializeAdSenseAd(ins)); 292 } 293 } 294 }); 295 }); 296 }); 297 298 observer.observe(document.body, { 299 childList: true, 300 subtree: true 301 }); 302 303 debugLog('MutationObserver watching for new AdSense ads'); 304 } 305 306 /** 307 * Process individual AdSense container 308 */ 309 function processAdSenseContainer(insElement) { 310 const adId = insElement.dataset.adSlot || 'unknown'; 311 debugLog('Processing AdSense container:', adId); 312 313 // Skip if already processed 314 if (processedAds.has(adId)) { 315 debugLog('Container already processed:', adId); 316 return; 317 } 318 319 const container = insElement.parentElement; 320 if (!container) { 321 debugLog('No parent container found for AdSense element'); 322 return; 323 } 324 325 // Force container sizing before checking width 326 const wasSized = forceContainerSizing(insElement); 327 if (wasSized) { 328 debugLog('Container sizing was forced for:', adId); 329 } 330 331 // Double-check width after forcing 332 if (!hasValidWidth(container)) { 333 debugLog('Container still has invalid width after forcing, observing for changes:', adId); 334 // Wait for valid width before loading 335 observeElementWidth(container, () => { 336 triggerAdSenseLoad(insElement); 337 }); 338 } else { 339 debugLog('Container has valid width, loading immediately:', adId); 340 triggerAdSenseLoad(insElement); 341 } 342 } 343 344 /** 345 * Initialize the width fix system 346 */ 347 function init() { 348 debugLog('AdSense Width Fix initializing...'); 349 350 // Patch adsbygoogle.push 351 patchAdsByGooglePush(); 352 353 // Process ads when DOM is ready 354 if (document.readyState === 'loading') { 355 document.addEventListener('DOMContentLoaded', () => { 356 processExistingAds(); 357 watchForNewAds(); 358 }); 359 } else { 360 processExistingAds(); 361 watchForNewAds(); 362 } 363 364 debugLog('AdSense Width Fix initialized'); 365 } 366 367 /** 368 * Expose utilities for debugging and control 369 */ 370 window.AdSenseWidthFix = { 371 enableDebug: () => { 372 config.debugMode = true; 373 debugLog('Debug mode enabled'); 374 }, 375 disableDebug: () => { 376 config.debugMode = false; 377 }, 378 processExistingAds: processExistingAds, 379 getProcessedAds: () => Array.from(processedAds), 380 clearProcessedAds: () => { 381 processedAds.clear(); 382 }, 383 config: config 384 }; 385 386 // Initialize immediately 387 init(); 388 389})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.