PageSourceSearch

https://saude.es.gov.br/AutarquiaTheme/js/menu-scroll.js

js saude.es.gov.br collected 2026-09-24 19:59:15 UTC 6,085 bytes, 192 lines download raw bytes

1(function () {
2    // Função de segurança
3    function isLocked() {
4        return window.IS_MENU_SCROLLING === true;
5    }
6
7    const DESKTOP_MEDIA = '(min-width: 992px)';
8    if (!window.matchMedia(DESKTOP_MEDIA).matches) return;
9
10    const bigBar = document.querySelector('.gov-bar-container.desktop-content');
11    const govBar = document.querySelector('.navbar-governo');
12    const header = document.getElementById('layout-header');
13    const root = document.documentElement;
14    const body = document.body;
15
16    if (!govBar || !header) return;
17
18    const panel = document.getElementById('menu-principal');
19    const toggle = document.getElementById('customMenuToggle');
20
21    const h = el => (el ? el.getBoundingClientRect().height : 0);
22    let threshold = 0;
23    let lastY = window.pageYOffset || 0;
24    let ticking = false;
25
26    function menuIsOpen() {
27        if (panel && (panel.classList.contains('show') || panel.classList.contains('collapsing'))) return true;
28        if (toggle && (toggle.classList.contains('active') || toggle.getAttribute('aria-expanded') === 'true')) return true;
29        return false;
30    }
31
32    function recalc() {
33        if (isLocked()) return; // Trava
34
35        const govH = h(govBar);
36        const headH = h(header);
37        root.style.setProperty('--gov-h', govH + 'px');
38        root.style.setProperty('--head-h', headH + 'px');
39        root.style.setProperty('--stack-h', (govH + headH) + 'px');
40
41        if (bigBar) {
42            threshold = bigBar.offsetTop + bigBar.offsetHeight;
43        } else {
44            threshold = (govBar.offsetTop || 0) + govH;
45        }
46        apply(true);
47    }
48
49    function apply(force = false) {
50        if (isLocked()) return; // Trava
51
52        if (!force && ticking) return;
53        ticking = false;
54
55        const y = Math.max(0, window.pageYOffset || 0);
56
57        if (y < threshold) {
58            body.classList.remove('sticky-nav', 'sticky-show');
59            lastY = y;
60            return;
61        }
62
63        body.classList.add('sticky-nav');
64
65        if (menuIsOpen()) {
66            body.classList.remove('sticky-show');
67            lastY = y;
68            return;
69        }
70
71        if (y < lastY) {
72            body.classList.add('sticky-show');
73        } else if (y > lastY) {
74            body.classList.remove('sticky-show');
75        }
76
77        lastY = y;
78    }
79
80    function onScroll() {
81        if (isLocked()) return; // Trava
82
83        if (!ticking) {
84            ticking = true;
85            requestAnimationFrame(apply);
86        }
87    }
88
89    if (panel) {
90        panel.addEventListener('show.bs.collapse', () => body.classList.remove('sticky-show'));
91        panel.addEventListener('shown.bs.collapse', () => body.classList.remove('sticky-show'));
92
93        // Só recalcula ao fechar se não estiver travado
94        panel.addEventListener('hidden.bs.collapse', () => { if (!isLocked()) apply(true); });
95    }
96
97    window.addEventListener('scroll', onScroll, { passive: true });
98    window.addEventListener('resize', recalc, { passive: true });
99    window.addEventListener('load', recalc);
100
101    if ('ResizeObserver' in window) {
102        const ro = new ResizeObserver(() => { if (!isLocked()) recalc(); });
103        ro.observe(govBar);
104        ro.observe(header);
105        if (bigBar) ro.observe(bigBar);
106    }
107
108    recalc();
109})();
110
111
112// === Sticky do MENU no MOBILE (<= 991.98px) ===
113(function () {
114    const MOBILE_MQ = '(max-width: 991.98px)';
115    if (!window.matchMedia(MOBILE_MQ).matches) return;
116
117    const body = document.body;
118    const root = document.documentElement;
119    const govBarMobile = document.querySelector('.gov-bar-container.gov-bar-container-mobile');
120    const navMobile = document.querySelector('.navbar-mobile');                              
121    const offcanvas = document.getElementById('custom-menu');
122    const overlay = document.getElementById('custom-overlay');
123    if (!navMobile) return;
124
125    let threshold = 0;
126    let lastY = window.pageYOffset || 0;
127    let ticking = false;
128
129    const h = (el) => (el ? el.getBoundingClientRect().height : 0);
130
131    function recalc() {
132        const brandH = h(govBarMobile);
133        const navH = h(navMobile);
134
135        root.style.setProperty('--mobile-brand-height', `${brandH}px`);
136        root.style.setProperty('--mobile-nav-height', `${navH}px`);
137        root.style.setProperty('--mobile-stack-height', `${brandH + navH}px`);
138
139        threshold = govBarMobile ? (govBarMobile.offsetTop + brandH) : navH;
140
141        apply(true);
142    }
143
144    function apply(force = false) {
145        if (!force && ticking) return;
146        ticking = false;
147
148        const y = Math.max(0, window.pageYOffset || 0);
149
150        if (y < threshold) {
151            body.classList.remove('sticky-mobile', 'sticky-show');
152            lastY = y;
153            return;
154        }
155
156        body.classList.add('sticky-mobile');
157
158        // Só altera a visibilidade se houver mudança de direção
159        if (y < lastY) {
160            body.classList.add('sticky-show');   
161        } else if (y > lastY) {
162            body.classList.remove('sticky-show'); 
163        } 
164
165        lastY = y;
166    }
167
168    function onScroll() {
169        if (!ticking) {
170            ticking = true;
171            requestAnimationFrame(apply);
172        }
173    }
174
175    // Ao abrir/fechar o off-canvas, só recalcula alturas (não mexe no estado do sticky)
176    const resyncHeights = () => setTimeout(recalc, 0);
177    const toggle = document.getElementById('custom-menu-toggle');
178    const close = document.getElementById('custom-close-menu');
179
180    if (toggle) toggle.addEventListener('click', resyncHeights);
181    if (close) close.addEventListener('click', resyncHeights);
182    if (overlay) overlay.addEventListener('click', resyncHeights);
183    if (offcanvas) offcanvas.addEventListener('transitionend', resyncHeights);
184
185    window.addEventListener('scroll', onScroll, { passive: true });
186    window.addEventListener('resize', recalc, { passive: true });
187    window.addEventListener('orientationchange', recalc, { passive: true });
188    window.addEventListener('load', recalc);
189
190    recalc();
191})();
192

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.