PageSourceSearch

https://radiovirtuall.com.br/themes/01/assets/js/theme.js?v=tktdfi

js radiovirtuall.com.br collected 2026-10-02 00:05:07 UTC 11,699 bytes, 377 lines download raw bytes

1(function () {
2  "use strict";
3
4  var READY = "data-theme-ready";
5
6  // Carousel
7  function initCarousel(root) {
8    var track = root.querySelector(".vcarousel__track");
9    if (!track) return;
10
11    var dots = root.querySelector(".vcarousel__dots, .hl__dots");
12    var prev = root.querySelector(".vcarousel__arrow--prev");
13    var next = root.querySelector(".vcarousel__arrow--next");
14    // Advances a full page: modules showing two items skip two at a time,
15    // which is what the dots below the carousel count
16    var step = function () {
17      var first = track.firstElementChild;
18      if (!first) return track.clientWidth;
19
20      var gap = parseFloat(getComputedStyle(track).columnGap) || 0;
21      var item = first.getBoundingClientRect().width + gap;
22      var perPage = Math.max(1, Math.round((track.clientWidth + gap) / item));
23
24      return item * perPage;
25    };
26
27    function overflows() {
28      return track.scrollWidth - track.clientWidth > 4;
29    }
30
31    function syncArrows() {
32      var on = overflows();
33      if (prev) prev.hidden = !on;
34      if (next) next.hidden = !on;
35    }
36
37    function syncDots() {
38      if (!dots) return;
39      var marks = dots.querySelectorAll("span");
40      if (!marks.length) return;
41      var max = track.scrollWidth - track.clientWidth;
42      var ratio = max > 0 ? track.scrollLeft / max : 0;
43      var idx = Math.round(ratio * (marks.length - 1));
44      for (var i = 0; i < marks.length; i++) {
45        marks[i].classList.toggle("is-active", i === idx);
46      }
47    }
48
49    function maxScroll() {
50      return track.scrollWidth - track.clientWidth;
51    }
52
53    // Wraps around instead of stopping at the edges
54    function go(direction) {
55      var limit = maxScroll();
56      var at = track.scrollLeft;
57
58      if (direction > 0 && at >= limit - 4) {
59        track.scrollTo({ left: 0, behavior: "smooth" });
60        return;
61      }
62
63      if (direction < 0 && at <= 4) {
64        track.scrollTo({ left: limit, behavior: "smooth" });
65        return;
66      }
67
68      track.scrollBy({ left: direction * step(), behavior: "smooth" });
69    }
70
71    if (prev) prev.addEventListener("click", function () { go(-1); });
72    if (next) next.addEventListener("click", function () { go(1); });
73
74    track.addEventListener("scroll", syncDots, { passive: true });
75    window.addEventListener("resize", syncArrows);
76
77    syncArrows();
78    syncDots();
79    autoplay(root, go, overflows);
80  }
81
82  // Slides walk on their own, pausing while the visitor is on them
83  function autoplay(root, go, overflows) {
84    var delay = parseInt(root.dataset.autoplay, 10);
85    if (!delay) return;
86
87    // Under four seconds there is no time to read what is on the slide
88    if (delay < 4000) delay = 4000;
89
90    var timer = null;
91
92    function stop() { clearInterval(timer); timer = null; }
93
94    function start() {
95      if (timer || !overflows() || document.hidden) return;
96      timer = setInterval(function () { go(1); }, delay);
97    }
98
99    root.addEventListener("mouseenter", stop);
100    root.addEventListener("mouseleave", start);
101    root.addEventListener("touchstart", stop, { passive: true });
102    document.addEventListener("visibilitychange", function () {
103      if (document.hidden) { stop(); } else { start(); }
104    });
105
106    start();
107  }
108
109  // Slides module: the panel sets the effect, the animation length and the
110  // time each image stays, so it gets its own controller
111  function initSlides(root) {
112    var track = root.querySelector(".vcarousel__track");
113    if (!track) return;
114
115    var items = Array.prototype.slice.call(track.children);
116    if (!items.length) return;
117
118    var dots = root.querySelectorAll(".vcarousel__dots span");
119    var prev = root.querySelector(".vcarousel__arrow--prev");
120    var next = root.querySelector(".vcarousel__arrow--next");
121    var speed = parseInt(root.dataset.speed, 10) || 400;
122    var delay = parseInt(root.dataset.autoplay, 10) || 0;
123    if (delay && delay < 4000) delay = 4000;
124    var fade = root.dataset.effect === "fade";
125    var index = 0;
126    var timer = null;
127    var animation = null;
128
129    function paint() {
130      items.forEach(function (item, i) { item.classList.toggle("is-on", i === index); });
131      dots.forEach(function (dot, i) { dot.classList.toggle("is-active", i === index); });
132    }
133
134    // Manual tween: native smooth scrolling ignores the configured duration
135    function slideTo(target) {
136      if (animation) cancelAnimationFrame(animation);
137
138      var from = track.scrollLeft;
139      var to = items[target].offsetLeft - track.offsetLeft;
140      var started = null;
141
142      function frame(now) {
143        if (started === null) started = now;
144
145        var progress = Math.min((now - started) / speed, 1);
146        var eased = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;
147
148        track.scrollLeft = from + (to - from) * eased;
149
150        if (progress < 1) { animation = requestAnimationFrame(frame); }
151      }
152
153      animation = requestAnimationFrame(frame);
154    }
155
156    function go(step) {
157      index = (index + step + items.length) % items.length;
158
159      if (!fade) slideTo(index);
160      paint();
161    }
162
163    function stop() { clearInterval(timer); timer = null; }
164
165    function start() {
166      if (timer || !delay || items.length < 2 || document.hidden) return;
167      timer = setInterval(function () { go(1); }, delay);
168    }
169
170    if (prev) prev.addEventListener("click", function () { stop(); go(-1); start(); });
171    if (next) next.addEventListener("click", function () { stop(); go(1); start(); });
172
173    dots.forEach(function (dot, i) {
174      dot.addEventListener("click", function () {
175        stop();
176        index = i;
177        if (!fade) slideTo(index);
178        paint();
179        start();
180      });
181    });
182
183    root.addEventListener("mouseenter", stop);
184    root.addEventListener("mouseleave", start);
185    root.addEventListener("touchstart", stop, { passive: true });
186
187    document.addEventListener("visibilitychange", function () {
188      if (document.hidden) { stop(); } else { start(); }
189    });
190
191    paint();
192    start();
193  }
194
195  // Menu: panel on phones, overflow into "more" on wider screens
196  function initMenu(menu) {
197    var list = menu.querySelector(".menu__list");
198    var more = menu.querySelector(".menu__more");
199    var toggle = menu.querySelector(".menu__toggle");
200    var phone = window.matchMedia("(max-width: 760px)");
201
202    if (toggle) {
203      toggle.addEventListener("click", function (e) {
204        e.stopPropagation();
205        var open = menu.classList.toggle("is-open");
206        toggle.setAttribute("aria-expanded", open ? "true" : "false");
207      });
208
209      document.addEventListener("click", function (e) {
210        if (!menu.contains(e.target)) closeMenu();
211      });
212
213      document.addEventListener("keydown", function (e) {
214        if (e.key === "Escape") closeMenu();
215      });
216
217      list.addEventListener("click", function (e) {
218        if (e.target.closest("a")) closeMenu();
219      });
220    }
221
222    function closeMenu() {
223      menu.classList.remove("is-open");
224      if (toggle) toggle.setAttribute("aria-expanded", "false");
225    }
226
227    if (!list || !more) return;
228
229    var submenu = more.querySelector(".submenu");
230    var pool = [];
231
232    list.querySelectorAll(":scope > li:not(.menu__more)").forEach(function (li) {
233      pool.push(li);
234    });
235
236    function reflow() {
237      pool.forEach(function (li) { list.insertBefore(li, more); });
238      submenu.innerHTML = "";
239      more.hidden = true;
240
241      // On a phone every item lives in the panel, nothing overflows
242      if (phone.matches) return;
243
244      var style = getComputedStyle(list);
245      var gap = parseFloat(style.columnGap) || 0;
246      var limit = list.clientWidth - parseFloat(style.paddingLeft || 0) - parseFloat(style.paddingRight || 0) - 1;
247
248      function widthOf(nodes) {
249        var total = 0;
250
251        nodes.forEach(function (li, i) {
252          total += li.offsetWidth + (i ? gap : 0);
253        });
254
255        return total;
256      }
257
258      if (widthOf(pool) <= limit) return;
259
260      // The row has to fit the items plus the "more" button itself
261      more.hidden = false;
262
263      var available = limit - more.offsetWidth - gap;
264      var used = 0;
265      var full = false;
266      var overflow = [];
267
268      pool.forEach(function (li) {
269        var next = used + li.offsetWidth + (used ? gap : 0);
270
271        // Once one item does not fit, the following ones go with it: the menu
272        // order has to stay the same as the panel
273        if (full || next > available) {
274          full = true;
275          overflow.push(li);
276          return;
277        }
278
279        used = next;
280      });
281
282      overflow.forEach(function (li) {
283        var link = li.querySelector("a");
284        var clone = document.createElement("li");
285        var anchor = document.createElement("a");
286        anchor.href = link.getAttribute("href");
287        anchor.textContent = link.textContent;
288        if (link.classList.contains("is-active")) anchor.classList.add("is-active");
289        clone.appendChild(anchor);
290        submenu.appendChild(clone);
291        li.remove();
292      });
293    }
294
295    // The panel belongs to the pointer: hover opens it. The click on the label
296    // is there for touch, where there is no hover, and it only opens, never
297    // takes the list away.
298    more.querySelector("a").addEventListener("click", function (e) {
299      e.preventDefault();
300      more.classList.add("is-open");
301    });
302
303    // Choosing a page closes the panel even with the pointer still over it. The
304    // hold is released as soon as the pointer leaves, so hovering opens again.
305    more.addEventListener("click", function (e) {
306      if (!e.target.closest(".submenu")) return;
307
308      more.classList.remove("is-open");
309      more.classList.add("is-picked");
310    });
311
312    more.addEventListener("mouseleave", function () {
313      more.classList.remove("is-open");
314      more.classList.remove("is-picked");
315    });
316
317    document.addEventListener("click", function (e) {
318      if (!more.contains(e.target)) more.classList.remove("is-open");
319    });
320
321    window.addEventListener("pronto.render", function () { more.classList.remove("is-open"); });
322
323    var timer;
324    window.addEventListener("resize", function () {
325      clearTimeout(timer);
326      timer = setTimeout(reflow, 150);
327    });
328
329    // The web font lands after the first pass and every label gets wider: a
330    // second measurement keeps the row from wrapping
331    if (document.fonts && document.fonts.ready) {
332      document.fonts.ready.then(reflow);
333    }
334
335    reflow();
336  }
337
338  // Active menu item
339  // The menu lives in the header, which pjax navigation never replaces,
340  // so the active state has to be refreshed on every render.
341  function syncMenu() {
342    var path = window.location.pathname.replace(/\/+$/, "") || "/";
343
344    document.querySelectorAll(".menu__list a, .submenu a").forEach(function (link) {
345      var href = (link.getAttribute("href") || "").replace(/\/+$/, "") || "/";
346      link.classList.toggle("is-active", href === path);
347    });
348  }
349
350  // Init
351  function init() {
352    document.querySelectorAll(".vcarousel:not(.slides):not([" + READY + "])").forEach(function (el) {
353      el.setAttribute(READY, "1");
354      initCarousel(el);
355    });
356
357    document.querySelectorAll(".slides:not([" + READY + "])").forEach(function (el) {
358      el.setAttribute(READY, "1");
359      initSlides(el);
360    });
361
362    document.querySelectorAll(".menu:not([" + READY + "])").forEach(function (el) {
363      el.setAttribute(READY, "1");
364      initMenu(el);
365    });
366
367    syncMenu();
368  }
369
370  if (document.readyState === "loading") {
371    document.addEventListener("DOMContentLoaded", init);
372  } else {
373    init();
374  }
375
376  window.addEventListener("pronto.render", init);
377})();

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.