PageSourceSearch

https://cirkuszbp.hu/js/main.js

js cirkuszbp.hu collected 2026-10-08 04:32:01 UTC 9,184 bytes, 259 lines download raw bytes

1/* ================================================================
2   CIRKUSZ BUDAPEST — Main JavaScript
3   ================================================================ */
4
5/* ── SITE CONFIG ─────────────────────────────────────────────── */
6var MENU_PDF_URL = "pdf/menu.pdf";
7(function () {
8  "use strict";
9
10  var onHeroReady = null; // called when loader finishes
11
12  /* ── LOADER ───────────────────────────────────────────────── */
13  var loader = document.getElementById("loader");
14  if (loader) {
15    document.body.style.overflow = "hidden";
16    var startLoader = function () {
17      loader.classList.add("loader-animate");
18      // total draw+fill time ≈ 3.9s → hide after 4.1s
19      setTimeout(function () {
20        loader.classList.add("loader-out");
21        document.body.classList.add("hero-ready");
22        document.body.style.overflow = "";
23        setTimeout(function () { loader.style.display = "none"; }, 650);
24        if (onHeroReady) onHeroReady();
25      }, 2600);
26    };
27    // wait for fonts so SVG text uses the correct typefaces
28    if (document.fonts && document.fonts.ready) {
29      document.fonts.ready.then(startLoader);
30    } else {
31      setTimeout(startLoader, 200);
32    }
33  }
34
35  /* ── TYPEWRITER: "Brunch Harder." ────────────────────────── */
36  var typEl = document.querySelector(".script-line");
37  if (typEl) {
38    var typFull = typEl.textContent;
39    typEl.textContent = "";
40    typEl.setAttribute("aria-label", typFull);
41
42    var typCursor = document.createElement("span");
43    typCursor.className = "typ-cursor";
44    typCursor.setAttribute("aria-hidden", "true");
45    typEl.appendChild(typCursor);
46
47    var typIdx = 0;
48    function typeTick() {
49      if (typIdx < typFull.length) {
50        typEl.insertBefore(document.createTextNode(typFull[typIdx]), typCursor);
51        typIdx++;
52        setTimeout(typeTick, typIdx === 1 ? 120 : 75);
53      } else {
54        typCursor.classList.add("typ-cursor-hide");
55      }
56    }
57    onHeroReady = function () { setTimeout(typeTick, 550); };
58    if (!document.getElementById("loader")) setTimeout(typeTick, 900);
59  }
60
61  /* ── MENU PDF LINKS + MODAL ──────────────────────────────── */
62  var pdfModal = document.getElementById("pdf-modal");
63  var pdfFrame = document.getElementById("pdf-modal-frame");
64  var pdfExt = document.getElementById("pdf-modal-ext");
65
66  pdfExt.href = MENU_PDF_URL;
67
68  function openPdfModal() {
69    pdfFrame.src = MENU_PDF_URL + "#toolbar=0&navpanes=0&scrollbar=1&view=FitH";
70    pdfModal.classList.add("open");
71    document.body.style.overflow = "hidden";
72  }
73  function closePdfModal() {
74    pdfModal.classList.remove("open");
75    document.body.style.overflow = "";
76    setTimeout(function () {
77      pdfFrame.src = "";
78    }, 300);
79  }
80
81  document.querySelectorAll("[data-menu-pdf]").forEach(function (el) {
82    el.href = MENU_PDF_URL;
83    el.removeAttribute("target");
84    el.addEventListener("click", function (e) {
85      e.preventDefault();
86      openPdfModal();
87    });
88  });
89
90  pdfModal
91    .querySelector(".pdf-modal-close")
92    .addEventListener("click", closePdfModal);
93  pdfModal.addEventListener("click", function (e) {
94    if (e.target === pdfModal) closePdfModal();
95  });
96  document.addEventListener("keydown", function (e) {
97    if (e.key === "Escape" && pdfModal.classList.contains("open"))
98      closePdfModal();
99  });
100
101  /* ── NAV: shadow on scroll ────────────────────────────────── */
102  var nav = document.getElementById("nav");
103  window.addEventListener(
104    "scroll",
105    function () {
106      nav.classList.toggle("scrolled", window.scrollY > 40);
107    },
108    { passive: true },
109  );
110
111  /* ── MOBILE MENU ──────────────────────────────────────────── */
112  var hamburger = document.getElementById("hamburger");
113  var mobileMenu = document.getElementById("mobile-menu");
114
115  function openMenu() {
116    mobileMenu.classList.add("open");
117    hamburger.classList.add("open");
118    document.body.style.overflow = "hidden";
119  }
120  function closeMenu() {
121    mobileMenu.classList.remove("open");
122    hamburger.classList.remove("open");
123    document.body.style.overflow = "";
124  }
125
126  hamburger.addEventListener("click", function () {
127    mobileMenu.classList.contains("open") ? closeMenu() : openMenu();
128  });
129
130  /* Close on any link tap */
131  mobileMenu.querySelectorAll("a").forEach(function (a) {
132    a.addEventListener("click", closeMenu);
133  });
134
135  /* Close on outside tap */
136  document.addEventListener("click", function (e) {
137    if (
138      mobileMenu.classList.contains("open") &&
139      !mobileMenu.contains(e.target) &&
140      !hamburger.contains(e.target)
141    ) {
142      closeMenu();
143    }
144  });
145
146  /* Close on Escape */
147  document.addEventListener("keydown", function (e) {
148    if (e.key === "Escape") closeMenu();
149  });
150
151  /* ── SCROLL REVEAL (IntersectionObserver) ─────────────────── */
152  var io = new IntersectionObserver(
153    function (entries) {
154      entries.forEach(function (entry) {
155        if (entry.isIntersecting) {
156          entry.target.classList.add("vis");
157          io.unobserve(entry.target);
158        }
159      });
160    },
161    { threshold: 0.1 },
162  );
163
164  document
165    .querySelectorAll(".rv-up, .rv-left, .rv-right, .rv-scale")
166    .forEach(function (el) {
167      io.observe(el);
168    });
169
170  /* ── COUNT-UP STATS ───────────────────────────────────────── */
171  var countEls = document.querySelectorAll("[data-countup]");
172  if (countEls.length && "IntersectionObserver" in window) {
173    var countIO = new IntersectionObserver(
174      function (entries) {
175        entries.forEach(function (entry) {
176          if (!entry.isIntersecting) return;
177          var el = entry.target;
178          var target = parseInt(el.dataset.countup, 10);
179          var prefix = el.dataset.prefix || "";
180          var comma = el.dataset.format === "comma";
181          var start = performance.now();
182          var dur = 1400;
183          countIO.unobserve(el);
184          (function tick(now) {
185            var t = Math.min((now - start) / dur, 1);
186            var ease = 1 - Math.pow(1 - t, 3);
187            var val = Math.round(ease * target);
188            el.textContent = prefix + (comma ? val.toLocaleString("en") : val);
189            if (t < 1) requestAnimationFrame(tick);
190          })(start);
191        });
192      },
193      { threshold: 0.6 },
194    );
195    countEls.forEach(function (el) {
196      countIO.observe(el);
197    });
198  }
199
200  /* ── LIGHTBOX ─────────────────────────────────────────────── */
201  var lb = document.getElementById("lightbox");
202  var lbImg = document.getElementById("lb-img");
203  var lbCaption = document.getElementById("lb-caption");
204  var lbTriggers = Array.from(document.querySelectorAll(".lb-trigger"));
205  var lbCurrent = 0;
206
207  function lbOpen(index) {
208    lbCurrent =
209      ((index % lbTriggers.length) + lbTriggers.length) % lbTriggers.length;
210    var t = lbTriggers[lbCurrent];
211    lbImg.style.opacity = "0";
212    lbImg.src = t.dataset.src;
213    lbImg.alt = t.dataset.alt;
214    lbCaption.textContent = t.dataset.alt;
215    lb.classList.add("open");
216    document.body.style.overflow = "hidden";
217    lbImg.onload = function () {
218      lbImg.style.opacity = "1";
219    };
220  }
221  function lbClose() {
222    lb.classList.remove("open");
223    document.body.style.overflow = "";
224  }
225
226  lbTriggers.forEach(function (t, i) {
227    t.addEventListener("click", function () {
228      lbOpen(i);
229    });
230  });
231  document.querySelector(".lb-close").addEventListener("click", lbClose);
232  document.querySelector(".lb-prev").addEventListener("click", function () {
233    lbOpen(lbCurrent - 1);
234  });
235  document.querySelector(".lb-next").addEventListener("click", function () {
236    lbOpen(lbCurrent + 1);
237  });
238  lb.addEventListener("click", function (e) {
239    if (e.target === lb) lbClose();
240  });
241  document.addEventListener("keydown", function (e) {
242    if (!lb.classList.contains("open")) return;
243    if (e.key === "Escape") lbClose();
244    if (e.key === "ArrowLeft") lbOpen(lbCurrent - 1);
245    if (e.key === "ArrowRight") lbOpen(lbCurrent + 1);
246  });
247
248  /* ── SMOOTH ANCHOR OFFSET (account for fixed nav height) ─── */
249  document.querySelectorAll('a[href^="#"]').forEach(function (anchor) {
250    anchor.addEventListener("click", function (e) {
251      var target = document.querySelector(this.getAttribute("href"));
252      if (!target) return;
253      e.preventDefault();
254      var offset = nav ? nav.offsetHeight : 72;
255      var top = target.getBoundingClientRect().top + window.scrollY - offset;
256      window.scrollTo({ top: top, behavior: "smooth" });
257    });
258  });
259})();

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.