PageSourceSearch

https://gablergroup.com/wp-content/themes/websureGablerGroup/_/js/functions.js?ver=1788154808

js gablergroup.com collected 2026-10-05 06:40:20 UTC 14,000 bytes, 485 lines download raw bytes

1// conflict bug solution
2var $ = jQuery.noConflict();
3
4$(function () {
5  /* ---------------------- GSAP + Lenis Setup ------------------------ */
6  gsap.registerPlugin(ScrollTrigger);
7
8  const lenis = new Lenis();
9  lenis.on("scroll", ScrollTrigger.update);
10
11  gsap.ticker.add((t) => lenis.raf(t * 1000));
12  gsap.ticker.lagSmoothing(0);
13  /* ---------------------- GSAP + Lenis Setup End -------------------- */
14
15  /* ---------------------- Text Reveal ------------------------ */
16  $(".text-reveal").each(function () {
17    const $this = $(this);
18    const html = $this.html();
19
20    if ($this.find("span").length) {
21      const spanHtml = $this.find("span")[0].outerHTML;
22      const parts = html.split(spanHtml);
23      const before = parts[0].trim();
24      const after = parts[1]?.trim() || "";
25
26      $this.html(`
27        ${spanHtml}
28        ${before || after ? `<span class="restText">${before || after}</span>` : ""}
29      `);
30    } else {
31      $this.html(`<span class="restText">${html}</span>`);
32    }
33  });
34  /* ---------------------- Text Reveal End ------------------------ */
35
36  /* -------------------- Show Header on Scroll Up -------------------- */
37  var lastScrollTop = 0;
38  var $header = $("header");
39  var $headerInner = $(".headerWrapper");
40  var headerHeight = $headerInner.outerHeight();
41  $header.css("height", `${headerHeight}px`);
42
43  $(window).on("scroll", function () {
44    if ($("body").hasClass("nav-expanded")) return;
45
46    var windowTop = $(window).scrollTop();
47
48    if (windowTop >= headerHeight) {
49      $header.addClass("header-sticky");
50    } else {
51      $header.removeClass("header-sticky header-show");
52    }
53
54    if ($header.hasClass("header-sticky")) {
55      if (windowTop < lastScrollTop) {
56        $header.addClass("header-show");
57      } else {
58        $header.removeClass("header-show");
59      }
60    }
61
62    lastScrollTop = windowTop;
63  });
64  /* -------------------- Show Header on Scroll Up End -------------------- */
65
66  /* ------------------ Mobile Menu Toggle ------------------ */
67  var isScrollingToAnchor = false;
68
69  function closeMobileNav() {
70    if ($(window).width() > 1024) return;
71
72    $("body").removeClass("nav-expanded").removeAttr("data-lenis-prevent");
73    $(
74      ".menu-item-has-children .megaMenu, .menu-item-has-children .sub-menu",
75    ).slideUp(200);
76  }
77
78  if ($(window).width() > 1024) {
79    $(document).on(
80      "mouseover mouseleave",
81      ".menu-item-has-children",
82      function (e) {
83        $("body").toggleClass("menu-extended", e.type === "mouseover");
84        $("header").toggleClass("menuShown", e.type === "mouseover");
85      },
86    );
87  } else {
88    $(".toggleNav").on("click", function (e) {
89      if (isScrollingToAnchor) return;
90      e.preventDefault();
91
92      $("body").toggleClass("nav-expanded");
93
94      if ($("body").hasClass("nav-expanded")) {
95        $("body").attr("data-lenis-prevent", "true");
96      } else {
97        // Close all submenus when nav is closed
98        $(
99          ".menu-item-has-children .megaMenu, .menu-item-has-children .sub-menu",
100        ).slideUp(200);
101        $("body").removeAttr("data-lenis-prevent");
102      }
103    });
104
105    $(".menu-item-has-children > a").on("click", function (e) {
106      e.preventDefault();
107
108      const $parentLi = $(this).parent();
109      const $siblings = $parentLi.siblings(".menu-item-has-children");
110
111      // Close siblings' submenus
112      $siblings.find(".megaMenu, .sub-menu").slideUp(200);
113
114      // Toggle current submenu
115      $(this).next(".megaMenu").slideToggle(200);
116      $(this).next(".sub-menu").slideToggle(200);
117    });
118
119    $(".main-menu").on("click", "a", function () {
120      const $parentLi = $(this).parent(".menu-item-has-children");
121
122      if (
123        $parentLi.length &&
124        $parentLi.children(".megaMenu, .sub-menu").length &&
125        $(this).is($parentLi.children("a").first())
126      ) {
127        return;
128      }
129
130      closeMobileNav();
131    });
132  }
133  /* ------------------ Mobile Menu Toggle End ------------------ */
134
135  /* ------------------ Smooth Scroll + Active Sync ------------------ */
136  const headerOffset = 40;
137  const $menuItems = $(".main--menu > li");
138  const $links = $(".main--menu > li > a[href*='#']");
139  const $sections = $("section[id]");
140  const $anchorLinks = $("a.achorLink[href^='#']");
141
142  // Main menu anchor click
143  $links.on("click", function (e) {
144    if (
145      window.location.pathname !== "/" &&
146      window.location.pathname !== "/home"
147    )
148      return;
149
150    e.preventDefault();
151
152    const target = $(this).attr("href").split("#")[1];
153    if (!target || $("#" + target).length === 0) return;
154
155    isScrollingToAnchor = true;
156
157    closeMobileNav();
158
159    $menuItems.removeClass("active");
160    $(this).parent().addClass("active");
161
162    $("html, body")
163      .stop()
164      .animate(
165        {
166          scrollTop: $("#" + target).offset().top - headerOffset,
167        },
168        600,
169        "swing",
170        function () {
171          isScrollingToAnchor = false;
172        },
173      );
174  });
175
176  // Generic anchor link click
177  $anchorLinks.on("click", function (e) {
178    const href = $(this).attr("href");
179    if (!href || href === "#") return;
180
181    const targetId = href.substring(1);
182    const $target = $("#" + targetId);
183    if (!$target.length) return;
184
185    e.preventDefault();
186    isScrollingToAnchor = true;
187
188    closeMobileNav();
189
190    $anchorLinks.removeClass("active");
191    $(this).addClass("active");
192
193    $("html, body")
194      .stop()
195      .animate(
196        {
197          scrollTop: $target.offset().top - headerOffset,
198        },
199        600,
200        "swing",
201        function () {
202          isScrollingToAnchor = false;
203        },
204      );
205  });
206
207  // Merged scroll handlers
208  $(window).on("scroll", function () {
209    if (isScrollingToAnchor) return;
210
211    const scrollTop = $(window).scrollTop();
212    const scrollPos = scrollTop + headerOffset + 10;
213
214    // Anchor link active sync
215    let currentAnchorId = "";
216    $anchorLinks.each(function () {
217      const href = $(this).attr("href");
218      if (!href || href === "#") return;
219
220      const targetId = href.substring(1);
221      const $section = $("#" + targetId);
222      if (!$section.length) return;
223
224      if (scrollTop >= $section.offset().top - headerOffset - 200) {
225        currentAnchorId = targetId;
226      }
227    });
228
229    $anchorLinks.removeClass("active");
230    if (currentAnchorId) {
231      $(`a.achorLink[href="#${currentAnchorId}"]`).addClass("active");
232    }
233
234    // Main menu active sync
235    let currentSection = "";
236    $sections.each(function () {
237      if ($(this).offset().top <= scrollPos) {
238        currentSection = $(this).attr("id");
239      }
240    });
241
242    if (currentSection) {
243      $menuItems.removeClass("active");
244      $links.each(function () {
245        if (
246          $(this)
247            .attr("href")
248            .includes("#" + currentSection)
249        ) {
250          $(this).parent().addClass("active");
251        }
252      });
253    }
254  });
255  /* ------------------ Smooth Scroll + Active Sync End ------------------ */
256
257  /* ---------------------- Intersection Observer ------------------------ */
258  const scrollers = document.querySelectorAll("[data-scroll], .wp-block-image");
259
260  const observer = new IntersectionObserver(function (entries) {
261    entries.forEach((entry) => {
262      if (entry.isIntersecting) {
263        entry.target.classList.add("in-view");
264        observer.unobserve(entry.target);
265      }
266    });
267  });
268
269  scrollers.forEach((scroller) => observer.observe(scroller));
270  /* ---------------------- Intersection Observer End -------------------- */
271
272  /* ---------------------- Accordion Block ------------------------ */
273  const $accordionHeader = $(".accordion-header");
274  const $accordionBody = $(".accordion-body");
275  const activeClass = "accordion-active";
276
277  $accordionHeader.on("click", function (e) {
278    e.stopPropagation();
279
280    const $this = $(this);
281
282    if (!$this.hasClass(activeClass)) {
283      $accordionBody.slideUp(400);
284      $accordionHeader.removeClass(activeClass);
285    }
286
287    $this.toggleClass(activeClass);
288    $this.next().stop(true, true).slideToggle(400);
289  });
290  /* ---------------------- Accordion Block End ------------------------ */
291
292  /* ---------------------- Popup ------------------------ */
293  function closeAllPopups() {
294    $(".teamPopup-wrap").removeClass("teamPopup-opened");
295    $(".teamPopup").removeClass("teamPopup-active");
296    $("body")
297      .removeClass("teamPopup-openeds formPopup-opened overflow-hidden")
298      .removeAttr("data-lenis-prevent");
299  }
300
301  $(".teamPopupButton").on("click", function (event) {
302    event.preventDefault();
303    event.stopPropagation();
304
305    const targetIndex = $(this).data("index");
306    const $teamBlock = $(this).closest(".teamBlock");
307    const $popupContainer = $teamBlock.find(".teamPopup[data-popup-container]");
308
309    $popupContainer.addClass("teamPopup-active");
310    $popupContainer
311      .find(`.teamPopup-wrap[data-index="${targetIndex}"]`)
312      .addClass("teamPopup-opened");
313
314    $("body")
315      .addClass("teamPopup-openeds overflow-hidden")
316      .attr("data-lenis-prevent", "");
317  });
318
319  $(".closePopup").on("click", function (event) {
320    event.preventDefault();
321    closeAllPopups();
322  });
323
324  $(".teamPopup").on("click", function (e) {
325    if (!$(e.target).closest(".teamPopup-wrap").length) {
326      closeAllPopups();
327    }
328  });
329
330  $(".formPopupButton").on("click", function (event) {
331    event.preventDefault();
332    event.stopPropagation();
333
334    $("body")
335      .addClass("formPopup-opened overflow-hidden")
336      .attr("data-lenis-prevent", "");
337  });
338  /* ---------------------- Popup End ------------------------ */
339
340  /* ---------------------- Copy Bio ------------------------ */
341  $(document).on("click", ".copyBio", function (e) {
342    e.preventDefault();
343
344    const $btn = $(this);
345    const text = $btn.data("copy");
346
347    $btn.html("Copied!");
348
349    navigator.clipboard.writeText(text).then(() => {
350      setTimeout(() => {
351        $btn.html(`
352          Copy bio
353          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="13" viewBox="0 0 16 13" fill="none">
354            <path d="M16 13H2V12H15V3H16V13ZM13 0V10H0V0H13ZM1 1V9H12V1H1Z" fill="#4E4E4F"/>
355          </svg>
356        `);
357      }, 1500);
358    });
359  });
360  /* ---------------------- Copy Bio End ------------------------ */
361
362  /* ---------------------- Team Slider ------------------------ */
363  let teamSlider;
364
365  function initTeamSlider() {
366    if (window.innerWidth >= 768 && !teamSlider) {
367      teamSlider = new Swiper(".teamSlider", {
368        slidesPerView: 3,
369        spaceBetween: 68,
370        navigation: {
371          nextEl: ".team-button-next",
372          prevEl: ".team-button-prev",
373        },
374        breakpoints: {
375          768: { slidesPerView: 1, spaceBetween: 30 },
376          840: { slidesPerView: 2, spaceBetween: 68 },
377          1170: { slidesPerView: 3, spaceBetween: 68 },
378        },
379      });
380    } else if (window.innerWidth < 768 && teamSlider) {
381      teamSlider.destroy(true, true);
382      teamSlider = null;
383    }
384  }
385
386  initTeamSlider();
387  window.addEventListener("resize", initTeamSlider);
388  /* ---------------------- Team Slider End ------------------------ */
389
390  /* ---------------------- Tab Slider ------------------------ */
391  let tabSlider;
392
393  function initTabSlider() {
394    const $tabSliderEl = $(".tabSLider");
395    if (!$tabSliderEl.length) return;
396
397    if (window.innerWidth < 1024 && !tabSlider) {
398      tabSlider = new Swiper(".tabSLider", {
399        autoHeight: true,
400        slidesPerView: 1,
401        spaceBetween: 20,
402        scrollbar: { el: ".tabSLider .swiper-scrollbar" },
403        navigation: {
404          nextEl: ".tab-button-next",
405          prevEl: ".tab-button-prev",
406        },
407      });
408    } else if (window.innerWidth >= 1024 && tabSlider) {
409      tabSlider.destroy(true, true);
410      tabSlider = null;
411    }
412  }
413
414  initTabSlider();
415  window.addEventListener("resize", initTabSlider);
416  /* ---------------------- Tab Slider End ------------------------ */
417
418  /* ---------------------- Tab Block ------------------------ */
419  const $tabs = $(".tab-item");
420  const $panes = $(".tab-pane");
421  const $images = $(".tab-image");
422  const $line = $(".tabs .line");
423  let $tabActive = $(".tab-item.active");
424
425  function positionTabLine() {
426    if (!$tabActive.length || !$line.length) return;
427    if (!$tabActive.is(":visible")) return;
428
429    $line.css({
430      left: $tabActive.position().left,
431      width: $tabActive.outerWidth(),
432    });
433  }
434
435  if (window.requestIdleCallback) {
436    requestIdleCallback(positionTabLine);
437  } else {
438    setTimeout(positionTabLine, 0);
439  }
440
441  window.addEventListener("resize", positionTabLine);
442
443  $images.removeClass("visible").addClass("invisible");
444  $images.first().removeClass("invisible").addClass("visible");
445
446  $tabs.each(function (index) {
447    $(this).on("click", function () {
448      $(".tab-item.active").removeClass("active");
449      $(".tab-pane.active").removeClass("active");
450      $images.removeClass("visible").addClass("invisible");
451
452      $line.css({
453        left: $(this).position().left,
454        width: $(this).outerWidth(),
455      });
456
457      $(this).addClass("active");
458      $panes.eq(index).addClass("active");
459      $images.eq(index).removeClass("invisible").addClass("visible");
460
461      $tabActive = $(this);
462    });
463  });
464  /* ---------------------- Tab Block End ------------------------ */
465
466  /* ---------------------- Portfolio Nested Scroll ------------------------ */
467  document.querySelectorAll(".projects .custom-scrollbar").forEach((el) => {
468    el.addEventListener(
469      "wheel",
470      (e) => {
471        if (el.scrollHeight <= el.clientHeight) return;
472
473        const atTop = el.scrollTop <= 0;
474        const atBottom =
475          el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
476
477        if ((e.deltaY < 0 && !atTop) || (e.deltaY > 0 && !atBottom)) {
478          e.stopPropagation();
479        }
480      },
481      { passive: true },
482    );
483  });
484  /* ---------------------- Portfolio Nested Scroll End ------------------------ */
485});

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.