document.addEventListener("DOMContentLoaded", () => { //#region Initialize all carousels on page ----------------------------------------------------- // Find all carousel containers const carouselContainers = document.querySelectorAll('.carousel-component'); carouselContainers.forEach((container) => { initializeCarousel(container); }); function initializeCarousel(container) { const componentElement = container.querySelector('[data-component="component"]'); if (!componentElement) { console.error('Carousel: [data-component="component"] element not found in container'); return; } const dataVariable = componentElement.dataset.srcVariable; if (!dataVariable) { console.error('Carousel: No data-src-variable attribute found'); return; } if (!window[dataVariable]) { console.error('Carousel: Data variable not found:', dataVariable); return; } const data = window[dataVariable]; if (!data.length) { console.warn('Carousel: No data found in', dataVariable); return; } //#endregion //#region Replier ----------------------------------------------------- class Replier { constructor(data) { this.data = data; } } //#endregion //#region Service ----------------------------------------------------- class Service { constructor(replier, container) { this.replier = replier; this.container = container; this.selectors; } initializeGlobalVariables() { this.items = this.selectors.carouselElement.querySelectorAll(".wrapper"); this.itemWidth = this.selectors.carouselElement.querySelector(".wrapper").offsetWidth; this.itemsWidth = Array.from(this.items).reduce((acc, item) => acc + item.offsetWidth, 0); this.onScreenComponentWidth = this.selectors.carouselElement.offsetWidth; this.maxComponentWidth = (this.itemsWidth - this.onScreenComponentWidth) + 8; this.currentPosition = 0; } triggerSelectors(componentElement) { this.selectors = { headerContentElement: componentElement.querySelector( '[data-component="header-content"]' ), indicatorsElement: componentElement.querySelector( '[data-component="indicators"]' ), headerButtonsElement: componentElement.querySelector( '[data-component="header-buttons"]' ), carouselElement: componentElement.querySelector( '[data-component="body-carousel"]' ) }; }; insertComponentSkeleton() { const componentElement = this.container.querySelector('[data-component="component"]'); componentElement.insertAdjacentHTML("afterbegin", this.getSkeletonHtml()); return componentElement; }; insertComponentContent(skeleton, selectors) { data.forEach((item, index) => { if (window.innerWidth < 768) { this.insertMobileIndicators(selectors.indicatorsElement, index); } selectors.carouselElement.insertAdjacentHTML( "beforeend", this.getContentCard(item, index) ); }); this.initializeGlobalVariables(); if (screen.width > 979.9 && data.length > 2) { this.insertDesktopButtons(skeleton, selectors, this.itemWidth); } }; insertMobileIndicators(indicatorsElement, index) { indicatorsElement.insertAdjacentHTML( "beforeend", this.getMobileIndicator(index) ); }; insertDesktopButtons(skeleton, selectors) { selectors.headerButtonsElement.insertAdjacentHTML("afterbegin", this.getDesktopButtons()); const prevButton = skeleton.querySelector( '[data-component="button-prev"]' ); const nextButton = skeleton.querySelector( '[data-component="button-next"]' ); prevButton.addEventListener("click", () => { service.updateDesktopCardPosition(this.currentPosition - this.itemWidth); }); nextButton.addEventListener("click", () => { service.updateDesktopCardPosition(this.currentPosition + this.itemWidth); }); }; getSkeletonHtml() { return `
`; }; getContentCard(item, index) { return `
  • ${item.keyword}
    ${item.mainText}

    ${item.secondaryText}

  • `; }; getMobileIndicator(index) { return ` `; }; getDesktopButtons() { return ` `; }; updateDesktopCardPosition(newPosition) { this.currentPosition = Math.max(0, Math.min(newPosition, this.maxComponentWidth)); const offset = -this.currentPosition; this.items.forEach((item) => { item.style.transition = `transform 0.4s ease`; item.style.transform = `translateX(${offset}px)`; }); }; updateMobileIndicators() { const indicators = this.selectors.indicatorsElement.querySelectorAll( '[data-component="indicator"]' ); let currentIndex; if (this.currentPosition < 0) { currentIndex = 0; this.currentPosition = 0; } else if (this.currentPosition > this.itemsWidth - this.onScreenComponentWidth) { currentIndex = this.items.length - 1; this.currentPosition = this.itemsWidth - this.onScreenComponentWidth; } else { currentIndex = Math.abs(this.currentPosition / this.itemWidth); currentIndex = Math.round(currentIndex); } indicators.forEach((indicator, index) => { indicator.classList.toggle( "active", index === currentIndex ); }); }; } //#endregion //#region Caller ------------------------------------------------------ class Caller { constructor(service, selectors) { this.service = service; this.selectors = selectors; this.selectors.carouselElement.addEventListener("touchstart", this.onTouchStart.bind(this)); this.selectors.carouselElement.addEventListener("touchmove", this.onTouchMove.bind(this)); this.selectors.carouselElement.addEventListener("touchend", this.onTouchEnd.bind(this)); this.selectors.carouselElement.addEventListener("scroll", this.onScroll.bind(this)); this.startX = 0; this.currentX = 0; } onTouchStart(event) { this.startX = event.touches[0].clientX; } onTouchMove(event) { this.currentX = event.touches[0].clientX; } onTouchEnd() { const deltaX = this.startX - this.currentX; this.service.currentPosition += deltaX; this.service.updateMobileIndicators(); } onScroll() { this.service.currentPosition = this.selectors.carouselElement.scrollLeft; this.service.updateMobileIndicators(); } } //#endregion //#region Main -------------------------------------------------------- const replier = new Replier(data); const service = new Service(replier, container); const skeleton = service.insertComponentSkeleton(); service.triggerSelectors(skeleton); service.insertComponentContent(skeleton, service.selectors); const caller = new Caller(service, service.selectors); service.updateDesktopCardPosition(0); service.updateMobileIndicators(); //#endregion } });