vendor: 5,575 bytes, lines 1-163
1/*! 2 * Bootstrap carousel.js v5.3.6 (https://getbootstrap.com/) 3 * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) 4 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 5 */ 6(function (global, factory) { 7 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./util/index.js'), require('./util/swipe.js')) : 8 typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './util/index', './util/swipe'], factory) : 9 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Carousel = factory(global.BaseComponent, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Index, global.Swipe)); 10})(this, (function (BaseComponent, EventHandler, Manipulator, SelectorEngine, index_js, Swipe) { 'use strict'; 11 12 /** 13 * -------------------------------------------------------------------------- 14 * Bootstrap carousel.js 15 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 16 * -------------------------------------------------------------------------- 17 */ 18 19 20 /** 21 * Constants 22 */ 23 24 const NAME = 'carousel'; 25 const DATA_KEY = 'bs.carousel'; 26 const EVENT_KEY = `.${DATA_KEY}`; 27 const DATA_API_KEY = '.data-api'; 28 const ARROW_LEFT_KEY = 'ArrowLeft'; 29 const ARROW_RIGHT_KEY = 'ArrowRight'; 30 const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch 31 32 const ORDER_NEXT = 'next'; 33 const ORDER_PREV = 'prev'; 34 const DIRECTION_LEFT = 'left'; 35 const DIRECTION_RIGHT = 'right'; 36 const EVENT_SLIDE = `slide${EVENT_KEY}`; 37 const EVENT_SLID = `slid${EVENT_KEY}`; 38 const EVENT_KEYDOWN = `keydown${EVENT_KEY}`; 39 const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`; 40 const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`; 41 const EVENT_DRAG_START = `dragstart${EVENT_KEY}`; 42 const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`; 43 const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`; 44 const CLASS_NAME_CAROUSEL = 'carousel'; 45 const CLASS_NAME_ACTIVE = 'active'; 46 const CLASS_NAME_SLIDE = 'slide'; 47 const CLASS_NAME_END = 'carousel-item-end'; 48 const CLASS_NAME_START = 'carousel-item-start'; 49 const CLASS_NAME_NEXT = 'carousel-item-next'; 50 const CLASS_NAME_PREV = 'carousel-item-prev'; 51 const SELECTOR_ACTIVE = '.active'; 52 const SELECTOR_ITEM = '.carousel-item'; 53 const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM; 54 const SELECTOR_ITEM_IMG = '.carousel-item img'; 55 const SELECTOR_INDICATORS = '.carousel-indicators'; 56 const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'; 57 const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]'; 58 const KEY_TO_DIRECTION = { 59 [ARROW_LEFT_KEY]: DIRECTION_RIGHT, 60 [ARROW_RIGHT_KEY]: DIRECTION_LEFT 61 }; 62 const Default = { 63 interval: 5000, 64 keyboard: true, 65 pause: 'hover', 66 ride: false, 67 touch: true, 68 wrap: true 69 }; 70 const DefaultType = { 71 interval: '(number|boolean)', 72 // TODO:v6 remove boolean support 73 keyboard: 'boolean', 74 pause: '(string|boolean)', 75 ride: '(boolean|string)', 76 touch: 'boolean', 77 wrap: 'boolean' 78 }; 79 80 /** 81 * Class definition 82 */ 83 84 class Carousel extends BaseComponent { 85 constructor(element, config) { 86 super(element, config); 87 this._interval = null; 88 this._activeElement = null; 89 this._isSliding = false; 90 this.touchTimeout = null; 91 this._swipeHelper = null; 92 this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element); 93 this._addEventListeners(); 94 if (this._config.ride === CLASS_NAME_CAROUSEL) { 95 this.cycle(); 96 } 97 } 98 99 // Getters 100 static get Default() { 101 return Default; 102 } 103 static get DefaultType() { 104 return DefaultType; 105 } 106 static get NAME() { 107 return NAME; 108 } 109 110 // Public 111 next() { 112 this._slide(ORDER_NEXT); 113 } 114 nextWhenVisible() { 115 // FIXME TODO use `document.visibilityState` 116 // Don't call next when the page isn't visible 117 // or the carousel or its parent isn't visible 118 if (!document.hidden && index_js.isVisible(this._element)) { 119 this.next(); 120 } 121 } 122 prev() { 123 this._slide(ORDER_PREV); 124 } 125 pause() { 126 if (this._isSliding) { 127 index_js.triggerTransitionEnd(this._element); 128 } 129 this._clearInterval(); 130 } 131 cycle() { 132 this._clearInterval(); 133 this._updateInterval(); 134 this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval); 135 } 136 _maybeEnableCycle() { 137 if (!this._config.ride) { 138 return; 139 } 140 if (this._isSliding) { 141 EventHandler.one(this._element, EVENT_SLID, () => this.cycle()); 142 return; 143 } 144 this.cycle(); 145 } 146 to(index) { 147 const items = this._getItems(); 148 if (index > items.length - 1 || index < 0) { 149 return; 150 } 151 if (this._isSliding) { 152 EventHandler.one(this._element, EVENT_SLID, () => this.to(index)); 153 return; 154 } 155 const activeIndex = this._getItemIndex(this._getActive()); 156 if (activeIndex === index) { 157 return; 158 } 159 const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV; 160 this._slide(order, items[index]); 161 } 162 dispose() { 163 if (this._swipeHelper) {
vendor: 7,657 bytes, lines 164-374
164 this._swipeHelper.dispose(); 165 } 166 super.dispose(); 167 } 168 169 // Private 170 _configAfterMerge(config) { 171 config.defaultInterval = config.interval; 172 return config; 173 } 174 _addEventListeners() { 175 if (this._config.keyboard) { 176 EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event)); 177 } 178 if (this._config.pause === 'hover') { 179 EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause()); 180 EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle()); 181 } 182 if (this._config.touch && Swipe.isSupported()) { 183 this._addTouchEventListeners(); 184 } 185 } 186 _addTouchEventListeners() { 187 for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) { 188 EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault()); 189 } 190 const endCallBack = () => { 191 if (this._config.pause !== 'hover') { 192 return; 193 } 194 195 // If it's a touch-enabled device, mouseenter/leave are fired as 196 // part of the mouse compatibility events on first tap - the carousel 197 // would stop cycling until user tapped out of it; 198 // here, we listen for touchend, explicitly pause the carousel 199 // (as if it's the second time we tap on it, mouseenter compat event 200 // is NOT fired) and after a timeout (to allow for mouse compatibility 201 // events to fire) we explicitly restart cycling 202 203 this.pause(); 204 if (this.touchTimeout) { 205 clearTimeout(this.touchTimeout); 206 } 207 this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval); 208 }; 209 const swipeConfig = { 210 leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)), 211 rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)), 212 endCallback: endCallBack 213 }; 214 this._swipeHelper = new Swipe(this._element, swipeConfig); 215 } 216 _keydown(event) { 217 if (/input|textarea/i.test(event.target.tagName)) { 218 return; 219 } 220 const direction = KEY_TO_DIRECTION[event.key]; 221 if (direction) { 222 event.preventDefault(); 223 this._slide(this._directionToOrder(direction)); 224 } 225 } 226 _getItemIndex(element) { 227 return this._getItems().indexOf(element); 228 } 229 _setActiveIndicatorElement(index) { 230 if (!this._indicatorsElement) { 231 return; 232 } 233 const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement); 234 activeIndicator.classList.remove(CLASS_NAME_ACTIVE); 235 activeIndicator.removeAttribute('aria-current'); 236 const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement); 237 if (newActiveIndicator) { 238 newActiveIndicator.classList.add(CLASS_NAME_ACTIVE); 239 newActiveIndicator.setAttribute('aria-current', 'true'); 240 } 241 } 242 _updateInterval() { 243 const element = this._activeElement || this._getActive(); 244 if (!element) { 245 return; 246 } 247 const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10); 248 this._config.interval = elementInterval || this._config.defaultInterval; 249 } 250 _slide(order, element = null) { 251 if (this._isSliding) { 252 return; 253 } 254 const activeElement = this._getActive(); 255 const isNext = order === ORDER_NEXT; 256 const nextElement = element || index_js.getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap); 257 if (nextElement === activeElement) { 258 return; 259 } 260 const nextElementIndex = this._getItemIndex(nextElement); 261 const triggerEvent = eventName => { 262 return EventHandler.trigger(this._element, eventName, { 263 relatedTarget: nextElement, 264 direction: this._orderToDirection(order), 265 from: this._getItemIndex(activeElement), 266 to: nextElementIndex 267 }); 268 }; 269 const slideEvent = triggerEvent(EVENT_SLIDE); 270 if (slideEvent.defaultPrevented) { 271 return; 272 } 273 if (!activeElement || !nextElement) { 274 // Some weirdness is happening, so we bail 275 // TODO: change tests that use empty divs to avoid this check 276 return; 277 } 278 const isCycling = Boolean(this._interval); 279 this.pause(); 280 this._isSliding = true; 281 this._setActiveIndicatorElement(nextElementIndex); 282 this._activeElement = nextElement; 283 const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END; 284 const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV; 285 nextElement.classList.add(orderClassName); 286 index_js.reflow(nextElement); 287 activeElement.classList.add(directionalClassName); 288 nextElement.classList.add(directionalClassName); 289 const completeCallBack = () => { 290 nextElement.classList.remove(directionalClassName, orderClassName); 291 nextElement.classList.add(CLASS_NAME_ACTIVE); 292 activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName); 293 this._isSliding = false; 294 triggerEvent(EVENT_SLID); 295 }; 296 this._queueCallback(completeCallBack, activeElement, this._isAnimated()); 297 if (isCycling) { 298 this.cycle(); 299 } 300 } 301 _isAnimated() { 302 return this._element.classList.contains(CLASS_NAME_SLIDE); 303 } 304 _getActive() { 305 return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); 306 } 307 _getItems() { 308 return SelectorEngine.find(SELECTOR_ITEM, this._element); 309 } 310 _clearInterval() { 311 if (this._interval) { 312 clearInterval(this._interval); 313 this._interval = null; 314 } 315 } 316 _directionToOrder(direction) { 317 if (index_js.isRTL()) { 318 return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT; 319 } 320 return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV; 321 } 322 _orderToDirection(order) { 323 if (index_js.isRTL()) { 324 return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT; 325 } 326 return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT; 327 } 328 329 // Static 330 static jQueryInterface(config) { 331 return this.each(function () { 332 const data = Carousel.getOrCreateInstance(this, config); 333 if (typeof config === 'number') { 334 data.to(config); 335 return; 336 } 337 if (typeof config === 'string') { 338 if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { 339 throw new TypeError(`No method named "${config}"`); 340 } 341 data[config](); 342 } 343 }); 344 } 345 } 346 347 /** 348 * Data API implementation 349 */ 350 351 EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) { 352 const target = SelectorEngine.getElementFromSelector(this); 353 if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) { 354 return; 355 } 356 event.preventDefault(); 357 const carousel = Carousel.getOrCreateInstance(target); 358 const slideIndex = this.getAttribute('data-bs-slide-to'); 359 if (slideIndex) { 360 carousel.to(slideIndex); 361 carousel._maybeEnableCycle(); 362 return; 363 } 364 if (Manipulator.getDataAttribute(this, 'slide') === 'next') { 365 carousel.next(); 366 carousel._maybeEnableCycle(); 367 return; 368 } 369 carousel.prev(); 370 carousel._maybeEnableCycle(); 371 }); 372 EventHandler.on(window, EVENT_LOAD_DATA_API, () => { 373 const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE); 374 for (const carousel of carousels) {
375 Carousel.getOrCreateInstance(carousel); 376 } 377 }); 378 379 /** 380 * jQuery 381 */ 382 383 index_js.defineJQueryPlugin(Carousel); 384 385 return Carousel; 386 387})); 388//# sourceMappingURL=carousel.js.map
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.