1(function () { 2 "use strict"; 3 4 var GA4_ID = "G-EDD07P75CL"; 5 var GTM_ID = "GTM-KZH5Z9GR"; 6 var INTERCOM_APP_ID = "p7ulgbr9"; 7 // Meta pixel of the ad sets (the previous value was the ad ACCOUNT id, not 8 // a pixel: every browser event went nowhere). 9 var META_PIXEL_ID = "1589487805675731"; 10 // ChatGPT / OpenAI Ads pixel. Single place to change it for www. 11 var OPENAI_ADS_PIXEL_ID = "2M76RfpzYwf3YUmc5kK3EX"; 12 var OPENAI_ADS_SDK_URL = "https://bzrcdn.openai.com/sdk/oaiq.min.js"; 13 var OPENAI_ADS_PRODUCTION_HOSTS = ["app.idomyou.fr", "www.idomyou.fr", "idomyou.fr"]; 14 var CROSS_DOMAIN_LINKER = { 15 domains: [ 16 "www.idomyou.fr", 17 "app.idomyou.fr", 18 "idomyou.fr", 19 "www.idomyou.com", 20 "app.idomyou.com", 21 "idomyou.com" 22 ] 23 }; 24 25 function onIdle(callback) { 26 if ("requestIdleCallback" in window) { 27 window.requestIdleCallback(callback, { timeout: 2500 }); 28 return; 29 } 30 31 window.setTimeout(callback, 1200); 32 } 33 34 function onReady(callback) { 35 if (document.readyState === "loading") { 36 document.addEventListener("DOMContentLoaded", callback, { once: true }); 37 return; 38 } 39 40 callback(); 41 } 42 43 function configureGtagLinker() { 44 window.dataLayer = window.dataLayer || []; 45 window.gtag = window.gtag || function () { 46 window.dataLayer.push(arguments); 47 }; 48 49 window.gtag("js", new Date()); 50 window.gtag("config", GA4_ID, { 51 linker: CROSS_DOMAIN_LINKER 52 }); 53 } 54 55 function loadGoogleTag() { 56 if (document.getElementById("idomyou-google-tag-script")) return; 57 58 var script = document.createElement("script"); 59 script.id = "idomyou-google-tag-script"; 60 script.async = true; 61 script.src = "https://www.googletagmanager.com/gtag/js?id=" + GA4_ID; 62 document.head.appendChild(script); 63 } 64 65 function loadGtm() { 66 if (document.getElementById("idomyou-gtm-script")) return; 67 68 window.dataLayer = window.dataLayer || []; 69 window.dataLayer.push({ 70 "gtm.start": new Date().getTime(), 71 event: "gtm.js" 72 }); 73 74 var script = document.createElement("script"); 75 script.id = "idomyou-gtm-script"; 76 script.async = true; 77 script.src = "https://www.googletagmanager.com/gtm.js?id=" + GTM_ID; 78 document.head.appendChild(script); 79 } 80 81 function loadMetaPixel() { 82 if (window.fbq || document.getElementById("idomyou-meta-pixel-script")) return; 83 84 var fbq = window.fbq = function () { 85 fbq.callMethod ? fbq.callMethod.apply(fbq, arguments) : fbq.queue.push(arguments); 86 }; 87 88 if (!window._fbq) window._fbq = fbq; 89 fbq.push = fbq; 90 fbq.loaded = true; 91 fbq.version = "2.0"; 92 fbq.queue = []; 93 94 var script = document.createElement("script"); 95 script.id = "idomyou-meta-pixel-script"; 96 script.async = true; 97 script.src = "https://connect.facebook.net/en_US/fbevents.js"; 98 document.head.appendChild(script); 99 100 fbq("init", META_PIXEL_ID); 101 fbq("track", "PageView"); 102 } 103 104 // OpenAI Ads (oaiq) â loaded once, async, only after marketing consent. 105 function loadOpenAiAdsPixel() { 106 if (window.oaiq || document.getElementById("idomyou-openai-ads-script")) return; 107 108 var oaiq = window.oaiq = function () { 109 oaiq.q.push(arguments); 110 }; 111 oaiq.q = []; 112 113 var script = document.createElement("script"); 114 script.id = "idomyou-openai-ads-script"; 115 script.async = true; 116 script.src = OPENAI_ADS_SDK_URL; 117 document.head.appendChild(script); 118 119 oaiq("init", { 120 pixelId: OPENAI_ADS_PIXEL_ID, 121 debug: OPENAI_ADS_PRODUCTION_HOSTS.indexOf(window.location.hostname) === -1 122 }); 123 } 124 125 function primeIntercomStub() { 126 var settings = window.intercomSettings || { 127 api_base: "https://api-iam.intercom.io", 128 app_id: INTERCOM_APP_ID 129 }; 130 var intercom = window.Intercom; 131 132 window.intercomSettings = settings; 133 134 if (typeof intercom === "function") return intercom; 135 136 var stub = function () { 137 stub.c(arguments); 138 }; 139 stub.q = []; 140 stub.c = function (args) { 141 stub.q.push(args); 142 }; 143 window.Intercom = typeof intercom === "function" ? intercom : stub; 144 145 return window.Intercom; 146 } 147 148 function loadIntercom() { 149 var intercom = primeIntercomStub(); 150 151 if (typeof intercom === "function" && intercom.booted) { 152 intercom("reattach_activator"); 153 intercom("update", window.intercomSettings); 154 return; 155 } 156 157 if (document.getElementById("idomyou-intercom-script")) return; 158 159 var script = document.createElement("script"); 160 script.id = "idomyou-intercom-script"; 161 script.async = true; 162 script.src = "https://widget.intercom.io/widget/" + INTERCOM_APP_ID; 163 document.head.appendChild(script); 164 } 165 166 function lazyLoadMapFrames() { 167 var frames = Array.prototype.slice.call( 168 document.querySelectorAll("iframe[data-src][data-lazy-map]") 169 ); 170 171 if (!frames.length) return; 172 173 function loadFrame(frame) {
174 if (frame.src || !frame.dataset.src) return; 175 frame.src = frame.dataset.src; 176 } 177 178 if (!("IntersectionObserver" in window)) { 179 frames.forEach(loadFrame); 180 return; 181 } 182 183 var observer = new IntersectionObserver(function (entries) { 184 entries.forEach(function (entry) { 185 if (!entry.isIntersecting) return; 186 loadFrame(entry.target); 187 observer.unobserve(entry.target); 188 }); 189 }, { rootMargin: "200px" }); 190 191 frames.forEach(function (frame) { 192 frame.addEventListener("click", function () { 193 loadFrame(frame); 194 }, { once: true }); 195 observer.observe(frame); 196 }); 197 } 198 199 function lazyLoadReviewsScript() { 200 var reviewRoots = document.querySelectorAll("[data-google-review-marquee]"); 201 if (!reviewRoots.length || document.getElementById("idomyou-google-reviews-script")) { 202 return; 203 } 204 205 function loadReviewsScript() { 206 if (document.getElementById("idomyou-google-reviews-script")) return; 207 208 var script = document.createElement("script"); 209 script.id = "idomyou-google-reviews-script"; 210 script.src = "js/google-reviews-marquee.js?v=20260504-1"; 211 script.defer = true; 212 document.body.appendChild(script); 213 } 214 215 if (!("IntersectionObserver" in window)) { 216 loadReviewsScript(); 217 return; 218 } 219 220 var observer = new IntersectionObserver(function (entries) { 221 if (!entries.some(function (entry) { return entry.isIntersecting; })) return; 222 loadReviewsScript(); 223 observer.disconnect(); 224 }, { rootMargin: "300px" }); 225 226 Array.prototype.forEach.call(reviewRoots, function (root) { 227 observer.observe(root); 228 }); 229 } 230 231 // Cross-domain continuity www -> app: forward the marketing query string on 232 // every link to app.idomyou.fr at click time. The idy_attr cookie 233 // (.idomyou.fr) is the primary carrier; the URL is belt and braces. Done in 234 // a capture-phase click listener so CMS-rendered cards, i18n-rewritten 235 // buttons and target="_blank" links are all covered without a load-time scan. 236 var APP_LINK_PATTERN = /^https?:\/\/app\.idomyou\.(fr|com)(\/|\?|#|$)/i; 237 // `idy_ref` = host of the external referrer recorded on www (the app's own 238 // document.referrer is always www once the visitor clicks through). Same 239 // treatment as a forwarded gclid: read from the attribution record the 240 // consent manager exposes, no storage of its own. 241 var FORWARDED_PARAM_KEYS = [ 242 "gclid", "gbraid", "wbraid", "fbclid", "msclkid", 243 "utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", 244 "idy_ref" 245 ]; 246 247 function collectForwardedParams() { 248 var params = {}; 249 250 try { 251 var current = new URLSearchParams(window.location.search || ""); 252 253 FORWARDED_PARAM_KEYS.forEach(function (key) { 254 var value = current.get(key); 255 256 if (value) params[key] = value; 257 }); 258 } catch (_error) { 259 // ignore malformed query strings 260 } 261 262 var attribution = 263 window.idomyouConsent && typeof window.idomyouConsent.getAttribution === "function" 264 ? window.idomyouConsent.getAttribution() 265 : null; 266 267 if (attribution) { 268 FORWARDED_PARAM_KEYS.forEach(function (key) { 269 if (!params[key] && attribution[key]) params[key] = attribution[key]; 270 }); 271 } 272 273 if ( 274 !params.idy_ref && 275 window.idomyouConsent && 276 typeof window.idomyouConsent.getExternalReferrerHost === "function" 277 ) { 278 var referrerHost = window.idomyouConsent.getExternalReferrerHost(); 279 280 if (referrerHost) params.idy_ref = referrerHost; 281 } 282 283 return params; 284 } 285 286 function decorateAppLink(anchor) { 287 var href = anchor.getAttribute("href") || ""; 288 289 if (!APP_LINK_PATTERN.test(href)) return; 290 291 var url; 292 293 try { 294 url = new URL(href); 295 } catch (_error) { 296 return; 297 } 298 299 if (url.protocol === "http:") url.protocol = "https:"; 300 301 var params = collectForwardedParams(); 302 303 Object.keys(params).forEach(function (key) { 304 if (!url.searchParams.has(key)) url.searchParams.set(key, params[key]); 305 }); 306 307 anchor.setAttribute("href", url.toString()); 308 } 309 310 function forwardAttributionToAppLinks() { 311 if (typeof URL !== "function" || typeof URLSearchParams !== "function") return; 312 313 function onLinkActivation(event) { 314 var target = event.target; 315 var anchor = target && typeof target.closest === "function" 316 ? target.closest("a[href]") 317 : null; 318 319 if (anchor) decorateAppLink(anchor); 320 } 321 322 // Capture phase, several activation paths: pointerdown/touchstart run 323 // before the navigation of a tap that never emits "click" in some mobile 324 // browsers, focusin covers keyboard users, contextmenu covers "copy link" 325 // / "open in new tab". decorateAppLink is idempotent (searchParams.has). 326 ["pointerdown", "touchstart", "mousedown", "click", "auxclick", "contextmenu", "focu
326sin"] 327 .forEach(function (eventName) { 328 document.addEventListener(eventName, onLinkActivation, true); 329 }); 330 331 // One pass over the links already in the DOM (CMS-rendered cards and the 332 // i18n rewrites come later; the listeners above cover those at click). 333 Array.prototype.forEach.call(document.querySelectorAll("a[href]"), decorateAppLink); 334 } 335 336 function getConsentPreferences() { 337 if (!window.idomyouConsent || typeof window.idomyouConsent.getPreferences !== "function") { 338 return null; 339 } 340 341 return window.idomyouConsent.getPreferences(); 342 } 343 344 function loadConsentDependentScripts(preferences) { 345 if (!preferences) return; 346 347 if (preferences.analytics === true) { 348 configureGtagLinker(); 349 loadGoogleTag(); 350 } 351 352 if (preferences.marketing === true) { 353 loadGtm(); 354 loadMetaPixel(); 355 loadOpenAiAdsPixel(); 356 } 357 358 if (preferences.support === true) { 359 primeIntercomStub(); 360 window.setTimeout(function () { 361 onIdle(loadIntercom); 362 }, 15000); 363 } 364 } 365 366 onReady(function () { 367 forwardAttributionToAppLinks(); 368 lazyLoadMapFrames(); 369 lazyLoadReviewsScript(); 370 371 loadConsentDependentScripts(getConsentPreferences()); 372 373 if (window.idomyouConsent && typeof window.idomyouConsent.onChange === "function") { 374 window.idomyouConsent.onChange(loadConsentDependentScripts); 375 } 376 }); 377}());
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.