PageSourceSearch

https://uksor.ru/js/widget-fab.js

js uksor.ru collected 2026-10-07 20:49:21 UTC 3,713 bytes, 85 lines download raw bytes

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.