Введите номер вашего счетчика Яндекс.Метрики, и скрипт автоматически обновится:
<script>
/**
* ============================================
* Скрипт защиты от ботов для мессенджеров
* Разработка: Истомин Антон
* TG-блог: "ADSкий Яндекс Директ"
* ============================================
*/
(function () {
// ==== КОНФИГУРАЦИЯ ====
var COUNTER_ID = 45588258; // ID Метрики
var DELAY_BEFORE_REDIRECT_GOAL = 500; // уменьшено с 15000 до 500ms для надежной отправки
var SS_PENDING_REDIRECT_KEY = 'phonePendingRedirect';
var lastClickTimestamp = 0; // для дебаунсинга
function unwrapRedirect(url) {
try {
if (!url) return url;
if (/^tel:/i.test(url)) return url;
var u = new URL(url, window.location.origin);
for (var pair of u.searchParams.entries()) {
var val = decodeURIComponent(pair[1] || '');
if (/^tel:\+?\d+/i.test(val)) return val;
if (/^\+?\d{6,15}$/.test(val)) return 'tel:' + val;
}
var m = u.search.match(/(\+?\d{6,15})/);
if (m) return 'tel:' + m[1];
return url;
} catch (e) {
return url;
}
}
function ymReach(goal) {
if (typeof ym !== 'undefined') {
try { ym(COUNTER_ID, 'reachGoal', goal); } catch(e) {}
}
}
function ymReachWithBeacon(goal) {
if (navigator.sendBeacon && typeof ym !== 'undefined') {
try { ym(COUNTER_ID, 'reachGoal', goal); } catch(e) {}
}
}
var pending = null, pendingTimeout = null;
function scheduleAfterSlider(info) {
pending = info;
try { sessionStorage.setItem(SS_PENDING_REDIRECT_KEY, JSON.stringify(pending)); } catch(e){}
if (pendingTimeout) clearTimeout(pendingTimeout);
pendingTimeout = setTimeout(function() {
if (pending && pending.type) {
ymReach('phone_redirect');
try { sessionStorage.removeItem(SS_PENDING_REDIRECT_KEY); } catch(e){}
}
pendingTimeout = null;
}, DELAY_BEFORE_REDIRECT_GOAL);
}
// === UI: слайдер ===
function showSliderAndCall(rawTarget) {
var target = unwrapRedirect(rawTarget);
if (document.getElementById('phone-pre-redirect')) return;
var overlay = document.createElement('div');
overlay.id = 'phone-pre-redirect';
overlay.style.cssText =
'position:fixed;inset:0;background:rgba(0,0,0,0.6);display:flex;' +
'align-items:center;justify-content:center;z-index:2147483647';
var box = document.createElement('div');
box.style.cssText =
'background:#fff;border-radius:14px;padding:22px;width:340px;max-width:90%;' +
'text-align:center;box-shadow:0 8px 30px rgba(0,0,0,.25);font-family:system-ui';
box.innerHTML =
'<div style="font-weight:700;font-size:18px;margin-bottom:8px">Позвонить</div>' +
'<div style="color:#444;font-size:14px;margin-bottom:12px">Проведите ползунок вправо, чтобы подтвердить вызов</div>' +
'<div id="phone-slider" style="position:relative;height:48px;background:#f0f2f7;border-radius:24px;overflow:hidden;touch-action:none">'+
'<div id="phone-track" style="position:absolute;inset:0;background:#f0f2f7;"></div>' +
'<div id="phone-handle" style="position:absolute;left:6px;top:4px;width:40px;height:40px;border-radius:50%;background:#2563eb;color:#fff;display:flex;align-items:center;justify-content:center;cursor:grab;font-size:18px;user-select:none">→</div>' +
'<div id="phone-text" style="position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);pointer-events:none;color:#6b7280;font-size:14px">Проведите вправо</div>' +
'</div>';
overlay.appendChild(box);
document.body.appendChild(overlay);
var container = box.querySelector('#phone-slider');
var handle = box.querySelector('#phone-handle');
var track = box.querySelector('#phone-track');
var maxLeft = 0;
var isDrag = false, startX = 0, startLeft = 6;
// ИСПРАВЛЕНИЕ: вычисляем maxLeft после отрисовки через requestAnimationFrame
requestAnimationFrame(function() {
maxLeft = container.offsetWidth - handle.offsetWidth - 8;
});
function start(e){
isDrag = true;
startX = e.touches ? e.touches[0].clientX : e.clientX;
startLeft = parseInt(handle.style.left) || 6;
handle.style.cursor = 'grabbing';
e.preventDefault();
}
function move(e){
if (!isDrag) return;
var x = e.touches ? e.touches[0].clientX : e.clientX;
var diff = x - startX;
var newLeft = Math.max(6, Math.min(startLeft + diff, maxLeft));
handle.style.left = newLeft + 'px';
var progress = maxLeft > 0 ? (newLeft - 6) / maxLeft : 0;
track.style.background =
'linear-gradient(90deg,#a0c3ff ' + (progress*100) + '%, #f0f2f7 ' + (progress*100) + '%)';
e.preventDefault();
}
function end(){
if (!isDrag) return;
isDrag = false;
handle.style.cursor = 'grab';
var pos = parseInt(handle.style.left) || 6;
if (pos >= maxLeft - 2) {
ymReach('phone_slider_success');
scheduleAfterSlider({ type: 'phone', target: target });
// ИСПРАВЛЕНИЕ: сначала удаляем обработчики, потом делаем переход
cleanup();
// === моментальный вызов — без задержек ===
try {
if (/^tel:/i.test(target)) location.href = target;
else location.href = 'tel:' + target.replace(/\D/g,'');
} catch(e) {
try { window.open(target, '_blank'); } catch(e){}
}
} else {
handle.style.transition = 'left .22s ease';
handle.style.left = '6px';
track.style.background = '#f0f2f7';
setTimeout(function(){ handle.style.transition = ''; }, 250);
}
}
function onOverlayClick(ev){
if (ev.target === overlay) close();
}
function onEscape(e){
if(e.key === 'Escape') close();
}
// ИСПРАВЛЕНИЕ: функция cleanup для удаления всех обработчиков
function cleanup(){
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', end);
document.removeEventListener('touchmove', move);
document.removeEventListener('touchend', end);
document.removeEventListener('keydown', onEscape);
overlay.removeEventListener('click', onOverlayClick);
handle.removeEventListener('mousedown', start);
handle.removeEventListener('touchstart', start);
}
function close(){
cleanup();
try { document.body.removeChild(overlay); } catch(e){}
}
// Добавляем все обработчики
handle.addEventListener('mousedown', start);
handle.addEventListener('touchstart', start, {passive:false});
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', end);
document.addEventListener('touchmove', move, {passive:false});
document.addEventListener('touchend', end);
overlay.addEventListener('click', onOverlayClick);
document.addEventListener('keydown', onEscape);
}
// делегирование кликов
function extractPhone(target) {
var a = target.closest && target.closest('a[href]');
if (a && a.getAttribute) {
var h = a.getAttribute('href');
if (h && /^tel:/i.test(h)) return h;
}
var n = target.closest && target.closest('[data-phone]');
if (n) {
var v = n.getAttribute('data-phone');
return v ? (/^tel:/i.test(v) ? v : 'tel:' + v.replace(/\D/g,'')) : null;
}
return null;
}
// ИСПРАВЛЕНИЕ: обработка кликов с дебаунсингом
['click','auxclick'].forEach(function(type){
document.addEventListener(type, function(e){
// ИСПРАВЛЕНИЕ: добавлен дебаунсинг для защиты от двойных кликов
var now = Date.now();
if (now - lastClickTimestamp < 300) return; // игнорируем клики чаще 300ms
var isMiddle = (type==='auxclick' && e.button===1);
var isLeftWithMod = (type==='click' && e.button===0 && (e.ctrlKey||e.metaKey||e.shiftKey));
if (type==='click' && e.button!==0) return;
var phone = extractPhone(e.target||e.srcElement);
if (!phone) return;
lastClickTimestamp = now; // обновляем timestamp только для валидных кликов
e.preventDefault();
// ИСПРАВЛЕНИЕ: для Ctrl/Cmd+Click и средней кнопки - сразу открываем без слайдера
if (isMiddle || isLeftWithMod) {
try { window.open(phone, '_blank'); } catch(e){}
return; // не показываем слайдер
}
ymReach('phone_click_try');
showSliderAndCall(phone);
});
});
// ИСПРАВЛЕНИЕ: используем sendBeacon для надежной отправки при закрытии
window.addEventListener('beforeunload', function(){
try{
var s = sessionStorage.getItem(SS_PENDING_REDIRECT_KEY);
if (!s) return;
var info = JSON.parse(s);
if (info && info.type === 'phone') {
ymReachWithBeacon('phone_redirect');
sessionStorage.removeItem(SS_PENDING_REDIRECT_KEY);
}
}catch(e){}
});
})();
</script>