PageSourceSearch

https://gsmgrowthagency.com/wp-content/themes/gsmnew-201/js/custom.js?ver=1.0.0.1791090103

js gsmgrowthagency.com collected 2026-10-04 05:02:09 UTC 13,553 bytes, 446 lines download raw bytes

1/**
2 * Custom JavaScript for GSM Growth Agency
3 */
4;(($) => {
5  // Custom cursor
6  const cursor = document.querySelector(".custom-cursor")
7
8  if (cursor) {
9    document.addEventListener("mousemove", (e) => {
10      cursor.style.left = e.clientX + "px"
11      cursor.style.top = e.clientY + "px"
12    })
13
14    document.addEventListener("mousedown", () => {
15      cursor.classList.add("active")
16    })
17
18    document.addEventListener("mouseup", () => {
19      cursor.classList.remove("active")
20    })
21
22    // Add hover effect to links and buttons
23    const interactiveElements = document.querySelectorAll('a, button, input[type="submit"], .interactive')
24    interactiveElements.forEach((element) => {
25      element.addEventListener("mouseenter", () => {
26        cursor.classList.add("active")
27      })
28
29      element.addEventListener("mouseleave", () => {
30        cursor.classList.remove("active")
31      })
32    })
33  }
34
35  // Header scroll effect
36  const header = document.querySelector(".header")
37
38  if (header) {
39    window.addEventListener("scroll", () => {
40      if (window.scrollY > 50) {
41        header.classList.add("scrolled")
42      } else {
43        header.classList.remove("scrolled")
44      }
45    })
46  }
47
48  // Mobile menu toggle
49  const menuToggle = document.querySelector(".mobile-menu-toggle")
50  const mobileMenu = document.querySelector(".mobile-menu")
51  const bars = document.querySelectorAll(".bar")
52
53  if (menuToggle && mobileMenu) {
54    menuToggle.addEventListener("click", () => {
55      mobileMenu.classList.toggle("active")
56      bars.forEach((bar) => bar.classList.toggle("active"))
57      document.body.classList.toggle("menu-open")
58    })
59
60    // Close mobile menu when clicking a link
61    const mobileLinks = mobileMenu.querySelectorAll("a")
62    mobileLinks.forEach((link) => {
63      link.addEventListener("click", () => {
64        mobileMenu.classList.remove("active")
65        bars.forEach((bar) => bar.classList.remove("active"))
66        document.body.classList.remove("menu-open")
67      })
68    })
69  }
70
71  // Animate elements on scroll
72  function animateOnScroll() {
73    const animatedElements = document.querySelectorAll(".animate-on-scroll")
74
75    animatedElements.forEach((element) => {
76      const elementPosition = element.getBoundingClientRect().top
77      const windowHeight = window.innerHeight
78
79      if (elementPosition < windowHeight - 100) {
80        element.classList.add("animated")
81      }
82    })
83  }
84
85  // Add animate-on-scroll class to elements that should animate
86  function setupAnimations() {
87    // Add to section titles
88    const sectionTitles = document.querySelectorAll(".section-title, .seo-section-title, .tech-section-title")
89    sectionTitles.forEach((title) => {
90      title.classList.add("animate-on-scroll")
91    })
92
93    // Add to cards and grid items
94    const cards = document.querySelectorAll(
95      ".benefit-card, .service-card, .tech-card, .seo-service-card, .tech-benefit",
96    )
97    cards.forEach((card, index) => {
98      card.classList.add("animate-on-scroll")
99      card.style.transitionDelay = `${index * 0.1}s`
100    })
101
102    // Add to process steps
103    const processSteps = document.querySelectorAll(".seo-process-step")
104    processSteps.forEach((step, index) => {
105      step.classList.add("animate-on-scroll")
106      step.style.transitionDelay = `${index * 0.15}s`
107    })
108  }
109
110  // Initialize animations
111  document.addEventListener("DOMContentLoaded", () => {
112    setupAnimations()
113    animateOnScroll() // Check on page load
114
115    // Check on scroll
116    window.addEventListener("scroll", animateOnScroll)
117  })
118
119  // SEO Page specific scripts
120  if (document.querySelector(".seo-page")) {
121    // FAQ accordion
122    const faqItems = document.querySelectorAll(".seo-faq-item")
123
124    faqItems.forEach((item) => {
125      const question = item.querySelector(".seo-faq-question")
126
127      if (question) {
128        question.addEventListener("click", () => {
129          // Toggle active class on the clicked item
130          item.classList.toggle("active")
131
132          // Optional: Close other items when one is opened
133          faqItems.forEach((otherItem) => {
134            if (otherItem !== item) {
135              otherItem.classList.remove("active")
136            }
137          })
138        })
139      }
140    })
141
142    // Testimonial slider
143    const testimonials = document.querySelectorAll(".seo-testimonial")
144    const prevButton = document.querySelector(".seo-testimonial-prev")
145    const nextButton = document.querySelector(".seo-testimonial-next")
146    let currentTestimonial = 0
147
148    function showTestimonial(index) {
149      testimonials.forEach((testimonial, i) => {
150        testimonial.style.display = i === index ? "block" : "none"
151      })
152    }
153
154    if (testimonials.length > 0 && prevButton && nextButton) {
155      showTestimonial(currentTestimonial)
156
157      prevButton.addEventListener("click", () => {
158        currentTestimonial = (currentTestimonial - 1 + testimonials.length) % testimonials.length
159        showTestimonial(currentTestimonial)
160      })
161
162      nextButton.addEventListener("click", () => {
163        currentTestimonial = (currentTestimonial + 1) % testimonials.length
164        showTestimonial(currentTestimonial)
165      })
166    }
167
168    // Counter animation for stats
169    const statNumbers = document.querySelectorAll(".seo-stat-number")
170    let statsAnimated = false
171
172    function animateStats() {
173      if (statsAnimated) return
174
175      statsAnimated = true
176
177      statNumbers.forEach((stat) => {
178        const target = Number.parseInt(stat.getAttribute("data-count"))
179        const duration = 2000 // 2 seconds
180        const step = target / (duration / 16) // 60fps
181        let current = 0
182
183        const timer = setInterval(() => {
184          current += step
185          if (current >= target) {
186            clearInterval(timer)
187            stat.textContent = target
188          } else {
189            stat.textContent = Math.floor(current)
190          }
191        }, 16)
192      })
193    }
194
195    // Check if stats are in viewport
196    function checkStats() {
197      if (statNumbers.length > 0) {
198        const statsSection = document.querySelector(".seo-hero-stats")
199        if (statsSection) {
200          const rect = statsSection.getBoundingClientRect()
201          if (rect.top < window.innerHeight && rect.bottom > 0) {
202            animateStats()
203            window.removeEventListener("scroll", checkStats)
204          }
205        }
206      }
207    }
208
209    window.addEventListener("scroll", checkStats)
210    checkStats() // Check on page load
211  }
212
213  // Tech We Use page specific scripts
214  if (document.querySelector(".tech-page")) {
215    // Category filtering
216    const tabs = document.querySelectorAll(".tech-tab")
217    const cards = document.querySelectorAll(".tech-card")
218
219    tabs.forEach((tab) => {
220      tab.addEventListener("click", () => {
221        // Update active tab
222        tabs.forEach((t) => t.classList.remove("active"))
223        tab.classList.add("active")
224
225        const category = tab.getAttribute("data-category")
226
227        // Filter cards
228        cards.forEach((card) => {
229          if (category === "all") {
230            card.style.display = "block"
231          } else {
232            const cardCategories = card.getAttribute("data-categories")
233            if (cardCategories && cardCategories.includes(category)) {
234              card.style.display = "block"
235            } else {
236              card.style.display = "none"
237            }
238          }
239        })
240      })
241    })
242  }
243
244  // Community page specific scripts
245  if (document.querySelector(".value-item")) {
246    // Reveal animations for value items
247    const valueItems = document.querySelectorAll(".value-item")
248
249    function checkValueItems() {
250      valueItems.forEach((item, index) => {
251        const itemTop = item.getBoundingClientRect().top
252        const windowHeight = window.innerHeight
253
254        if (itemTop < windowHeight - 100) {
255          // Add staggered delay based on index
256          setTimeout(() => {
257            item.classList.add("visible")
258          }, index * 150)
259        }
260      })
261    }
262
263    // Check on scroll
264    window.addEventListener("scroll", checkValueItems)
265
266    // Check on page load
267    document.addEventListener("DOMContentLoaded", checkValueItems)
268
269    // Add animation to hero content when page loads
270    setTimeout(() => {
271      document.body.classList.add("loaded")
272    }, 500)
273
274    // Reveal animation for pricing card
275    const pricingCard = document.querySelector(".pricing-card")
276
277    if (pricingCard) {
278      function checkPricingCard() {
279        const cardTop = pricingCard.getBoundingClientRect().top
280        const windowHeight = window.innerHeight
281
282        if (cardTop < windowHeight - 100) {
283          pricingCard.classList.add("visible")
284        }
285      }
286
287      // Check on scroll
288      window.addEventListener("scroll", checkPricingCard)
289
290      // Check on page load
291      document.addEventListener("DOMContentLoaded", checkPricingCard)
292    }
293  }
294
295  // Careers page specific scripts
296  if (document.querySelector(".careers-page")) {
297    const form = document.getElementById("application-form")
298    const fileInput = document.getElementById("cvFile")
299    const fileName = document.getElementById("file-name")
300    const successMessage = document.getElementById("success-message")
301
302    // Show success message if URL parameter is present
303    if (window.location.search.includes("submission=success") && successMessage && form) {
304      successMessage.style.display = "block"
305      form.style.display = "none"
306    }
307
308    // Display file name when file is selected
309    if (fileInput && fileName) {
310      fileInput.addEventListener("change", function () {
311        if (this.files.length > 0) {
312          fileName.textContent = this.files[0].name
313        } else {
314          fileName.textContent = "No file selected"
315        }
316      })
317    }
318
319    // Form validation
320    if (form) {
321      form.addEventListener("submit", (e) => {
322        let isValid = true
323
324        // Reset error messages
325        document.querySelectorAll(".error-message").forEach((el) => {
326          el.style.display = "none"
327        })
328
329        // Validate required fields
330        const requiredFields = ["firstName", "lastName", "email", "phone", "position", "additionalInfo", "referral"]
331        requiredFields.forEach((field) => {
332          const input = document.getElementById(field)
333          if (input && !input.value.trim()) {
334            const errorEl = document.getElementById(field + "-error")
335            if (errorEl) {
336              errorEl.style.display = "block"
337            }
338            isValid = false
339          }
340        })
341
342        // Validate email format
343        const email = document.getElementById("email")
344        if (email && email.value.trim()) {
345          const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
346          if (!emailRegex.test(email.value.trim())) {
347            const errorEl = document.getElementById("email-error")
348            if (errorEl) {
349              errorEl.style.display = "block"
350            }
351            isValid = false
352          }
353        }
354
355        // Validate CV (either link or file)
356        const cvLink = document.getElementById("cvLink")
357        if (cvLink && fileInput && !cvLink.value.trim() && !fileInput.files.length) {
358          const errorEl = document.getElementById("cv-error")
359          if (errorEl) {
360            errorEl.style.display = "block"
361          }
362          isValid = false
363        }
364
365        if (!isValid) {
366          e.preventDefault()
367        }
368      })
369    }
370  }
371})(jQuery)(
372  /**
373   * Custom JavaScript for BadMarketing theme
374   */
375  ($) => {
376    $(document).ready(() => {
377      // Custom cursor animation
378      const cursor = document.querySelector(".custom-cursor")
379
380      if (cursor) {
381        document.addEventListener("mousemove", (e) => {
382          cursor.style.left = e.clientX + "px"
383          cursor.style.top = e.clientY + "px"
384        })
385
386        document.addEventListener("mousedown", () => {
387          cursor.classList.add("active")
388        })
389
390        document.addEventListener("mouseup", () => {
391          cursor.classList.remove("active")
392        })
393
394        // Add hover effect to links
395        const links = document.querySelectorAll("a")
396        links.forEach((link) => {
397          link.addEventListener("mouseenter", () => {
398            cursor.classList.add("active")
399          })
400
401          link.addEventListener("mouseleave", () => {
402            cursor.classList.remove("active")
403          })
404        })
405      }
406
407      // Fix for blog post links
408      if ($("body").hasClass("single-post") || $("body").hasClass("page-template-page-blog")) {
409        // Ensure social sharing buttons work correctly
410        $(".social-button").on("click", function (e) {
411          e.preventDefault()
412          const url = $(this).attr("href")
413          window.open(url, "share-dialog", "width=626,height=436")
414        })
415      }
416
417      // Smooth scroll for anchor links
418      $('a[href^="#"]').on("click", function (e) {
419        if (this.hash !== "") {
420          e.preventDefault()
421          const hash = this.hash
422          $("html, body").animate(
423            {
424              scrollTop: $(hash).offset().top - 100,
425            },
426            800,
427          )
428        }
429      })
430
431      // Header scroll effect
432      $(window).on("scroll", () => {
433        if ($(window).scrollTop() > 50) {
434          $(".header").addClass("scrolled")
435        } else {
436          $(".header").removeClass("scrolled")
437        }
438      })
439
440      // Initialize header state on page load
441      if ($(window).scrollTop() > 50) {
442        $(".header").addClass("scrolled")
443      }
444    })
445  },
446)(jQuery)

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.