PageSourceSearch

https://ormaplanet.com/js/cookie-consent.js?v=IMvR6WMoXSael7IODuaWarVoC6iFMKuqNVMsrhUaKXU

js ormaplanet.com collected 2026-10-04 03:17:26 UTC 8,943 bytes, 292 lines download raw bytes

1/*
2 * Cookie consent (banner + preferences panel).
3 *
4 * Stores a granular choice per category instead of a single "seen the banner" flag,
5 * and is the only thing allowed to load non-technical trackers: nothing that writes a
6 * non-essential cookie may be loaded until the matching category has been granted.
7 *
8 * Public API: window.OrmaCookieConsent
9 *   .get()             -> { technical, statistics, profiling, ts } | null (null = no choice yet)
10 *   .allows(category)  -> bool
11 *   .onChange(fn)      -> fn(state); fires immediately if a choice already exists
12 *   .openPreferences() -> opens the second layer (used by the footer link)
13 */
14(function (window, document) {
15    'use strict';
16
17    var STORAGE_KEY = 'orma_cookie_consent';
18    var LEGACY_KEY = 'Cookie';
19    // Bump when the categories or the wording change: a bump re-asks everyone.
20    var VERSION = 1;
21
22    var listeners = [];
23    var current = null;
24    var root = null;
25
26    function readStored() {
27        try {
28            var raw = window.localStorage.getItem(STORAGE_KEY);
29            if (!raw) {
30                return null;
31            }
32            var parsed = JSON.parse(raw);
33            if (!parsed || parsed.v !== VERSION) {
34                return null;
35            }
36            return {
37                technical: true,
38                statistics: parsed.statistics === true,
39                profiling: parsed.profiling === true,
40                ts: parsed.ts
41            };
42        } catch (e) {
43            return null;
44        }
45    }
46
47    function persist(state) {
48        try {
49            window.localStorage.setItem(STORAGE_KEY, JSON.stringify({
50                v: VERSION,
51                technical: true,
52                statistics: state.statistics === true,
53                profiling: state.profiling === true,
54                ts: state.ts
55            }));
56            // The old flag only recorded "banner dismissed" and carried no categories.
57            window.localStorage.removeItem(LEGACY_KEY);
58        } catch (e) {
59            /* private mode / storage disabled: the choice holds for this page only */
60        }
61    }
62
63    function notify() {
64        for (var i = 0; i < listeners.length; i++) {
65            try {
66                listeners[i](current);
67            } catch (e) {
68                /* one bad listener must not block the others */
69            }
70        }
71    }
72
73    function apply(statistics, profiling) {
74        current = {
75            technical: true,
76            statistics: statistics === true,
77            profiling: profiling === true,
78            ts: new Date().toISOString()
79        };
80        persist(current);
81        hideBanner();
82        closePreferences();
83        notify();
84    }
85
86    /* ----- Google consent mode / analytics loading ----- */
87
88    var gtagLoaded = false;
89
90    function gtag() {
91        window.dataLayer.push(arguments);
92    }
93
94    function initGoogleConsent() {
95        window.dataLayer = window.dataLayer || [];
96        // Denied until the user says otherwise, and set before any Google tag can run.
97        gtag('consent', 'default', {
98            ad_storage: 'denied',
99            ad_user_data: 'denied',
100            ad_personalization: 'denied',
101            analytics_storage: 'denied',
102            functionality_storage: 'granted',
103            security_storage: 'granted'
104        });
105    }
106
107    function syncGoogleConsent(state, measurementId) {
108        if (!state) {
109            return;
110        }
111
112        gtag('consent', 'update', {
113            ad_storage: state.profiling ? 'granted' : 'denied',
114            ad_user_data: state.profiling ? 'granted' : 'denied',
115            ad_personalization: state.profiling ? 'granted' : 'denied',
116            analytics_storage: state.statistics ? 'granted' : 'denied'
117        });
118
119        if (!measurementId || gtagLoaded || !(state.statistics || state.profiling)) {
120            return;
121        }
122
123        gtagLoaded = true;
124        var script = document.createElement('script');
125        script.async = true;
126        script.src = 'https://www.googletagmanager.com/gtag/js?i
126d=' + encodeURIComponent(measurementId);
127        document.head.appendChild(script);
128
129        gtag('js', new Date());
130        gtag('config', measurementId);
131    }
132
133    /* ----- DOM ----- */
134
135    function banner() {
136        return root ? root.querySelector('[data-cookie-banner]') : null;
137    }
138
139    function panel() {
140        return root ? root.querySelector('[data-cookie-prefs]') : null;
141    }
142
143    function showBanner() {
144        var el = banner();
145        if (el) {
146            el.classList.remove('d-none');
147        }
148    }
149
150    function hideBanner() {
151        var el = banner();
152        if (el) {
153            el.classList.add('d-none');
154        }
155    }
156
157    function toggleInput(category) {
158        return root ? root.querySelector('[data-cookie-toggle="' + category + '"]') : null;
159    }
160
161    function openPreferences() {
162        var el = panel();
163        if (!el) {
164            return;
165        }
166
167        // Non-technical categories open unchecked unless the user previously granted them.
168        var stats = toggleInput('statistics');
169        var prof = toggleInput('profiling');
170        if (stats) {
171            stats.checked = current ? current.statistics === true : false;
172        }
173        if (prof) {
174            prof.checked = current ? current.profiling === true : false;
175        }
176
177        el.classList.remove('d-none');
178        var focusable = el.querySelector('[data-cookie-action="save"]');
179        if (focusable) {
180            focusable.focus();
181        }
182    }
183
184    function closePreferences() {
185        var el = panel();
186        if (el) {
187            el.classList.add('d-none');
188        }
189    }
190
191    function onAction(action) {
192        if (action === 'accept-all') {
193            apply(true, true);
194        } else if (action === 'reject-all') {
195            apply(false, false);
196        } else if (action === 'open-preferences') {
197            openPreferences();
198        } else if (action === 'save') {
199            var stats = toggleInput('statistics');
200            var prof = toggleInput('profiling');
201            apply(stats ? stats.checked : false, prof ? prof.checked : false);
202        } else if (action === 'close-preferences') {
203            closePreferences();
204        }
205    }
206
207    function bind() {
208        root = document.querySelector('[data-cookie-consent]');
209        if (!root) {
210            return;
211        }
212
213        document.addEventListener('click', function (e) {
214            var target = e.target && e.target.closest ? e.target.closest('[data-cookie-action]') : null;
215            if (!target) {
216                return;
217            }
218            e.preventDefault();
219            onAction(target.getAttribute('data-cookie-action'));
220        });
221
222        document.addEventListener('keydown', function (e) {
223            var el = panel();
224            if (e.key === 'Escape' && el && !el.classList.contains('d-none')) {
225                closePreferences();
226            }
227        });
228
229        var overlay = panel();
230        if (overlay) {
231            overlay.addEventListener('click', function (e) {
232                if (e.target === overlay) {
233                    closePreferences();
234                }
235            });
236        }
237
238        var measurementId = root.getAttribute('data-ga-id') || '';
239        api.onChange(function (state) {
240            syncGoogleConsent(state, measurementId);
241        });
242
243        if (current) {
244            hideBanner();
245        } else {
246            showBanner();
247        }
248    }
249
250    var api = {
251        get: function () {
252            return current ? {
253                technical: true,
254                statistics: current.statistics,
255                profiling: current.profiling,
256                ts: current.ts
257            } : null;
258        },
259        allows: function (category) {
260            if (category === 'technical') {
261                return true;
262            }
263            return !!current && current[category] === true;
264        },
265        onChange: function (fn) {
266            if (typeof fn !== 'function') {
267                return;
268            }
269            listeners.push(fn);
270            if (current) {
271                fn(current);
272            }
273        },
274        openPreferences: openPreferences,
275        acceptAll: function () {
276            apply(true, true);
277        },
278        rejectAll: function () {
279            apply(false, false);
280        }
281    };
282
283    initGoogleConsent();
284    current = readStored();
285    window.OrmaCookieConsent = api;
286
287    if (document.readyState === 'loading') {
288        document.addEventListener('DOMContentLoaded', bind);
289    } else {
290        bind();
291    }
292})(window, document);

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.