PageSourceSearch

https://www.archeoroma.it/wp-content/themes/jellyfish/js/script.js?ver=1781892148

js archeoroma.it collected 2026-10-03 00:19:08 UTC 67,469 bytes, 1,891 lines download raw bytes

1/**
2 * Modern Carousel Implementation
3 * Lightweight vanilla JS with touch drag support and infinite scrolling
4 */
5
6// Script.js loaded - production optimized
7
8// Prevent duplicate class declaration
9if (typeof window.ModernCarousel === 'undefined') {
10
11class ModernCarousel {
12    constructor(element) {
13        this.carousel = element;
14        this.container = this.carousel.querySelector('.carousel-container');
15        this.items = this.carousel.querySelectorAll('.carousel-item');
16        this.prevBtn = this.carousel.querySelector('.carousel-nav-left');
17        this.nextBtn = this.carousel.querySelector('.carousel-nav-right');
18
19        this.currentIndex = 0;
20        this.itemsPerView = parseInt(this.carousel.dataset.size) || 4;
21        this.isDragging = false;
22        this.hasMove = false;
23        this.startX = 0;
24        this.currentX = 0;
25        this.threshold = 10;
26        this.clickThreshold = 5;
27        this.itemWidth = 0;
28        this.clones = [];
29        this.totalItems = 0;
30        this.realItemsCount = 0;
31
32        this.init();
33    }
34
35    init() {
36        if (this.items.length === 0) return;
37
38        this.realItemsCount = this.items.length;
39
40        // Set initial responsive breakpoint
41        this.setResponsiveItemsPerView();
42
43        // Calculate and set item widths immediately
44        this.calculateItemWidth();
45
46        this.setupInfiniteLoop();
47        this.setupLayout();
48        this.setupEventListeners();
49        this.updateButtons();
50
51        // Handle resize
52        window.addEventListener('resize', this.debounce(() => {
53            this.handleResize();
54        }, 250));
55
56        // Initial setup with delay to ensure DOM is ready
57        setTimeout(() => {
58            this.handleResize();
59            this.updatePosition();
60        }, 100);
61    }
62
63    setResponsiveItemsPerView() {
64        const width = window.innerWidth;
65
66        // Responsive items per view
67        if (width < 480) {
68            this.itemsPerView = 1;
69        } else if (width < 768) {
70            this.itemsPerView = 2;
71        } else if (width < 992) {
72            this.itemsPerView = 3;
73        } else {
74            this.itemsPerView = parseInt(this.carousel.dataset.size) || 4;
75        }
76    }
77
78    calculateItemWidth() {
79        const containerWidth = this.carousel.offsetWidth;
80        this.itemWidth = containerWidth / this.itemsPerView;
81
82        // Set width for original items immediately
83        this.items.forEach(item => {
84            item.style.flex = `0 0 ${this.itemWidth}px`;
85            item.style.maxWidth = `${this.itemWidth}px`;
86        });
87    }
88
89    setupInfiniteLoop() {
90        // Clone first k items at the end
91        for (let i = 0; i < this.itemsPerView; i++) {
92            if (this.items[i]) {
93                const clone = this.items[i].cloneNode(true);
94                clone.classList.add('carousel-clone');
95                this.container.appendChild(clone);
96                this.clones.push(clone);
97            }
98        }
99
100        // Clone last k items at the beginning
101        for (let i = Math.max(0, this.items.length - this.itemsPerView); i < this.items.length; i++) {
102            if (this.items[i]) {
103                const clone = this.items[i].cloneNode(true);
104                clone.classList.add('carousel-clone');
105                this.container.insertBefore(clone, this.container.firstChild);
106                this.clones.push(clone);
107            }
108        }
109
110        // Set initial position to show original items (skip the prepended clones)
111        this.currentIndex = this.itemsPerView;
112
113        // Update items list to include clones
114        this.allItems = this.container.querySelectorAll('.carousel-item');
115        this.totalItems = this.allItems.length;
116    }
117
118    setupLayout() {
119        this.container.style.display = 'flex';
120        this.container.style.transition = 'transform 0.3s ease';
121        this.updatePosition();
122    }
123
124    setupEventListeners() {
125        // Navigation buttons with proper event handling
126        if (this.prevBtn) {
127            this.prevBtn.addEventListener('click', (e) => {
128                e.preventDefault();
129                e.stopPropagation();
130                this.prev();
131            });
132        }
133        if (this.nextBtn) {
134            this.nextBtn.addEventListener('click', (e) => {
135                e.preventDefault();
136                e.stopPropagation();
137                this.next();
138            });
139        }
140
141        // Touch events for mobile
142        this.container.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: false });
143        this.container.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });
144        this.container.addEventListener('touchend', (e) => this.handleTouchEnd(e), { passive: false });
145
146        // Mouse events for desktop drag
147        this.container.addEventListener('mousedown', (e) => this.handleMouseDown(e));
148        this.container.addEventListener('mousemove', (e) => this.handleMouseMove(e));
149        this.container.addEventListener('mouseup', (e) => this.handleMouseUp(e));
150        this.container.addEventListener('mouseleave', (e) => this.handleMouseUp(e));
151
152        // Prevent click events on links when dragging
153        this.container.addEventListener('click', (e) => this.handleClick(e), true);
154
155        // Listen for transition end to handle infinite loop reset
156        this.container.addEventListener('transitionend', () => this.handleTransitionEnd());
157    }
158
159    handleResize() {
160        this.setResponsiveItemsPerView();
161
162        // Rebuild infinite loop with new items per view
163        this.rebuildInfiniteLoop();
164        this.updateItemWidths();
165        this.positionNavigation();
166        this.updateButtons();
167    }
168
169    rebuildInfiniteLoop() {
170        // Remove existing clones
171        this.clones.forEach(clone => {
172            if (clone.parentNode) {
173                clone.parentNode.removeChild(clone);
174            }
175        });
176        this.clones = [];
177
178        // Clone first k items at the end
179        for (let i = 0; i < this.itemsPerView; i++) {
180            if (this.items[i]) {
181                const clone = this.items[i].cloneNode(true);
182                clone.classList.add('carousel-clone');
183                this.container.appendChild(clone);
184                this.clones.push(clone);
185            }
186        }
187
188        // Clone last k items at the beginning
189        for (let i = Math.max(0, this.items.length - this.itemsPerView); i < this.items.length; i++) {
190            if (this.items[i]) {
191                const clone = this.items[i].cloneNode(true);
192                clone.classList.add('carousel-clone');
193                this.container.insertBefore(clone, this.container.firstChild);
194                this.clones.push(clone);
195            }
196        }
197
198        // Update items list to include clones
199        this.allItems = this.container.querySelectorAll('.carousel-item');
200        this.totalItems = this.allItems.length;
201
202        // Reset current index to show original items
203        this.currentIndex = this.itemsPerView;
204    }
205
206    updateItemWidths() {
207        const containerWidth = this.carousel.offsetWidth || this.container.parentElement.offsetWidth;
208        this.itemWidth = containerWidth / this.itemsPerView;
209
210        // Update all items including clones
211        this.allItems.forEach(item => {
212            item.style.flex = `0 0 ${this.itemWidth}px`;
213            item.style.maxWidth = `${this.itemWidth}px`;
214            item.style.minWidth = `${this.itemWidth}px`;
215        });
216
217        // Reset container positioning
218        this.container.style.left = '';
219        this.container.style.right = '';
220
221        this.positionNavigation();
222        this.updatePosition();
223    }
224
225    positionNavigation() {
226        // Position navigation 33px from bottom of image
227        const firstItem = this.carousel.querySelector('.carousel-item .widget-box-2-img');
228        if (firstItem) {
229            const imageHeight = firstItem.offsetHeight;
230            const navigation = this.carousel.querySelector('.carousel-navigation');
231            if (navigation) {
232                navigation.style.top = `${imageHeight - 90}px`;
233                navigation.style.transform = 'none';
234            }
235        }
236    }
237
238    // Touch handlers
239    handleTouchStart(e) {
240        this.isDragging = true;
241        this.hasMove = false;
242        this.startX = e.touches[0].clientX;
243        this.container.style.transition = 'none';
244    }
245
246    handleTouchMove(e) {
247        if (!this.isDragging) return;
248
249        this.currentX = e.touches[0].clientX;
250        const deltaX = this.currentX - this.startX;
251
252        if (Math.abs(deltaX) > this.clickThreshold) {
253            this.hasMove = true;
254            e.preventDefault();
255
256            const currentTransform = -(this.currentIndex * this.itemWidth);
257            const newTransform = currentTransform + deltaX;
258
259            this.container.style.transform = `translateX(${newTransform}px)`;
260        }
261    }
262
263    handleTouchEnd(e) {
264        if (!this.isDragging) return;
265
266        this.isDragging = false;
267        this.container.style.transition = 'transform 0.3s ease';
268
269        if (this.hasMove) {
270            const deltaX = this.currentX - this.startX;
271            const threshold = this.itemWidth * 0.3; // 30% of item width
272
273            if (Math.abs(deltaX) > threshold) {
274                if (deltaX > 0) {
275                    this.prev();
276                } else {
277                    this.next();
278                }
279            } else {
280                this.updatePosition();
281            }
282        }
283    }
284
285    // Mouse handlers (for desktop drag)
286    handleMouseDown(e) {
287        this.isDragging = true;
288        this.hasMove = false;
289        this.startX = e.clientX;
290        this.container.style.transition = 'none';
291        this.container.style.cursor = 'grabbing';
292        e.preventDefault();
293    }
294
295    handleMouseMove(e) {
296        if (!this.isDragging) return;
297
298        this.currentX = e.clientX;
299        const deltaX = this.currentX - this.startX;
300
301        if (Math.abs(deltaX) > this.clickThreshold) {
302            this.hasMove = true;
303
304            const currentTransform = -(this.currentIndex * this.itemWidth);
305            const newTransform = currentTransform + deltaX;
306
307            this.container.style.transform = `translateX(${newTransform}px)`;
308        }
309    }
310
311    handleMouseUp(e) {
312        if (!this.isDragging) return;
313
314        this.isDragging = false;
315        this.container.style.transition = 'transform 0.3s ease';
316        this.container.style.cursor = 'grab';
317
318        if (this.hasMove) {
319            const deltaX = this.currentX - this.startX;
320            const threshold = this.itemWidth * 0.3; // 30% of item width
321
322            if (Math.abs(deltaX) > threshold) {
323                if (deltaX > 0) {
324                    this.prev();
325                } else {
326                    this.next();
327                }
328            } else {
329                this.updatePosition();
330            }
331        }
332    }
333
334    handleClick(e) {
335        if (this.hasMove) {
336            e.preventDefault();
337            e.stopPropagation();
338            e.stopImmediatePropagation();
339        }
340    }
341
342    prev() {
343        if (!this.isDragging) {
344            this.currentIndex--;
345            this.updatePosition();
346            this.updateButtons();
347        }
348    }
349
350    next() {
351        if (!this.isDragging) {
352            this.currentIndex++;
353            this.updatePosition();
354            this.updateButtons();
355        }
356    }
357
358    updatePosition() {
359        const translateX = -(this.currentIndex * this.itemWidth);
360        this.container.style.transform = `translateX(${translateX}px)`;
361    }
362
363    handleTransitionEnd() {
364        // Check if we need to reset position for infinite loop
365        if (this.currentIndex <= 0) {
366            // We're at the beginning clones, jump to the end of real items
367            this.container.style.transition = 'none';
368            this.currentIndex = this.realItemsCount;
369            this.updatePosition();
370            // Force reflow
371            this.container.offsetHeight;
372            setTimeout(() => {
373                this.container.style.transition = 'transform 0.3s ease';
374            }, 10);
375        } else if (this.currentIndex >= this.realItemsCount + this.itemsPerView) {
376            // We're at the end clones, jump to the beginning of real items
377            this.container.style.transition = 'none';
378            this.currentIndex = this.itemsPerView;
379            this.updatePosition();
380            // Force reflow
381            this.container.offsetHeight;
382            setTimeout(() => {
383                this.container.style.transition = 'transform 0.3s ease';
384            }, 10);
385        }
386    }
387
388    updateButtons() {
389        // Infinite carousel, buttons always enabled
390        if (this.prevBtn) {
391            this.prevBtn.classList.remove('disabled');
392        }
393        if (this.nextBtn) {
394            this.nextBtn.classList.remove('disabled');
395        }
396    }
397
398    debounce(func, wait) {
399        let timeout;
400        return function executedFunction(...args) {
401            const later = () => {
402                clearTimeout(timeout);
403                func(...args);
404            };
405            clearTimeout(timeout);
406            timeout = setTimeout(later, wait);
407        };
408    }
409
410    static init() {
411        const carousels = document.querySelectorAll('.carousel:not(.carousel-modern-initialized)');
412        carousels.forEach(carousel => {
413            // Mark as initialized to prevent double initialization
414            carousel.classList.add('carousel-modern-initialized');
415            new ModernCarousel(carousel);
416        });
417    }
418}
419
420// Store on window to prevent duplicate declaration
421window.ModernCarousel = ModernCarousel;
422
423} // End if (typeof window.ModernCarousel === 'undefined')
424
425// Initialize when DOM is ready
426if (document.readyState === 'loading') {
427    document.addEventListener('DOMContentLoaded', function() {
428        if (window.ModernCarousel && window.ModernCarousel.init) {
429            window.ModernCarousel.init();
430        }
431    });
432} else {
433    if (window.ModernCarousel && window.ModernCarousel.init) {
434        window.ModernCarousel.init();
435    }
436}
437
438// Re-initialize on AJAX content load (for WordPress)
439document.addEventListener('DOMContentLoaded', () => {
440    const observer = new MutationObserver((mutations) => {
441        mutations.forEach((mutation) => {
442            if (mutation.addedNodes.length > 0) {
443                mutation.addedNodes.forEach((node) => {
444                    if (node.nodeType === 1 && node.querySelector && node.querySelector('.carousel:not(.carousel-modern-initialized)')) {
445                        setTimeout(() => ModernCarousel.init(), 100);
446                    }
447                });
448            }
449        });
450    });
451
452    observer.observe(document.body, {
453        childList: true,
454        subtree: true
455    });
456});
457
458//Carousel script end
459
460
461
462// Custom TOC
463// -------------------------------------------------
464/*!
465/*!
466 * Bootstrap Table of Contents v<%= version %> (http://afeld.github.io/bootstrap-toc/)
467 * Copyright 2015 Aidan Feldman
468 * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
469(function($) {
470    'use strict';
471
472    window.Toc = {
473        helpers: {
474            // return all matching elements in the set, or their descendants
475            findOrFilter: function($el, selector) {
476                // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
477                // http://stackoverflow.com/a/12731439/358804
478                var $descendants = $el.find(selector);
479                return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])');
480            },
481
482            generateUniqueIdBase: function(el) {
483                var text = $(el).text();
484                var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-');
485                return anchor || el.tagName.toLowerCase();
486            },
487
488            generateUniqueId: function(el) {
489                var anchorBase = this.generateUniqueIdBase(el);
490                for (var i = 0;; i++) {
491                    var anchor = anchorBase;
492                    if (i > 0) {
493                        // add suffix
494                        anchor += '-' + i;
495                    }
496                    // check if ID already exists
497                    if (!document.getElementById(anchor)) {
498                        return anchor;
499                    }
500                }
501            },
502
503            generateAnchor: function(el) {
504                if (el.id) {
505                    return el.id;
506                } else {
507                    var anchor = this.generateUniqueId(el);
508                    el.id = anchor;
509                    return anchor;
510                }
511            },
512
513            createNavList: function() {
514                return $('<ul class="nav navbar-nav"></ul>');
515            },
516
517            createChildNavList: function($parent) {
518                var $childList = this.createNavList();
519                $parent.append($childList);
520                return $childList;
521            },
522
523            generateNavEl: function(anchor, text) {
524                var $a = $('<a class="nav-link"></a>');
525                $a.attr('href', '#' + anchor);
526                $a.text(text);
527                var $li = $('<li></li>');
528                $li.append($a);
529                return $li;
530            },
531
532            generateNavItem: function(headingEl) {
533                var anchor = this.generateAnchor(headingEl);
534                var $heading = $(headingEl);
535                var text = $heading.data('toc-text') || $heading.text();
536                return this.generateNavEl(anchor, text);
537            },
538
539            // Find the first heading level (`<h1>`, then `<h2>`, etc.) that has more than one element. Defaults to 1 (for `<h1>`).
540            getTopLevel: function($scope) {
541                for (var i = 1; i <= 6; i++) {
542                    var $headings = this.findOrFilter($scope, 'h' + i);
543                    if ($headings.length > 1) {
544                        return i;
545                    }
546                }
547
548                return 1;
549            },
550
551            // returns the elements for the top level, and the next below it
552            getHeadings: function($scope, topLevel) {
553                var topSelector = 'h' + topLevel;
554
555                var secondaryLevel = topLevel + 1;
556                var secondarySelector = 'h' + secondaryLevel;
557
558                return this.findOrFilter($scope, topSelector + ',' + secondarySelector);
559            },
560
561            getNavLevel: function(el) {
562                return parseInt(el.tagName.charAt(1), 10);
563            },
564
565            populateNav: function($topContext, topLevel, $headings) {
566                var $context = $topContext;
567                var $prevNav;
568
569                var helpers = this;
570                $headings.each(function(i, el) {
571                    var $newNav = helpers.generateNavItem(el);
572                    var navLevel = helpers.getNavLevel(el);
573
574                    // determine the proper $context
575                    if (navLevel === topLevel) {
576                        // use top level
577                        $context = $topContext;
578                    } else if ($prevNav && $context === $topContext) {
579                        // create a new level of the tree and switch to it
580                        $context = helpers.createChildNavList($prevNav);
581                    } // else use the current $context
582
583                    $context.append($newNav);
584
585                    $prevNav = $newNav;
586                });
587            },
588
589            parseOps: function(arg) {
590                var opts;
591                if (arg.jquery) {
592                    opts = {
593                        $nav: arg
594                    };
595                } else {
596                    opts = arg;
597                }
598                opts.$scope = opts.$scope || $(document.body);
599                return opts;
600            }
601        },
602
603        // accepts a jQuery object, or an options object
604        init: function(opts) {
605            opts = this.helpers.parseOps(opts);
606
607            // ensure that the data attribute is in place for styling
608            opts.$nav.attr('data-toggle', 'toc');
609
610            var $topContext = this.helpers.createChildNavList(opts.$nav);
611            var topLevel = this.helpers.getTopLevel(opts.$scope);
612            var $headings = this.helpers.getHeadings(opts.$scope, topLevel);
613            this.helpers.populateNav($topContext, topLevel, $headings);
614        }
615    };
616
617    $(function() {
618        $('nav[data-toggle="toc"]').each(function(i, el) {
619            var $nav = $(el);
620            Toc.init($nav);
621        });
622    });
623})(jQuery);
624
625
626// Multilevel Mega Menu Public start
627
628
629(function($) {
630    'use strict';
631
632    /**
633     * All of the code for your public-facing JavaScript source
634     * should reside in this file.
635     *
636     * Note: It has been assumed you will write jQuery code here, so the
637     * $ function reference has been prepared for usage within the scope
638     * of this function.
639     *
640     * This enables you to define handlers, for when the DOM is ready:
641     *
642     * $(function() {
643     *
644     * });
645     *
646     * When the window is loaded:
647     *
648     * $( window ).load(function() {
649     *
650     * });
651     *
652     * ...and/or other possibilities.
653     *
654     * Ideally, it is not considered best practise to attach more than a
655     * single DOM-ready or window-load handler for a particular page.
656     * Although scripts in the WordPress core, Plugins and Themes may be
657     * practising this, we should strive to set a better example in our own work.
658     */
659
660    $(function() {
661
662        jQuery('.search-toggle').on('click', function() {
663            jQuery('.primary-nav-tab,#mobile-nav').removeClass('active');
664        })
665
666        // Guard to prevent duplicate registration
667        if (!window.menuHandlerRegistered) {
668            window.menuHandlerRegistered = true;
669            
670            $('.primary-nav-tab-button').on('click', function() {
671                $(this).parent('li').siblings().removeClass('active');
672                $(this).parent('li').toggleClass('active');
673                $('.search-modal').removeClass('active');
674                $('#primary-nav').toggleClass('active-boder');
675            });
676        } // End guard
677
678        /*$('.primary-nav-tab-button').on('click', function () {
679        	$('#primary-nav').toggleClass('active-boder');
680        });*/
681
682        // Guard to prevent duplicate mobile nav handler registration
683        if (!window.mobileNavHandlerRegistered) {
684            window.mobileNavHandlerRegistered = true;
685            
686            // Use .off() to remove any existing handlers
687            $('#mobile-nav-toggle').off('click').on('click', function(e) {
688                $('#mobile-nav').toggleClass('active');
689                $('.search-modal').removeClass('active');
690                
691                // Prevent default and stop propagation
692                e.preventDefault();
693                e.stopPropagation();
694                return false;
695            });
696        }
697
698        // Mobile Nav - Open Submenu
699        $('.primary-nav-item-button').on('click', function() {
700            $(this).parent('li').siblings().removeClass('active');
701            $(this).parent('li').addClass('active')
702            $('.search-modal').removeClass('active');
703            var level = $(this).parent('li').siblings('.primary-subnav-items-container').find('ul').first().attr('data-nav-level');
704            $('#mobile-nav-container').attr('data-nav-level', level);
705        });
706
707        // Mobile Nav - Open Submenu
708        $('.primary-subnav-item-back-button').on('click', function() {
709            $('.primary-subnav-item').removeClass('active');
710
711            $(this).parent('li').addClass('active')
712            var level = $('#mobile-nav-container').attr('data-nav-level');
713            $('#mobile-nav-container').attr('data-nav-level', level - 1);
714        });
715
716    });
717
718    // Close desktop & mobile nav when clicking outside the navbar (including outside open mega menu)
719    jQuery(document).on('click', function(event) {
720        if (!jQuery(event.target).closest(".navbar").length) {
721            jQuery('.primary-nav-tab,#mobile-nav').removeClass('active');
722            jQuery('.search-modal').removeClass('active');
723        }
724    });
725
726    // DUPLICATE STICKY CODE COMMENTED OUT - Instance #1 (originally line 709)
727    // This is now handled by archive-filters.js for events archive
728    /*
729    window.onscroll = function() {
730        if (jQuery('#filterMenudisplay').length && jQuery('#stickyMenuSidebar').length) {
731            // alert();
732            filterSticky();
733        }
734    }
735
736    var headerHeight = $('.navbar').outerHeight();
737    var navbar = document.getElementById("sticky-box-topfixed");
738    var sticky = navbar.offsetTop;
739
740    function filterSticky() {
741        var left = document.getElementById("filterMenudisplay");
742        var right = document.getElementById("displayPostsData");
743        var sidebar = document.getElementById("stickyMenuSidebar");
744
745        //var max = $('#stickyMenuSidebar').outerHeight();
746
747        if (window.pageYOffset >= sticky - headerHeight) {
748            navbar.classList.add("stickymenu");
749            //$('body').css('padding', '55px');
750            left.classList.add("topclass");
751            sidebar.classList.add("stickysidebar");
752            right.classList.add("topclass");
753
754            if ($("#filterForm ul").length) {
755                // var last_element_position = $("#filterForm ul:lastchild li:last-child").offset().top+25;
756                var last_element_position = $("#filterForm ul").last().find('li:last-child label').offset().top + 25; //25 px padding
757                var footer_position = $(".footer.bg-white").offset().top;
758                // console.log('last_element_position', last_element_position);
759                // console.log('footer_position', footer_position);
760
761                // remove side bar sticky class when footer show
762                if (parseInt(last_element_position) >= parseInt(footer_position)) {
763                    $('#stickyMenuSidebar').removeClass('stickysidebar');
764                }
765            }
766        } else {
767            sidebar.classList.remove("stickysidebar");
768            navbar.classList.remove("stickymenu");
769            //$('body').css('padding', '0px');
770            left.classList.remove("topclass");
771            right.classList.remove("topclass");
772        }
773    }
774    */
775    // END DUPLICATE #1
776
777    $('.postfiltercheckbox').on('click', function() { // on change of state
778        var optionSelected = $('#sorting').find("option:selected");
779        var valueSelected = optionSelected.val();
780        $('#sortingchecktxt').val(valueSelected);
781        jQuery('#loading').show();
782        formSubmitCall('filterForm');
783    });
784
785    $(document).on('change', '.filter_dropdown', function() { // on change of state
786        var optionSelected = $('#sorting').find("option:selected");
787        var valueSelected = optionSelected.val();
788        $("#sortingtxt").val(valueSelected);
789
790        jQuery('#loading').show();
791        formSubmitCall('filterFormSelect');
792    });
793
794    function formSubmitCall(formName) {
795        var postType = jQuery('#postType').val();
796        jQuery.ajax({
797            url: ajaxurl,
798            type: "post",
799            // dataType: "json",
800            data: $('#' + formName).serialize() + "&action="+postType+"_posts_filter",
801            success: function(response) {
802                jQuery('#displayPostsData').html(response);
803            },
804            complete: function() {
805                jQuery('#loading').hide();
806            }
807        });
808    }
809
810    $(document).on('change', '.filter_dropdown_set', function() {
811        //  alert();
812        // on change of state
813        jQuery('#loading').show();
814
815        var optionSelected = $('#sorting').find("option:selected");
816        var valueSelected = optionSelected.val();
817        $("#sortingtxt").val(valueSelected);
818        $("#sortingchecktxt").val(valueSelected);
819        // filter selct option
820        if ($(".mobilefilterOption").length) {
821            formSubmitCall('filterFormSelect');
822        }
823        // filter checkbox option
824        else if ($(".sticky-box").length) {
825            formSubmitCall('filterForm');
826        }
827        // fallback: always submit if form exists
828        else if ($("#filterForm").length) {
829            formSubmitCall('filterForm');
830        }
831
832    });
833    $(document).on('click', '.dropdown-check-list .anchor', function() {
834        jQuery('.dropdown-check-list').not($(this).closest('.dropdown-check-list')).removeClass('visible');
835        $(this).closest('.dropdown-check-list').toggleClass('visible');
836    });
837
838    $(document).on('click', function(event) {
839        if (!$(event.target).closest('.mobileFilter').length) {
840            jQuery('.dropdown-check-list').removeClass('visible');
841        }
842    });
843
844    // var checkList = document.getElementsByClassName('dropdown-check-list');
845    // checkList.getElementsByClassName('anchor')[0].onclick = function(evt) {
846    //     if (checkList.classList.contains('visible'))
847    //         checkList.classList.remove('visible');
848    //     else
849    //         checkList.classList.add('visible');
850    // }
851
852})(jQuery);
853
854
855//Carousel script end
856
857
858
859// All Social Media Sites
860// -------------------------------------------------
861
862// All Social Media Sites ~ Nice Names
863// -------------------------------------------------
864
865function GetSocialMediaSites_NiceNames() {
866    return {
867        'add.this': 'AddThis',
868        'blogger': 'Blogger',
869        'buffer': 'Buffer',
870        'diaspora': 'Diaspora',
871        'digg': 'Digg',
872        'douban': 'Douban',
873        'email': 'EMail',
874        'evernote': 'EverNote',
875        'getpocket': 'Pocket',
876        'facebook': 'FaceBook',
877        'flattr': 'Flattr',
878        'flipboard': 'FlipBoard',
879        'google.bookmarks': 'GoogleBookmarks',
880        'instapaper': 'InstaPaper',
881        'line.me': 'Line.me',
882        'linkedin': 'LinkedIn',
883        'livejournal': 'LiveJournal',
884        'gmail': 'GMail',
885        'hacker.news': 'HackerNews',
886        'ok.ru': 'OK.ru',
887        'pinterest.com': 'Pinterest',
888        'google.plus': 'GooglePlus',
889        'qzone': 'QZone',
890        'reddit': 'Reddit',
891        'renren': 'RenRen',
892        'skype': 'Skype',
893        'sms': 'SMS',
894        'stumbleupon': 'StumbleUpon',
895        'surfingbird.ru': 'SurfingBird.ru',
896        'telegram.me': 'Telegram.me',
897        'threema': 'Threema',
898        'tumblr': 'Tumblr',
899        'twitter': 'Twitter',
900        'vk': 'VK',
901        'weibo': 'Weibo',
902        'xing': 'Xing',
903        'yahoo': 'Yahoo',
904    };
905}
906
907// Social Media Sites With Share Links
908// -------------------------------------------------
909
910function GetSocialMediaSites_WithShareLinks_OrderedByPopularity() {
911    return [
912        'google.plus',
913        'google.bookmarks',
914        'facebook',
915        'reddit',
916        'twitter',
917        'linkedin',
918        'tumblr',
919        'pinterest',
920        'blogger',
921        'livejournal',
922        'evernote',
923        'add.this',
924        'getpocket',
925        'hacker.news',
926        'stumbleupon',
927        'digg',
928        'buffer',
929        'flipboard',
930        'instapaper',
931        'surfingbird.ru',
932        'flattr',
933        'diaspora',
934        'qzone',
935        'vk',
936        'weibo',
937        'ok.ru',
938        'douban',
939        'xing',
940        'renren',
941        'threema',
942        'sms',
943        'line.me',
944        'skype',
945        'telegram.me',
946        'email',
947        'gmail',
948        'yahoo',
949    ];
950}
951
952function GetSocialMediaSites_WithShareLinks_OrderedByAlphabet() {
953    const nice_names = GetSocialMediaSites_NiceNames();
954
955    return Object.keys(nice_names);
956}
957
958// Social Media Site Links With Share Links
959// -------------------------------------------------
960
961function GetSocialMediaSiteLinks_WithShareLinks(args) {
962    const validargs = [
963        'url',
964        'title',
965        'image',
966        'desc',
967        'appid',
968        'redirecturl',
969        'via',
970        'hashtags',
971        'provider',
972        'language',
973        'userid',
974        'category',
975        'phonenumber',
976        'emailaddress',
977        'cemailaddress',
978        'bccemailaddress',
979    ];
980
981    for (var i = 0; i < validargs.length; i++) {
982        const validarg = validargs[i];
983        if (!args[validarg]) {
984            args[validarg] = '';
985        }
986    }
987
988    const url = encodeURIComponent(args.url);
989    const title = encodeURIComponent(args.title);
990    const image = encodeURIComponent(args.image);
991    const desc = encodeURIComponent(args.desc);
992    const app_id = encodeURIComponent(args.appid);
993    const redirect_url = encodeURIComponent(args.redirecturl);
994    const via = encodeURIComponent(args.via);
995    const hash_tags = encodeURIComponent(args.hashtags);
996    const provider = encodeURIComponent(args.provider);
997    const language = encodeURIComponent(args.language);
998    const user_id = encodeURIComponent(args.userid);
999    const category = encodeURIComponent(args.category);
1000    const phone_number = encodeURIComponent(args.phonenumber);
1001    const email_address = encodeURIComponent(args.emailaddress);
1002    const cc_email_address = encodeURIComponent(args.ccemailaddress);
1003    const bcc_email_address = encodeURIComponent(args.bccemailaddress);
1004
1005    var text = title;
1006
1007    if (desc) {
1008        text += '%20%3A%20'; // This is just this, " : "
1009        text += desc;
1010    }
1011
1012    return {
1013        'add.this': 'http://www.addthis.com/bookmark.php?url=' + url,
1014        'blogger': 'https://www.blogger.com/blog-this.g?u=' + url + '&n=' + title + '&t=' + desc,
1015        'buffer': 'https://buffer.com/add?text=' + text + '&url=' + url,
1016        'diaspora': 'https://share.diasporafoundation.org/?title=' + title + '&url=' + url,
1017        'digg': 'http://digg.com/submit?url=' + url + '&title=' + text,
1018        'douban': 'http://www.douban.com/recommend/?url=' + url + '&title=' + text,
1019        'email': 'mailto:' + email_address + '?subject=' + title + '&body=' + desc,
1020        'evernote': 'http://www.evernote.com/clip.action?url=' + url + '&title=' + text,
1021        'getpocket': 'https://getpocket.com/edit?url=' + url,
1022        'facebook': 'http://www.facebook.com/sharer.php?u=' + url,
1023        'flattr': 'https://flattr.com/submit/auto?user_id=' + user_id + '&url=' + url + '&title=' + title + '&description=' + text + '&language=' + language + '&tags=' + hash_tags + '&hidden=HIDDEN&category=' + category,
1024        'flipboard': 'https://share.flipboard.com/bookmarklet/popout?v=2&title=' + text + '&url=' + url,
1025        'gmail': 'https://mail.google.com/mail/?view=cm&to=' + email_address + '&su=' + title + '&body=' + url + '&bcc=' + bcc_email_address + '&cc=' + cc_email_address,
1026        'google.bookmarks': 'https://www.google.com/bookmarks/mark?op=edit&bkmk=' + url + '&title=' + title + '&annotation=' + text + '&labels=' + hash_tags + '',
1027        'instapaper': 'http://www.instapaper.com/edit?url=' + url + '&title=' + title + '&description=' + desc,
1028        'line.me': 'https://lineit.line.me/share/ui?url=' + url + '&text=' + text,
1029        'linkedin': 'https://www.linkedin.com/shareArticle?mini=true&url=' + url + '&title=' + title + '&summary=' + text + '&source=' + provider,
1030        'livejournal': 'http://www.livejournal.com/update.bml?subject=' + text + '&event=' + url,
1031        'hacker.news': 'https://news.ycombinator.com/submitlink?u=' + url + '&t=' + title,
1032        'ok.ru': 'https://connect.ok.ru/dk?st.cmd=WidgetSharePreview&st.shareUrl=' + url,
1033        'pinterest': 'http://pinterest.com/pin/create/button/?url=' + url,
1034        'google.plus': 'https://plus.google.com/share?url=' + url + '&text=' + text + '&hl=' + language,
1035        'qzone': 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + url,
1036        'reddit': 'https://reddit.com/submit?url=' + url + '&title=' + title,
1037        'renren': 'http://widget.renren.com/dialog/share?resourceUrl=' + url + '&srcUrl=' + url + '&title=' + text + '&description=' + desc,
1038        'skype': 'https://web.skype.com/share?url=' + url + '&text=' + text,
1039        'sms': 'sms:' + phone_number + '?body=' + text,
1040        'stumbleupon': 'http://www.stumbleupon.com/submit?url=' + url + '&title=' + text,
1041        'surfingbird.ru': 'http://surfingbird.ru/share?url=' + url + '&description=' + desc + '&screenshot=' + image + '&title=' + title,
1042        'telegram.me': 'https://t.me/share/url?url=' + url + '&text=' + text + '&to=' + phone_number,
1043        'threema': 'threema://compose?text=' + text + '&id=' + user_id,
1044        'tumblr': 'https://www.tumblr.com/widgets/share/tool?canonicalUrl=' + url + '&title=' + title + '&caption=' + desc + '&tags=' + hash_tags,
1045        'twitter': 'https://twitter.com/intent/tweet?url=' + url + '&text=' + text + '&via=' + via + '&hashtags=' + hash_tags,
1046        'vk': 'http://vk.com/share.php?url=' + url + '&title=' + title + '&comment=' + desc,
1047        'weibo': 'http://service.weibo.com/share/share.php?url=' + url + '&appkey=&title=' + title + '&pic=&ralateUid=',
1048        'xing': 'https://www.xing.com/app/user?op=share&url=' + url,
1049        'yahoo': 'http://compose.mail.yahoo.com/?to=' + email_address + '&subject=' + title + '&body=' + text,
1050    };
1051}
1052
1053
1054// Custom TOC
1055// -------------------------------------------------
1056/*!
1057/*!
1058 * Bootstrap Table of Contents v<%= version %> (http://afeld.github.io/bootstrap-toc/)
1059 * Copyright 2015 Aidan Feldman
1060 * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
1061(function($) {
1062    'use strict';
1063
1064    window.Toc = {
1065        helpers: {
1066            // return all matching elements in the set, or their descendants
1067            findOrFilter: function($el, selector) {
1068                // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
1069                // http://stackoverflow.com/a/12731439/358804
1070                var $descendants = $el.find(selector);
1071                return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])');
1072            },
1073
1074            generateUniqueIdBase: function(el) {
1075                var text = $(el).text();
1076                var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-');
1077                return anchor || el.tagName.toLowerCase();
1078            },
1079
1080            generateUniqueId: function(el) {
1081                var anchorBase = this.generateUniqueIdBase(el);
1082                for (var i = 0;; i++) {
1083                    var anchor = anchorBase;
1084                    if (i > 0) {
1085                        // add suffix
1086                        anchor += '-' + i;
1087                    }
1088                    // check if ID already exists
1089                    if (!document.getElementById(anchor)) {
1090                        return anchor;
1091                    }
1092                }
1093            },
1094
1095            generateAnchor: function(el) {
1096                if (el.id) {
1097                    return el.id;
1098                } else {
1099                    var anchor = this.generateUniqueId(el);
1100                    el.id = anchor;
1101                    return anchor;
1102                }
1103            },
1104
1105            createNavList: function() {
1106                return $('<ul class="nav navbar-nav"></ul>');
1107            },
1108
1109            createChildNavList: function($parent) {
1110                var $childList = this.createNavList();
1111                $parent.append($childList);
1112                return $childList;
1113            },
1114
1115            generateNavEl: function(anchor, text) {
1116                var $a = $('<a class="nav-link"></a>');
1117                $a.attr('href', '#' + anchor);
1118                $a.text(text);
1119                var $li = $('<li></li>');
1120                $li.append($a);
1121                return $li;
1122            },
1123
1124            generateNavItem: function(headingEl) {
1125                var anchor = this.generateAnchor(headingEl);
1126                var $heading = $(headingEl);
1127                var text = $heading.data('toc-text') || $heading.text();
1128                return this.generateNavEl(anchor, text);
1129            },
1130
1131            // Find the first heading level (`<h1>`, then `<h2>`, etc.) that has more than one element. Defaults to 1 (for `<h1>`).
1132            getTopLevel: function($scope) {
1133                for (var i = 1; i <= 6; i++) {
1134                    var $headings = this.findOrFilter($scope, 'h' + i);
1135                    if ($headings.length > 1) {
1136                        return i;
1137                    }
1138                }
1139
1140                return 1;
1141            },
1142
1143            // returns the elements for the top level, and the next below it
1144            getHeadings: function($scope, topLevel) {
1145                var topSelector = 'h' + topLevel;
1146
1147                var secondaryLevel = topLevel + 1;
1148                var secondarySelector = 'h' + secondaryLevel;
1149
1150                return this.findOrFilter($scope, topSelector + ',' + secondarySelector);
1151            },
1152
1153            getNavLevel: function(el) {
1154                return parseInt(el.tagName.charAt(1), 10);
1155            },
1156
1157            populateNav: function($topContext, topLevel, $headings) {
1158                var $context = $topContext;
1159                var $prevNav;
1160
1161                var helpers = this;
1162                $headings.each(function(i, el) {
1163                    var $newNav = helpers.generateNavItem(el);
1164                    var navLevel = helpers.getNavLevel(el);
1165
1166                    // determine the proper $context
1167                    if (navLevel === topLevel) {
1168                        // use top level
1169                        $context = $topContext;
1170                    } else if ($prevNav && $context === $topContext) {
1171                        // create a new level of the tree and switch to it
1172                        $context = helpers.createChildNavList($prevNav);
1173                    } // else use the current $context
1174
1175                    $context.append($newNav);
1176
1177                    $prevNav = $newNav;
1178                });
1179            },
1180
1181            parseOps: function(arg) {
1182                var opts;
1183                if (arg.jquery) {
1184                    opts = {
1185                        $nav: arg
1186                    };
1187                } else {
1188                    opts = arg;
1189                }
1190                opts.$scope = opts.$scope || $(document.body);
1191                return opts;
1192            }
1193        },
1194
1195        // accepts a jQuery object, or an options object
1196        init: function(opts) {
1197            opts = this.helpers.parseOps(opts);
1198
1199            // ensure that the data attribute is in place for styling
1200            opts.$nav.attr('data-toggle', 'toc');
1201
1202            var $topContext = this.helpers.createChildNavList(opts.$nav);
1203            var topLevel = this.helpers.getTopLevel(opts.$scope);
1204            var $headings = this.helpers.getHeadings(opts.$scope, topLevel);
1205            this.helpers.populateNav($topContext, topLevel, $headings);
1206        }
1207    };
1208
1209    $(function() {
1210        $('nav[data-toggle="toc"]').each(function(i, el) {
1211            var $nav = $(el);
1212            Toc.init($nav);
1213        });
1214    });
1215})(jQuery);
1216
1217
1218// Multilevel Mega Menu Public start
1219
1220
1221(function($) {
1222    'use strict';
1223
1224    /**
1225     * All of the code for your public-facing JavaScript source
1226     * should reside in this file.
1227     *
1228     * Note: It has been assumed you will write jQuery code here, so the
1229     * $ function reference has been prepared for usage within the scope
1230     * of this function.
1231     *
1232     * This enables you to define handlers, for when the DOM is ready:
1233     *
1234     * $(function() {
1235     *
1236     * });
1237     *
1238     * When the window is loaded:
1239     *
1240     * $( window ).load(function() {
1241     *
1242     * });
1243     *
1244     * ...and/or other possibilities.
1245     *
1246     * Ideally, it is not considered best practise to attach more than a
1247     * single DOM-ready or window-load handler for a particular page.
1248     * Although scripts in the WordPress core, Plugins and Themes may be
1249     * practising this, we should strive to set a better example in our own work.
1250     */
1251
1252    $(function() {
1253
1254        jQuery('.search-toggle').on('click', function() {
1255            jQuery('.primary-nav-tab,#mobile-nav').removeClass('active');
1256        })
1257
1258        $(document).click(function(event) {
1259            //if you click on anything except the modal itself or the "open modal" link, close the modal
1260            if (!$(event.target).closest("header").length) {
1261                // $("#desktop-nav").find("li").removeClass("active");
1262            }
1263        });
1264
1265        // Guard to prevent duplicate registration
1266        if (!window.menuHandlerRegistered) {
1267            window.menuHandlerRegistered = true;
1268            
1269            $('.primary-nav-tab-button').on('click', function() {
1270                $(this).parent('li').siblings().removeClass('active');
1271                $(this).parent('li').toggleClass('active');
1272                $('.search-modal').removeClass('active');
1273                $('#primary-nav').toggleClass('active-boder');
1274            });
1275        } // End guard
1276
1277        /*$('.primary-nav-tab-button').on('click', function () {
1278        	$('#primary-nav').toggleClass('active-boder');
1279        });*/
1280
1281        // Guard to prevent duplicate mobile nav handler registration
1282        if (!window.mobileNavHandlerRegistered) {
1283            window.mobileNavHandlerRegistered = true;
1284            
1285            // Use .off() to remove any existing handlers
1286            $('#mobile-nav-toggle').off('click').on('click', function(e) {
1287                $('#mobile-nav').toggleClass('active');
1288                $('.search-modal').removeClass('active');
1289                
1290                // Prevent default and stop propagation
1291                e.preventDefault();
1292                e.stopPropagation();
1293                return false;
1294            });
1295        }
1296
1297        // Mobile Nav - Open Submenu
1298        $('.primary-nav-item-button').on('click', function() {
1299            $(this).parent('li').siblings().removeClass('active');
1300            $(this).parent('li').addClass('active')
1301            $('.search-modal').removeClass('active');
1302            var level = $(this).parent('li').siblings('.primary-subnav-items-container').find('ul').first().attr('data-nav-level');
1303            $('#mobile-nav-container').attr('data-nav-level', level);
1304        });
1305
1306        // Mobile Nav - Open Submenu
1307        $('.primary-subnav-item-back-button').on('click', function() {
1308            $('.primary-subnav-item').removeClass('active');
1309
1310            $(this).parent('li').addClass('active')
1311            var level = $('#mobile-nav-container').attr('data-nav-level');
1312            $('#mobile-nav-container').attr('data-nav-level', level - 1);
1313        });
1314
1315    });
1316
1317    // TEMPORARILY COMMENTED OUT TO DEBUG MENU ISSUE - This was removing active class immediately
1318    /*
1319    jQuery(document).click(function(event) {
1320        //if you click on anything except the modal itself or the "open modal" link, close the modal
1321        if (!jQuery(event.target).closest(".navbar").length) {
1322            jQuery('.primary-nav-tab,#mobile-nav').removeClass('active');
1323            $('.search-modal').removeClass('active');
1324        }
1325    });
1326    */
1327
1328    // DUPLICATE STICKY CODE COMMENTED OUT - Instance #2 (originally line 1297)
1329    // This is now handled by archive-filters.js for events archive
1330    /*
1331    window.onscroll = function() {
1332        if (jQuery('#filterMenudisplay').length && jQuery('#stickyMenuSidebar').length) {
1333            // alert();
1334            filterSticky();
1335        }
1336    }
1337
1338    var headerHeight = $('.navbar').outerHeight();
1339    var navbar = document.getElementById("sticky-box-topfixed");
1340    var sticky = navbar.offsetTop;
1341
1342    function filterSticky() {
1343        var left = document.getElementById("filterMenudisplay");
1344        var right = document.getElementById("displayPostsData");
1345        var sidebar = document.getElementById("stickyMenuSidebar");
1346
1347        //var max = $('#stickyMenuSidebar').outerHeight();
1348
1349        if (window.pageYOffset >= sticky - headerHeight) {
1350            navbar.classList.add("stickymenu");
1351            //$('body').css('padding', '55px');
1352            left.classList.add("topclass");
1353            sidebar.classList.add("stickysidebar");
1354            right.classList.add("topclass");
1355
1356            if ($("#filterForm ul").length) {
1357                // var last_element_position = $("#filterForm ul:lastchild li:last-child").offset().top+25;
1358                var last_element_position = $("#filterForm ul").last().find('li:last-child label').offset().top + 25; //25 px padding
1359                var footer_position = $(".footer.bg-white").offset().top;
1360                // console.log('last_element_position', last_element_position);
1361                // console.log('footer_position', footer_position);
1362
1363                // remove side bar sticky class when footer show
1364                if (parseInt(last_element_position) >= parseInt(footer_position)) {
1365                    $('#stickyMenuSidebar').removeClass('stickysidebar');
1366                }
1367            }
1368        } else {
1369            sidebar.classList.remove("stickysidebar");
1370            navbar.classList.remove("stickymenu");
1371            //$('body').css('padding', '0px');
1372            left.classList.remove("topclass");
1373            right.classList.remove("topclass");
1374        }
1375    }
1376    */
1377    // END DUPLICATE #2
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390// Responsive Filters and Lightbox Functionality
1391// Responsive Filters and Lightbox Functionality
1392jQuery(document).ready(function($) {
1393
1394  /**
1395   * Animates a number from a start value to an end value within a specified duration.
1396   *
1397   * @param {jQuery Element} $element - The jQuery element containing the number.
1398   * @param {number} start - The starting number.
1399   * @param {number} end - The ending number.
1400   * @param {number} duration - Duration of the animation in milliseconds.
1401   */
1402  function animateNumber($element, start, end, duration) {
1403    $({ countNum: start }).animate({ countNum: end }, {
1404      duration: duration,
1405      easing: 'linear',
1406      step: function(now) {
1407        $element.text(Math.floor(now));
1408      },
1409      complete: function() {
1410        $element.text(end);
1411      }
1412    });
1413  }
1414
1415  // Debounce function to limit the rate of function execution
1416  function debounce(func, delay) {
1417    let debounceTimer;
1418    return function() {
1419      const context = this;
1420      const args = arguments;
1421      clearTimeout(debounceTimer);
1422      debounceTimer = setTimeout(() => func.apply(context, args), delay);
1423    }
1424  }
1425
1426  /**
1427   * Function to handle AJAX filter submission.
1428   *
1429   * @param {string} formSelector - The selector for the form to serialize.
1430   * @param {boolean} showLoader - Whether to show the page loader. Defaults to true.
1431   */
1432  function submitFilters(formSelector, showLoader = true) {
1433    // Skip if REST API mode is active (tickets-archive.js handles it)
1434    if (window.arRestApiActive) {
1435      console.log('submitFilters: Skipping - REST API mode active');
1436      return;
1437    }
1438    
1439    var postType = $('#postType').val(); // Get postType from hidden input
1440    var action = postType + '_posts_filter'; // Define AJAX action
1441    var action_type = 'filter'; // Define action type
1442
1443    var data = $(formSelector).serialize(); // Serialize the form data
1444    data += '&action=' + action; // Append AJAX action
1445    data += '&action_type=' + action_type; // Append action type
1446
1447    $.ajax({
1448      url: ajax_object.ajax_url, // Defined earlier in the page
1449      type: 'POST',
1450      data: data,
1451      beforeSend: function() {
1452        if (showLoader) {
1453          $('#loading').show(); // Show loading spinner (ensure #loading exists)
1454        }
1455      },
1456      success: function(response) {
1457        $('#displayPostsData').html(response); // Update events listing
1458        // Smooth scroll to the events listing
1459        $('html, body').animate({
1460          scrollTop: $("#displayPostsData").offset().top - 100 // Adjust offset as needed
1461        }, 500);
1462      },
1463      error: function(xhr, status, error) {
1464        console.error('AJAX Error:', status, error);
1465        $('#displayPostsData').html('<div class="empty_posts">Error loading content.</div>');
1466      },
1467      complete: function() {
1468        if (showLoader) {
1469          $('#loading').hide(); // Hide loading spinner
1470        }
1471      }
1472    });
1473  }
1474
1475  /**
1476   * Function to handle AJAX filter count.
1477   *
1478   * @param {string} formSelector - The selector for the form to serialize.
1479   * @param {boolean} showLoader - Whether to show the count loader. Defaults to true.
1480   */
1481  function getFilterCount(formSelector, showLoader = true) {
1482    // Skip if REST API mode is active (tickets-archive.js handles it)
1483    if (window.arRestApiActive) {
1484      console.log('getFilterCount: Skipping - REST API mode active');
1485      return;
1486    }
1487    
1488    var postType = $('#postType').val(); // Get postType from hidden input
1489    var action = postType + '_posts_filter_count'; // Define AJAX action
1490    var action_type = 'count'; // Define action type
1491
1492    var data = $(formSelector).serialize(); // Serialize the form data
1493    data += '&action=' + action; // Append AJAX action
1494    data += '&action_type=' + action_type; // Append action type
1495
1496    $.ajax({
1497      url: ajax_object.ajax_url,
1498      type: 'POST',
1499      dataType: 'json',
1500      data: data,
1501      beforeSend: function() {
1502        if (showLoader) {
1503          $('.button-loader').addClass('active'); // Show the loader
1504        }
1505      },
1506      success: function(response) {
1507        if (response.success && typeof response.data.count !== 'undefined') {
1508          var newCount = parseInt(response.data.count, 10);
1509          var $countElement = $('.event-count');
1510          var $button = $('.ar-mobile-event-count-button');
1511          var oldCount = parseInt($countElement.text(), 10);
1512
1513          // Update data-count attribute
1514          $button.attr('data-count', newCount);
1515
1516          // Animate the number
1517          animateNumber($countElement, oldCount, newCount, 500); // 500ms duration
1518
1519          // Handle button enabling/disabling
1520          if (newCount === 0) {
1521            $button.prop('disabled', true).addClass('disabled');
1522          } else {
1523            // FORCE enable - remove both attribute and class
1524            $button.removeAttr('disabled').removeClass('disabled');
1525            // Double-check it worked
1526            setTimeout(function() {
1527              if ($button.prop('disabled') || $button.hasClass('disabled')) {
1528                console.warn('Button re-disabled by something else! Force-enabling again.');
1529                $button.removeAttr('disabled').removeClass('disabled');
1530              }
1531            }, 100);
1532          }
1533
1534          // No need to replace button text as PHP handles static parts
1535        } else {
1536          console.error('Error counting filtered posts.');
1537          $('.event-count').text('0');
1538          $('.ar-mobile-event-count-button').prop('disabled', true).addClass('disabled');
1539        }
1540      },
1541      error: function(xhr, status, error) {
1542        console.error('AJAX Error (Count):', status, error);
1543        $('.event-count').text('0');
1544        $('.ar-mobile-event-count-button').prop('disabled', true).addClass('disabled');
1545      },
1546      complete: function() {
1547        if (showLoader) {
1548          $('.button-loader').removeClass('active'); // Hide the loader
1549        }
1550      }
1551    });
1552  }
1553
1554  // Handle changes in sidebar filter inputs (checkboxes, radio buttons, selects)
1555  $('#filterForm').on('change', 'input[type="checkbox"], input[type="radio"], select', function() {
1556    // Update sorting value
1557    var sortingValue = $('#sorting').val() || '0'; // Get selected sorting value
1558    $('#sortingchecktxt').val(sortingValue); // Update hidden input
1559
1560    // Reset to first page
1561    $('#page').val('1');
1562
1563    // Submit the filters via AJAX with loader
1564    submitFilters('#filterForm', true);
1565
1566    // Update the event count via AJAX with loader
1567    getFilterCount('#filterForm', true);
1568  });
1569
1570  // Handle pagination link clicks
1571  $(document).on('click', '.pgn-item:not(.disabled):not(.pgn-current)', function(e) {
1572    e.preventDefault(); // Prevent default link behavior (scroll to #)
1573    var newPage = $(this).data('page'); // Get target page number
1574    if (newPage) {
1575      $('#page').val(newPage); // Update the hidden page input
1576      submitFilters('#filterForm', true); // Show loader for main filters
1577
1578      // Update the event count via AJAX with loader
1579      getFilterCount('#filterForm', true);
1580    }
1581  });
1582
1583  // Prevent default form submission for sidebar filters
1584  $('#filterForm').on('submit', function(e) {
1585    e.preventDefault(); // Prevent full page reload
1586    submitFilters('#filterForm', true);
1587
1588    // Update the event count via AJAX with loader
1589    getFilterCount('#filterForm', true);
1590  });
1591
1592  /* Mobile Lightbox Functionality */
1593
1594  // Clone the sidebar filter form into the lightbox on button click
1595  $('#mobileFilterButton').on('click', function() {
1596    // Check if the filter form is already cloned
1597    if ($('#lightboxFilterContainer form').length === 0) {
1598      // Clone the filter form without events and IDs
1599      var clonedForm = $('#filterForm').clone(false, false); // clone with events set to false
1600
1601      // Remove the form's ID to avoid duplicate IDs (already done by wrapping labels)
1602      clonedForm.removeAttr('id');
1603
1604      // Append the cloned form to the lightbox container
1605      $('#lightboxFilterContainer').html(clonedForm);
1606    }
1607
1608    // Hide the "Filtri +" button
1609    $('.ar-mobile-filter-button').hide();
1610
1611    // Show the lightbox
1612    $('.ar-mobile-filter-lightbox').fadeIn(300, function() {
1613      // Optionally, set focus to the first input in the lightbox
1614      $('.ar-lightbox-content').find('input, select, textarea, button').first().focus();
1615    });
1616
1617    // Initialize event count
1618    getFilterCount('#lightboxFilterContainer form', false); // No loader
1619  });
1620
1621  // Close the lightbox when "X" button is clicked
1622  $('.ar-close-lightbox').on('click', function() {
1623    $('.ar-mobile-filter-lightbox').fadeOut(300, function() {
1624      // Show the "Filtri +" button after lightbox is closed
1625      $('.ar-mobile-filter-button').show();
1626    });
1627  });
1628
1629  // Close the lightbox when clicking outside the lightbox content
1630  $('.ar-mobile-filter-lightbox').on('click', function(e) {
1631    if ($(e.target).is('.ar-mobile-filter-lightbox')) {
1632      $('.ar-mobile-filter-lightbox').fadeOut(300, function() {
1633        // Show the "Filtri +" button after lightbox is closed
1634        $('.ar-mobile-filter-button').show();
1635      });
1636    }
1637  });
1638
1639  // Debounced function to handle filter changes in lightbox
1640  var debouncedGetFilterCount = debounce(function() {
1641    getFilterCount('#lightboxFilterContainer form', false); // No loader
1642  }, 300); // Adjust the delay as needed (300ms)
1643
1644  // Handle changes in mobile filter inputs (checkboxes, radio buttons, selects)
1645  $(document).on('change', '#lightboxFilterContainer form', function() {
1646    // Update sorting value
1647    var sortingValue = $(this).find('select[name="sorting"]').val() || '0'; // Get selected sorting value
1648    $(this).find('input[name="sortingchecktxt"]').val(sortingValue); // Update hidden input
1649
1650    // Reset to first page
1651    $(this).find('input[name="page"]').val('1');
1652
1653    // Submit the filters via AJAX without loader
1654    submitFilters('#lightboxFilterContainer form', false);
1655
1656    // Update the event count via AJAX without loader
1657    getFilterCount('#lightboxFilterContainer form', false);
1658  });
1659
1660  // Handle click on the event count button to load events
1661  $(document).on('click', '.ar-mobile-event-count-button', function(e) {
1662    var $btn = $(this);
1663    console.log('Button clicked! Has .disabled class:', $btn.hasClass('disabled'), 'Disabled attr:', $btn.prop('disabled'));
1664    
1665    // Prevent action if disabled
1666    if ($btn.hasClass('disabled') || $btn.prop('disabled')) {
1667      console.log('Button is disabled, ignoring click');
1668      return false;
1669    }
1670    
1671    // Get the cloned form data
1672    var formData = $('#lightboxFilterContainer form').serialize();
1673
1674    // Reset to first page
1675    formData = formData.replace(/page=\d+/, 'page=1'); // Ensure page is set to 1
1676
1677    // Append AJAX action and action_type
1678    var postType = $('#postType').val();
1679    formData += '&action=' + postType + '_posts_filter';
1680    formData += '&action_type=filter';
1681
1682    $.ajax({
1683      url: ajax_object.ajax_url,
1684      type: 'POST',
1685      data: formData,
1686      beforeSend: function() {
1687        // Optionally, show a loader elsewhere if needed
1688      },
1689      success: function(response) {
1690        $('#displayPostsData').html(response); // Update events listing
1691        $('.ar-mobile-filter-lightbox').fadeOut(300, function() {
1692          // Show the "Filtri +" button after lightbox is closed
1693          $('.ar-mobile-filter-button').show();
1694        }); // Close lightbox
1695      },
1696      error: function(xhr, status, error) {
1697        console.error('AJAX Error:', status, error);
1698        $('#displayPostsData').html('<div class="empty_posts">Error loading content.</div>');
1699      },
1700      complete: function() {
1701        // Optionally, hide any loaders if you added them
1702      }
1703    });
1704  });
1705
1706});
1707
1708
1709
1710
1711
1712// START js for sticky submenu
1713// COMMENTED OUT - This is now handled by archive-filters.js for better control
1714// The AJAX recalculation (line 1697) was causing issues by getting offsetTop while element was sticky
1715
1716/*
1717jQuery(document).ready(function($) {
1718    // Initialize variables for the new sticky menu
1719    var headerHeight = $('.navbar').outerHeight();
1720    var navbar2 = document.getElementById("sticky-box-topfixed");
1721    
1722    // Check if the new sticky menu element exists
1723    if (!navbar2) {
1724        console.error('Element with ID "sticky-box-topfixed" not found.');
1725        return;
1726    }
1727    
1728    var sticky2 = navbar2.offsetTop;
1729    
1730    function filterSticky2() {
1731        var left = document.getElementById("filterMenudisplay");
1732        var right = document.getElementById("displayPostsData");
1733        var sidebar = document.getElementById("stickyMenuSidebar");
1734    
1735        if (window.pageYOffset >= sticky2 - headerHeight) {
1736            navbar2.classList.add("stickymenu");
1737            if (left) left.classList.add("topclass");
1738            if (sidebar) sidebar.classList.add("stickysidebar");
1739            if (right) right.classList.add("topclass");
1740    
1741            if ($("#filterForm ul").length) {
1742                var last_element_position = $("#filterForm ul").last().find('li:last-child label').offset().top + 25; // 25 px padding
1743                var footer_position = $(".footer.bg-white").offset().top;
1744    
1745                // Remove sidebar sticky class when footer shows
1746                if (parseInt(last_element_position) >= parseInt(footer_position)) {
1747                    if (sidebar) {
1748                        $('#stickyMenuSidebar').removeClass('stickysidebar');
1749                    }
1750                }
1751            }
1752        } else {
1753            if (sidebar) sidebar.classList.remove("stickysidebar");
1754            navbar2.classList.remove("stickymenu");
1755            if (left) left.classList.remove("topclass");
1756            if (right) right.classList.remove("topclass");
1757        }
1758    }
1759    
1760    // Attach the scroll event listener for the new sticky menu
1761    $(window).on('scroll', filterSticky2);
1762    console.log('Scroll event listener for sticky-box-topfixed attached.');
1763    
1764    // Initial check in case the page is loaded scrolled down
1765    filterSticky2();
1766    
1767    // Recalculate sticky positions after AJAX content load
1768    $(document).ajaxComplete(function() {
1769        // Recalculate header height and sticky position
1770        headerHeight = $('.navbar').outerHeight();
1771        sticky2 = navbar2.offsetTop;
1772        console.log('AJAX content loaded. Recalculating sticky positions for sticky-box-topfixed.');
1773        filterSticky2();
1774    });
1775});
1776*/
1777// END js for sticky submenu
1778
1779
1780// Start translations 2025
1781// COMMENTED OUT - Translation object not being localized yet
1782/*
1783jQuery(document).ready(function($) {
1784    // Update filter button text with translated string
1785    $('#filter-button').text(filter_translation.filter_button);
1786    
1787    // Update a label with translated string
1788    $('label[for="event-filter"]').text(filter_translation.filter_label);
1789    
1790    // Display "No events found" message dynamically
1791    if ( $('.empty_posts').length ) {
1792        $('.empty_posts').text(filter_translation.no_events_found);
1793    }
1794    
1795    // Update pagination text
1796    $('.showing_posts').each(function() {
1797        var showing = filter_translation.showing_events;
1798        var of = filter_translation.of_events;
1799        var total = $(this).data('total'); // From data-total attribute
1800        var shown = $(this).data('shown'); // From data-shown attribute
1801        $(this).text(showing + ' 1-' + shown + ' ' + of + ' ' + total + ' ' + filter_translation.events);
1802    });
1803    
1804    // Responsive Filters and Lightbox remain in default language
1805    $('#lightbox-button').text('Open Lightbox'); // Remains in English
1806});
1807*/
1808
1809// END translations 2025
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823    $(document).on('change', '.filter_dropdown', function() { // on change of state
1824        var optionSelected = $('#sorting').find("option:selected");
1825        var valueSelected = optionSelected.val();
1826        $("#sortingtxt").val(valueSelected);
1827
1828        jQuery('#loading').show();
1829        formSubmitCall('filterFormSelect');
1830    });
1831
1832    function formSubmitCall(formName) {
1833        var postType = jQuery('#postType').val();
1834        jQuery.ajax({
1835            url: ajaxurl,
1836            type: "post",
1837            // dataType: "json",
1838            data: $('#' + formName).serialize() + "&action="+postType+"_posts_filter",
1839            success: function(response) {
1840                jQuery('#displayPostsData').html(response);
1841            },
1842            complete: function() {
1843                jQuery('#loading').hide();
1844            }
1845        });
1846    }
1847
1848    $(document).on('change', '.filter_dropdown_set', function() {
1849        //  alert();
1850        // on change of state
1851        jQuery('#loading').show();
1852
1853        var optionSelected = $('#sorting').find("option:selected");
1854        var valueSelected = optionSelected.val();
1855        $("#sortingtxt").val(valueSelected);
1856        $("#sortingchecktxt").val(valueSelected);
1857        // filter selct option
1858        if ($(".mobilefilterOption").length) {
1859            formSubmitCall('filterFormSelect');
1860        }
1861        // filter checkbox option
1862        else if ($(".sticky-box2").length) {
1863            formSubmitCall('filterForm');
1864        }
1865        // fallback: always submit if form exists
1866        else if ($("#filterForm").length) {
1867            formSubmitCall('filterForm');
1868        }
1869
1870    });
1871    $(document).on('click', '.dropdown-check-list .anchor', function() {
1872        jQuery('.dropdown-check-list').not($(this).closest('.dropdown-check-list')).removeClass('visible');
1873        $(this).closest('.dropdown-check-list').toggleClass('visible');
1874    });
1875
1876    $(document).on('click', function(event) {
1877        if (!$(event.target).closest('.mobileFilter').length) {
1878            jQuery('.dropdown-check-list').removeClass('visible');
1879        }
1880    });
1881
1882    // var checkList = document.getElementsByClassName('dropdown-check-list');
1883    // checkList.getElementsByClassName('anchor')[0].onclick = function(evt) {
1884    //     if (checkList.classList.contains('visible'))
1885    //         checkList.classList.remove('visible');
1886    //     else
1887    //         checkList.classList.add('visible');
1888    // }
1889
1890})(jQuery);
1891

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.