1/* 2 * cm-clickpass.js â [alefrenz 2026-08-07, memoria lunga 2026-08-23] 3 * PONTE DEI CLICK-ID: le campagne (Google/Meta/TikTok/Bing) atterrano sui siti satellite, 4 * ma la prenotazione avviene su clubmagellano.it. In quel salto di dominio l'identificativo 5 * del click (gclid & co.) resta sul satellite e la conversione non è MAI stata attribuita. 6 * Questo script prende i click-id e gli utm_ dall'URL di atterraggio e li appende a ogni 7 * link verso clubmagellano.it â così il Conversion Linker dall'altra parte li raccoglie. 8 * 9 * [2026-08-23] MEMORIA LUNGA. Prima la memoria era di SESSIONE: chi cliccava l'annuncio, guardava 10 * e tornava tre giorni dopo arrivava su clubmagellano.it come visita organica, e la campagna 11 * spariva. Ora il tocco di campagna resta 90 giorni su QUESTO dominio (localStorage) e viaggia 12 * verso clubmagellano.it in un parametro a parte, `cm_camp`. 13 * Perché a parte e non riusando gli utm_: gli utm_ dicono «questa visita arriva dalla campagna», 14 * e per la visita di oggi non sarebbe vero. `cm_camp` alimenta soltanto la memoria lunga 15 * dall'altra parte; il canale della sessione resta quello vero di oggi. 16 * 17 * Nessun dato personale, nessuna chiamata di rete. Deployato sui 13 satelliti. 18 */ 19(function () { 20 var KEYS = ['gclid', 'gbraid', 'wbraid', 'fbclid', 'ttclid', 'msclkid', 21 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; 22 var MEM = 'cm_clickids_p'; /* memoria lunga (90 giorni) */ 23 var GIORNI = 90; 24 25 var found = {}; 26 try { 27 var qs = new URLSearchParams(location.search); 28 KEYS.forEach(function (k) { var v = qs.get(k); if (v) found[k] = v; }); 29 } catch (e) { return; } 30 31 /* memoria di sessione: navigazione multi-pagina prima di cliccare «prenota» */ 32 try { 33 var stored = JSON.parse(sessionStorage.getItem('cm_clickids') || '{}'); 34 var merged = {}; 35 KEYS.forEach(function (k) { if (stored[k]) merged[k] = stored[k]; }); 36 Object.keys(found).forEach(function (k) { merged[k] = found[k]; }); /* l'URL vince */ 37 if (Object.keys(found).length) sessionStorage.setItem('cm_clickids', JSON.stringify(merged)); 38 found = merged; 39 } catch (e) { /* sessionStorage bloccato: si decora solo dalla pagina di atterraggio */ } 40 41 /* memoria lunga: si aggiorna solo con un arrivo TAGGATO, e si legge finché non scade */ 42 var camp = null; 43 try { 44 if (Object.keys(found).length) { 45 var utm = {}, cid = ''; 46 ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'].forEach(function (k) { 47 if (found[k]) utm[k] = String(found[k]).slice(0, 160); 48 }); 49 if (found.gclid || found.gbraid || found.wbraid) cid = 'gclid'; 50 else if (found.fbclid) cid = 'fbclid'; 51 else if (found.ttclid) cid = 'ttclid'; 52 else if (found.msclkid) cid = 'msclkid'; 53 if (Object.keys(utm).length || cid) { 54 camp = { v: 1, ts: Math.floor(Date.now() / 1000), utm: utm, cid: cid, 55 ref: location.hostname.toLowerCase().replace(/^www\./, '').slice(0, 120), 56 land: location.pathname.slice(0, 160) }; 57 localStorage.setItem(MEM, JSON.stringify(camp)); 58 } 59 } 60 if (!camp) { 61 var vecchio = JSON.parse(localStorage.getItem(MEM) || 'null'); 62 if (vecchio && vecchio.ts && (Math.floor(Date.now() / 1000) - vecchio.ts) < GIORNI * 86400) camp = vecchio; 63 else if (vecchio) localStorage.removeItem(MEM); 64 } 65 } catch (e) { /* storage bloccato o pieno: si continua senza memoria lunga */ } 66 67 var campParam = null; 68 if (camp) { 69 try { 70 campParam = btoa(unescape(encodeURIComponent(JSON.stringify(camp)))) 71 .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); 72 if (campParam.length > 1200) campParam = null; 73 } catch (e) { campParam = null; } 74 } 75 76 if (!Object.keys(found).length && !campParam) return; 77 78 function decorate(a) { 79 try { 80 var u = new URL(a.getAttribute('href'), location.href); 81 if (!/(^|\.)clubmagellano\.it$/i.test(u.hostname)) return; 82 var changed = false; 83 KEYS.forEach(function (k) { 84 if (found[k] && !u.searchParams.has(k)) { u.searchParams.set(k, found[k]); changed = true; } 85 }); 86 if (campParam && !u.searchParams.has('cm_camp')) { u.searchParams.set('cm_camp', campParam); changed = true; } 87 if (changed) a.setAttribute('href', u.toString()); 88 } catch (e) { /* href relativo malformato o javascript: â si lascia stare */ } 89 } 90
91 function runAll() { 92 var links = document.querySelectorAll('a[href]'); 93 for (var i = 0; i < links.length; i++) decorate(links[i]); 94 } 95 96 if (document.readyState === 'loading') { 97 document.addEventListener('DOMContentLoaded', runAll); 98 } else { 99 runAll(); 100 } 101 /* link creati DOPO (calendari e tabelle via AJAX): si decora all'ultimo istante, al click */ 102 document.addEventListener('click', function (e) { 103 var n = e.target; 104 while (n && n.nodeType === 1 && n.tagName !== 'A') n = n.parentNode; 105 if (n && n.tagName === 'A' && n.getAttribute('href')) decorate(n); 106 }, true); 107})();
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.