PageSourceSearch

https://maritime-executive.com/js/adsense-width-fix.js

js maritime-executive.com collected 2026-10-01 06:30:33 UTC 12,370 bytes, 389 lines download raw bytes

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.