1/* ========================================================================== 2 WIDGET: FAB (Contacts + Smart Scroll) 3 ========================================================================== */ 4document.addEventListener('DOMContentLoaded', () => { 5 if (window.innerWidth <= 1024) return; // ÐÑклÑÑаем на Ð¼Ð¾Ð±Ð¸Ð»ÐºÐ°Ñ 6 7 // --- 1. ÐÐµÐ½Ñ ÐºÐ¾Ð½ÑакÑов --- 8 const contactWrapper = document.querySelector('.fab-contact-wrapper'); 9 const mainFabBtn = document.getElementById('fab-chat-btn'); 10 11 if (contactWrapper && mainFabBtn) { 12 let closeTimeout; 13 14 contactWrapper.addEventListener('mouseenter', () => { 15 clearTimeout(closeTimeout); 16 contactWrapper.classList.add('is-open'); 17 }); 18 19 contactWrapper.addEventListener('mouseleave', () => { 20 closeTimeout = setTimeout(() => { 21 contactWrapper.classList.remove('is-open'); 22 }, 300); 23 }); 24 25 mainFabBtn.addEventListener('click', () => { 26 contactWrapper.classList.toggle('is-open'); 27 }); 28 } 29 30 // --- 2. УмнÑй ÑкÑолл Ñ Ð±Ð»Ð¾ÐºÐ¸Ñовкой анимаÑии --- 31 const scrollBtn = document.getElementById('fab-scroll-btn'); 32 if (scrollBtn) { 33 let lastScrollTop = 0; 34 let isAtTop = false; 35 let isAnimating = false; // "Ðамок" Ð´Ð»Ñ Ð¿ÑогÑаммного ÑкÑолла 36 let scrollTimeout; 37 const showThreshold = 400; 38 39 window.addEventListener('scroll', () => { 40 const currentScroll = window.scrollY; 41 42 // ÐоказÑваем кнопкÑ, еÑли пÑокÑÑÑили 400px или еÑÑÑ ÑÐ¾Ñ ÑÐ°Ð½ÐµÐ½Ð½Ð°Ñ Ð¿Ð¾Ð·Ð¸ÑÐ¸Ñ Ð´Ð»Ñ Ð²Ð¾Ð·Ð²ÑаÑа 43 if (currentScroll > showThreshold || isAtTop) { 44 scrollBtn.classList.add('is-visible'); 45 } else { 46 scrollBtn.classList.remove('is-visible'); 47 } 48 49 // УмнÑй ÑбÑоÑ: еÑли Ñеловек Ñам наÑал кÑÑÑиÑÑ ÐºÐ¾Ð»ÐµÑиком вниз (> 50px) 50 // Ð ÐÐÐÐÐ: еÑли ÑейÑÐ°Ñ Ð½Ðµ Ð¸Ð´ÐµÑ Ð°Ð½Ð¸Ð¼Ð°ÑÐ¸Ñ ÐºÐ»Ð¸ÐºÐ°! 51 if (isAtTop && currentScroll > 50 && !isAnimating) { 52 isAtTop = false; 53 lastScrollTop = 0; 54 scrollBtn.classList.remove('is-returned'); 55 } 56 57 // Снимаем блокиÑовкÑ, как ÑолÑко ÑкÑолл (даже пÑогÑаммнÑй) оÑÑановилÑÑ 58 if (isAnimating) { 59 clearTimeout(scrollTimeout); 60 scrollTimeout = setTimeout(() => { 61 isAnimating = false; 62 }, 100); 63 } 64 }, { passive: true }); 65 66 // Ðлик по кнопке ÑкÑолла 67 scrollBtn.addEventListener('click', () => { 68 isAnimating = true; // ÐамÑкаем "замок", ÑÑÐ¾Ð±Ñ Ð±ÑаÑÐ·ÐµÑ Ð½Ðµ ÑбÑоÑил ÐºÐ½Ð¾Ð¿ÐºÑ 69 70 if (!isAtTop) { 71 // ÐÐÐСТÐÐÐ: ÐÐÐРХ 72 lastScrollTop = window.scrollY; 73 isAtTop = true; 74 scrollBtn.classList.add('is-returned'); 75 window.scrollTo({ top: 0, behavior: 'smooth' }); 76 } else { 77 // ÐÐÐСТÐÐÐ: ÐÐÐ ÐТÐÐ ÐÐÐÐ 78 isAtTop = false; 79 scrollBtn.classList.remove('is-returned'); 80 window.scrollTo({ top: lastScrollTop, behavior: 'smooth' }); 81 lastScrollTop = 0; 82 } 83 }); 84 } 85});
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.