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.