PageSourceSearch

https://www.ifa-berlin.com/js/custom/ads.js?eb76bc9151083b63fd9431b9c96d1cf2

js ifa-berlin.com collected 2026-09-24 08:42:20 UTC 16,570 bytes, 445 lines download raw bytes

1// Global debug variable to control console.log output
2const DEBUG_MODE = stage === 'dev';
3//const DEBUG_MODE = false;
4
5// Utility function to append a banner to a given element
6function showBanner(element, banner, type = null) {
7    if (!element || !banner) return;
8
9    if (DEBUG_MODE) {
10        console.log('showBanner', banner.type);
11    }
12
13    // If banner.html is a string, use it as innerHTML
14    if (typeof banner.html === 'string') {
15        const wrapper = document.createElement('div');
16        wrapper.innerHTML = banner.html;
17        // Wrappa il contenuto del wrapper se serve
18        if (banner.url && banner.key) {
19            const link = document.createElement('a');
20            link.href = `/external/rdr?id=${banner.key}&language=${language}`;
21            link.target = banner.target ? banner.target : '_self';
22            // Sposta tutti i figli dentro il link
23            while (wrapper.firstChild) {
24                link.appendChild(wrapper.firstChild);
25            }
26            wrapper.appendChild(link);
27        }
28        element.appendChild(wrapper);
29        observeImpression(wrapper, banner.key);
30        return;
31    }
32
33    // If banner.image exists, add it
34    if (banner.image) {
35        const img = document.createElement('img');
36        img.src = banner.image;
37        img.alt = banner.name || '';
38        img.classList.add('banner-image-desktop');
39        if (banner.key) {
40            img.setAttribute('data-banner-key', banner.key);
41        }
42
43        let imgMobile;
44        if (type == 'skyscraper') {
45            // Create mobile banner for skyscraper only if it doesn't exist
46            const mainContent = document.querySelector('.main-content');
47            const existingMobileBanner = document.querySelector('.skyscraper-mobile');
48            if (mainContent && !existingMobileBanner && banner.image_mobile) {
49                const mobileBannerWrapper = document.createElement('div');
50                mobileBannerWrapper.classList.add('banner-wrapper', 'skyscraper-mobile');
51                imgMobile = document.createElement('img');
52                imgMobile.src = banner.image_mobile;
53                imgMobile.alt = banner.name || '';
54                imgMobile.classList.add('banner-image-mobile');
55                if (banner.key) {
56                    imgMobile.setAttribute('data-banner-key', banner.key);
57                }
58                mobileBannerWrapper.appendChild(imgMobile);
59                mainContent.insertBefore(mobileBannerWrapper, mainContent.firstChild);
60            }
61        } else {
62            imgMobile = document.createElement('img');
63            imgMobile.src = banner.image_mobile || banner.image;
64            imgMobile.alt = banner.name || '';
65            imgMobile.classList.add('banner-image-mobile');
66            if (banner.key) {
67                imgMobile.setAttribute('data-banner-key', banner.key);
68            }
69        }
70
71        const wrapper = document.createElement('div');
72        wrapper.classList.add('banner-images-wrapper');
73        wrapper.appendChild(img);
74        if (type != 'skyscraper' && imgMobile) {
75            wrapper.appendChild(imgMobile);
76        }
77
78        let nodeToAppend = wrapper;
79        if (banner.url && banner.key) {
80            const link = document.createElement('a');
81            link.href = `/external/rdr?key=${banner.key}`;
82            link.target = banner.target ? banner.target : '_self';
83            link.appendChild(wrapper);
84            nodeToAppend = link;
85        }
86        element.appendChild(nodeToAppend);
87
88        observeImpression(nodeToAppend, banner.key);
89        return;
90    }
91}
92
93// Utility function to save the impression for a banner
94function saveImpression(bannerKey) {
95    if (!bannerKey) return;
96    fetch(`/external/view?key=${bannerKey}`, {
97        method: "POST",
98        headers: {
99            "X-CSRF-Token": window.csrfToken
100        }
101    });
102}
103
104// Nuova funzione per osservare la visibilità e salvare l'impression
105function observeImpression(target, bannerKey) {
106    if (!target || !bannerKey) return;
107
108    const observer = new IntersectionObserver((entries, obs) => {
109        entries.forEach(entry => {
110            if (entry.isIntersecting) {
111                saveImpression(bannerKey);
112                obs.disconnect(); // Disconnetti dopo il primo trigger
113            }
114        });
115    }, { threshold: 0.1 }); // 10% visibile
116
117    observer.observe(target);
118}
119
120function createCampaign(campaign) {
121    if (DEBUG_MODE) {
122        console.log('createCampaign', campaign);
123    }
124
125    // parse all the banners and print the type
126    if (!Array.isArray(campaign.banners)) return;
127
128    campaign.banners.forEach(banner => {
129        // console.log(banner.type);
130        // search for .ads-component-inner.{type}
131        let adsComponentInner = document.querySelector('.ads-component-inner.' + banner.type);
132        if (adsComponentInner && typeof currentPage.options[banner.type] !== 'undefined' && currentPage.options[banner.type] == 1) {
133            if (campaign.key) {
134                adsComponentInner.setAttribute('data-campaign-key', 'campaign-' + campaign.key);
135            }
136            if (campaign.background_color) {
137                adsComponentInner.style.backgroundColor = campaign.background_color;
138            }
139
140            // Use the new utility function
141            const bannerDiv = document.createElement('div');
142            bannerDiv.classList.add('banner-wrapper');
143            showBanner(bannerDiv, banner);
144            adsComponentInner.appendChild(bannerDiv);
145
146            // add margin to ads-component parent
147            const adsComponent = adsComponentInner.closest('.ads-component');
148            if (adsComponent) {
149                // Handle top margin
150                if (adsComponent.dataset.removeMarginTop != 1) {
151                    adsComponent.classList.add('mt-double');
152                }
153
154                // Handle bottom margin
155                if (adsComponent.dataset.removeMarginBottom != 1) {
156                    adsComponent.classList.add('mb-double');
157                }
158            }
159        }
160
161        // Manage Header
162        // if (currentPage.options && typeof currentPage.options.ads_sticky_header !== 'undefined') {
163        //     if (banner.type == 'Header' && currentPage.options.ads_sticky_header == 1) {
164        //         createStickyHeaderBanner(banner);
165        //     }
166        // }
167
168        // Manage Footer
169        if (currentPage.options && typeof currentPage.options['Footer-Sticky'] !== 'undefined') {
170            if (banner.type == 'Footer-Sticky' && currentPage.options['Footer-Sticky'] == 1) {
171                createStickyFooterBanner(banner, campaign);
172            }
173        }
174
175        if (currentPage.options && typeof currentPage.options['Skyscraper-Right'] !== 'undefined' && typeof currentPage.options['Skyscraper-Left'] !== 'undefined') {
176            // Manage Skyscraper
177            if ((banner.type == 'Skyscraper-Left' || banner.type == 'Skyscraper-Right') && (currentPage.options['Skyscraper-Left'] == 1 || currentPage.options['Skyscraper-Right'] == 1)) {
178                createSkyscraperBanner(banner);
179            }
180        }
181
182    });
183}
184
185function createStickyFooterBanner(banner, campaign) {
186    if (DEBUG_MODE) {
187        console.log('createStickyFooterBanner: persistent_sticky_footer: ', campaign.persistent_sticky_footer);
188    }
189
190    // Crea il div del banner
191    const bannerDiv = document.createElement('div');
192    bannerDiv.id = 'sticky-footer-banner';
193
194    // Use the new utility function
195    showBanner(bannerDiv, banner);
196
197    // Aggiungi un pulsante per chiudere il banner
198    const closeBtn = document.createElement('button');
199    closeBtn.textContent = '×';
200    closeBtn.className = 'sticky-footer-banner-close';
201    closeBtn.onclick = () => bannerDiv.remove();
202    bannerDiv.appendChild(closeBtn);
203
204    if (campaign.key) {
205        bannerDiv.setAttribute('data-campaign-key', 'campaign-' + campaign.key);
206    }
207
208    if (campaign.background_color) {
209        bannerDiv.style.backgroundColor = campaign.background_color;
210    }
211
212    // Aggiungi il banner al body
213    document.body.appendChild(bannerDiv);
214
215    // Add class to #body_wrapper
216    const bodyWrapper = document.body;
217    if (bodyWrapper) {
218        bodyWrapper.classList.add('footer-banner-enabled');
219    }
220
221    // Auto-remove banner after 10 seconds if persistent_sticky_footer is not 1
222    if (campaign.persistent_sticky_footer !== 1) {
223        setTimeout(() => {
224            if (bannerDiv && bannerDiv.parentNode) {
225                bannerDiv.remove();
226                // Remove the class from body when banner is removed
227                if (bodyWrapper) {
228                    bodyWrapper.classList.remove('footer-banner-enabled');
229                }
230            }
231        }, 10000); // 10 seconds
232    }
233
234    // Add CSS rules for elements that might be loaded later
235    addFooterBannerCSS();
236
237    // Observe for dynamically loaded elements
238    observeForDynamicElements();
239}
240
241function createSkyscraperBanner(banner) {
242    //console.log('createSkyscraperBanner');
243    // Only show the banner in the correct sidebar based on its type
244    if (banner.type === 'Skyscraper-Left') {
245        const leftSidebar = document.querySelector('aside.left-sidebar .skyscraper');
246        if (leftSidebar) {
247            showBanner(leftSidebar, banner, 'skyscraper');
248        }
249    } else if (banner.type === 'Skyscraper-Right') {
250        const rightSidebar = document.querySelector('aside.right-sidebar .skyscraper');
251        if (rightSidebar) {
252            showBanner(rightSidebar, banner, 'skyscraper');
253        }
254    }
255}
256
257// Function to add CSS rules for footer banner
258function addFooterBannerCSS() {
259    // Check if CSS already exists
260    if (document.getElementById('footer-banner-css')) return;
261
262    const style = document.createElement('style');
263    style.id = 'footer-banner-css';
264    style.textContent = `
265        .frontnow-button {
266            bottom: 100px !important;
267        }
268        #q-messenger-frame {
269            bottom: 100px !important;
270        }
271    `;
272    document.head.appendChild(style);
273}
274
275// Function to observe for dynamically loaded elements
276function observeForDynamicElements() {
277    const observer = new MutationObserver((mutations) => {
278        mutations.forEach((mutation) => {
279            mutation.addedNodes.forEach((node) => {
280                if (node.nodeType === Node.ELEMENT_NODE) {
281                    // Check if the added element is one we're looking for
282                    if (node.classList && node.classList.contains('frontnow-button')) {
283                        // Element already has the class, CSS will apply automatically
284                    } else if (node.id === 'q-messenger-frame') {
285                        // Element already has the id, CSS will apply automatically
286                    } else {
287                        // Check if any of our target elements are inside the added node
288                        const frontnowButton = node.querySelector('.frontnow-button');
289                        const qMessengerFrame = node.querySelector('#q-messenger-frame');
290
291                        if (frontnowButton || qMessengerFrame) {
292                            // Elements found, CSS will apply automatically due to the body class
293                        }
294                    }
295                }
296            });
297        });
298    });
299
300    observer.observe(document.body, {
301        childList: true,
302        subtree: true
303    });
304}
305
306document.addEventListener("DOMContentLoaded", function () {
307    if (DEBUG_MODE) {
308        console.log("ads.js loaded");
309        // these are set in the ads.html partial
310        console.log('adsSettings', adsSettings);
311        console.log('currentPage', currentPage);
312    }
313
314    // load ADS is based on the currentPage.packages
315    if (currentPage.packages && currentPage.packages.length > 0) {
316        // Function to select a package based on weighted probabilities from available packages
317        function selectWeightedPackage(availablePackages) {
318            if (DEBUG_MODE) {
319                debug = true;
320            } else {
321                debug = false;
322            }
323
324            if (debug) {
325                console.log('Available packages:', availablePackages);
326            }
327
328            // Define weights for each package type
329            const weights = {
330                'premium': 0.5,
331                'medium': 0.3,
332                'base': 0.2
333            };
334
335            // Filter available packages and calculate their total weight
336            const availableWeights = availablePackages
337                .map(pkgType => {
338                    if (debug) {
339                        console.log('Package type:', pkgType, 'Weight:', weights[pkgType]);
340                    }
341                    return weights[pkgType] || 0;
342                })
343                .filter(weight => weight > 0);
344
345            if (debug) {
346                console.log('Available weights:', availableWeights);
347            }
348
349            if (availableWeights.length === 0) {
350                console.log('No valid weights found, returning first package');
351                return availablePackages[0];
352            }
353
354            // Normalize weights to sum to 1
355            const totalWeight = availableWeights.reduce((sum, weight) => sum + weight, 0);
356            const normalizedWeights = availableWeights.map(weight => weight / totalWeight);
357
358            if (debug) {
359                console.log('Normalized weights:', normalizedWeights);
360            }
361
362            // Select package based on normalized weights
363            const random = Math.random();
364            if (debug) {
365                console.log('Random value:', random);
366            }
367            let cumulativeWeight = 0;
368
369            for (let i = 0; i < availablePackages.length; i++) {
370                const weight = weights[availablePackages[i]];
371                if (weight > 0) {
372                    const normalizedWeight = normalizedWeights[availableWeights.indexOf(weight)];
373                    cumulativeWeight += normalizedWeight;
374                    if (debug) {
375                        console.log('Package:', availablePackages[i], 'Cumulative weight:', cumulativeWeight);
376                    }
377                    if (random < cumulativeWeight) {
378                        if (debug) {
379                            console.log('Selected package:', availablePackages[i]);
380                        }
381                        return availablePackages[i];
382                    }
383                }
384            }
385
386            // Fallback to first available package
387            if (debug) {
388                console.log('Falling back to first package:', availablePackages[0]);
389            }
390            return availablePackages[0];
391        }
392
393        const selectedPackage = selectWeightedPackage(currentPage.packages);
394
395        if (selectedPackage) {
396            if (DEBUG_MODE) {
397                console.log('Selected package:', selectedPackage);
398            }
399
400            fetch("/external/fetch?template=" + currentPage.template + "&package=" + selectedPackage + "&entity=" + currentPage.entity + "&id=" + currentPage.id + "&language=" + language)
401                .then((response) => response.json())
402                .then((campaign) => {
403                    if (campaign && campaign.campaign) {
404                        createCampaign(campaign.campaign);
405                    }
406                });
407
408        }
409    }
410
411});
412
413// function createStickyHeaderBanner(banner) {
414//     console.log('createStickyHeaderBanner');
415
416//     // Crea il div del banner
417//     const bannerDiv = document.createElement('div');
418//     bannerDiv.id = 'sticky-header-banner';
419
420//     // Use the new utility function
421//     showBanner(bannerDiv, banner);
422
423//     // Aggiungi un pulsante per chiudere il banner
424//     const closeBtn = document.createElement('button');
425//     closeBtn.textContent = '×';
426//     closeBtn.className = 'sticky-header-banner-close';
427//     closeBtn.onclick = () => {
428//         bannerDiv.remove();
429//         // Rimuovi la classe dal bodyWrapper
430//         const bodyWrapper = document.body;
431//         if (bodyWrapper) {
432//             bodyWrapper.classList.remove('header-banner-enabled');
433//         }
434//     };
435//     bannerDiv.appendChild(closeBtn);
436
437//     // Inserisci il banner come primo figlio del body
438//     document.body.insertBefore(bannerDiv, document.body.firstChild);
439
440//     // Add class to #body_wrapper
441//     const bodyWrapper = document.body;
442//     if (bodyWrapper) {
443//         bodyWrapper.classList.add('header-banner-enabled');
444//     }
445// }

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.