PageSourceSearch

https://psms114.org/js/components/icon-matrix/icon-matrix-scroll-slick.js

js psms114.org collected 2026-09-29 22:36:16 UTC 8,376 bytes, 226 lines download raw bytes

1/**
2 * Icon Matrix Slick Slider Implementation
3 * Alternative to custom scroll implementation using Slick Slider
4 */
5
6// Define timeout constants for better maintainability
7const BREAKPOINT_STYLING_DELAY = 100;
8const REINIT_STYLING_DELAY = 50;
9
10function initializeIconMatrixScrollSlick() {
11    const scrollContainers = document.querySelectorAll('.ss-im-scroll');
12
13    scrollContainers.forEach(function setupContainerHandler(container) {
14        setupSlickContainer(container);
15    });
16}
17
18function setupSlickContainer(container) {
19    const iconsList = container.querySelector('.ss-im-icons-list');
20    const iconsPerRow = parseInt(container.dataset.iconsPerRow, 10) || 6;
21
22    if (!iconsList) return;
23
24    const icons = iconsList.querySelectorAll('.ss-im-icon-wrapper');
25    const totalIcons = icons.length;
26
27    if (totalIcons <= iconsPerRow) return;
28
29    // Initialize slick slider - each icon wrapper becomes its own slide
30    const $iconsList = $(iconsList);
31
32    // Remove conflicting CSS classes that set widths
33    icons.forEach(function removeFlexClasses(icon) {
34        // Remove the original flex classes that interfere with slick widths
35        icon.classList.remove('ss-flex-1', 'ss-flex-2', 'ss-flex-3', 'ss-flex-4', 'ss-flex-5', 'ss-flex-6');
36    });
37
38    // Hide the original pagination dots since slick creates its own
39    const originalDots = container.querySelector('.ss-im-pagination-dots');
40    if (originalDots) {
41        originalDots.style.display = 'none';
42    }
43
44    // Add accessibility features
45    if (typeof window.slickSliderA11y === 'function') {
46        window.slickSliderA11y($iconsList, $iconsList.closest('.ss-im-scroll'));
47    }
48    bindCustomDotSync($iconsList);
49
50    // Get mobile responsive settings
51    const mobileSettings = getMobileSlickSettings(container, icons);
52
53    $iconsList.slick({
54        infinite: false,
55        slidesToShow: iconsPerRow,
56        slidesToScroll: iconsPerRow,
57        adaptiveHeight: false,
58        centerMode: false,
59        arrows: false,
60        dots: true,
61        dotsClass: 'ss-im-slick-dots slick-dots',
62        speed: 500,
63        variableWidth: false, // Let slick handle equal widths
64        responsive: [
65            {
66                breakpoint: 768,
67                settings: mobileSettings.tablet
68            },
69            {
70                breakpoint: 640,
71                settings: mobileSettings.mobile
72            }
73        ]
74    });
75
76    // Monitor breakpoint changes and re-apply custom dot styling
77    $iconsList.on('breakpoint', function handleBreakpointChange(event, slick, breakpoint) {
78        setTimeout(function reapplyDotsAfterBreakpoint() {
79            // Re-apply custom dot styling after breakpoint change
80            customizeSlickDots(container);
81        }, BREAKPOINT_STYLING_DELAY);
82    });
83
84    // Custom dot styling to match existing design
85    customizeSlickDots(container);
86
87    // Also re-apply dots on any slick reinitialization
88    $iconsList.on('reInit', function handleSlickReInit(event, slick) {
89        setTimeout(function reapplyDotsAfterReInit() {
90            customizeSlickDots(container);
91        }, REINIT_STYLING_DELAY);
92    });
93}
94
95// Slick will handle slide widths automatically based on slidesToShow
96
97function getMobileSlickSettings(container, icons) {
98    const displayStyle = getDisplayStyle(container);
99    const hasText = icons[0] && icons[0].querySelector('.ss-icon-text');
100    const iconsPerRow = parseInt(container.dataset.iconsPerRow, 10);
101
102    // Mobile: 2 per row for solid/outline circle/square with title only, 1 for others
103    const iconsPerRowMobile = getMobileIconsPerRow(displayStyle, hasText);
104
105    return {
106        tablet: {
107            slidesToShow: Math.min(4, iconsPerRow), // Don't override desktop value so aggressively
108            slidesToScroll: Math.min(4, iconsPerRow),
109            dots: true
110        },
111        mobile: {
112            slidesToShow: iconsPerRowMobile,
113            slidesToScroll: iconsPerRowMobile,
114            dots: true
115        }
116    };
117}
118
119function getDisplayStyle(container) {
120    const iconMatrix = container.closest('.ss-icon-matrix .ss-component-column');
121    if (!iconMatrix) return 'simple';
122
123    if (iconMatrix.classList.contains('ss-im-solid-circle')) return 'solid-circle';
124    if (iconMatrix.classList.contains('ss-im-outline-circle')) return 'outline-circle';
125    if (iconMatrix.classList.contains('ss-im-solid-square')) return 'solid-square';
126    if (iconMatrix.classList.contains('ss-im-outline-square')) return 'outline-square';
127    if (iconMatrix.classList.contains('ss-im-left-aligned')) return 'left-aligned';
128    if (iconMatrix.classList.contains('ss-im-solid-boxes')) return 'solid-boxes';
129    if (iconMatrix.classList.contains('ss-im-outline-boxes')) return 'outline-boxes';
130    if (iconMatrix.classList.contains('ss-im-solid-overlap-boxes')) return 'solid-overlap-boxes';
131    if (iconMatrix.classList.contains('ss-im-outline-overlap-boxes')) return 'outline-overlap-boxes';
132
133    return 'simple';
134}
135
136function getMobileIconsPerRow(displayStyle, hasText) {
137    // For solid/outline circle and square with title only: 2 per row
138    if ((displayStyle === 'solid-circle' || displayStyle === 'outline-circle' ||
139         displayStyle === 'solid-square' || displayStyle === 'outline-square' ||
140         displayStyle === 'simple') && !hasText) {
141        return 2;
142    }
143
144    // For all other styles or with paragraph text: 1 per row
145    return 1;
146}
147
148function customizeSlickDots(container) {
149    // Replace slick's default dots with our custom styling
150    const slickDots = container.querySelector('.ss-im-slick-dots');
151    if (slickDots) {
152        // Add our custom classes to make dots look like the original implementation
153        slickDots.className = 'ss-im-pagination-dots ss-im-slick-dots';
154
155        const dots = slickDots.querySelectorAll('li button');
156        dots.forEach(function setupDotButton(dot, index) {
157            dot.className = 'ss-im-dot';
158            dot.textContent = ''; // Remove slick's default text
159            dot.setAttribute('aria-label', `Go to slide ${index + 1}`);
160        });
161
162        // Add active class to first dot
163        if (dots.length > 0) {
164            dots[0].classList.add('active');
165        }
166    }
167}
168
169// Update custom dot active states on slide change
170function bindCustomDotSync($iconsList) {
171    $iconsList.on('afterChange', function handleDotSync() {
172        const closestScrollContainer = $iconsList.closest('.ss-im-scroll');
173        if (closestScrollContainer.length === 0) return;
174
175        const container = closestScrollContainer[0];
176        const dots = container.querySelectorAll('.ss-im-dot');
177        const activeSlideIndex = $iconsList.slick('slickCurrentSlide');
178
179        dots.forEach(function updateDotActiveState(dot, index) {
180            dot.classList.toggle('active', index === activeSlideIndex);
181        });
182    });
183}
184
185// Icon Matrix Scroll initialization using Slick Slider
186(function initIconMatrixScrollModule() {
187    let iconMatrixScrollInitialized = false;
188
189    // Check if we have any scroll icon matrices on the page and initialize if needed
190    function checkForScrollIconMatrices() {
191        const scrollContainers = document.querySelectorAll('.ss-im-scroll');
192        if (scrollContainers.length > 0 && !iconMatrixScrollInitialized) {
193            initializeIconMatrixScrollSlick();
194            iconMatrixScrollInitialized = true;
195        }
196    }
197
198    // Initialize on DOM ready
199    if (document.readyState === 'loading') {
200        document.addEventListener('DOMContentLoaded', checkForScrollIconMatrices);
201    } else {
202        checkForScrollIconMatrices();
203    }
204
205    // Also check when new content is dynamically added (for AJAX updates)
206    const observer = new MutationObserver(function handleMutations(mutations) {
207        mutations.forEach(function processMutation(mutation) {
208            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
209                checkForScrollIconMatrices();
210            }
211        });
212    });
213
214    observer.observe(document.body, {
215        childList: true,
216        subtree: true
217    });
218
219    // Expose function globally for AJAX re-initialization
220    window.reinitializeIconMatrixScroll = function reinitializeIconMatrixScroll() {
221        iconMatrixScrollInitialized = false;
222        checkForScrollIconMatrices();
223    };
224})();
225
226// Module auto-initializes, no exports needed

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.