1// EAD Plataforma â shared site JS 2(function () { 3 function boot() { 4 // Icons 5 if (window.lucide) lucide.createIcons(); 6 7 // Solutions accordion inside the mobile navigation 8 var mobileSolutionsToggle = document.getElementById('mobileSolutionsToggle'); 9 var mobileSolutionsList = document.getElementById('mobileSolutionsList'); 10 var setMobileSolutions = function () {}; 11 if (mobileSolutionsToggle && mobileSolutionsList) { 12 setMobileSolutions = function (open) { 13 mobileSolutionsToggle.setAttribute('aria-expanded', open ? 'true' : 'false'); 14 mobileSolutionsList.hidden = !open; 15 }; 16 setMobileSolutions(false); 17 mobileSolutionsToggle.addEventListener('click', function () { 18 setMobileSolutions(mobileSolutionsToggle.getAttribute('aria-expanded') !== 'true'); 19 }); 20 } 21 22 // Mobile menu toggle 23 var toggle = document.getElementById('navToggle'); 24 var menu = document.getElementById('mobileMenu'); 25 var setMenu = function () {}; 26 if (toggle && menu) { 27 setMenu = function (open) { 28 menu.classList.toggle('open', open); 29 toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); 30 toggle.setAttribute('aria-label', open ? 'Fechar menu' : 'Abrir menu'); 31 menu.setAttribute('aria-hidden', open ? 'false' : 'true'); 32 document.body.classList.toggle('mobile-menu-open', open); 33 if (!open) setMobileSolutions(false); 34 }; 35 setMenu(false); 36 toggle.addEventListener('click', function () { 37 setMenu(!menu.classList.contains('open')); 38 }); 39 // Close on link click 40 menu.querySelectorAll('a').forEach(function (a) { 41 a.addEventListener('click', function () { 42 setMenu(false); 43 }); 44 }); 45 menu.addEventListener('click', function (event) { 46 if (event.target === menu) { 47 setMenu(false); 48 toggle.focus(); 49 } 50 }); 51 document.addEventListener('keydown', function (event) { 52 if (event.key === 'Escape' && menu.classList.contains('open')) { 53 setMenu(false); 54 toggle.focus(); 55 } 56 }); 57 window.addEventListener('resize', function () { 58 if (window.innerWidth > 920 && menu.classList.contains('open')) { 59 setMenu(false); 60 } 61 }); 62 } 63 64 // Desktop solutions dropdown 65 var solutionsNav = document.querySelector('[data-solutions-nav]'); 66 if (solutionsNav) { 67 var solutionsTrigger = solutionsNav.querySelector('.site-solutions-trigger'); 68 var solutionsPanel = solutionsNav.querySelector('.site-solutions-menu'); 69 var solutionsCloseTimer; 70 var solutionsOpenedByHover = false; 71 var setSolutions = function (open, fromHover) { 72 window.clearTimeout(solutionsCloseTimer); 73 solutionsOpenedByHover = !!(open && fromHover); 74 solutionsNav.classList.toggle('is-open', open); 75 if (solutionsTrigger) solutionsTrigger.setAttribute('aria-expanded', open ? 'true' : 'false'); 76 if (solutionsPanel) solutionsPanel.setAttribute('aria-hidden', open ? 'false' : 'true'); 77 }; 78 setSolutions(false); 79 if (solutionsTrigger) { 80 solutionsTrigger.addEventListener('click', function () { 81 // O primeiro clique confirma a abertura feita pelo mouseenter. 82 setSolutions(solutionsOpenedByHover || !solutionsNav.classList.contains('is-open')); 83 }); 84 } 85 solutionsNav.addEventListener('mouseenter', function () { 86 window.clearTimeout(solutionsCloseTimer); 87 if (window.innerWidth > 920 && !solutionsNav.classList.contains('is-open')) setSolutions(true, true); 88 }); 89 solutionsNav.addEventListener('mouseleave', function () { 90 solutionsCloseTimer = window.setTimeout(function () { setSolutions(false); }, 200); 91 }); 92 solutionsNav.addEventListener('focusout', function (event) { 93 if (!solutionsNav.contains(event.relatedTarget)) setSolutions(false); 94 }); 95 solutionsNav.querySelectorAll('a').forEach(function (link) { 96 link.addEventListener('click', function () { setSolutions(false); }); 97 }); 98 document.addEventListener('click', function (event) { 99 if (!solutionsNav.contains(event.target)) setSolutions(false); 100 }); 101 document.addEventListener('keydown', function (event) { 102 if (event.key === 'Escape' && solutionsNav.classList.contains('is-open')) { 103 setSolutions(false); 104 if (solutionsTrigger) solutionsTrigger.focus(); 105 } 106 }); 107 window.addEventListener('resize', function () { 108 if (window.innerWidth <= 920) setSolutions(false); 109 }); 110 } 111 112 // Seamless logos marquee â duplicate each set once for a perfect loop 113 document.querySelectorAll('.logos-viewport .logos-track, .demo-clients-viewport .logos-track, .hero-logos-viewport .logos-track, .about-logos-viewport .logos-track').forEach(function (track) { 114 if (!track.dataset.cloned) { 115 track.innerHTML += track.innerHTML; 116 track.dataset.cloned = '1'; 117 } 118 }); 119 120 var heroAudience = document.querySelector('[data-hero-audience]'); 121 if (heroAudience) { 122 var heroSub = heroAudience.querySelector('[data-hero-sub]'); 123 var heroCta = heroAudience.querySelector('[data-hero-cta]'); 124 var heroChips = heroAudience.querySelectorAll('[data-audience]'); 125 heroChips.forEach(function (chip) { 126 chip.addEventListener('click', function () { 127 heroChips.forEach(function (item) { 128 var on = item === chip; 129 item.classList.toggle('is-active', on); 130 item.setAttribute('aria-pressed', on ? 'true' : 'false'); 131 }); 132 if (heroSub) { 133 heroSub.textContent = chip.getAttribute('data-sub') || ''; 134 } 135 if (heroCta) { 136 var fonte = chip.getAttribute('data-fonte') || 'home'; 137 heroCta.setAttribute('href', '/demonstracao/?fonte=' + encodeURIComponent(fonte)); 138 } 139 }); 140 }); 141 } 142 143 // Reveal-more toggle for card grids (home, empresas, infoprodutores) 144 document.querySelectorAll('.cards-toggle').forEach(function (ct) { 145 var gridId = ct.getAttribute('aria-controls'); 146 var grid = gridId ? document.getElementById(gridId) : null; 147 var more = ct.querySelector('.label-more'); 148 var less = ct.querySelector('.label-less'); 149 ct.addEventListener('click', function () { 150 var next = ct.getAttribute('aria-expanded') !== 'true'; 151 ct.setAttribute('aria-expanded', next ? 'true' : 'false'); 152 if (grid) { 153 grid.querySelectorAll('.card.extra').forEach(function (el) { el.hidden = !next; }); 154 grid.classList.toggle('show-all', next); 155 } 156 if (more) more.hidden = next; 157 if (less) less.hidden = !next; 158 if (window.lucide) lucide.createIcons(); 159 }); 160 }); 161 162 // Blog category filter 163 var bf = document.getElementById('blogFilters'); 164 if (bf) { 165 var filters = bf.querySelectorAll('.blog-filter'); 166 var posts = document.querySelectorAll('[data-post]'); 167 var empty = document.getElementById('blogEmpty');
168 filters.forEach(function (f) { 169 f.addEventListener('click', function () { 170 var cat = f.getAttribute('data-cat'); 171 filters.forEach(function (x) { x.classList.toggle('active', x === f); }); 172 var visible = 0; 173 posts.forEach(function (card) { 174 var show = cat === 'all' || card.getAttribute('data-cat') === cat; 175 card.style.display = show ? '' : 'none'; 176 if (show) visible++; 177 }); 178 if (empty) empty.style.display = visible ? 'none' : 'block'; 179 }); 180 }); 181 } 182 183 // Cookie consent banner: HTML/CSS/JS autocontidos em includes/cookie-banner.php 184 185 var mobileCta = document.getElementById('mobileCta'); 186 if (mobileCta) { 187 document.body.classList.add('has-mcta'); 188 mobileCta.setAttribute('aria-hidden', 'true'); 189 } 190 191 // Faixa de campanha: fechar grava cookie, então o PHP nem renderiza nas 192 // próximas páginas e o layout já vem sem o espaço reservado. 193 var promoBar = document.getElementById('promoBar'); 194 if (promoBar) { 195 var promoClose = document.getElementById('promoBarClose'); 196 if (promoClose) { 197 promoClose.addEventListener('click', function () { 198 var id = promoBar.getAttribute('data-promo-id') || '1'; 199 var maxAge = 30 * 24 * 60 * 60; 200 document.cookie = 'ead_promo_dismissed=' + encodeURIComponent(id) + ';path=/;max-age=' + maxAge + ';SameSite=Lax'; 201 document.body.classList.remove('has-promo-bar'); 202 if (promoBar.parentNode) { 203 promoBar.parentNode.removeChild(promoBar); 204 } 205 }); 206 } 207 } 208 209 // Header + widget comercial / mobile CTA â scroll down oculta header / exibe widgets 210 var siteHeader = document.querySelector('.site-header'); 211 var contactWidget = document.getElementById('contactWidget'); 212 var WIDGET_CLOSED_KEY = 'ead_contact_widget_closed'; 213 214 function isWidgetClosed() { 215 try { 216 return sessionStorage.getItem(WIDGET_CLOSED_KEY) === '1'; 217 } catch (e) { 218 return false; 219 } 220 } 221 222 function setWidgetCollapsed(collapsed) { 223 if (!contactWidget) return; 224 contactWidget.classList.toggle('is-collapsed', collapsed); 225 try { 226 if (collapsed) { 227 sessionStorage.setItem(WIDGET_CLOSED_KEY, '1'); 228 } else { 229 sessionStorage.removeItem(WIDGET_CLOSED_KEY); 230 } 231 } catch (e) { /* storage blocked */ } 232 } 233 234 if (contactWidget) { 235 var compactWidget = window.matchMedia && window.matchMedia('(max-width: 640px)').matches; 236 if (isWidgetClosed()) { 237 setWidgetCollapsed(true); 238 } else if (compactWidget) { 239 contactWidget.classList.add('is-collapsed'); 240 } else { 241 setWidgetCollapsed(false); 242 } 243 var closeBtn = document.getElementById('contactWidgetClose'); 244 var launcherBtn = document.getElementById('contactWidgetLauncher'); 245 if (closeBtn) { 246 closeBtn.addEventListener('click', function () { 247 setWidgetCollapsed(true); 248 }); 249 } 250 if (launcherBtn) { 251 launcherBtn.addEventListener('click', function () { 252 setWidgetCollapsed(false); 253 }); 254 } 255 document.addEventListener('keydown', function (event) { 256 if (event.key === 'Escape' && contactWidget.classList.contains('is-visible') && !contactWidget.classList.contains('is-collapsed')) { 257 setWidgetCollapsed(true); 258 } 259 }); 260 } 261 262 if (siteHeader || contactWidget || mobileCta) { 263 var lastScrollY = window.scrollY || 0; 264 var ticking = false; 265 var minScroll = 80; 266 var delta = 8; 267 // Contato flutuante e CTA mobile aparecem por engajamento de leitura, 268 // não pela direção do scroll, para não sumirem quando o visitante volta. 269 var engagedRatio = 0.25; 270 var engagedFallback = 800; 271 272 function setHeaderVisible(show) { 273 if (promoBar) { 274 promoBar.classList.toggle('is-hidden', !show); 275 } 276 if (!siteHeader) return; 277 siteHeader.classList.toggle('is-hidden', !show); 278 if (!show && menu) { 279 setMenu(false); 280 } 281 } 282 283 function setContactWidgetVisible(show) { 284 if (!contactWidget) return; 285 contactWidget.classList.toggle('is-visible', show); 286 contactWidget.setAttribute('aria-hidden', show ? 'false' : 'true'); 287 } 288 289 function setMobileCtaVisible(show) { 290 if (!mobileCta) return; 291 mobileCta.classList.toggle('is-visible', show); 292 mobileCta.setAttribute('aria-hidden', show ? 'false' : 'true'); 293 document.body.classList.toggle('is-mcta-visible', show); 294 } 295 296 function isEngaged(y) { 297 if (y <= minScroll) { 298 return false;
299 } 300 301 var doc = document.documentElement; 302 var scrollable = (doc.scrollHeight || 0) - window.innerHeight; 303 if (scrollable <= 0) { 304 return true; 305 } 306 307 return (y / scrollable) >= engagedRatio || y >= engagedFallback; 308 } 309 310 function onScroll() { 311 var y = window.scrollY || document.documentElement.scrollTop || 0; 312 313 if (siteHeader) { 314 if (y <= minScroll) { 315 setHeaderVisible(true); 316 } else if (y > lastScrollY + delta) { 317 setHeaderVisible(false); 318 } else if (y < lastScrollY - delta) { 319 setHeaderVisible(true); 320 } 321 } 322 323 if (contactWidget || mobileCta) { 324 var engaged = isEngaged(y); 325 setContactWidgetVisible(engaged); 326 setMobileCtaVisible(engaged); 327 } 328 329 lastScrollY = y; 330 ticking = false; 331 } 332 333 window.addEventListener('scroll', function () { 334 if (!ticking) { 335 window.requestAnimationFrame(onScroll); 336 ticking = true; 337 } 338 }, { passive: true }); 339 340 window.addEventListener('resize', function () { 341 onScroll(); 342 }); 343 344 onScroll(); 345 } 346 347 } 348 349 if (document.readyState === 'loading') { 350 document.addEventListener('DOMContentLoaded', boot); 351 } else { 352 boot(); 353 } 354})();
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.