PageSourceSearch

https://proverit-propusk.ru/leadflow.js?v=1790230155

js proverit-propusk.ru collected 2026-09-24 12:24:32 UTC 10,919 bytes, 206 lines download raw bytes

1/* leadflow.js v1.9 (копия lead.js эталона; адрес /leadflow.php задаётся data-endpoint у скрипта) */
2(function () {
3  var D = (document.currentScript && document.currentScript.dataset) || {};
4  var EP = D.endpoint || '/lead.php', PREFIX = (D.prefix || '').toUpperCase().charAt(0), YM = parseInt(D.ym, 10) || 0;
5  var ALPHABET = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ', cid = '', cidReady = false, token = '', tokenAt = 0;
6  var TOKEN_AGE = 3200;
7  var TOKEN_REFRESH = 3600e3, refreshing = false, inited = false;
8
9  function cookie(n) { var m = document.cookie.match('(?:^|; )' + n + '=([^;]*)'); return m ? decodeURIComponent(m[1]) : ''; }
10  function getCid(cb) {
11    if (cidReady) return cb(cid);
12    var tries = 25, done = false;
13    var finish = function (v) { if (done) return; done = true; cid = v || cookie('_ym_uid'); cidReady = true; cb(cid); };
14    (function go() {
15      if (window.ym && YM) {
16        ym(YM, 'getClientID', finish);
17        setTimeout(function () { finish(''); }, 3000);
18      }
19      else if (tries-- > 0) { setTimeout(go, 200); }
20      else { finish(''); }
21    })();
22  }
23  function getToken(cb, force) {
24    if (token && !force) return cb(token);
25    fetch(EP + '?action=token', { credentials: 'same-origin' }).then(function (r) { return r.json(); })
26      .then(function (j) {
27        if (j.token) { token = j.token; tokenAt = Date.now(); }
28        if (!YM && j.ym) YM = parseInt(j.ym, 10) || 0;
29        if (!PREFIX && j.prefix) PREFIX = String(j.prefix).toUpperCase().charAt(0);
30        mail(j);
31        cb(token);
32      }).catch(function () { cb(token); });
33  }
34
35
36  var MAIL = { def: '', cur: '', seen: {}, touched: 0, live: false };
37  function mail(j) {
38    if (!j || !j.default) return;
39    MAIL.def = String(j.default).toLowerCase();
40    MAIL.seen[MAIL.def] = 1;
41    MAIL.cur = String(j.email || j.default).toLowerCase();
42    MAIL.touched = Date.now();
43    MAIL.live = !!(j.tracked || j.busy);
44    if (MAIL.cur !== MAIL.def || document.querySelector('[data-email]')) swapMail(document);
45  }
46  function swapMail(root) {
47    if (!MAIL.cur) return;
48    var known = function (a) { return !!MAIL.seen[String(a || '').toLowerCase()]; };
49    Array.prototype.forEach.call(root.querySelectorAll('a[href^="mailto:"]'), function (a) {
50      var m = a.getAttribute('href').match(/^mailto:([^?]*)(.*)$/i);
51      if (!m || !known(decodeURIComponent(m[1]))) return;
52      a.setAttribute('href', 'mailto:' + MAIL.cur + m[2]);
53      if (known(a.textContent.trim())) a.textContent = MAIL.cur;
54    });
55    Array.prototype.forEach.call(root.querySelectorAll('[data-email]'), function (el) {
56      el.textContent = MAIL.cur;
57      if (el.tagName === 'A') el.setAttribute('href', 'mailto:' + MAIL.cur);
58    });
59    Array.prototype.forEach.call(root.querySelectorAll('[data-messenger="email"]'), function (a) {
60      if (!a.dataset.to || known(a.dataset.to)) a.dataset.to = MAIL.cur;
61    });
62    MAIL.seen[MAIL.cur] = 1;
63  }
64  function touchMail() {
65    if (!MAIL.live || Date.now() - MAIL.touched < 300e3) return;
66    MAIL.touched = Date.now();
67    fetch(EP + '?action=email&ym_client_id=' + encodeURIComponent(cid), { credentials: 'same-origin' })
68      .then(function (r) { return r.json(); }).then(mail).catch(function () {});
69  }
70  function refreshToken() {
71    touchMail();
72    if (!inited || refreshing || (token && Date.now() - tokenAt < TOKEN_REFRESH)) return;
73    refreshing = true;
74    getToken(function () { refreshing = false; prepareAll(); }, true);
75  }
76  function hidden(f, name, value) {
77    var el = f.querySelector('input[name="' + name + '"]');
78    if (!el) { el = document.createElement('input'); el.type = 'hidden'; el.name = name; f.appendChild(el); }
79    el.value = value || '';
80  }
81  function prepare(f) {
82    hidden(f, 'ym_client_id', cid);
83    hidden(f, 'token', token);
84    if (!f.querySelector('input[name="website"]')) {
85      var h = document.createElement('input'); h.name = 'website'; h.tabIndex = -1; h.autocomplete = 'off';
86      h.style.cssText = 'position:absolute;left:-9999px;opacity:0;height:0'; f.appendChild(h);
87    }
88  }
89  function prepareAll() { Array.prototype.forEach.call(document.querySelectorAll('form'), prepare); }
90  function goals(next) {
91    next = next || function () {};
92    var m = document.cookie.match('(?:^|; )lead_goal=([^;]*)'), raw = m ? decodeURIComponent(m[1].replace(/\+/g, ' ')) : '', list = [];
93    if (!raw) return next();
94    document.cookie = 'lead_goal=; path=/; max-age=0; samesite=Lax';
95    try { list = JSON.parse(raw) || []; } catch (e) {}
96    if (!list.length || !YM || !window.ym) return next();
97    var once = false, go = function () { if (!once) { once = true; next(); } };
98    list.forEach(function (x, i) { ym(YM, 'reachGoal', x.g, x.p || {}, i === list.length - 1 ? go : undefined); });
99    setTimeout(go, 500);
100  }
101  function finish(f, j) {
102    if (j.ok) { if (f.dataset.redirect) location.href = f.dataset.redirect; else f.reset(); }
103    else alert(j.message || 'Проверьте поля формы');
104  }
105
106
107  function submit(f) {
108    if (!f || !f.dataset || !f.dataset.lead) return;
109    var btn = f.querySelector('[type=submit]'); if (btn) btn.disabled = true;
110    getToken(function () {
111      prepare(f);
112      var fd = new FormData(f); fd.set('action', 'lead'); fd.set('channel', f.dataset.lead);
113      var wait = Math.max(0, TOKEN_AGE - (Date.now() - tokenAt));
114      new Promise(function (res) { setTimeout(res, wait); })
115        .then(function () { return fetch(EP, { method: 'POST', body: fd, credentials: 'same-origin' }); })
116        .then(function (r) { return r.json(); })
117        .then(function (j) {
118          f.dispatchEvent(new CustomEvent('lead:done', { detail: j, bubbles: true }));
119          goals(function () { finish(f, j); });
120        })
121        .catch(function () { alert('Не удалось отправить, попробуйте ещё раз'); })
122        .then(function () { if (btn) btn.disabled = false; });
123    });
124  }
125
126  function leadSend(data) {
127    data = data || {};
128    return new Promise(function (resolve) {
129      getToken(function () {
130        var fd = new FormData();
131        ['channel', 'phone', 'name', 'email', 'comment', 'portal_id', 'embed'].forEach(function (k) { if (data[k] != null) fd.set(k, String(data[k])); });
132        fd.set('action', 'lead'); fd.set('token', token);
132 fd.set('ym_client_id', cid); fd.set('website', ''); fd.set('page', location.href.slice(0, 255));
133        setTimeout(function () {
134          fetch(EP, { method: 'POST', body: fd, credentials: 'same-origin' }).then(function (r) { return r.json(); })
135            .then(function (j) {
136              document.dispatchEvent(new CustomEvent('lead:done', { detail: Object.assign({ embed: data.embed || '', channel: data.channel || '' }, j) }));
137              goals(function () { resolve(j); });
138            })
139            .catch(function () { resolve({ ok: false, field: '', message: 'Не удалось отправить, попробуйте ещё раз' }); });
140        }, Math.max(0, TOKEN_AGE - (Date.now() - tokenAt)));
141      });
142    });
143  }
144
145  document.addEventListener('submit', function (e) {
146    var f = e.target;
147    if (!f || !f.dataset || !f.dataset.lead) return;
148    e.preventDefault();
149    if (f.dataset.leadManual === undefined) submit(f);
150  }, true);
151
152
153  function code() {
154    var c = PREFIX || 'A', r = new Uint32Array(4);
155    if (window.crypto && crypto.getRandomValues) crypto.getRandomValues(r); else for (var j = 0; j < 4; j++) r[j] = Math.floor(Math.random() * 1e9);
156    for (var i = 0; i < 4; i++) c += ALPHABET.charAt(r[i] % ALPHABET.length);
157    return c;
158  }
159  function link(kind, to, c) {
160    var text = encodeURIComponent('Здравствуйте, мой промокод ' + c);
161    if (kind === 'whatsapp')     return 'https://wa.me/' + to.replace(/\D/g, '') + '?text=' + text;
162    if (kind === 'telegram-bot') return 'https://t.me/' + to.replace(/^@/, '') + '?start=' + c;
163    if (kind === 'telegram')     return 'https://t.me/' + to.replace(/^@/, '') + '?text=' + text;
164    if (kind === 'max-bot')      return 'https://max.ru/' + to.replace(/^@/, '') + '?start=' + c;
165    if (kind === 'email')        return 'mailto:' + to + '?subject=' + encodeURIComponent('Заявка с сайта · промокод ' + c) + '&body=' + text;
166    return '#';
167  }
168  function channelOf(kind) { return kind === 'max-bot' ? 'max' : kind.replace('-bot', ''); }
169  function send(body) {
170    var fd = new FormData(); Object.keys(body).forEach(function (k) { fd.append(k, body[k]); });
171    var ok = false;
172    try { ok = navigator.sendBeacon && navigator.sendBeacon(EP, fd); } catch (e) {}
173    if (!ok) fetch(EP, { method: 'POST', body: fd, keepalive: true, credentials: 'same-origin' }).catch(function () { queue(body); });
174  }
175  function queue(body) { try { var q = JSON.parse(localStorage.getItem('visitq') || '[]'); q.push(body); localStorage.setItem('visitq', JSON.stringify(q.slice(-20))); } catch (e) {} }
176  function flush() {
177    try {
178      var q = JSON.parse(localStorage.getItem('visitq') || '[]'); localStorage.removeItem('visitq');
179      q.filter(function (b) { return Date.now() - b.t < 864e5; }).forEach(send);
180    } catch (e) {}
181  }
182  document.addEventListener('click', function (e) {
183    var m = e.target.closest && e.target.closest('a[href^="mailto:"]');
184    if (m && m.parentNode) swapMail(m.parentNode);
185  }, true);
186  document.addEventListener('click', function (e) {
187    var a = e.target.closest && e.target.closest('[data-messenger]');
188    if (!a) return;
189    e.preventDefault();
190    if (a.dataset.messenger === 'email' && MAIL.cur && (!a.dataset.to || MAIL.seen[a.dataset.to.toLowerCase()])) a.dataset.to = MAIL.cur;
191    var c = code(), kind = a.dataset.messenger, url = link(kind, a.dataset.to || '', c);
192    var hint = a.dataset.hint && document.querySelector(a.dataset.hint); if (hint) hint.textContent = c;
193    if (kind === 'email') { location.href = url; } else { var w = window.open(url, '_blank'); if (!w) location.href = url; }
194    send({ action: 'visit', code: c, channel: channelOf(kind), landing: location.pathname, ym_client_id: cid, t: Date.now() });
195  });
196
197  function init() { getCid(function () { getToken(function () { inited = true; prepareAll(); }); }); flush(); goals(); }
198  setInterval(function () { if (document.cookie.indexOf('lead_goal=') > -1) goals(); }, 1500);
199  ['scroll', 'click', 'keydown', 'touchstart'].forEach(function (ev) { document.addEventListener(ev, refreshToken, { passive: true, capture: true }); });
200  document.addEventListener('visibilitychange', function () { if (!document.hidden) refreshToken(); });
201  window.addEventListener('pageshow', function (e) { if (e.persisted) refreshToken(); });
202  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); else init();
203  window.leadVisitCode = code;
204  window.leadSubmit = submit;
205  window.leadSend = leadSend;
206})();

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.