1// Support for swiper v8 2(function () { 3 function BreakdanceSwiper() { 4 const { mergeObjects, matchMedia, getCurrentBreakpoint, is, isBuilder } = BreakdanceFrontend.utils; 5 6 function isElementInDom(selector) { 7 // An element can be "hidden" (aka not in the DOM) with Hide on breakpoint -> in builder preview 8 // and Swiper needs the element to be part of the DOM to work on it 9 // This code was removed in https://github.com/soflyy/breakdance-elements/pull/2184/files#diff-897333d33555b463d7a30b1328e025df240eeb851ed79e85b643c65c6c6b4bffL12 10 // but that introduced the following bug: https://github.com/soflyy/breakdance/issues/5956 11 // so we put this code back, since the element might be SSRing. 12 const isElementInDom = document.querySelector(selector); 13 return !!isElementInDom; 14 } 15 16 function setBreakpoint(swiper, settings) { 17 const { BASE_BREAKPOINT_ID } = window.BreakdanceFrontend.data; 18 const isLoop = settings.infinite === "enabled" && !isBuilder(); 19 const slidesPerView = settings.advanced.slides_per_view; 20 const slidesPerGroup = settings.advanced.slides_per_group; 21 const spaceBetween = settings.advanced.between_slides; 22 23 const onePerViewAt = settings.advanced.one_per_view_at; 24 const onePerViewAtDesktop = onePerViewAt === BASE_BREAKPOINT_ID; 25 const alwaysOne = settings.effect === "fade" || settings.effect === "flip" || onePerViewAtDesktop; 26 27 const { activeIndex, initialized, loopedSlides = 0 } = swiper; 28 const needsReLoop = isLoop && ((slidesPerView !== swiper.params.slidesPerView) || (slidesPerGroup !== swiper.params.slidesPerGroup)); 29 30 if (alwaysOne || matchMedia(onePerViewAt)) { 31 swiper.params.slidesPerView = 1; 32 swiper.params.slidesPerGroup = 1; 33 } else { 34 setBreakpointProperty(swiper, "slidesPerView", slidesPerView); 35 setBreakpointProperty(swiper, "slidesPerGroup", slidesPerGroup); 36 } 37 38 setBreakpointProperty(swiper, "spaceBetween", spaceBetween); 39 40 // A reloop is necessary when changing `slidesPerView` or `direction`* 41 // when swiper has already been initialized. 42 // *cargo cult addition: when slidesPerGroup was implemented, it was added to the needsReLoop calculation without 43 // taking into consideration whether it is required 44 if (needsReLoop && initialized) { 45 // Tip: This logic is different on >= v9. 46 // See: https://github.com/nolimits4web/swiper/blob/master/src/core/breakpoints/setBreakpoint.js 47 swiper.loopDestroy(); 48 swiper.loopCreate(); 49 swiper.updateSlides(); 50 swiper.slideTo(activeIndex - loopedSlides + swiper.loopedSlides, 0, false); 51 } else { 52 swiper.updateSlides(); 53 swiper.slideReset(0); 54 } 55 } 56 57 function setBreakpointProperty(swiper, key, value) { 58 if (Number.isFinite(value)) { 59 // version >= 1.3 - backwards compatibility for non-breakpoint values. 60 swiper.params[key] = value; 61 } else if (is.obj(value)) { 62 // The value is an object, but we don't know if it's a breakpoint yet. 63 const availableBreakpoints = Object.keys(value);
64 const currBreakpoint = getCurrentBreakpoint(availableBreakpoints); 65 const bpValue = value[currBreakpoint.id]; 66 67 // Found a breakpoint value, use it. 68 if (bpValue) { 69 swiper.params[key] = isUnitValue(bpValue) ? bpValue.number : bpValue; 70 } else if (isUnitValue(value) && !isResponsiveValue(value)) { 71 // Otherwise, if the value is a unit value, use it. 72 // Due to unknown reasons, the value is sometimes a breakpoint + unit value object, we ignore those. 73 swiper.params[key] = value.number; 74 } 75 } 76 } 77 78 function isResponsiveValue(value) { 79 const { breakpoints } = window.BreakdanceFrontend.data; 80 const ids = breakpoints.map((bp) => bp.id); 81 return Object.keys(value).some(key => ids.includes(key)); 82 } 83 84 function isUnitValue(value) { 85 return is.obj(value) && "number" in value; 86 } 87 88 function resetSlideAnimations(slide) { 89 const customEvent = new Event("breakdance_reset_animations", { bubbles: true }); 90 slide.dispatchEvent(customEvent); 91 } 92 93 function playSlideAnimations(slide, delay) { 94 const customEvent = new CustomEvent("breakdance_play_animations", { 95 bubbles: true, 96 detail: { delay: delay / 1000 } 97 }); 98 slide.dispatchEvent(customEvent); 99 } 100 101 function supportEntranceAnimations(swiper, settings) { 102 let lastVisibleSlides = swiper.visibleSlides || []; 103 const playOn = settings.advanced.play_animations_on || "transition_end"; 104 105 const getNewestSlides = () => swiper.visibleSlides?.filter(x => !lastVisibleSlides.includes(x)) || []; 106 const getHiddenSlides = () => swiper.slides?.filter((slide) => !swiper.visibleSlides.includes(slide)) || []; 107 108 // This is a workaround for when the user drags the slider before slideChange is triggered. 109 swiper.on("sliderFirstMove", () => { 110 const hiddenSlides = getHiddenSlides(); 111 hiddenSlides.forEach((slide) => resetSlideAnimations(slide)); 112 }); 113 114 swiper.on("slideChange", () => { 115 const delay = playOn === "transition_start" ? 0 : swiper.params.speed * 0.3; 116 const newSlides = getNewestSlides(); 117
118 newSlides.forEach(slide => { 119 resetSlideAnimations(slide); 120 playSlideAnimations(slide, delay); 121 }); 122 123 lastVisibleSlides = swiper.visibleSlides; 124 }); 125 } 126 127 // This prevents memory leak from event listeners 128 function destroy(id) { 129 if ( 130 window.swiperInstances && 131 window.swiperInstances[id] && 132 // if the element is not in the DOM, "el" will be the selector instead of the element reference 133 typeof window.swiperInstances[id].el === "object" 134 ) { 135 window.swiperInstances[id].destroy(true, true); 136 delete window.swiperInstances[id]; 137 } 138 } 139 140 function update({ id, selector, settings, paginationSettings, extras }) { 141 142 if (!isElementInDom(`${selector} > .breakdance-swiper-wrapper > .swiper`)) return; 143 144 destroy(id); 145 146 const defaultOptions = { 147 settings: { 148 effect: "slide", 149 coverflow: { 150 rotate: { 151 number: 50 152 }, 153 depth: { 154 number: 100 155 }, 156 stretch: { 157 number: 0 158 } 159 }, 160 speed: { number: 1000 }, 161 autoplay_settings: { 162 speed: { 163 number: 3000 164 } 165 }, 166 advanced: { 167 between_slides: 0, 168 slides_per_view: 1, 169 slides_per_group: 1, 170 initial_slide: 0, 171 }, 172 direction: "horizontal", 173 }, 174 pagination: { 175 type: "bullets" 176 } 177 }; 178 179 settings = mergeObjects(defaultOptions.settings, settings); 180 paginationSettings = mergeObjects( 181 defaultOptions.pagination, 182 paginationSettings 183 ); 184 185 const advancedSettings = settings.advanced; 186 const isBuilder = !!window?.BreakdanceFrontend.utils.isBuilder(); 187 188 const isCoverflowEffect = settings.effect === "coverflow"; 189 const coverFlowEffect = isCoverflowEffect 190 ? { 191 coverflowEffect: { 192 rotate: settings.coverflow.rotate.number, 193 slideShadows: !!settings.coverflow.shadow, 194 depth: settings.coverflow.depth.number, 195 stretch: settings.coverflow.stretch.number 196 } 197 } 198 : {}; 199 200 const fadeEffect = 201 settings.effect === "fade" 202 ? { 203 fadeEffect: { 204 crossFade: true 205 } 206 } 207 : {}; 208 209 const builderOnlySettings = isBuilder 210 ? { 211 // this prevents bugs caused by Swiper swallowing events 212 preventClicksPropagation: false, 213 preventClicks: false, 214 simulateTouch: false, 215 // doesn't play nice with our drag events 216 allowTouchMove: false 217 } 218 : {}; 219 220 const forceAutoplay = extras && extras.autoplay === true; 221 222 const swiperInstance = new Swiper( 223 `${selector} > .breakdance-swiper-wrapper > .swiper`, 224 { 225 ...extras, 226 speed: settings.speed.number, 227 loop: settings.infinite === "enabled" && !isBuilder, 228 autoplay: 229 settings.autoplay === "enabled" && (!isBuilder || forceAutoplay) 230 ? { 231 delay: settings.autoplay_settings.speed.number, 232 pauseOnMouseEnter: 233 !!settings.autoplay_settings.pause_on_hover, 234 disableOnInteraction: 235 !!settings.autoplay_settings.stop_on_interaction, 236 stopOnLastSlide: settings.infinite !== "enabled", 237 } 238 : false, 239 240 effect: settings.effect, 241 pagination: { 242 el: `${selector} > .breakdance-swiper-wrapper > .swiper-pagination`, 243 type: paginationSettings.type, 244 clickable: true, 245 }, 246 navigation: { 247 nextEl: `${selector} > .breakdance-swiper-wrapper > .swiper-button-next`, 248 prevEl: `${selector} > .breakdance-swiper-wrapper > .swiper-button-prev`, 249 }, 250 keyboard: !advancedSettings.disable_keyboard_control, 251 ...coverFlowEffect, 252 ...fadeEffect, 253 254 ...builderOnlySettings, 255 256 // Advanced options 257 mousewheel: advancedSettings.swipe_on_scroll 258 ? { 259 releaseOnEdges: true 260 } 261 : false, 262 263 autoHeight: !!advancedSettings.auto_height, 264 loopPreventsSlide: false, 265 centeredSlides: isCoverflowEffect 266 ? // We decided to make it always true because otherwise it looks ugly 267 true 268 : settings.center_slides, 269 // Swiper docs advise to do this 270 watchSlidesProgress: advancedSettings.slides_per_view !== 1, 271 // doesn't do anything on its own, but enables elements to create cool effects with HTML 272 parallax: true, 273 274 direction: settings.direction, 275 a11y: { 276 slideRole: "" 277 }, 278 initialSlide: settings.advanced.initial_slide, 279 }); 280 281 setBreakpoint(swiperInstance, settings); 282 supportEntranceAnimations(swiperInstance, settings); 283 284 swiperInstance.on("resize", () => { 285 setBreakpoint(swiperInstance, settings); 286 }); 287 288 window.swiperInstances = { 289 ...window.swiperInstances, 290 [id]: swiperInstance 291 }; 292 } 293 294 function updateSliderFromChild(id) { 295 const sliderId = document 296 // select itself 297 .querySelector(`[data-node-id="${id}"]`) 298 // get parent (slider) node id 299 .parentElement.closest("[data-node-id]").dataset.nodeId; 300 301 const sliderIdNumber = sliderId && parseInt(sliderId); 302 303 if (window.swiperInstances && window.swiperInstances[sliderIdNumber]) { 304 window.swiperInstances[sliderIdNumber].update(); 305 } 306 } 307 308 function selectSlide(id) { 309 const slideElement = document 310 .querySelector(`[data-node-id="${id}"]`) 311 .closest(".swiper-slide"); 312 313 if (slideElement) { 314 const slideIndex = Array.from( 315 slideElement.parentElement.children 316 ).indexOf(slideElement); 317 318 const sliderElement = 319 slideElement.parentElement && 320 slideElement.parentElement.closest("[data-node-id]"); 321 322 const sliderId = sliderElement ? sliderElement.dataset.nodeId : null; 323 324 if ( 325 sliderId && 326 slideIndex !== null && 327 window.swiperInstances && 328 window.swiperInstances[sliderId] 329 ) { 330 if (window.swiperInstances[sliderId].visibleSlides.includes(slideElement)) { 331 return; 332 } 333 334 window.swiperInstances[sliderId].slideTo(slideIndex, 0); 335 } 336 } 337 } 338 339 return { 340 update, 341 destroy, 342 updateSliderFromChild, 343 selectSlide 344 }; 345 } 346 347 window.BreakdanceSwiper = BreakdanceSwiper; 348})();
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.