PageSourceSearch

https://eadplataforma.com/assets/js/site.js?v=1789756602

js eadplataforma.com collected 2026-10-02 10:27:28 UTC 12,610 bytes, 354 lines download raw bytes

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.