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.