document.addEventListener("DOMContentLoaded", function (){
function initTaxonomySliders(){
if(window.innerWidth >=992){
return;
}
const wrappers=document.querySelectorAll('.taxonomy-slider-wrapper:not(.no-mobile-carousel)');
wrappers.forEach(function(wrapper){
if(wrapper.offsetParent===null||wrapper.offsetWidth===0||wrapper.offsetHeight===0){
return;
}
const slider=wrapper.querySelector('.taxonomy-responsive-slider');
const controlsContainer=wrapper.querySelector('.taxonomy-slider-controls-container');
if(!slider||!controlsContainer){
return;
}
const prevButton=controlsContainer.querySelector('.taxonomy-slide-prev');
const nextButton=controlsContainer.querySelector('.taxonomy-slide-next');
const dotsContainer=controlsContainer.querySelector('.taxonomy-dots');
const items=slider.querySelectorAll('.category-small-box, .category-small-box-alt');
if(!prevButton||!nextButton||!dotsContainer||items.length===0){
return;
}
let currentPosition=0;
function getItemWidth(){
if(items.length > 0){
const itemRect=items[0].getBoundingClientRect();
const itemStyle=window.getComputedStyle(items[0]);
const marginRight=parseFloat(itemStyle.marginRight)||0;
return itemRect.width + marginRight + 20;
}
if(window.innerWidth <=480){
return (window.innerWidth / 2 - 10) + 20;
}
return (window.innerWidth / 3 - 20) + 20;
}
function getMaxTranslateX(){
const itemWidth=getItemWidth();
const totalContentWidth=items.length * itemWidth;
const visibleWidth=wrapper.clientWidth;
if(totalContentWidth <=visibleWidth){
return 0;
}
return Math.max(0, totalContentWidth - visibleWidth - 20);
}
function calculateVisibleItems(){
const containerWidth=wrapper.clientWidth;
const itemWidth=getItemWidth();
return Math.floor(containerWidth / itemWidth);
}
function getTotalSlides(){
const visibleItems=calculateVisibleItems();
return Math.ceil(items.length / visibleItems);
}
function generateDots(){
const totalSlides=getTotalSlides();
dotsContainer.innerHTML='';
for (let i=0; i < totalSlides; i++){
const li=document.createElement('li');
li.setAttribute('role', 'presentation');
li.setAttribute('aria-selected', i===0 ? 'true':'false');
li.setAttribute('aria-controls', `navigation${i}`);
li.setAttribute('id', `slick-slide${i}`);
if(i===0){
li.classList.add('active');
}
const button=document.createElement('button');
button.type='button';
button.setAttribute('data-role', 'none');
button.setAttribute('role', 'button');
button.setAttribute('tabindex', '0');
button.textContent=(i + 1).toString();
li.appendChild(button);
dotsContainer.appendChild(li);
li.addEventListener('click', function(){
goToSlide(i);
});
}}
function goToSlide(slideIndex){
const visibleItems=calculateVisibleItems();
const targetPosition=slideIndex * visibleItems;
currentPosition=Math.min(targetPosition, items.length - visibleItems);
currentPosition=Math.max(0, currentPosition);
updateSliderPosition();
updateDots();
}
function updateDots(){
const dots=dotsContainer.querySelectorAll('li');
const visibleItems=calculateVisibleItems();
const currentSlide=Math.floor(currentPosition / visibleItems);
dots.forEach((dot, index)=> {
dot.classList.remove('active');
dot.setAttribute('aria-selected', 'false');
if(index===currentSlide){
dot.classList.add('active');
dot.setAttribute('aria-selected', 'true');
}});
}
function updateSliderPosition(){
const itemWidth=getItemWidth();
const requestedTranslateX=currentPosition * itemWidth;
const maxTranslateX=getMaxTranslateX();
const actualTranslateX=Math.min(requestedTranslateX, maxTranslateX);
slider.style.transform=`translateX(-${actualTranslateX}px)`;
updateNavigationButtons();
updateDots();
}
function updateNavigationButtons(){
if(currentPosition <=0){
prevButton.classList.add('slick-disabled');
}else{
prevButton.classList.remove('slick-disabled');
}
const itemWidth=getItemWidth();
const nextPositionTranslateX=(currentPosition + 1) * itemWidth;
const maxTranslateX=getMaxTranslateX();
if(nextPositionTranslateX > maxTranslateX){
nextButton.classList.add('slick-disabled');
}else{
nextButton.classList.remove('slick-disabled');
}}
prevButton.addEventListener("click", function (e){
e.preventDefault();
e.stopPropagation();
if(currentPosition > 0){
currentPosition--;
updateSliderPosition();
}});
nextButton.addEventListener("click", function (e){
e.preventDefault();
e.stopPropagation();
const itemWidth=getItemWidth();
const requestedTranslateX=(currentPosition + 1) * itemWidth;
const maxTranslateX=getMaxTranslateX();
if(requestedTranslateX <=maxTranslateX){
currentPosition++;
updateSliderPosition();
}});
function handleResize(){
if(window.innerWidth >=992){
slider.style.transform='none';
return;
}
const visibleItems=calculateVisibleItems();
currentPosition=Math.min(currentPosition,
Math.max(0, items.length - visibleItems)
);
generateDots();
updateSliderPosition();
}
window.addEventListener("resize", handleResize);
let startX=0;
let endX=0;
let touchStartTime=0;
slider.addEventListener("touchstart", function (e){
startX=e.touches[0].clientX;
touchStartTime=Date.now();
});
slider.addEventListener("touchmove", function (e){
endX=e.touches[0].clientX;
});
slider.addEventListener("touchend", function (e){
const deltaX=endX - startX;
const touchDuration=Date.now() - touchStartTime;
if(Math.abs(deltaX) > 50&&touchDuration < 300){
if(deltaX > 0){
if(currentPosition > 0){
currentPosition--;
updateSliderPosition();
}}else{
const itemWidth=getItemWidth();
const requestedTranslateX=(currentPosition + 1) * itemWidth;
const maxTranslateX=getMaxTranslateX();
if(requestedTranslateX <=maxTranslateX){
currentPosition++;
updateSliderPosition();
}}
}});
generateDots();
updateSliderPosition();
});
}
initTaxonomySliders();
let resizeTimeout;
window.addEventListener("resize", function(){
clearTimeout(resizeTimeout);
resizeTimeout=setTimeout(function(){
if(window.innerWidth < 992){
initTaxonomySliders();
}}, 250);
});
});
(function($){
'use strict';
class ListeoContentCarousel {
constructor(element){
this.$widget=$(element);
if(this.$widget.data('carousel-initialized')){
return;
}
this.$widget.data('carousel-initialized', true);
this.$track=this.$widget.find('.carousel-track');
this.$tabs=this.$widget.find('.carousel-tab');
this.$prevBtn=this.$widget.find('.nav-prev');
this.$nextBtn=this.$widget.find('.nav-next');
this.$wrapper=this.$widget.find('.carousel-wrapper');
this.currentPosition=0;
this.cardWidth=0;
this.gap=24;
this.maxScrollPosition=0;
this.visibleCards=0;
this.totalCards=this.$track.find('.carousel-card').length;
this.autoplayTimer=null;
this.isMobile=window.innerWidth <=992;
this.settings={
autoplay: this.$widget.data('autoplay')==='yes',
autoplaySpeed: this.$widget.data('autoplay-speed')||5000,
animationSpeed: this.$widget.data('animation-speed')||600
};
this.init();
}
init(){
this.calculateDimensions();
this.bindEvents();
this.updateNavigation();
if(this.settings.autoplay){
this.startAutoplay();
}
$(window).on('resize.carousel', $.proxy(this.handleResize, this));
}
calculateDimensions(){
const $firstCard=this.$track.find('.carousel-card').first();
if($firstCard.length){
this.isMobile=window.innerWidth <=992;
this.cardWidth=$firstCard.outerWidth(false);
const computedStyle=getComputedStyle(this.$track[0]);
this.gap=parseInt(computedStyle.gap)||(this.isMobile ? 16:24);
const wrapperWidth=this.$wrapper.width();
const trackWidth=this.$track[0].scrollWidth;
this.maxScrollPosition=Math.max(0, trackWidth - wrapperWidth);
if(this.isMobile){
this.maxPosition=Math.max(0, this.totalCards - Math.floor(wrapperWidth / (this.cardWidth + this.gap)));
}else{
const $allCards=this.$track.find('.carousel-card');
let maxPos=0;
let scrollFromStart=0;
for (let i=0; i < $allCards.length; i++){
const $card=$allCards.eq(i);
const cardWidth=$card.outerWidth(false);
const scrollToThisCard=scrollFromStart;
if(scrollToThisCard <=this.maxScrollPosition + 50){
maxPos=i;
}else{
break;
}
scrollFromStart +=cardWidth + this.gap;
}
this.maxPosition=Math.max(0, maxPos);
}
this.visibleCards=Math.floor(wrapperWidth / (this.cardWidth + this.gap));
}}
bindEvents(){
this.$tabs.on('click.carousel', $.proxy(this.handleTabClick, this));
this.$prevBtn.on('click.carousel', $.proxy(this.goToPrevious, this));
this.$nextBtn.on('click.carousel', $.proxy(this.goToNext, this));
this.bindTouchEvents();
this.$widget.on('keydown.carousel', $.proxy(this.handleKeyboard, this));
this.$widget.on('mouseenter.carousel', $.proxy(this.pauseAutoplay, this));
this.$widget.on('mouseleave.carousel', $.proxy(this.resumeAutoplay, this));
let scrollTimeout;
this.$wrapper.on('scroll.carousel', ()=> {
clearTimeout(scrollTimeout);
scrollTimeout=setTimeout(()=> {
this.updatePositionFromScroll();
}, 100);
});
}
bindTouchEvents(){
let startX=0;
let startY=0;
let isDown=false;
let hasMoved=false;
let startTime=0;
this.$wrapper.on('mousedown.carousel touchstart.carousel', (e)=> {
isDown=true;
hasMoved=false;
startTime=Date.now();
const touch=e.originalEvent.touches ? e.originalEvent.touches[0]:e.originalEvent;
startX=touch.pageX;
startY=touch.pageY;
this.$wrapper.css('cursor', 'grabbing');
this.pauseAutoplay();
});
this.$wrapper.on('mouseleave.carousel mouseup.carousel touchend.carousel', (e)=> {
if(!isDown) return;
isDown=false;
this.$wrapper.css('cursor', 'grab');
this.resumeAutoplay();
if(hasMoved){
const endTime=Date.now();
const timeDiff=endTime - startTime;
const touch=e.originalEvent.changedTouches ? e.originalEvent.changedTouches[0]:e.originalEvent;
const endX=touch.pageX||e.originalEvent.pageX;
const endY=touch.pageY||e.originalEvent.pageY;
const deltaX=endX - startX;
const deltaY=endY - startY;
const absDeltaX=Math.abs(deltaX);
const absDeltaY=Math.abs(deltaY);
if(absDeltaX > absDeltaY&&absDeltaX > 50&&timeDiff < 500){
e.preventDefault();
e.stopPropagation();
if(deltaX > 0){
this.goToPrevious();
}else{
this.goToNext();
}}else{
this.goToPosition(this.currentPosition);
}}
});
this.$wrapper.on('mousemove.carousel touchmove.carousel', (e)=> {
if(!isDown) return;
const touch=e.originalEvent.touches ? e.originalEvent.touches[0]:e.originalEvent;
const currentX=touch.pageX||e.originalEvent.pageX;
const currentY=touch.pageY||e.originalEvent.pageY;
const deltaX=Math.abs(currentX - startX);
const deltaY=Math.abs(currentY - startY);
if(deltaX > 10||deltaY > 10){
hasMoved=true;
}
if(hasMoved&&deltaX > deltaY&&deltaX > 20){
e.preventDefault();
}});
}
handleTabClick(e){
const $tab=$(e.currentTarget);
const targetPosition=parseInt($tab.data('position'), 10)||0;
this.$tabs.removeClass('active');
$tab.addClass('active');
this.goToPosition(targetPosition);
}
goToPosition(position){
position=Math.max(0, Math.min(position, this.maxPosition));
let scrollPosition=0;
if(position===0){
scrollPosition=0;
}else if(position >=this.maxPosition){
scrollPosition=this.maxScrollPosition;
}else{
scrollPosition=this.calculateScrollPositionForCard(position);
}
this.$wrapper.scrollLeft(scrollPosition);
this.currentPosition=position;
this.updateNavigation();
}
calculateScrollPositionForCard(targetPosition){
const $cards=this.$track.find('.carousel-card');
let scrollPosition=0;
if(this.isMobile){
scrollPosition=targetPosition * (this.cardWidth + this.gap);
}else{
for (let i=0; i < targetPosition&&i < $cards.length; i++){
const $card=$cards.eq(i);
const cardWidth=$card.outerWidth(false);
scrollPosition +=cardWidth + this.gap;
}}
return scrollPosition;
}
goToNext(){
if(this.currentPosition < this.maxPosition){
this.goToPosition(this.currentPosition + 1);
}else if(this.settings.autoplay){
this.goToPosition(0);
}}
goToPrevious(){
if(this.currentPosition <=0){
return;
}
const targetPosition=this.currentPosition - 1;
this.goToPosition(targetPosition);
}
updateNavigation(){
this.$prevBtn.prop('disabled', this.currentPosition <=0);
this.$nextBtn.prop('disabled', this.currentPosition >=this.maxPosition);
this.updateActiveTab();
}
updateActiveTab(){
if(this.$tabs.length===0) return;
let activeTabIndex=0;
let closestDistance=Infinity;
this.$tabs.each((index, tab)=> {
const tabPosition=parseInt($(tab).data('position'), 10)||0;
const distance=Math.abs(this.currentPosition - tabPosition);
if(distance < closestDistance){
closestDistance=distance;
activeTabIndex=index;
}});
this.$tabs.removeClass('active');
this.$tabs.eq(activeTabIndex).addClass('active');
}
updatePositionFromScroll(){
const scrollPosition=this.$wrapper.scrollLeft();
let newPosition=0;
if(scrollPosition >=this.maxScrollPosition - 10){
newPosition=this.maxPosition;
}else if(scrollPosition <=10){
newPosition=0;
}else{
newPosition=this.findClosestCardPosition(scrollPosition);
newPosition=Math.max(0, Math.min(newPosition, this.maxPosition));
}
if(newPosition!==this.currentPosition){
this.currentPosition=newPosition;
this.updateNavigation();
}}
findClosestCardPosition(scrollPosition){
const $cards=this.$track.find('.carousel-card');
if(this.isMobile){
const cardAndGapWidth=this.cardWidth + this.gap;
const position=Math.round(scrollPosition / cardAndGapWidth);
return Math.max(0, Math.min(position, this.totalCards - 1));
}
let currentScroll=0;
let closestPosition=0;
let closestDistance=Infinity;
for (let i=0; i < $cards.length; i++){
const distance=Math.abs(scrollPosition - currentScroll);
if(distance < closestDistance){
closestDistance=distance;
closestPosition=i;
}
const $card=$cards.eq(i);
const cardWidth=$card.outerWidth(false);
currentScroll +=cardWidth + this.gap;
}
const wrapperWidth=this.$wrapper.width();
if(scrollPosition >=this.maxScrollPosition - 20){
let totalWidthFromEnd=0;
let bestEndPosition=$cards.length - 1;
for (let i=$cards.length - 1; i >=0; i--){
const $card=$cards.eq(i);
const cardWidth=$card.outerWidth(false);
totalWidthFromEnd=0;
for (let j=i; j < $cards.length; j++){
const $cardInner=$cards.eq(j);
totalWidthFromEnd +=$cardInner.outerWidth(false);
if(j < $cards.length - 1) totalWidthFromEnd +=this.gap;
}
if(totalWidthFromEnd <=wrapperWidth * 1.1){
bestEndPosition=i;
break;
}}
return Math.max(0, bestEndPosition);
}
return Math.max(0, Math.min(closestPosition, this.totalCards - 1));
}
handleKeyboard(e){
switch(e.key){
case 'ArrowLeft':
e.preventDefault();
this.goToPrevious();
break;
case 'ArrowRight':
e.preventDefault();
this.goToNext();
break;
case ' ':
e.preventDefault();
if(this.settings.autoplay){
this.toggleAutoplay();
}
break;
}}
startAutoplay(){
if(!this.settings.autoplay) return;
this.autoplayTimer=setInterval(()=> {
this.goToNext();
}, this.settings.autoplaySpeed);
}
pauseAutoplay(){
if(this.autoplayTimer){
clearInterval(this.autoplayTimer);
this.autoplayTimer=null;
}}
resumeAutoplay(){
if(this.settings.autoplay&&!this.autoplayTimer){
this.startAutoplay();
}}
toggleAutoplay(){
this.settings.autoplay = !this.settings.autoplay;
if(this.settings.autoplay){
this.startAutoplay();
}else{
this.pauseAutoplay();
}}
handleResize(){
clearTimeout(this.resizeTimer);
this.resizeTimer=setTimeout(()=> {
this.calculateDimensions();
this.updateNavigation();
}, 250);
}
destroy(){
$(window).off('resize.carousel');
this.$tabs.off('.carousel');
this.$prevBtn.off('.carousel');
this.$nextBtn.off('.carousel');
this.$widget.off('.carousel');
this.$wrapper.off('.carousel');
this.pauseAutoplay();
if(this.resizeTimer){
clearTimeout(this.resizeTimer);
}}
}
if(!$.easing.easeInOutCubic){
$.easing.easeInOutCubic=function (x, t, b, c, d){
if((t/=d/2) < 1) return c/2*t*t*t + b;
return c/2*((t-=2)*t*t + 2) + b;
};}
$(window).on('elementor/frontend/init', function(){
elementorFrontend.hooks.addAction('frontend/element_ready/listeo-content-carousel.default', function($scope){
const $carousel=$scope.find('.listeo-carousel-widget');
if($carousel.length){
setTimeout(()=> {
new ListeoContentCarousel($carousel[0]);
}, 200);
}});
});
$(document).ready(function(){
$('.listeo-carousel-widget').each(function(){
setTimeout(()=> {
new ListeoContentCarousel(this);
}, 300);
});
});
$(document).on('elementor/popup/show', function(){
setTimeout(()=> {
$('.listeo-carousel-widget').each(function(){
if(!$(this).data('carousel-initialized')){
$(this).data('carousel-initialized', true);
new ListeoContentCarousel(this);
}});
}, 500);
});
$(document).ready(function(){
$('.carousel-track').attr('role', 'region').attr('aria-label', 'Content carousel');
$('.carousel-tabs').attr('role', 'tablist');
$('.carousel-tab').attr('role', 'tab').attr('tabindex', '0');
$('.nav-arrow').attr('aria-label', function(){
return $(this).hasClass('nav-prev') ? 'Previous slide':'Next slide';
});
$('.carousel-tab').on('keydown', function(e){
if(e.key==='Enter'||e.key===' '){
e.preventDefault();
$(this).click();
}});
});
window.ListeoContentCarousel=ListeoContentCarousel;
})(jQuery);
(function($){
'use strict';
if(typeof elementor!=='undefined'&&elementor.modules&&elementor.modules.controls){
$(document).ready(function(){
elementor.hooks.addAction('panel/open_editor/widget/listeo-content-carousel', function(panel, model, view){
setTimeout(function(){
setupTaxonomyFiltering();
}, 500);
});
function setupTaxonomyFiltering(){
$('[data-setting$="_taxonomy_type"]').off('change.taxonomyFilter').on('change.taxonomyFilter', function(){
const $this=$(this);
const selectedTaxonomy=$this.val();
const settingName=$this.data('setting');
const termSettingName=settingName.replace('_taxonomy_type', '_taxonomy_term');
const $termControl=$('[data-setting="' + termSettingName + '"]');
if($termControl.length){
filterTermOptions($termControl, selectedTaxonomy);
}});
$('[data-setting$="_taxonomy_type"]').each(function(){
const $this=$(this);
const selectedTaxonomy=$this.val();
const settingName=$this.data('setting');
const termSettingName=settingName.replace('_taxonomy_type', '_taxonomy_term');
const $termControl=$('[data-setting="' + termSettingName + '"]');
if($termControl.length&&selectedTaxonomy){
filterTermOptions($termControl, selectedTaxonomy);
}});
}
function filterTermOptions($termControl, taxonomyType){
const $select=$termControl.find('select');
if(!$select.length) return;
if(!$select.data('original-options')){
const originalOptions=[];
$select.find('option').each(function(){
originalOptions.push({
value: $(this).val(),
text: $(this).text()
});
});
$select.data('original-options', originalOptions);
}
const originalOptions=$select.data('original-options');
$select.empty();
const filterPrefix=taxonomyType==='listing_category' ? 'category_':'region_';
originalOptions.forEach(function(option){
if(!option.value||option.value.startsWith(filterPrefix)){
$select.append($('<option>', {
value: option.value,
text: option.text
}));
}});
if($select.hasClass('select2-hidden-accessible')){
$select.select2('destroy').select2();
}
const currentValue=$select.val();
if(currentValue&&!currentValue.startsWith(filterPrefix)){
$select.val('').trigger('change');
}}
$(document).off('click.listeoContentCarousel').on('click.listeoContentCarousel', '.elementor-repeater-add', function(){
var currentElement=elementor.getPanelView().getCurrentPageView();
if(!currentElement||!currentElement.model){
return;
}
var widgetType=currentElement.model.get('widgetType')||'';
if(widgetType!=='listeo-content-carousel'){
return;
}
setTimeout(function(){
setupTaxonomyFiltering();
}, 100);
});
});
}})(jQuery);