PageSourceSearch

https://jaba-discount.ru/local/js/cookie-consent.js

js jaba-discount.ru collected 2026-10-07 18:06:20 UTC 11,794 bytes, 316 lines download raw bytes

1// Cookie consent center (152-ФЗ amendments in force since 2025-09-01:
2// marketing widgets need explicit, per-category consent; analytics was
3// exempted by the owner decision of 2026-09-19 and runs unconditionally).
4// First visit gets a bottom-right card with the widgets switch:
5//   necessary   — always on, runs the site (session, basket, city);
6//   widgets     — Jivo chat (wlnBSkDprV) and the Marquiz quiz.
7// The Yandex.Metrika counter 96864379 loads from here for every visitor
8// (moved out of the yandex.metrika module option 'counters' cleared on
9// production; see ops/bitrix/pdn-consent-gate.php). The widgets decision
10// is stored in the jaba_cookie_consent cookie for 12 months ('widgets' or
11// 'none'; legacy 'analytics,…' values are still parsed — the analytics
12// token is ignored). Other scripts gate on
13// window.JabaCookieConsent.allows('widgets') or listen for the
14// jaba-cookie-consent document event ({ detail: { analytics, widgets } }).
15(function () {
16    'use strict';
17
18    var COOKIE_NAME = 'jaba_cookie_consent';
19    var COOKIE_MAX_AGE = 31536000; // 12 months, in seconds
20    var POLICY_URL = '/info/requisites/#privacy';
21
22    // admin pages and kernel endpoints (/bitrix/admin, /bitrix/tools, ...)
23    // are not user-facing and must not carry the banner
24    if (window.location.pathname.indexOf('/bitrix/') === 0) {
25        return;
26    }
27
28    // ---- consent state -------------------------------------------------
29
30    function readCookie(name) {
31        var parts = document.cookie ? document.cookie.split(';') : [];
32        for (var i = 0; i < parts.length; i++) {
33            var pair = parts[i].trim();
34            if (pair.indexOf(name + '=') === 0) {
35                return pair.substring(name.length + 1);
36            }
37        }
38        return '';
39    }
40
41    // v1 values: 'accepted' granted analytics and widgets, 'rejected'
42    // turned optional widgets off — keep that state. v2 comma lists may
43    // still carry an 'analytics' token; it is ignored since the counter
44    // no longer depends on consent.
45    function parseStatus() {
46        var raw = readCookie(COOKIE_NAME);
47        if (raw === 'accepted') {
48            return { decided: true, widgets: true };
49        }
50        if (raw === 'rejected') {
51            return { decided: true, widgets: false };
52        }
53        var granted = raw ? raw.split(',') : [];
54        return {
55            decided: raw !== '',
56            widgets: granted.indexOf('widgets') >= 0,
57        };
58    }
59
60    function persistStatus(status) {
61        var cookie = COOKIE_NAME + '=' + (status.widgets ? 'widgets' : 'none')
62            + '; max-age=' + COOKIE_MAX_AGE + '; path=/; SameSite=Lax';
63        if (window.location.protocol === 'https:') {
64            cookie += '; Secure';
65        }
66        document.cookie = cookie;
67    }
68
69    // ---- vendors --------------------------------------------------------
70
71    var METRIKA_COUNTER = 96864379;
72    var JIVO_WIDGET_ID = 'wlnBSkDprV';
73    var MARQUIZ_QUIZ_ID = '66daf91be3e0e2002674a23d';
74
75    var loaded = {};
76
77    // Same init params the yandex.metrika module used (module option
78    // 'counters' cleared on production; see ops/bitrix/pdn-consent-gate.php).
79    function loadAnalytics() {
80        if (loaded.analytics || window.ym) {
81            return;
82        }
83        loaded.analytics = true;
84        window.dataLayer = window.dataLayer || [];
85        (function (m, e, t, r, i, k, a) {
86            m[i] = m[i] || function () { (m[i].a = m[i].a || []).push(arguments); };
87            m[i].l = 1 * new Date();
88            k = e.createElement(t);
89            a = e.getElementsByTagName(t)[0];
90            k.async = 1;
91            k.src = r;
92            a.parentNode.insertBefore(k, a);
93        })(window, document, 'script', 'https://mc.yandex.ru/metrika/tag.js', 'ym');
94        window.ym(METRIKA_COUNTER, 'init', {
95            clickmap: true,
96            trackLinks: true,
97            accurateTrackBounce: true,
98            webvisor: true,
99            ecommerce: 'dataLayer',
100        });
101        // aspro metrika.goals reads this to address the counter
102        window.counters = [String(METRIKA_COUNTER)];
103    }
104
105    // Jivo: the standard module snippet (option 'widget_id' cleared on
106    // production) only inserts the widget script.
107    function loadJivo() {
108        var s = document.createElement('script');
109        s.async = true;
110        s.src = '//code.jivosite.com/script/widget/' + JIVO_WIDGET_ID;
111        var first = document.getElementsByTagName('script')[0];
112        first.parentNode.insertBefore(s, first);
113    }
114
115    // Marquiz: loader + init from the aspro header.php block and the Pop
116    // side-button config from footer.php, both removed on production.
117    function loadMarquiz() {
118        window.addEventListener('marquizLoaded', function () {
119            try {
120                window.Marquiz.add(['Pop', {
121                    id: MARQUIZ_QUIZ_ID,
122                    title: 'Пройти тест',
123                    text: 'Качественные стройматериалы в дискаунтере "Жаба"',
124                    delay: 0,
125                    textColor: '#ffffff',
126                    bgColor: '#59b130',
127                    svgColor: '#ffffff',
128                    closeColor: '#ffffff',
129                    bonusCount: 2,
130                    bonusText: 'Вам доступны бонусы',
131                    type: 'side',
132                    position: 'position_bottom-left',
133                    rounded: true,
134                    shadow: 'rgba(89, 177, 48, 0)',
135                    blicked: true,
136                }]);
137            } catch (e) {
138                // the quiz button is optional and must never break the page
139            }
140        });
141        (function (w, d, s, o) {
142            var j = d.createElement(s);
143            j.async = true;
144            j.src = '//script.marquiz.ru/v2.js';
145            j.onload = function () {
146                if (document.readyState !== 'loading') {
147                    w.Marquiz.init(o);
148                } else {
149                    d.addEventListener('DOMContentLoaded', function () {
150                        w.Marquiz.init(o);
151                    });
152                }
153            };
154            d.head.insertBefore(j, d.head.firstElementChild);
155        })(window, document, 'script', {
156            host: '//quiz.marquiz.ru',
157            region: 'eu',
158            id: MARQUIZ_QUIZ_ID,
159            autoOpen: 10,
160            autoOpenFreq: 'once',
161            openOnExit: true,
162            disableOnMobile: false,
163        });
164    }
165
166    function loadWidgets() {
167        if (loaded.widgets) {
168            return;
169        }
170        loaded.widgets = true;
171        loadJivo();
172        loadMarquiz();
173    }
174
175    // The Metrika counter runs for every visitor (owner decision
176    // 2026-09-19); only the widgets stay behind the consent decision.
177    loadAnalytics();
178
179    function applyStatus(status) {
180        if (status.widgets) {
181            loadWidgets();
182        }
183    }
184
185    function decide(banner, widgets) {
186        var status = { decided: true, widgets: widgets };
187        persistStatus(status);
188        banner.remove();
189        applyStatus(status);
190        try {
191            document.dispatchEvent(new CustomEvent('jaba-cookie-consent', {
192                detail: { analytics: true, widgets: widgets },
193            }));
194        } catch (e) {
195            // browsers without CustomEvent keep the cookie flow intact
196        }
197    }
198
199    // ---- banner ---------------------------------------------------------
200
201    function makeGroup(className, checked, locked, labelHtml) {
202        var label = document.createElement('label');
203        label.className = className;
204        var input = document.createElement('input');
205        input.type = 'checkbox';
206        input.checked = checked;
207        input.disabled = locked;
208        var span = document.createElement('span');
209        span.innerHTML = labelHtml;
210        label.appendChild(input);
211        label.appendChild(span);
212        return { label: label, input: input };
213    }
214
215    function render() {
216        var banner = document.createElement('div');
217        banner.className = 'jaba-cookie-consent';
218        banner.setAttribute('role', 'region');
219        banner.setAttribute('aria-label', 'Использование cookie-файлов');
220
221        var text = document.createElement('p');
222        text.className = 'jaba-cookie-consent__text';
223        text.innerHTML = 'Сайт «ЖАБА» использует cookie-файлы: необходимые — '
224            + 'для работы сайта, корзины и выбранного города, виджеты '
225            + 'онлайн-чата и подбора товара — только с вашего разрешения. '
226            + 'Подробнее — '
227            + '<a href="' + POLICY_URL + '" target="_blank" rel="noopener">Персональные данные и cookie</a>.';
228
229        var groups = document.createElement('div');
230        groups.className = 'jaba-cookie-consent__groups';
231        groups.appendChild(makeGroup(
232            'jaba-cookie-consent__group jaba-cookie-consent__group--locked',
233            true,
234            true,
235            'Необходимые — работа сайта, корзина, выбранный город (всегда включены)'
236        ).label);
237        var widgets = makeGroup(
238            'jaba-cookie-consent__group',
239            false,
240            false,
241            'Виджеты — онлайн-чат и подбор товара (Jivo, Marquiz)'
242        );
243        groups.appendChild(widgets.label);
244
245        var actions = document.createElement('div');
246        actions.className = 'jaba-cookie-consent__actions';
247
248        var accept = document.createElement('button');
249        accept.type = 'button';
250        accept.className = 'jaba-cookie-consent__accept';
251        accept.textContent = 'Принять выбранные';
252        accept.addEventListener('click', function () {
253            decide(banner, widgets.input.checked);
254        });
255
256        var reject = document.createElement('button');
257        reject.type = 'button';
258        reject.className = 'jaba-cookie-consent__reject';
259        reject.textContent = 'Только необходимые';
260        reject.addEventListener('click', function () {
261            decide(banner, false);
262        });
263
264        actions.appendChild(accept);
265        actions.appendChild(reject);
266        banner.appendChild(text);
267        banner.appendChild(groups);
268        banner.appendChild(actions);
269        document.body.appendChild(banner);
270    }
271
272    function mount() {
273        if (document.body) {
274            render();
275            return true;
276        }
277        return false;
278    }
279
280    // ---- public API ------------------------------------------------------
281
282    window.JabaCookieConsent = {
283        cookieName: COOKIE_NAME,
284        status: function () {
285            return parseStatus();
286        },
287        allows: function (category) {
288            if (category === 'analytics') {
289                // Metrika runs for every visitor (owner decision
290                // 2026-09-19) — kept true for the goal scripts
291                return true;
292            }
293            if (category === 'widgets') {
294                return parseStatus().widgets;
295            }
296            return false;
297        },
298        // legacy alias: the v1 banner gated analytics only
299        isAccepted: function () {
300            return true;
301        },
302    };
303
304    var initial = parseStatus();
305    if (initial.decided) {
306        applyStatus(initial);
307        return;
308    }
309
310    if (mount()) {
311        return;
312    }
313    document.addEventListener('DOMContentLoaded', function () {
314        mount();
315    });
316}());

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.