UNPKG

lumecss

Version:

LumeCss is a modern, lightweight, and flexible CSS library designed for building fast and responsive user interfaces. Built with SCSS and TypeScript, LumeCss provides utility-first classes, customizable themes, and reusable components to speed up your dev

985 lines (764 loc) 36.5 kB
// Get an array of carousel objects const carouselArray: HTMLElement[] = Array.from(document.querySelectorAll('.carousel')); // Declare the startPosition and endPosition variables used for the touch-enabled carousel let startPosition: number = 0; let endPosition: number = 0; // Iterate of each carousel in the carouselArray carouselArray.forEach((carousel: HTMLElement): void => { // Get an array of the carousel items const carouselItemsArray: HTMLElement[] = Array.from(document.querySelectorAll('.carousel-item')); /* Define the isFadeCarousel variable, which can be either true or false, and specifies whether the carousel uses a fade effect */ const isFadeCarousel: boolean = carousel.classList.contains('carousel-fade'); // Make sure the carouselItemsArray is not empty if (carouselItemsArray.length < 1) return; // Call the setDefaultPosition function setDefaultPosition(carouselItemsArray); // Call the addIndicatorButtons function addIndicatorButtons(carousel, carouselItemsArray); // Call the loadCarouselItemImage function loadCarouselItemImage(carouselItemsArray); if (!isFadeCarousel) { // Call the moveCarouselToDefaultPosition function if the carousel is not fade-carousel moveCarouselToDefaultPosition(carousel, carouselItemsArray); } // Add event listeners to the carousel navigation buttons addEventListenersToNavigationButtons(carousel, carouselItemsArray, isFadeCarousel); }); function addIndicatorButtons( carousel: HTMLElement, carouselItemsArray: HTMLElement[] ): void { /* The function is responsible for adding indicator buttons to * the carousel indicator wrapper if the indicator wrapper exists. * * Attributes: * - carousel: The carousel HTML object which is used to get carousel indicators wrapper * - carouselItemsArray: An array of the carousel item objects * */ // Define the defaultSlideIsSpecified variable let defaultSlideIsSpecified: boolean = false; // Get the carousel indicators wrapper or null if it does not exist const indicatorsWrapper: HTMLElement | null = carousel.querySelector('.carousel-indicators'); // Make sure the indicatorsWrapper exists (is not null) if (!indicatorsWrapper) return; // Iterate over each item in the carouselItemsArray carouselItemsArray.forEach((item: HTMLElement, index: number): void => { // Create the indicator button object const indicatorBtn: HTMLSpanElement = document.createElement("span"); // Add the 'carousel-indicator' class to the indicatorBtn indicatorBtn.classList.add('carousel-indicator'); // Add the 'data-carousel-slide-index' attribute to the indicatorBtn indicatorBtn.setAttribute('data-carousel-slide-index', `${index}`); // Add the 'active' class to the indicatorBtn if the item object contains the 'active' class if (item.classList.contains('active') && !defaultSlideIsSpecified) { indicatorBtn.classList.add('active'); defaultSlideIsSpecified = true; } // Append the indicatorBtn into the indicatorsWrapper indicatorsWrapper.appendChild(indicatorBtn); }); } function loadCarouselItemImage(carouselItemsArray: HTMLElement[]): void { /* The function iterates over each carousel item in the carouselItemsArray, looks * for the .carousel-img tag, and if it exists, it takes the image src link and adds it * as a background-image style to the carousel item using the found src. * * Attributes: * - carouselItemsArray: An array of the carousel item objects * */ // Iterate over each item in the carouselItemsArray carouselItemsArray.forEach((item: HTMLElement): void => { // Retrieve the .carousel-img or null if it does not exist const carouselItemImage: HTMLImageElement | null = item.querySelector('.carousel-img'); // Make sure the carouselItemImage exists (is not null) if (!carouselItemImage) return; // Retrieve the image src or null if it is not provided const src: string | null = carouselItemImage.getAttribute('src') ? carouselItemImage.getAttribute('src') : null; // Make sure the image's src is not null if (!src) return; // Update the carousel item background-image CSS property item.style.backgroundImage = `url(${src})`; }); } function moveCarouselToDefaultPosition( carousel: HTMLElement, carouselItemsArray: HTMLElement[] ): void { /* The function is responsible for moving the carousel to its initial * position when the web page is loaded. * * Attributes: * - carousel: The carousel HTML object is used to get the carousel inner element * - carouselItemsArray: An array of the carousel item objects * */ // Retrieve the carousel inner HTML object or null if it does not exist const carouselInner: HTMLElement | null = carousel.querySelector('.carousel-inner'); // Make sure the carouselInner exists (is not null) if (!carouselInner) return; // Iterate over each item in the carouselItemsArray for (let index: number = 0; index < carouselItemsArray.length; index++) { const item: HTMLElement = carouselItemsArray[index]; // Check if the item contains the 'active' class if (item.classList.contains('active')) { // Get the computed style of the element let style: CSSStyleDeclaration = window.getComputedStyle(carouselInner); // Retrieve the transition property value let transition: string = style.transition; // Disable the carouselInner transition property for a while carouselInner.style.transition = 'none'; // Update the carousel inner position carouselInner.style.left = `-${index * 100}%`; // Enable the carouselInner transition property after a while setTimeout((): void => { carouselInner.style.transition = transition }, 100); // End the function execution return; } } }; function setDefaultPosition(carouselItemsArray: HTMLElement[]): void { /* The function is responsible for setting the default active slide if it * is not specified by the user. * * Attributes: * - carouselItemsArray: An array of the carousel item objects * */ // Define the defaultSlideIsSpecified variable let defaultSlideIsSpecified: boolean = false; // Iterate over each item in the carouselItemsArray carouselItemsArray.forEach((item: HTMLElement, index: number): void => { // Check if the item contains the 'active' class if (item.classList.contains('active')) defaultSlideIsSpecified = true; }); // Make sure the defaultSlideIsSpecified is not true if (defaultSlideIsSpecified) return; // Make the first item default by adding the 'active' class carouselItemsArray[0].classList.add('active'); } function updateCarouselCurrentIndex( carouselItemsArray: HTMLElement[], carouselDirection: 'forward' | 'backward' | null, newIndex: number | null ): { previousIndex: number | null, currentIndex: number | null } { /* The function is responsible for updating the carousel's current index * and returns the previousIndex and currentIndex. * * Attributes: * - carouselItemsArray: An array of the carousel item objects * - carouselDirection: It indicates whether the currentIndex should * be increased or decreased by one * - newIndex: The new current position * */ // Define the currentIndex, and previousIndex variable let currentIndex: number | null = null; let previousIndex: number | null = null; // Define the numberOfCarouselItems variable const numberOfCarouselItems: number = carouselItemsArray.length; // Make sure the numberOfCarouselItems is grater than 0 if (numberOfCarouselItems <= 0) return { previousIndex: null, currentIndex: null }; // Iterate over each item in the carouselItemsArray for (let index: number = 0; index < carouselItemsArray.length; index++) { // Check if the carousel item contains the 'active' class if (carouselItemsArray[index].classList.contains('active')) { // Update the current index currentIndex = index; break; // End the loop execution } } // Make sure the currentIndex is not null if (currentIndex === null) return { previousIndex: null, currentIndex: null }; // Check if the carouselDirection is specified if (carouselDirection) { // Check the state of the carouselDirection if (carouselDirection === 'forward') { // Make sure the currentIndex is lower than the numberOfCarouselItems if (currentIndex + 1 >= numberOfCarouselItems) { previousIndex = currentIndex; // Specify the previous index currentIndex = 0; // Reset the currentIndex } else { previousIndex = currentIndex; // Specify the previous index currentIndex++; // Update the currentIndex } } else if (carouselDirection === 'backward') { // Make sure the currentIndex is greater than or equal to 0 if (currentIndex <= 0) { previousIndex = currentIndex; // Specify the previous index currentIndex = numberOfCarouselItems - 1; // Update the currentIndex } else { previousIndex = currentIndex; // Specify the previous index currentIndex--; // Update the currentIndex } } // End the function execution return { previousIndex, currentIndex }; } // Check if the newIndex is provided if (newIndex != null) { previousIndex = currentIndex; // Specify the previous index currentIndex = newIndex; // Update the currentIndex // End the function execution return { previousIndex, currentIndex }; } return { previousIndex: null, currentIndex: null }; } function addEventListenersToNavigationButtons( carousel: HTMLElement, carouselItemsArray: HTMLElement[], isFadeCarousel: boolean ): void { /* The function adds event listeners to the carousel navigation buttons. * * Attributes: * - carousel: The main carousel wrapper * - carouselItemsArray: An array of the carousel item objects * - isFadeCarousel: it specifies whether the carousel uses a fade effect * */ /* Define the carouselIsMoving variable; it is used to prevent the user from spamming the carousel navigation buttons.*/ let carouselIsMoving: boolean = false; // Define the carousel previousIndex and nextIndex variables let previousIndex: number | null = null; let nextIndex: number | null = null; // Retrieve the carousel carousel-control-prev button or null if it does not exist const prevButton: HTMLElement | null = carousel.querySelector('.carousel-control-prev'); // Retrieve the carousel carousel-control-next button or null if it does not exist const nextButton: HTMLElement | null = carousel.querySelector('.carousel-control-next'); // Retrieve an array of the carousel indicator buttons const indicatorButtonsArray: HTMLElement[] = Array.from(carousel.querySelectorAll('.carousel-indicator')); const updateCarouselIsMoving: () => void = (): void => { // Assign true to the carouselIsMoving variable if the carousel does not use a fade effect if (!isFadeCarousel) { carouselIsMoving = true; // Assign false to the carouselIsMoving after 500 milliseconds setTimeout((): void => {carouselIsMoving = false}, 500); } } // Add an array listener to the prevButton if it exists (is not null) if (prevButton) { prevButton.addEventListener('click', (event: MouseEvent): void => { event.preventDefault(); // Make sure the carouselIsMoving variable is false if (carouselIsMoving) return; // Call the updateCarouselCurrentIndex function const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex( carouselItemsArray, 'backward', null ); // Retrieve the carousel previousIndex and nextIndex previousIndex = prev; nextIndex = next; // Make sure the previousIndex and nextIndex are not null if (previousIndex != null && nextIndex != null) { manageCarouselMovement(carousel, carouselItemsArray, previousIndex, nextIndex, 'backward'); } // Call the updateCarouselIsMoving function updateCarouselIsMoving(); }); } // Add an array listener to the nextButton if it exists (is not null) if (nextButton) { nextButton.addEventListener('click', (event: MouseEvent): void => { event.preventDefault(); // Make sure the carouselIsMoving variable is false if (carouselIsMoving) return; // Call the updateCarouselCurrentIndex function const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex( carouselItemsArray, 'forward', null ); // Retrieve the carousel previousIndex and nextIndex previousIndex = prev; nextIndex = next; // Make sure the previousIndex and nextIndex are not null if (previousIndex != null && nextIndex != null) { manageCarouselMovement(carousel, carouselItemsArray, previousIndex, nextIndex, 'forward'); } // Call the updateCarouselIsMoving function updateCarouselIsMoving(); }); } // Add event listeners to the indicator buttons if the indicatorButtonsArray is not empty if (indicatorButtonsArray.length > 0) { // Iterate over each item in the indicatorButtonsArray indicatorButtonsArray.forEach((item: HTMLElement, index: number): void => { item.addEventListener('click', (event: MouseEvent): void => { event.preventDefault(); // Make sure the carouselIsMoving variable is false if (carouselIsMoving) return; // Call the updateCarouselCurrentIndex function const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex( carouselItemsArray, null, index ); // Retrieve the carousel previousIndex and nextIndex previousIndex = prev; nextIndex = next; // Make sure the previousIndex and nextIndex are not null if (previousIndex != null && nextIndex != null) { manageCarouselMovement( carousel, carouselItemsArray, previousIndex, nextIndex, getCarouselMovementDirection(previousIndex, nextIndex) ); } // Call the updateCarouselIsMoving function updateCarouselIsMoving(); }); }); } // Handle the movement of the touch-enabled carousel carousel.addEventListener('touchstart', (event: TouchEvent): void => { event.preventDefault(); // Make sure the carouselIsMoving variable is false if (carouselIsMoving) return; // Store the horizontal position where the touch started const touch: Touch = event.touches[0]; startPosition = touch.clientX; }); carousel.addEventListener('touchend', (event: TouchEvent): void => { event.preventDefault(); // Make sure the carouselIsMoving variable is false if (carouselIsMoving) return; // Store the horizontal position where the touch started const touch: Touch = event.changedTouches[0]; endPosition = touch.clientX; // Define the swipeDirection variable const swipeDirection: 'forward' | 'backward' | null = calculateTouchDirection( carousel.offsetWidth/3, startPosition, endPosition ); // Make sure the swipeDirection is not null if (!swipeDirection) return; // Call the updateCarouselCurrentIndex function const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex( carouselItemsArray, swipeDirection, null ); // Retrieve the carousel previousIndex and nextIndex previousIndex = prev; nextIndex = next; // Fire the handleCarouselMovement function manageCarouselMovement( carousel, carouselItemsArray, previousIndex, nextIndex, swipeDirection, ); }); // Handle the movement of the mouse-enabled carousel carousel.addEventListener('mousedown', (event: MouseEvent): void => { event.preventDefault(); // Make sure the carouselIsMoving variable is false if (carouselIsMoving) return; // Store the horizontal position where the mouse click started startPosition = event.clientX; const onMouseUp: (event: MouseEvent) => void = (event: MouseEvent): void => { // Store the horizontal position where the mouse was released endPosition = event.clientX; // Define the swipeDirection variable const swipeDirection: 'forward' | 'backward' | null = calculateTouchDirection( carousel.offsetWidth/3, startPosition, endPosition ); // Make sure the swipeDirection is not null if (!swipeDirection) return; // Call the updateCarouselCurrentIndex function const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex( carouselItemsArray, swipeDirection, null ); // Retrieve the carousel previousIndex and nextIndex previousIndex = prev; nextIndex = next; // Fire the handleCarouselMovement function manageCarouselMovement( carousel, carouselItemsArray, previousIndex, nextIndex, swipeDirection, ); // Remove the mouseup listener document.removeEventListener('mouseup', onMouseUp); }; // Attach mouseup event to the document document.addEventListener('mouseup', onMouseUp); }); // Retrieve the 'data-carousel-move-interval' attribute value from the carousel element, or return null if it doesn't exist const carouselMoveInterval: number | null = carousel.hasAttribute('data-carousel-move-interval') ? parseInt(carousel.getAttribute('data-carousel-move-interval')!) : null; // Check if the carouselMoveInterval exists (is not null) if (carouselMoveInterval != null) { /* Define the isHovering variable, which indicates whether the user's cursor is hovering over the carousel container. */ let isHovering: boolean = false; setInterval((): void => { // Make sure the carouselIsMoving and isHovering variables are false if (carouselIsMoving || isHovering) return; // Call the updateCarouselCurrentIndex function const { previousIndex: prev, currentIndex: next } = updateCarouselCurrentIndex( carouselItemsArray, 'forward', null ); // Retrieve the carousel previousIndex and nextIndex previousIndex = prev; nextIndex = next; // Make sure the previousIndex and nextIndex are not null if (previousIndex != null && nextIndex != null) { manageCarouselMovement(carousel, carouselItemsArray, previousIndex, nextIndex, 'forward'); } // Call the updateCarouselIsMoving function updateCarouselIsMoving(); }, carouselMoveInterval); // Clear the carouselMovingInterval if the user hovers over the carousel or touch it. carousel.addEventListener('mouseenter', (event: MouseEvent): void => { // Assign true to the isHovering variable isHovering = true; }); carousel.addEventListener('touchstart', (event: TouchEvent): void => { // Assign true to the isHovering variable isHovering = true; }); // Restore the carouselMovingInterval if the user's cursor leaves the carousel block or untouch it carousel.addEventListener('mouseleave', (event: MouseEvent): void => { // Assign false to the isHovering varialble after carouselMoveInterval milliseconds setTimeout((): void => { isHovering = false; }, carouselMoveInterval); }); carousel.addEventListener('touchend', (event: TouchEvent): void => { // Assign false to the isHovering variable after carouselMoveInterval milliseconds setTimeout((): void => { isHovering = false; }, carouselMoveInterval); }); } } function manageCarouselMovement( carousel: HTMLElement, carouselItemsArray: HTMLElement[], previousIndex: number | null, nextIndex: number | null, carouselMovementDirection: 'forward' | 'backward' ): void { /* The function manages the carousel movement based on the provided * attributes of the HTML tags. * * Attributes: * - carousel: The carousel HTML object is used to get carousel attributes * - carouselItemsArray: An array of the carousel items * - previousIndex: Previous carousel's items position * - nextIndex: Next carousel's items position * - carouselMovementDirection: It specifies the carousel movement direction * */ // Make sure the previousIndex and nextIndex are not null if (previousIndex == null || nextIndex == null) return; // Call the updateCarouselItemActiveClass function updateCarouselItemActiveClass(carouselItemsArray, previousIndex, nextIndex); // Call the updateCarouselIndicatorActiveClass function updateCarouselIndicatorActiveClass(carousel, previousIndex, nextIndex); /* Define the isSlideCarousel variable, which can be either true or false, and specifies whether the carousel uses a slide effect */ const isSlideCarousel: boolean = carousel.classList.contains('carousel-slide'); /* Define the isInfinitySlideCarousel variable, which can be either true or false, and specifies whether the carousel uses an infinity slider loop effect */ const isInfinitySlideCarousel: boolean = carousel.classList.contains('infinity'); // Move the carousel inner if the isSlideCarousel variable is true if (isSlideCarousel) { // Check if the isInfinitySlideCarousel is true if (isInfinitySlideCarousel) { // Call the handleCarouselInfinityMovement function handleCarouselInfinityMovement( carousel, carouselItemsArray, previousIndex, nextIndex, carouselMovementDirection ); return; } // Call the moveCarouselInner function to create a carousel movement animation moveCarouselInner(carousel, nextIndex); } } function updateCarouselItemActiveClass( carouselItemsArray: HTMLElement[], previousIndex: number, nextIndex: number ): void { /* The function is responsible for removing the 'active' class from the carousel * item based on the provided previousIndex and adding the 'active' class to the * carousel item based on the provided nextIndex. * * Attributes: * - carouselItemsArray: An array of the carousel item objects * - previousIndex: Previous carousel's items position * - nextIndex: Next carousel's items position * */ /* Make sure the carousel item at the provided previousIndex contains the 'active' class */ if (!carouselItemsArray[previousIndex].classList.contains('active')) return; // Remove the 'active' class to the carouselItemsArray[previousIndex] carouselItemsArray[previousIndex].classList.remove('active'); // Add the 'active' class to the carouselItemsArray[nextIndex] carouselItemsArray[nextIndex].classList.add('active'); } function updateCarouselIndicatorActiveClass( carousel: HTMLElement, previousIndex: number, nextIndex: number ): void { /* The function is responsible for assigning the active class to the carousel * indicator buttons, if they exist. * * Attributes: * - carousel: The carousel HTML object is used to get the carousel indicator buttons * - previousIndex: Previous carousel's items position * - nextIndex: Next carousel's items position * */ // Get an array of the carousel indicator buttons const indicatorButtonsArray: HTMLElement[] = Array.from(carousel.querySelectorAll('.carousel-indicator')); // Make sure the indicatorButtonsArray is not empty if (indicatorButtonsArray.length < 1) return; // Remove the 'active' class from the indicator button corresponding to the previousIndex indicatorButtonsArray[previousIndex].classList.remove('active'); // Add the 'active' class to the indicator button corresponding to the nextIndex indicatorButtonsArray[nextIndex].classList.add('active'); } function moveCarouselInner( carousel: HTMLElement, nextIndex: number, ): void { /* The function is responsible for moving the carousel inner element * to correspond with the next index. * * Attributes: * - carousel: The carousel HTML object is used to get carouselInner * - nextIndex: Next carousel's items position * */ // Get the carouselInner object or null if it does not exist const carouselInner: HTMLElement | null = carousel.querySelector('.carousel-inner'); // Make sure the carouselInner exists (is not null) if (!carouselInner) return; // Update the carouselInner style, imitating the movement carouselInner.style.left = `-${nextIndex * 100}%`; } function handleCarouselInfinityMovement( carousel: HTMLElement, carouselItemsArray: HTMLElement[], previousIndex: number, nextIndex: number, carouselMovementDirection: 'forward' | 'backward' ): void { /* The function is responsible for managing the infinite loop movement * of the carousel. It applies the display: none CSS property to all * carousel items that do not correspond to the previousIndex or nextIndex, * then moves the carousel inner element accordingly. * * Attributes: * - carousel: The carousel HTML object is used to get the carouselInner * - carouselItemsArray: An array of the carousel items * - previousIndex: Previous carousel's items position * - nextIndex: Next carousel's items position * - carouselMovementDirection: It specifies the carousel movement direction * */ // Retrieve the carousel inner object or null if it does not exist const carouselInner: HTMLElement | null = carousel.querySelector('.carousel-inner'); // Make sure the carouselInner exists (is not null) if (!carouselInner) return; // Call the hideNonAdjacentItems function hideNonAdjacentItems(carouselInner, carouselItemsArray); // Call the moveCarouselInnerToSpecificDirection function moveCarouselInnerToSpecificDirection( carouselInner, carouselMovementDirection, carouselItemsArray, previousIndex, nextIndex, ); } function hideNonAdjacentItems( carouselInner: HTMLElement, carouselItemsArray: HTMLElement[] ): void { /* The function is responsible for applying the display: none CSS property to all * carousel items * * Attributes: * - carouselInner: The carouselInner HTML object is used for the carousel movement * - carouselItemsArray: An array of the carousel items * */ // Apply the display: none CSS property to all carousel items carouselItemsArray.forEach((item: HTMLElement): string => item.style.display = 'none'); // Retrieve an array of the carousel temporary items const temporaryItems: HTMLElement[] = Array.from(carouselInner.querySelectorAll('.temporary-item')); // Make sure the temporaryItems array is not empty if (temporaryItems.length < 1) return; // Delete all items in the temporaryItems array temporaryItems.forEach((item: HTMLElement): void => item.remove()); } function getCarouselMovementDirection( previousIndex: number, nextIndex: number, ): 'forward' | 'backward' { /* The function is responsible for determining and returning the carousel movement * direction by comparing the previousIndex and nextIndex. * * Attributes: * - previousIndex: Previous carousel's items position * - nextIndex: Next carousel's items position * */ return nextIndex > previousIndex ? 'forward' : 'backward'; } function moveCarouselInnerToSpecificDirection( carouselInner: HTMLElement, carouselMovementDirection: 'forward' | 'backward', carouselItemsArray: HTMLElement[], previousIndex: number, nextIndex: number, ): void { /* The function is responsible for moving the inner carousel corresponding * to the carousel movement direction. * * Attributes: * - carouselInner: The carouselInner HTML object is used for the carousel movement * - carouselMovementDirection: It specifies the carousel movement direction * - carouselItemsArray: An array of the carousel items * - previousIndex: Previous carousel's items position * - nextIndex: Next carousel's items position * */ // Get computed styles const computedStyles: CSSStyleDeclaration = window.getComputedStyle(carouselInner); // Get the transition property const transitionStyle: string = computedStyles.transition; // Disable the carouselInner transition style carouselInner.style.transition = 'none'; if (carouselMovementDirection === 'forward') { // Update the carouselInner CSS left property to imitate movement forward // Call the appendCarouselItemAfterCurrent function appendCarouselItemAfterCurrent( carouselInner, carouselItemsArray, previousIndex, nextIndex, ); // Set the default inner position of the carousel carouselInner.style.left = `0`; setTimeout((): void => { // Enable the carouselInner transition style carouselInner.style.transition = transitionStyle; // Update the carousel inner position carouselInner.style.left = '-100%'; }, 10); } else if (carouselMovementDirection === 'backward') { // Update the carouselInner CSS left property to imitate movement backward // Call the appendCarouselItemBeforeCurrent function appendCarouselItemBeforeCurrent( carouselInner, carouselItemsArray, previousIndex, nextIndex, ); // Set the default inner position of the carousel carouselInner.style.left = '-100%'; setTimeout((): void => { // Enable the carouselInner transition style carouselInner.style.transition = transitionStyle; // Update the carousel inner position carouselInner.style.left = '0'; }, 10); } } function appendCarouselItemAfterCurrent( carouselInner: HTMLElement, carouselItemsArray: HTMLElement[], previousIndex: number, nextIndex: number ): void { /* The function is responsible for appending the carousel item corresponding to * the nextIndex after the current carousel item. * * Attributes: * - carouselInner: The carouselInner HTML object is used for the carousel movement * - carouselItemsArray: An array of the carousel items * - previousIndex: Previous carousel's items position * - nextIndex: Next carousel's items position * */ // Get the carouselItemsArray length const carouselItemsArrayLength: number = carouselItemsArray.length; // Make sure the carouselItemsArrayLength is grater than zero if (carouselItemsArrayLength < 1) return; // Append the current carousel item to the end of the carousel-inner object const currentItem = carouselItemsArray[previousIndex].cloneNode(true) as HTMLElement; // Add the display flex CSS property to the currentItem currentItem.style.display = 'flex'; // Add the 'temporary-item' class to the currentItem currentItem.classList.add('temporary-item'); carouselInner.appendChild(currentItem); // Append the next carousel item after the currentItem const nextItem = carouselItemsArray[nextIndex].cloneNode(true) as HTMLElement; // Add the display flex CSS property to the nextItem nextItem.style.display = 'flex'; // Add the 'temporary-item' class to the nextItem nextItem.classList.add('temporary-item'); carouselInner.appendChild(nextItem); } function appendCarouselItemBeforeCurrent( carouselInner: HTMLElement, carouselItemsArray: HTMLElement[], previousIndex: number, nextIndex: number ): void { /* The function is responsible for appending the carousel item corresponding to * the nextIndex before the current carousel item. * * Attributes: * - carouselInner: The carouselInner HTML object is used for the carousel movement * - carouselItemsArray: An array of the carousel items * - previousIndex: Previous carousel's items position * - nextIndex: Next carousel's items position * */ // Get the carouselItemsArray length const carouselItemsArrayLength: number = carouselItemsArray.length; // Make sure the carouselItemsArrayLength is grater than zero if (carouselItemsArrayLength < 1) return; // Append the next carousel item to the end of the carousel-inner object const nextItem = carouselItemsArray[nextIndex].cloneNode(true) as HTMLElement; // Add the display flex CSS property to the nextItem nextItem.style.display = 'flex'; // Add the 'temporary-item' class to the nextItem nextItem.classList.add('temporary-item'); carouselInner.appendChild(nextItem); // Append the current carousel item after the nextItem const currentItem = carouselItemsArray[previousIndex].cloneNode(true) as HTMLElement; // Add the display flex CSS property to the currentItem currentItem.style.display = 'flex'; // Add the 'temporary-item' class to the currentItem currentItem.classList.add('temporary-item'); carouselInner.appendChild(currentItem); } function calculateTouchDirection( carouselWrapperWidth: number, startPosition: number, endPosition: number ): 'forward' | 'backward' | null { /* The function is responsible for returning 'forward' or 'backward' after calculating the touch movement * * Attributes: * - carouselWrapperWidth: The width of the carousel wrapper element divided by three, used to check whether * the difference between the start position and the end position exceeds this value. * - startPosition: The initial position of the touch, as obtained by the touchstart event listener * - endPosition: Final position of the touch, captured when the touchend event is triggered * */ /* Determine swipe direction based on how far the user swiped. If the horizontal swipe distance exceeds half the width of the carousel, return 'forward' for a left swipe or 'backward' for a right swipe. */ if (startPosition - endPosition > carouselWrapperWidth) { return 'forward'; } else if (endPosition - startPosition > carouselWrapperWidth) { return 'backward'; } return null; }