PageSourceSearch

https://www.optimus.lv/cookie/cookie-consent.js

js optimus.lv collected 2026-10-02 00:12:36 UTC 25,965 bytes, 677 lines download raw bytes

1(function () {
2    // 1. Ensure this only runs on the client (browser)
3    if (typeof window === 'undefined') return;
4
5    var consentScript = document.currentScript || document.querySelector('script[src*="cookie-consent.js"]');
6    var scriptSrc = consentScript ? (consentScript.getAttribute('src') || '') : '';
7    var versionMatch = scriptSrc.match(/[?&]v=([^&]+)/);
8    var versionParam = versionMatch ? '?v=' + encodeURIComponent(versionMatch[1]) : '';
9    var privacyPolicyUrl = consentScript
10        ? consentScript.getAttribute('data-privacy-policy-url')
11        : null;
12    var privacyPolicyLabel = consentScript
13        ? consentScript.getAttribute('data-privacy-policy-label')
14        : null;
15
16    // 2. CHECK FOR CAPACITOR: Abort if running in a native Android/iOS app
17    if (window.Capacitor && window.Capacitor.isNativePlatform()) {
18        console.log("Running in Capacitor Native App - Skipping Cookie Consent");
19        return; // Stops the rest of the script from executing
20    }
21    
22    window.dataLayer = window.dataLayer || [];
23    function gtag() { window.dataLayer.push(arguments); }
24
25
26    // 2. Store your raw HTML as a string
27    function getCookieHtml() {
28        var t = window.COOKIE_CONFIG?.text || {};
29
30            return `
31    <div id="cookie-wrapper" class="cookie-wrapper" style="display:none;">
32        <div class="cookie-modal">
33            <div class="tab-additional">
34                <div class="cookie-close">
35                    <button class="close-btn" onclick="closeTab()" aria-label="Close">
36                        ×
37                    </button>
38                </div>
39            </div>
40
41            <div class="cookie-modal-inside">
42                <div id="tab-consent" class="tab-content">
43                    <div class="tab-content-left-side">
44                    <div class="cookie-header">
45                    <div class="cookie-tabs">
46                        <button class="cookie-tab active" onclick="showTab('consent')">
47                            ${t.consentTab || 'consentTab'}
48                        </button>
49                        <button class="cookie-tab" onclick="showTab('info')">
50                            ${t.infoTab || 'infoTab'}
51                        </button>
52                    </div>
53                    <div class="cookie-close" style="display:none">
54                        <button class="close-btn" onclick="closeTab()" aria-label="Close">
55                            ×
56                        </button>
57                    </div>
58                </div>
59                    <div class="cookie-content">
60                        <p>
61                            ${t.description || 'description'}
62                        </p>
63                        <div class="cookie-disclosure-links">
64                            <a
65                                class="cookie-disclosure-link"
66                                href="${privacyPolicyUrl || '/pages/privacy_policy'}"
67                            >${privacyPolicyLabel || 'Privacy Policy'}</a>
68                            <a
69                                class="cookie-disclosure-link"
70                                href="https://business.safety.google/privacy/"
71                                target="_blank"
72                                rel="noopener noreferrer"
73                            >${t.googleDataUseLink || 'Learn how Google uses personal data'}</a>
74                        </div>
75                    </div>
76
77                    <div class="wrap-sections-headers">
78                        <div class="cookie-section">
79                            <div class="cookie-section-header">
80                                <label class="checkbox-container disabled">
81                                    <input type="checkbox" checked disabled>
82                                    <span class="checkmark"></span>
83                                </label>
84                                <span>
84${t.necessaryCookies || 'necessaryCookies'}</span>
85                            </div>
86                        </div>
87
88                        <div class="cookie-section">
89                            <div class="cookie-section-header" onclick="toggleSection(event,this)">
90                                <label class="checkbox-container">
91                                    <input type="checkbox" id="statistics">
92                                    <span class="checkmark"></span>
93                                </label>
94                                <span>${t.statisticsCookies || 'statisticsCookies'}</span>
95                            </div>
96                        </div>
97
98                        <div class="cookie-section">
99                            <div class="cookie-section-header" onclick="toggleSection(event,this)">
100                                <label class="checkbox-container">
101                                    <input type="checkbox" id="marketing">
102                                    <span class="checkmark"></span>
103                                </label>
104                                <span>${t.marketingCookies || 'marketingCookies'}</span>
105                            </div>
106                        </div>
107                        <div class="cookie-section">
108                            <div class="cookie-section-header" onclick="toggleSection(event,this)">
109                                <label class="checkbox-container">
110                                    <input type="checkbox" id="functional">
111                                    <span class="checkmark"></span>
112                                </label>
113                                <span>${t.functionalCookies || 'functionalCookies'}</span>
114                            </div>
115                        </div>
116                    </div>
117                    </div>
118                    <div class="tab-content-right-side">
119
120                    <div class="cookie-buttons">
121                        <button id="primary-cookie-btn" onclick="handlePrimaryClick()" class="cookie-btn cookie-btn-primary">
122                            ${t.acceptAll || 'Accept All'}
123                        </button>
124                        <button onclick="declineAll()" class="cookie-btn cookie-btn-secondary">
125                            ${t.declineAll || 'declineAll'}
126                        </button>
127                    </div>
128                    </div>
129                </div>
130
131                <div id="tab-info" class="tab-content hidden">
132                    <div class="cookie-tabs">
133                        <button class="cookie-tab" onclick="showTab('consent')">
134                            ${t.consentTab || 'consentTab'}
135                        </button>
136                        <button class="cookie-tab active" onclick="showTab('info')">
137                            ${t.infoTab || 'infoTab'}
138                        </button>
139                    </div>
140                    <div class="cookie-content" style="display:flex;flex-direction:column;gap:16px;">
141                        <div class="cookie-group">
142                            <p>
143                                ${t.infoText1 || 'infoText1'} </br>
144                                ${t.infoText2 || 'infoText2'}</br>
145                                ${t.infoText3 || 'infoText3'}</br>
146                                ${t.infoText4 || 'infoText4'}</br>
147                                </p>
148                        </div>
149                        <div class="cookie-group">
150                            <h4>
150${t.necessaryCookies || 'Necessary'}</h4>
151                            <p>${t.necessaryDesc || 'Required for site to work.'}</p>
152                        </div>
153
154                        <div class="cookie-group">
155                            <h4>${t.statisticsCookies || 'Performance'}</h4>
156                            <p>${t.performanceDesc || 'Used for analytics.'}</p>
157                        </div>
158
159                        <div class="cookie-group">
160                            <h4>${t.marketingCookies || 'Marketing'}</h4>
161                            <p>${t.marketingDesc || 'Used for ads.'}</p>
162                        </div>
163
164                        <div class="cookie-group">
165                            <h4>${t.functionalCookies || 'Functional'}</h4>
166                            <p>${t.functionalDesc || 'Remember preferences.'}</p>
167                        </div>
168                    </div>
169                </div>
170            </div>
171        </div>
172    </div>
173    `;
174    }
175
176    function getDeviceType() {
177        const ua = navigator.userAgent.toLowerCase()
178
179        const isTablet = /ipad|tablet|android(?!.*mobile)/.test(ua)
180        const isMobile = /iphone|ipod|android.*mobile|windows phone/.test(ua)
181
182        if (isTablet) return 'tablet'
183        if (isMobile) return 'mobile'
184        return 'desktop'
185    }
186
187    // 3. Function to inject HTML into the body
188    function injectHTML() {
189        if (document.getElementById('cookie-wrapper')) return
190
191        var container = document.createElement('div')
192        container.innerHTML = getCookieHtml()
193
194        var wrapper = container.firstElementChild
195        if (!wrapper) return
196
197        const device = getDeviceType()
198
199        if (device === 'mobile') {
200            wrapper.classList.add('cookie-wrapper-mobile')
201        } else {
202            wrapper.classList.add('cookie-wrapper-desktop')
203        }
204
205        document.body.appendChild(container)
206    }
207
208    var IDS = {
209        wrapper: "cookie-wrapper",
210        note: "notification",
211        marketing: "marketing",
212        statistics: "statistics",
213        functional: "functional"
214    };
215    
216    function $(id) { return document.getElementById(id); }
217    function getChecked(id) { var el = $(id); return !!(el && el.checked); }
218    function setChecked(id, v) { var el = $(id); if (el) el.checked = !!v; }
219    function hasEl(id) { return !!$(id); }
220    function uuidv4() {
221        return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
222            var r = Math.random() * 16 | 0, v = c === "x" ? r : (r & 0x3 | 0x8);
223            return v.toString(16);
224        });
225    }
226
227    // NEW: State for the requested behavior
228    var consentCustomized = false;
229    var backgroundDismissArmed = false;
230    var backgroundDismissTimer = null;
231
232    // NEW: Update primary button text based on state
233    function updatePrimaryButton() {
234        var btn = document.getElementById('primary-cookie-btn');
235        if (!btn) return;
236        var t = window.COOKIE_CONFIG?.text || {};
237        var newText = consentCustomized 
238            ? (t.saveAndClose || 'Save and Close') 
239            : (t.acceptAll || 'Accept All');
240        btn.textContent = newText;
241    }
242
243    // NEW: Handle click on the primary blue button
244    function handlePrimaryClick() {
245        if (!consentCustomized) {
246            // "Accept All" was clicked → grant everything
247            setChecked(IDS.statistics, true);
248            setChecked(IDS.marketing, true);
249            setChecked(IDS.functional, true);
250        }
251        // In both cases (Accept All OR Save and Close) we just save current state
252        saveSelected();
253    }
254
255    // NEW: Listen for any checkbox change (including row clicks via toggleSection)
256    function setupCheckboxListeners() {
257        var checkboxes = [
258            document.getElementById(IDS.statistics),
259            document.getElementById(IDS.marketing),
260            document.getElementById(IDS.functional)
261        ];
262        checkboxes.forEach(function (cb) {
263            if (cb) {
264                cb.addEventListener('change', function () {
265                    consentCustomized = true;
266                    updatePrimaryButton();
267                });
268            }
269        });
270    }
271
272    function resetBackgroundDismissHint() {
273        backgroundDismissArmed = false;
274        // if (backgroundDismissTimer) {
275        //     window.clearTimeout(backgroundDismissTimer);
276        //     backgroundDismissTimer = null;
277        // }
278
279        var wrapper = $(IDS.wrapper);
280        if (wrapper) wrapper.classList.remove("cookie-background-hint");
281    }
282
283    function handleBackgroundClick(event) {
284        var wrapper = $(IDS.wrapper);
285        if (!wrapper) return;
286
287        // Only the dark overlay counts. Clicks inside the banner never close it.
288        if (event.target !== wrapper) {
289            resetBackgroundDismissHint();
290            return;
291        }
292
293        if (backgroundDismissArmed) {
294            resetBackgroundDismissHint();
295            closeTab();
296            return;
297        }
298
299        backgroundDismissArmed = true;
300        wrapper.classList.add("cookie-background-hint");
301        // backgroundDismissTimer = window.setTimeout(function () {
302        //     resetBackgroundDismissHint();
303        // }, 3900);
304    }
305
306    function setupBackgroundDismiss() {
307        var wrapper = $(IDS.wrapper);
308        if (!wrapper || wrapper.dataset.backgroundDismissReady === "true") return;
309
310        wrapper.dataset.backgroundDismissReady = "true";
311        wrapper.addEventListener("click", handleBackgroundClick);
312    }
313  
314    // 1. Updated showBanner: Now it ONLY handles UI visibility
315    function showBanner() {
316        resetBackgroundDismissHint();
317        var w = $(IDS.wrapper);
318        if (w) w.style.display = "flex";
319        
320        var r = $(IDS.reopen);
321        if (r) r.classList.add("hidden");
322
323        window.dataLayer.push({
324            event: "consent_banner_shown"
325        });
326    }
327    function hideBanner() {
328        resetBackgroundDismissHint();
329        var w = $(IDS.wrapper);
330        if (w)
331            w.style.display = "none";
332        var r = $(IDS.reopen);
333        if (r)
334            r.classList.remove("hidden");
335    }
336
337    var LS_KEY = "cookieConsent";
338
339    function getCookie(name) {
340        try {
341            var value = "; " + document.cookie;
342            var parts = value.split("; " + name + "=");
343            if (parts.length === 2) return decodeURIComponent(parts.pop().split(";").shift());
344        } catch (e) {}
345        return null;
346    }
347
348    function setCookie(name, value, days) {
349        try {
350            var expires = "";
351            if (days) {
352                var date = new Date();
353                date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
354                expires = "; expires=" + date.toUTCString();
355            }
356            document.cookie = name + "=" + encodeURIComponent(value) + expires + "; path=/; SameSite=Lax";
357        } catch (e) {}
358    }
359
360    function readConsent() {
361        var raw = null;
362        try {
363            raw = window.localStorage.getItem(LS_KEY);
364        } catch (e) {}
365
366        if (!raw) {
367            raw = getCookie(LS_KEY);
368        }
369
370        if (!raw) {
371            try {
372                raw = window.sessionStorage.getItem(LS_KEY);
373            } catch (e) {}
374        }
375
376        if (!raw) return null;
377
378        try {
379            return JSON.parse(raw);
380        } catch (e) {
381            console.error("Consent parse error", e);
382            return null;
383        }
384    }
385
386    function writeConsent(c) {
387        var str = JSON.stringify(c);
388        try {
389            window.localStorage.setItem(LS_KEY, str);
390        } catch (e) {
391            console.error("Consent write error", e);
392        }
393        setCookie(LS_KEY, str, 180);
394        try {
395            window.sessionStorage.setItem(LS_KEY, str);
396        } catch (e) {}
397    }
398
399    var stored = readConsent();
400
401    function isConsentExpired(consent) {
402        if (!consent || !consent.updatedAt) return false;
403
404        var lastUpdate = new Date(consent.updatedAt).getTime();
405        var sixMonthsInMs = 180 * 24 * 60 * 60 * 1000;
406
407        return !isNaN(lastUpdate) && new Date().getTime() - lastUpdate > sixMonthsInMs;
408    }
409
410    if (stored && !isConsentExpired(stored)) {
411        // Tell Google RIGHT NOW so tags don't error out
412        gtag("consent", "update", {
413            ad_storage: stored.marketing ? "granted" : "denied",
414            ad_user_data: stored.marketing ? "granted" : "denied",
415            ad_personalization: stored.marketing ? "granted" : "denied",
416            analytics_storage: stored.statistics ? "granted" : "denied",
417            functionality_storage: stored.functional ? "granted" : "denied"
418        });
419        window.dataLayer.push({ event: "consent_ready", hasStoredConsent: true });
420
421        if (typeof fbq !== 'undefined') {
422            if (typeof window.fbq === 'function') {
423                if (stored.marketing) {
424                    window.fbq('consent', 'grant');
425                } else {
426                    window.fbq('consent', 'revoke');
427                }
428            }
429        }
430    }
431
432    function applyConsent(consent, source, previousConsent) {
433        var marketing = !!consent.marketing;
434        var statistics = !!consent.statistics;
435        var functional = !!consent.functional;
436        var statisticsWasGranted = !!(previousConsent && previousConsent.statistics);
437
438        gtag("consent", "update", {
439            ad_storage: marketing ? "granted" : "denied",
440            ad_user_data: marketing ? "granted" : "denied",
441            ad_personalization: marketing ? "granted" : "denied",
442            analytics_storage: statistics ? "granted" : "denied",
443            functionality_storage: functional ? "granted" : "denied",
444        });
445
446            // ✅ Facebook
447        if (typeof fbq !== 'undefined') {
448            if (typeof window.fbq === 'function') {
449                if (marketing) {
450                    window.fbq('consent', 'grant');
451                } else {
452                    window.fbq('consent', 'revoke');
453                }
454            }
455        }
456
457        // Initial page views are created while consent is denied. Send one
458        // when statistics consent is granted for the first time.
459        if (statistics && !statisticsWasGranted) {
460            var pageViewParameters = {
461                page_title: document.title,
462                page_location: window.location.href,
463                page_path: window.location.pathname + window.location.search
464            };
465
466            if (window.__googleAnalyticsProvider === 'gtag' && typeof window.gtag === 'function') {
467                if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
468                    pageViewParameters.debug_mode = true;
469                }
470                window.gtag('event', 'page_view', pageViewParameters);
471            } else {
472                window.dataLayer.push({ ecommerce: null });
473                window.dataLayer.push(Object.assign({ event: 'page_view' }, pageViewParameters));
474            }
475        }
476
477        window.dataLayer.push({
478            event: "consent_updated",
479            source: source || "unknown",
480            marketing: marketing,
481            statistics: statistics,
482            functional: functional,
483            necessary: true,
484            consentId: consent.consentId || null,
485            updatedAt: consent.updatedAt || null,
486            version: consent.version || 1
487        });
488
489        window.dispatchEvent(new CustomEvent('consent_updated', { detail: consent }));
490    }
491
492    function saveSelected() {
493        var existing = readConsent() || {};
494        var consent = {
495            marketing: hasEl(IDS.marketing) ? getChecked(IDS.marketing) : false,
496            statistics: hasEl(IDS.statistics) ? getChecked(IDS.statistics) : false,
497            functional: hasEl(IDS.functional) ? getChecked(IDS.functional) : false,
498            necessary: true,
499            consentId: existing.consentId || uuidv4(),
500            updatedAt: new Date().toISOString(),
501            version: (existing.version || 1)
502        };
503        writeConsent(consent);
504        hideBanner();
505        applyConsent(consent, "user_action", existing);
506    }
507   
508    function declineAll(){
509        setChecked(IDS.marketing, false);
510        setChecked(IDS.statistics, false);
511        setChecked(IDS.functional, false);
512        saveSelected();
513    }
514    function reopenConsent() {
515        var stored = readConsent();
516        
517        // If we have stored data, use it. If not (new user), default to true.
518        var statsValue = (stored && stored.hasOwnProperty('statistics')) ? !!stored.statistics : true;
519        var marketingValue = (stored && stored.hasOwnProperty('marketing')) ? !!stored.marketing : true;
520        var functionalValue = (stored && stored.hasOwnProperty('functional')) ? !!stored.functional : true;
521
522        if (hasEl(IDS.statistics)) setChecked(IDS.statistics, statsValue);
523        if (hasEl(IDS.marketing)) setChecked(IDS.marketing, marketingValue);
524        if (hasEl(IDS.functional)) setChecked(IDS.functional, functionalValue);
525
526        // NEW: Re-open is always "customized" mode (user is editing previous consent)
527        consentCustomized = true;
528        updatePrimaryButton();
529
530        showBanner();
531        
532        // hasStoredConsent is true here because we are RE-opening based on existing data
533        window.dataLayer.push({ event: "consent_ready", hasStoredConsent: true });
534    }
535
536    function showTab(id) {
537        try {
538            var tabs = document.querySelectorAll(".tab-content");
539            for (var i = 0; i < tabs.length; i++) {
540                tabs[i].classList.add("hidden");
541            }
542            var btns = document.querySelectorAll(".cookie-tab");
543            // for (var j = 0; j < btns.length; j++) {
544            //     btns[j].classList.remove("active");
545            // }
546            var tgt = document.getElementById("tab-" + id);
547            if (tgt)
548                tgt.classList.remove("hidden");
549            // if (window.event && window.event.target)
550                // window.event.target.classList.add("active");
551        } catch (e) { }
552    }
553
554    function closeTab(){
555        declineAll()
556    }
557
558    function toggleSection(event, header) {
559        if (!header) return;
560        
561        // 1. Check if the user clicked directly on the checkbox or its custom design.
562        // We use .closest() to see if the click happened inside our checkbox container.
563        var clickedElement = event.target;
564        if (
565            clickedElement.tagName === 'INPUT' || 
566            clickedElement.tagName === 'LABEL' || 
567            clickedElement.classList.contains('checkmark') ||
568            clickedElement.closest('.checkbox-container')
569        ) {
570            // Let the browser handle the native click/toggle
571            return; 
572        }
573
574        // 2. Find the checkbox inside this specific header
575        var checkbox = header.querySelector('input[type="checkbox"]');
576        
577        // 3. Toggle its checked state manually since the user clicked the row background
578        if (checkbox) {
579            checkbox.checked = !checkbox.checked;
580            
581            // 4. Important: Manually trigger the 'change' event 
582            // because changing .checked via JS doesn't fire it automatically.
583            checkbox.dispatchEvent(new Event('change', { bubbles: true }));
584        }
585    }
586
587    window.saveSelected = saveSelected;
588    window.declineAll = declineAll;
589    window.reopenConsent = reopenConsent;
590    window.showTab = showTab;
591    window.closeTab = closeTab;
592    window.toggleSection = toggleSection;
593    window.handlePrimaryClick = handlePrimaryClick;   // NEW
594
595    // 3. Updated initCookie: Logic remains clean
596    function initCookie() {
597        injectHTML(); 
598        
599        // NEW: Setup change listeners once (right after HTML is injected)
600        setupCheckboxListeners();
601        setupBackgroundDismiss();
602
603        var stored = readConsent();
604        var isExpired = isConsentExpired(stored);
605
606        // Logic: If we have valid (non-expired) consent, hide the banner
607        // Logic: If we have valid (non-expired) consent, hide the banner
608        if (stored && !isExpired) {
609            if (hasEl(IDS.marketing)) setChecked(IDS.marketing, !!stored.marketing);
610            if (hasEl(IDS.statistics)) setChecked(IDS.statistics, !!stored.statistics);
611            if (hasEl(IDS.functional)) setChecked(IDS.functional, !!stored.functional);
612            hideBanner();
613        } 
614        // Logic: First time / expired → UNMARKED checkboxes + "Accept All" button
615        else {
616            if (hasEl(IDS.statistics)) setChecked(IDS.statistics, false);
617            if (hasEl(IDS.marketing)) setChecked(IDS.marketing, false);
618            if (hasEl(IDS.functional)) setChecked(IDS.functional, false);
619            
620            consentCustomized = false;
621            updatePrimaryButton();
622            
623            showBanner();
624            
625            window.dataLayer.push({ 
626                event: "consent_ready", 
627                hasStoredConsent: false,
628            });
629        }
630    }
631
632    function loadScript(src, callback, errorCallback) {
633        var s = document.createElement('script');
634        s.src = src;
635        s.defer = true;
636        s.onload = callback;
637        s.onerror = errorCallback;
638        document.head.appendChild(s);
639    }
640
641
642    var domain = window.location.hostname; 
643    // example: optimus, site.ee
644
645    var lang = document.documentElement.lang || navigator.language || 'en';
646    lang = lang.toLowerCase().substring(0, 2); 
647
648    domain = domain.replace('www.', '');
649
650    var configFile = '/cookie/translations/cookie-' + lang  + '.js' + versionParam;
651    var defaultFile = '/cookie/translations/cookie-en.js' + versionParam;
652
653    function loadConfigAndInit() {
654        loadScript(configFile, function () {
655            initCookie();
656        }, function () {
657            if (configFile === defaultFile) {
658                initCookie();
659                return;
660            }
661
662            loadScript(defaultFile, function () {
663                initCookie();
664            }, function () {
665                // The banner still works with the inline fallback labels.
666                initCookie();
667            });
668        });
669    }
670
671    // Run when DOM is ready
672    if (document.readyState === "loading") {
673        document.addEventListener("DOMContentLoaded", loadConfigAndInit);
674    } else {
675        loadConfigAndInit()
676    }
677})();

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.