1/** 2 * Corporate Promotions Carousel Block JavaScript 3 * 4 * @package Corporate_Events_Display 5 * @since 1.0.0 6 */ 7 8(function () { 9 "use strict"; 10 11 /** 12 * Initialize a single carousel 13 */ 14 function initializeCarousel(carouselElement) { 15 console.log("Initializing corporate promotions carousel:", carouselElement); 16 17 // Check if already initialized 18 if (carouselElement.classList.contains("splide-initialized")) { 19 console.log("Carousel already initialized, skipping"); 20 return; 21 } 22 23 // Get configuration from data attribute 24 let config = {}; 25 try { 26 const configData = carouselElement.getAttribute("data-splide"); 27 if (configData) { 28 config = JSON.parse(configData); 29 console.log("Loaded configuration from data attribute:", config); 30 } 31 } catch (error) { 32 console.warn("Error parsing carousel configuration:", error); 33 } 34 35 // Default configuration (fallback) 36 const defaultConfig = { 37 type: config.enableLoop !== false ? "loop" : "slide", 38 perPage: 3, 39 perMove: 1, 40 pagination: true, 41 arrows: true, 42 autoplay: false, 43 pauseOnHover: true, 44 breakpoints: { 45 768: { perPage: 2 }, 46 480: { perPage: 1 }, 47 }, 48 }; 49 50 // Merge configurations (config from data attribute takes priority) 51 const finalConfig = { ...defaultConfig, ...config }; 52 53 // Calculate responsive padding/peek values if padding is set 54 if (finalConfig.padding && finalConfig.padding !== "0") { 55 const originalPadding = finalConfig.padding; 56 57 // Try to extract numeric value for responsive calculations 58 let paddingValue = 0; 59 if (typeof originalPadding === "string") { 60 paddingValue = parseInt(originalPadding) || 0; 61 } else { 62 paddingValue = originalPadding || 0; 63 } 64 65 // Calculate responsive padding 66 const tabletPadding = 67 paddingValue > 0 ? Math.max(paddingValue * 0.6, 10) + "px" : 0; 68 const mobilePadding = 69 paddingValue > 0 ? Math.max(paddingValue * 0.3, 5) + "px" : 0; 70 71 // Update breakpoints with responsive padding 72 finalConfig.breakpoints = { 73 ...finalConfig.breakpoints, 74 768: { 75 ...finalConfig.breakpoints[768], 76 padding: tabletPadding, 77 }, 78 480: { 79 ...finalConfig.breakpoints[480], 80 padding: mobilePadding, 81 }, 82 }; 83 } 84 85 console.log("Final carousel configuration:", finalConfig); 86 87 // Wait for Splide.js to be available 88 function waitForSplide() { 89 if (typeof window.Splide !== "undefined") { 90 console.log("Splide.js is available, creating carousel instance"); 91 try { 92 // Create and mount the Splide instance 93 const splide = new window.Splide(carouselElement, finalConfig); 94 splide.mount(); 95 96 // Mark as initialized 97 carouselElement.classList.add("splide-initialized"); 98 console.log("Corporate promotions carousel initialized successfully"); 99 } catch (error) { 100 console.error("Error initializing Splide carousel:", error); 101 } 102 } else { 103 console.log("Splide.js not yet available, retrying..."); 104 setTimeout(waitForSplide, 100); 105 } 106 } 107 108 waitForSplide(); 109 } 110 111 /** 112 * Initialize all corporate promotions carousels on the page 113 */ 114 function initCarousels() { 115 const carousels = document.querySelectorAll( 116 ".corporate-promotions-carousel__splide" 117 ); 118 console.log( 119 `Found ${carousels.length} corporate promotions carousel(s) to initialize` 120 ); 121 122 carousels.forEach(function (carousel, index) { 123 console.log(`Initializing carousel ${index + 1}/${carousels.length}`); 124 initializeCarousel(carousel); 125 }); 126 } 127 128 /** 129 * Initialize when DOM is ready 130 */ 131 if (document.readyState === "loading") { 132 document.addEventListener("DOMContentLoaded", initCarousels); 133 } else {
134 initCarousels(); 135 } 136 137 /** 138 * Reinitialize carousels when new content is loaded (e.g., via AJAX) 139 */ 140 window.corporatePromotionsInitCarousels = initCarousels; 141 142 // Handle ACF block preview updates 143 if (typeof window.acf !== "undefined") { 144 window.acf.addAction("render_block_preview", function () { 145 setTimeout(function () { 146 const carousels = document.querySelectorAll( 147 ".corporate-promotions-carousel__splide" 148 ); 149 carousels.forEach(function (carousel) { 150 if (!carousel.classList.contains("splide-initialized")) { 151 initializeCarousel(carousel); 152 } 153 }); 154 }, 100); 155 }); 156 } 157 158 // MutationObserver to handle dynamically added content 159 const observer = new MutationObserver(function (mutations) { 160 mutations.forEach(function (mutation) { 161 if (mutation.type === "childList") { 162 mutation.addedNodes.forEach(function (node) { 163 if (node.nodeType === Node.ELEMENT_NODE) { 164 // Check if the added node is a carousel or contains carousels 165 const carousels = node.classList?.contains( 166 "corporate-promotions-carousel__splide" 167 ) 168 ? [node] 169 : node.querySelectorAll?.( 170 ".corporate-promotions-carousel__splide" 171 ) || []; 172 173 if (carousels.length > 0) { 174 console.log( 175 `Found ${carousels.length} new corporate promotions carousel(s), initializing...` 176 ); 177 carousels.forEach(initializeCarousel); 178 } 179 } 180 }); 181 } 182 }); 183 }); 184 185 // Start observing 186 observer.observe(document.body, { 187 childList: true, 188 subtree: true, 189 }); 190 191 console.log("Corporate Promotions Carousel: Initialization complete"); 192})(); 193 194// ============================================ 195// Read More / Read Less functionality for event descriptions 196// ============================================ 197document.addEventListener("DOMContentLoaded", () => { 198 const cards = Array.from( 199 document.querySelectorAll(".corporate-promotions-carousel__description") 200 ); 201 202 // debounce helper 203 function debounce(fn, wait = 120) { 204 let t; 205 return function (...args) { 206 clearTimeout(t); 207 t = setTimeout(() => fn.apply(this, args), wait); 208 }; 209 } 210 211 // find the related button for a given card 212 function getButtonForCard(card) { 213 const cardBody = card.closest(".corporate-promotions-carousel__body"); 214 if (!cardBody) return null; 215 return cardBody.querySelector(".btn-read-more"); 216 } 217 218 // check if card content is truncated 219 function cardNeedsButton(card) { 220 const btn = getButtonForCard(card); 221 if (!btn) return false; 222 223 card.classList.remove("read-more"); // ensure clamped for measuring 224 const full = card.scrollHeight; 225 const visible = card.clientHeight; 226 227 return full > visible + 2; // truncated if full > visible 228 } 229 230 // update a single card 231 function updateCard(card) { 232 const btn = getButtonForCard(card); 233 if (!btn) return; 234 235 if (card.classList.contains("read-more")) { 236 btn.style.display = "block"; 237 btn.textContent = "Read less"; 238 } else if (cardNeedsButton(card)) { 239 btn.style.display = "block"; 240 btn.textContent = "Read more"; 241 } else { 242 btn.style.display = "none"; 243 } 244 } 245 246 // update all cards 247 const updateAll = () => cards.forEach(updateCard); 248 const debouncedUpdateAll = debounce(updateAll, 120); 249 250 // attach click handlers 251 cards.forEach((card) => { 252 const btn = getButtonForCard(card); 253 if (!btn) return; 254 255 btn.addEventListener("click", () => { 256 card.classList.toggle("read-more"); 257 258 if (card.classList.contains("read-more")) { 259 btn.textContent = "Read less"; 260 } else { 261 if (cardNeedsButton(card)) btn.textContent = "Read more"; 262 else btn.style.display = "none"; 263 } 264 }); 265 }); 266 267 // handle resize + load 268 window.addEventListener("resize", debouncedUpdateAll); 269 window.addEventListener("load", updateAll); 270 271 // observe card size changes 272 if (window.ResizeObserver) {
273 const ro = new ResizeObserver(debouncedUpdateAll); 274 cards.forEach((card) => ro.observe(card)); 275 } 276 277 // initial check 278 updateAll(); 279});
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.