PageSourceSearch

https://www.horizoneye.com/wp-content/themes/hello-elementor-child/js/custom.js?ver=1791139510

js horizoneye.com collected 2026-10-04 19:08:24 UTC 15,309 bytes, 525 lines download raw bytes

1// ======================== Analytics: Gravity Forms dataLayer push ===============================
2/**
3 * Push a `form_submitted` event to the GTM dataLayer when a Gravity Form
4 * confirms successfully.  GTM's built-in form trigger doesn't reliably
5 * catch Gravity Forms' AJAX submits, so we hook into GF's own jQuery
6 * event (`gform_confirmation_loaded`) which fires for both AJAX and
7 * non-AJAX confirmations.
8 *
9 * Matches the existing GTM Custom Event trigger "Form Submitted" which
10 * fans out to GA4, Facebook, Google Ads, and Microsoft Ads tags.
11 * Available dataLayer variables: form_id, form_title.
12 */
13(function () {
14    if (typeof window.jQuery === 'undefined') return;
15
16    window.dataLayer = window.dataLayer || [];
17
18    jQuery(document).on('gform_confirmation_loaded', function (event, formId) {
19        var formEl   = document.getElementById('gform_wrapper_' + formId);
20        var formTitle = formEl ? (formEl.querySelector('.gform_title') || {}).textContent : '';
21
22        window.dataLayer.push({
23            event: 'form_submitted',
24            form_id: formId,
25            form_title: (formTitle || '').trim()
26        });
27    });
28}());
29
30// ======================== Chat widget ===============================
31
32/**
33 * Programmatically open the RingCentral chat window.
34 * Retries up to 5 times (500ms apart) while the widget loads.
35 */
36function openChat(retry) {
37    retry = retry || 0;
38
39    var trigger = document.querySelector('.dimelo_chat_item_action')
40              || document.querySelector('.dimelo-chat-bubble');
41
42    if (trigger) {
43        trigger.click();
44        return;
45    }
46
47    if (retry < 5) {
48        setTimeout(function () { openChat(retry + 1); }, 500);
49    }
50}
51
52// Delegate clicks on every .button--live-chat instance
53document.addEventListener('click', function (e) {
54    if (e.target.closest('.button--live-chat')) {
55        e.preventDefault();
56        openChat();
57    }
58});
59
60// ======================== Homepage header — at-top state ===============================
61
62(function () {
63    if (!document.body.classList.contains('home')) return;
64
65    var header = document.querySelector('header.elementor-location-header');
66    if (!header) return;
67
68    // Add immediately — the <header> element exists in the initial HTML
69    header.classList.add('header--at-top');
70
71    function onScroll() {
72        if (window.scrollY === 0) {
73            header.classList.add('header--at-top');
74        } else {
75            header.classList.remove('header--at-top');
76        }
77    }
78
79    window.addEventListener('scroll', onScroll, { passive: true });
80})();
81
82// =================== rank math breadcrumbs single blog limit =====================
83
84document.addEventListener('DOMContentLoaded', function () {
85    const lastBreadcrumb = document.querySelector('.rank-math-breadcrumb .last');
86
87    if (lastBreadcrumb) {
88        const fullText = lastBreadcrumb.textContent.trim();
89        const words = fullText.split(' ');
90
91        if (words.length > 6) {
92            const truncated = words.slice(0, 6).join(' ') + '…';
93            lastBreadcrumb.innerHTML = `<span class="truncated">${truncated}</span>`;
94        }
95    }
96});
97// ======================== Function to add/remove class based on scroll on header ===============================
98jQuery(document).ready(function($) {
99    // Function to add/remove class based on scroll
100    function checkScroll() {
101        if ($(window).scrollTop() > 50) {
102            $('.light-header-wy').addClass('scrolled');
103        } else {
104            $('.light-header-wy').removeClass('scrolled');
105        }
106    }
107
108    // Run on scroll
109    $(window).on('scroll', checkScroll);
110
111    // Run on page load
112    checkScroll();
113});
114
115// ======================== Menu fadein  ===============================
116jQuery(document).ready(function($){
117    $('.menu-wy .e-n-menu-item').hover(
118        function() {
119            // Fade all other menu titles except the hovered one
120            $('.menu-wy .e-n-menu-item').not(this).children('.e-n-menu-title').css({
121                'opacity': '0.7',
122                'transition': 'opacity 0.3s'
123            });
124            // Make hovered menu fully visible
125            $(this).children('.e-n-menu-title').css({
126                'opacity': '1',
127                'transition': 'opacity 0.3s'
128            });
129        },
130        function() {
131            // Reset opacity when hover out
132            $('.menu-wy .e-n-menu-item .e-n-menu-title').css({
133                'opacity': '1',
134                'transition': 'opacity 0.3s'
135            });
136        }
137    );
138});
139// =================== Google Review navigation Arrow Trigger =====================
140jQuery(document).ready(function ($) {
141	
142	$('.left-icon-wy').addClass('disabled');
143
144  	function updateArrowState() {
145
146    const $prev = $('.ti-prev');
147    const $next = $('.ti-next');
148
149    // LEFT DISABLED
150    if ($prev.css('display') === 'none') {
151      $('.left-icon-wy').addClass('disabled');
152    } else {
153      $('.left-icon-wy').removeClass('disabled');
154    }
155	  
156    // RIGHT DISABLED
157    if ($next.css('display') === 'none') {
158      $('.right-icon-wy').addClass('disabled');
159    } else {
160      $('.right-icon-wy').removeClass('disabled');
161    }
162  }
163
164  // Wait for Trustindex to fully initialize
165  setTimeout(updateArrowState, 2000);
166
167  // When internal arrows clicked
168  $(document).on('click', '.ti-prev, .ti-next', function () {
169    setTimeout(updateArrowState, 300);
170  });
171
172  // Custom arrow clicks
173  $('.left-icon-wy .elementor-icon').on('click', function (e) {
174    e.preventDefault();
175    if ($('.left-icon-wy').hasClass('disabled')) return;
176    $('.ti-prev').trigger('click');
177  });
178
179  $('.right-icon-wy .elementor-icon').on('click', function (e) {
180    e.preventDefault();
181    if ($('.right-icon-wy').hasClass('disabled')) return;
182    $('.ti-next').trigger('click');
183  });
184
185});
186
187// stop auto scrolling
188
189window.addEventListener("load", function () {
190
191  const interval = setInterval(function () {
192    const widgets = document.querySelectorAll('.ti-widget[data-layout-category="slider"]');
193
194    widgets.forEach(widget => {
195      if (widget.tiWidget && widget.tiWidget.slider) {
196        // Stop autoplay without destroying slider
197        if (typeof widget.tiWidget.slider.stopAutoplay === "function") {
198          widget.tiWidget.slider.stopAutoplay();
199        }
200      }
201    });
202
203  }, 500);
204
205});
206// =================== Slick Carousel in Single Doctor page =====================
207jQuery(document).ready(function ($) {
208  $('.associated-services-carousel').slick({
209    slidesToShow: 5,
210    slidesToScroll: 1,
211    arrows: true,
212    dots: false,
213    infinite: true,
214
215    prevArrow: `
216      <button type="button" class="slick-prev custom-arrow">
217        <img src="/wp-content/uploads/2026/01/Button-Previous.svg">
218      </button>
219    `,
220    nextArrow: `
221      <button type="button" class="slick-next custom-arrow">
222        <img src="/wp-content/uploads/2026/01/Button-Next.svg">
223      </button>
224    `,
225
226    responsive: [
227      {
228        breakpoint: 1024,
229        settings: { slidesToShow: 4 }
230      },
231      {
232        breakpoint: 920,
233        settings: { slidesToShow: 3 }
234      },
235      {
236        breakpoint: 767,
237        settings: { slidesToShow: 2 }
238      }
239    ]
240  });
241});
242
243// =================== Slick Carousel in Single services page =====================
244jQuery(document).ready(function ($) {
245  $('.treatment-cards').slick({
246    slidesToShow: 4,
247    slidesToScroll: 1,
248    infinite: true,
249    arrows: true,
250    dots: false,
251    centerMode: false,
252
253    prevArrow: `
254      <button type="button" class="slick-prev custom-arrow">
255        <img src="/wp-content/uploads/2026/01/Button-Previous.svg">
256      </button>
257    `,
258    nextArrow: `
259      <button type="button" class="slick-next custom-arrow">
260        <img src="/wp-content/uploads/2026/01/Button-Next.svg">
261      </button>
262    `,
263
264    responsive: [
265      {
266        breakpoint: 1024,
267        settings: { slidesToShow: 3 }
268      },
269      {
270        breakpoint: 767,
271        settings: { 
272			slidesToShow: 1.12,
273			infinite: false
274		}
275      }
276    ]
277  });
278});
279// =================== Tab content  =====================
280// document.addEventListener('DOMContentLoaded', function () {
281
282//     const tabButtons   = document.querySelectorAll('.tab-button');
283//     const tabPanes     = document.querySelectorAll('.tab-pane');
284//     const nextButton   = document.getElementById('nextButton');
285//     const nextLabel    = document.getElementById('nextTabLabel');
286
287//     let currentIndex = 0;
288
289//     /* Activate Tab */
290//     function activateTab(index) {
291//         if (index < 0 || index >= tabButtons.length) return;
292
293//         // Remove active states
294//         tabButtons.forEach(btn => btn.classList.remove('active'));
295//         tabPanes.forEach(pane => pane.classList.remove('active'));
296
297//         // Activate current
298//         tabButtons[index].classList.add('active');
299//         tabPanes[index].classList.add('active');
300
301//         currentIndex = index;
302//         updateNextLabel();
303//     }
304// // 	console.log(currentIndex,'index');
305
306//     /* Update Next Tab Label */
307//     function updateNextLabel() {
308//         const nextIndex = currentIndex + 1;
309
310//         if (nextIndex < tabButtons.length) {
311//             nextLabel.textContent = tabButtons[nextIndex].textContent;
312//             nextButton.style.display = 'inline-flex';
313//         } else {
314//             nextLabel.textContent = '';
315//             nextButton.style.display = 'none';
316//         }
317//     }
318
319//     /* Tab Click */
320//     tabButtons.forEach((button, index) => {
321//         button.addEventListener('click', () => {
322//             activateTab(index);
323//         });
324//     });
325
326//     /* Next Button Click */
327// //     nextButton.addEventListener('click', (e) => {
328// //         e.preventDefault();
329// //         activateTab(currentIndex + 1);
330// //     });
331// 	if (nextButton) {
332// 		nextButton.addEventListener('click', (e) => {
333// 			e.preventDefault();
334// 			activateTab(currentIndex + 1);
335// 		});
336// 	}
337
338//     /* Init */
339//     updateNextLabel();
340
341// });
342
343
344
345
346// jQuery(document).ready(function ($) {
347//   const $tabs = $('.tab-button');
348//   const $panes = $('.tab-pane');
349//   const $dropdown = $('#tabsDropdown');
350//   const $nextBtn = $('#nextButton');
351//   const $nexttabLabel = $('.next-tab-label ');
352
353//   function updateNextButton(index) {
354//     if (index == $tabs.length - 1) {
355//       $nextBtn.hide();
356// 	  $nexttabLabel.hide();
357//     } else {
358//       $nextBtn.show(); // any other tab → show again
359//       $nexttabLabel.show(); 
360//     }
361//   }
362
363//   function activateTab(index) {
364//     index = parseInt(index); // important for dropdown
365
366//     $tabs.removeClass('active');
367//     $panes.removeClass('active');
368
369//     $tabs.eq(index).addClass('active');
370//     $panes.eq(index).addClass('active');
371
372//     $dropdown.val(index);
373
374//     updateNextButton(index); // 👈 IMPORTANT
375//   }
376
377//   // Desktop click
378//   $tabs.on('click', function () {
379//     activateTab($(this).data('tab'));
380//   });
381
382//   // Dropdown change
383//   $dropdown.on('change', function () {
384//     activateTab($(this).val());
385//   });
386
387//   // Next button click
388//   $nextBtn.on('click', function () {
389//     let current = $('.tab-button.active').data('tab');
390//     let next = current + 1;
391
392//     if (next >= $tabs.length) return; // stop on last
393//     activateTab(next);
394//   });
395
396//   // Init first tab
397//   activateTab(0);
398// });
399
400
401
402document.addEventListener('DOMContentLoaded', function () {
403
404    const tabButtons = document.querySelectorAll('.tab-button');
405    const tabPanes = document.querySelectorAll('.tab-pane');
406    const dropdown = document.getElementById('tabsDropdown');
407    const nextButton = document.getElementById('nextButton');
408    const nextLabel = document.querySelector('.next-tab-label');
409
410    let currentIndex = 0;
411
412    function updateNextButton(index) {
413        if (!nextButton) return;
414
415        if (index >= tabButtons.length - 1) {
416            nextButton.style.display = 'none';
417            if (nextLabel) nextLabel.style.display = 'none';
418        } else {
419            nextButton.style.display = 'inline-flex';
420            if (nextLabel) nextLabel.style.display = 'inline';
421            
422            if (nextLabel) {
423                nextLabel.textContent = tabButtons[index + 1].textContent;
424            }
425        }
426    }
427
428    function activateTab(index) {
429        index = parseInt(index);
430        if (index < 0 || index >= tabButtons.length) return;
431
432        tabButtons.forEach(btn => btn.classList.remove('active'));
433        tabPanes.forEach(pane => pane.classList.remove('active'));
434
435        tabButtons[index].classList.add('active');
436        tabPanes[index].classList.add('active');
437
438        if (dropdown) dropdown.value = index;
439
440        currentIndex = index;
441        updateNextButton(index);
442    }
443
444    // Tab Click
445    tabButtons.forEach((button, index) => {
446        button.addEventListener('click', function () {
447            activateTab(index);
448        });
449    });
450
451    // Dropdown Change (Mobile)
452    if (dropdown) {
453        dropdown.addEventListener('change', function () {
454            activateTab(this.value);
455        });
456    }
457
458    // Next Button
459    if (nextButton) {
460        nextButton.addEventListener('click', function (e) {
461            e.preventDefault();
462            activateTab(currentIndex + 1);
463        });
464    }
465
466    // Init
467    activateTab(0);
468});
469// =================== Filter counter  =====================
470
471document.addEventListener("DOMContentLoaded", function() {
472  // Select all filter buttons except "All"
473  const buttons = document.querySelectorAll('.blog-taxonomy-filter-wy .e-filter-item[data-filter]:not([data-filter="__all"])');
474
475  buttons.forEach(button => {
476    const categorySlug = button.getAttribute('data-filter');
477
478    // Fetch category info from WP REST API
479    fetch(`/wp-json/wp/v2/categories?slug=${categorySlug}`)
480      .then(response => response.json())
481      .then(data => {
482        if (data && data[0] && typeof data[0].count !== 'undefined') {
483          const count = data[0].count;
484			
485           // Create a <span> for the count
486          let countSpan = document.createElement('span');
487          countSpan.className = 'category-count';
488          countSpan.textContent = ` (${count})`;
489
490          // Append the count <span> inside the button
491          button.appendChild(countSpan);
492			
493        }
494      })
495      .catch(err => console.error(err));
496  });
497});
498// =================== Services Page Faqs =====================
499jQuery(document).ready(function($){
500    $('.services-main-faqs .e-n-accordion details').attr('open', true);
501});
502
503
504// =================== Viewport entrance animations =====================
505(function () {
506    document.addEventListener('DOMContentLoaded', function () {
507        var targets = document.querySelectorAll('[data-animate]');
508        if (!targets.length) return;
509
510        var observer = new IntersectionObserver(function (entries) {
511            entries.forEach(function (entry) {
512                if (entry.isIntersecting) {
513                    entry.target.classList.add('is-visible');
514                    observer.unobserve(entry.target);
515                }
516            });
517        }, {
518            threshold: 0.15
519        });
520
521        targets.forEach(function (el) {
522            observer.observe(el);
523        });
524    });
525})();

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.