PageSourceSearch

https://falco.org/js/scripts.js

js falco.org collected 2026-09-24 08:40:41 UTC 6,150 bytes, 237 lines download raw bytes

1(() => {
2  const [yesButton] = document.getElementsByClassName("feedback--answer-yes");
3  const [noButton] = document.getElementsByClassName("feedback--answer-no");
4  const [yesResponse] = document.getElementsByClassName(
5    "feedback--response-yes"
6  );
7  const [noResponse] = document.getElementsByClassName("feedback--response-no");
8
9  const disableButtons = () => {
10    yesButton.disabled = true;
11    noButton.disabled = true;
12  };
13
14  const sendFeedback = (value) => {
15    if (typeof gtag !== 'function') return;
16    gtag('event', 'page_helpful', {
17      'event_category': 'Helpful',
18      'event_label': window.location.pathname,
19      'value': value
20    });
21  };
22
23  if (yesButton)
24    yesButton.addEventListener("click", () => {
25      yesResponse.classList.remove("d-none");
26      disableButtons();
27      sendFeedback(1);
28    });
29
30  if (noButton)
31    noButton.addEventListener("click", () => {
32      noResponse.classList.remove("d-none");
33      disableButtons();
34      sendFeedback(0);
35    });
36})();
37
38;
39const initSwiper = () => {
40  const swiperElements = document.querySelectorAll(".swiper");
41  swiperElements.forEach((element) => {
42    if (!element.swiper) {
43      const container = element.closest(".swiper__container");
44      new Swiper(element, {
45        loop: false,
46        slidesPerView: 1,
47        slidesPerGroup: 1,
48        pagination: {
49          el: container?.querySelector(".swiper__pagination") || element.querySelector(".swiper__pagination"),
50          clickable: true,
51          bulletClass: "swiper__bullet",
52          bulletActiveClass: "swiper__bullet--active",
53        },
54        breakpoints: {
55          1024: {
56            slidesPerView: 3,
57            slidesPerGroup: 3,
58          },
59          768: {
60            slidesPerView: 2,
61            slidesPerGroup: 2,
62          },
63        },
64        navigation: {
65          nextEl: container?.querySelector(".swiper__control-reverse"),
66          prevEl: container?.querySelector(".swiper__control"),
67          disabledClass: "swiper__control--disabled",
68        },
69      });
70    }
71  });
72};
73
74// Coordinate DOM readiness and Swiper library availability
75let domReady = document.readyState !== 'loading';
76let swiperLoaded = typeof Swiper !== 'undefined';
77
78const tryInit = () => {
79  if (domReady && swiperLoaded) {
80    initSwiper();
81  }
82};
83
84if (!domReady) {
85  document.addEventListener('DOMContentLoaded', () => {
86    domReady = true;
87    tryInit();
88  });
89}
90
91// Called by Swiper script onload
92window.onSwiperLoaded = () => {
93  swiperLoaded = true;
94  tryInit();
95};
96
97// Try to initialize immediately (handles case where Swiper loaded first)
98tryInit();
99
100;
101(() => {
102  const STORE = "showAnnouncementBar";
103  const CLASS_NAME = "announcement-bar";
104
105  const startDate = document.getElementById(
106    `${CLASS_NAME}-start-date`
107  )?.innerText;
108  const endDate = document.getElementById(`${CLASS_NAME}-end-date`)?.innerText;
109  const index = document.getElementById(`${CLASS_NAME}-index`)?.textContent;
110
111  const isInDateRange = () => {
112    const currentDate = new Date().toISOString();
113
114    if (startDate && currentDate < startDate) return false;
115    if (endDate && currentDate > endDate) return false;
116
117    return true;
118  };
119
120  const updateStore = () => {
121    const { index: storedIndex, show: storedShow } = JSON.parse(
122      localStorage.getItem(STORE) || "{}"
123    );
124
125    let show;
126    if (!storedIndex || storedIndex !== index) {
127      show = true;
128    }
129    if (index === storedIndex) show = storedShow;
130
131    const store = { index, show };
132    localStorage.setItem(STORE, JSON.stringify({ index, show }));
133
134    return store;
135  };
136
137  const [announcementBar] = document.getElementsByClassName(CLASS_NAME);
138  const [navbar] = document.getElementsByClassName("td-navbar");
139
140  let prevScroll = 0;
141  const scrollOffset = 50;
142  const scrollHandler = () => {
143    if (prevScroll < window.scrollY) {
144      // scrolling down
145      if (window.scrollY > scrollOffset) {
146        navbar.classList.remove("td-navbar_transparent");
147      }
148    } else {
149      // scrolling up
150      if (window.scrollY < scrollOffset) {
151        navbar.classList.add("td-navbar_transparent");
152      }
153    }
154    prevScroll = window.scrollY;
155  };
156
157  if (announcementBar) {
158    const store = updateStore();
159    const inDateRange = isInDateRange();
160
161    const show = () => {
162      navbar.classList.add("td-navbar_transparent");
163      window.addEventListener("scroll", scrollHandler, false);
164    };
165
166    const hide = () => {
167      localStorage.setItem(STORE, JSON.stringify({ ...store, show: false }));
168      announcementBar.classList.add(`${CLASS_NAME}--hide`);
169      navbar.classList.remove("td-navbar_transparent");
170      window.removeEventListener("scroll", scrollHandler, false);
171    };
172
173    if (store.show && inDateRange) {
174      show();
175    } else {
176      hide();
177    }
178
179    return (announcementBarHide = () => {
180      hide();
181    });
182  }
183})();
184
185;
186(() => {
187  const form = document.getElementById("events-subscribe");
188  
189  if (form) {
190    const submitButton = form.querySelector("button[type=submit]");
191
192    const checkboxes = Array.from(
193      form.querySelectorAll("input[type=checkbox]")
194    );
195    const nameInput = form.querySelector("[id=subscribeName]");
196    const emailInput = form.querySelector("[id=subscribeEmail]");
197
198    form.addEventListener("change", () => {
199      submitButton.disabled = [
200        ...checkboxes.map(({ checked }) => checked),
201        !!nameInput.value,
202        !!emailInput.value,
203      ].some((val) => !val);
204    });
205
206    form.addEventListener("submit", (e) => {
207      // TODO: handler
208      e.preventDefault();
209    });
210  }
211})();
212
213;
214const copyLinkClickHandler = (link) => {
215  navigator.clipboard.writeText(link);
216
217  const toast = $("#toast");
218
219  if (toast.length) {
220    const [el] = toast;
221    el.classList.remove("d-none");
222    el.getElementsByClassName("toast__content")[0].innerText =
223      "Link copied to clipboard";
224
225    toast.toast("show");
226  }
227};
228
229document
230  .querySelectorAll("[data-faq-id]")
231  .forEach((el) =>
232    el.addEventListener("click", (e) =>
233      copyLinkClickHandler(
234        `${window.location.origin}/about/faq/#${el.getAttribute("data-faq-id")}`
235      )
236    )
237  );

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.