1/** 2 * Creates a carousel scroller for a given unordered list element. The carousel 3 * will be scrollable if the list items exceed the width of the viewport. 4 * 5 * @param {HTMLElement} ulElement The unordered list element to be scrolled. 6 * @param {HTMLElement} scrollLeftButton The button to be displayed when scrolling 7 * to the left is possible. 8 * @param {HTMLElement} scrollRightButton The button to be displayed when scrolling 9 * to the right is possible. 10 * @returns {Object} An object with the following properties: 11 * 12 * - `scroll`: A function that takes a positive or negative number as an argument 13 * and scrolls the list to that position. 14 * - `destroy`: A function to be called when the carousel is no longer needed. 15 * - `canScrollLeft`: A getter that returns true if the list can be scrolled to the 16 * left. 17 * - `canScrollRight`: A getter that returns true if the list can be scrolled to the 18 * right. 19 */ 20function createCarouselScroller( 21 ulElement, 22 scrollLeftButton, 23 scrollRightButton 24) { 25 if (!(ulElement instanceof HTMLElement)) { 26 throw new Error("You must pass a valid DOM element."); 27 } 28 29 let scrollX = 0; 30 let scrollEnd = false; 31 const scrollThreshold = 10; 32 33 const tagScroller = { 34 scroll, 35 scrollCheck, 36 destroy() { 37 window.removeEventListener("resize", scrollCheck); 38 ulElement.removeEventListener("scroll", scrollCheck); 39 }, 40 get canScrollLeft() { 41 return scrollX > 0; 42 }, 43 get canScrollRight() { 44 return !scrollEnd; 45 }, 46 }; 47 48 function scroll(pos) { 49 const scrollLeft = (ulElement.scrollLeft += pos); 50 scrollX = scrollLeft; 51 scrollEnd = 52 scrollLeft >= 53 ulElement.scrollWidth - ulElement.clientWidth - scrollThreshold; 54 updateState(); 55 } 56 57 function scrollCheck() { 58 scrollX = ulElement.scrollLeft; 59 scrollEnd = 60 scrollX >= 61 ulElement.scrollWidth - ulElement.clientWidth - scrollThreshold; 62 updateState(); 63 64 if (tagScroller.canScrollLeft) { 65 scrollLeftButton.style.display = "flex"; 66 } else { 67 scrollLeftButton.style.display = "none"; 68 } 69 if (tagScroller.canScrollRight) { 70 scrollRightButton.style.display = "flex"; 71 } else { 72 scrollRightButton.style.display = "none"; 73 } 74 } 75 76 function updateState() { 77 tagScroller.canScrollLeft = scrollX > 0; 78 tagScroller.canScrollRight = !scrollEnd; 79 } 80 81 // Initialize scroll state on load 82 scrollCheck(); 83 84 // Set up event listeners 85 window.addEventListener("resize", scrollCheck); 86 ulElement.addEventListener("scroll", scrollCheck); 87 88 const observer = new MutationObserver(() => { 89 scrollCheck(); 90 }); 91 92 observer.observe(ulElement, { 93 childList: true, // watches for added/removed elements 94 }); 95 96 return tagScroller; 97} 98 99function initCarousel() { 100 try { 101 const carousel = document.getElementsByClassName("carousel"); 102 103 if (carousel && carousel.length > 0) { 104 Array.from(carousel).forEach((tag) => { 105 if (!tag) return; 106 const wrapper = tag.getElementsByClassName("carousel-container")[0]; 107 const scrollLeft = tag.getElementsByClassName("scroll-left")[0]; 108 const scrollRight = tag.getElementsByClassName("scroll-right")[0]; 109 const scroller = createCarouselScroller( 110 wrapper, 111 scrollLeft, 112 scrollRight 113 ); 114 const pos = 325; 115 116 scrollLeft.addEventListener("click", () => { 117 scroller.scroll(-pos); 118 }); 119 120 scrollRight.addEventListener("click", () => { 121 scroller.scroll(pos); 122 }); 123 124 window.addEventListener("beforeunload", () => { 125 scroller.destroy(); 126 }); 127 }); 128 } 129 } catch (error) { 130 console.error(error); 131 } 132}
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.