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