diff options
Diffstat (limited to 'js/src/carousel.js')
| -rw-r--r-- | js/src/carousel.js | 216 |
1 files changed, 93 insertions, 123 deletions
diff --git a/js/src/carousel.js b/js/src/carousel.js index 75f8a4da7..b0aed3872 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -1,22 +1,20 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.0-beta2): carousel.js + * Bootstrap (v5.1.0): carousel.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ import { defineJQueryPlugin, - emulateTransitionEnd, getElementFromSelector, - getTransitionDurationFromElement, - isVisible, isRTL, + isVisible, + getNextActiveElement, reflow, triggerTransitionEnd, typeCheckConfig } from './util/index' -import Data from './dom/data' import EventHandler from './dom/event-handler' import Manipulator from './dom/manipulator' import SelectorEngine from './dom/selector-engine' @@ -56,11 +54,16 @@ const DefaultType = { touch: 'boolean' } -const DIRECTION_NEXT = 'next' -const DIRECTION_PREV = 'prev' +const ORDER_NEXT = 'next' +const ORDER_PREV = 'prev' const DIRECTION_LEFT = 'left' const DIRECTION_RIGHT = 'right' +const KEY_TO_DIRECTION = { + [ARROW_LEFT_KEY]: DIRECTION_RIGHT, + [ARROW_RIGHT_KEY]: DIRECTION_LEFT +} + const EVENT_SLIDE = `slide${EVENT_KEY}` const EVENT_SLID = `slid${EVENT_KEY}` const EVENT_KEYDOWN = `keydown${EVENT_KEY}` @@ -129,16 +132,14 @@ class Carousel extends BaseComponent { return Default } - static get DATA_KEY() { - return DATA_KEY + static get NAME() { + return NAME } // Public next() { - if (!this._isSliding) { - this._slide(DIRECTION_NEXT) - } + this._slide(ORDER_NEXT) } nextWhenVisible() { @@ -150,9 +151,7 @@ class Carousel extends BaseComponent { } prev() { - if (!this._isSliding) { - this._slide(DIRECTION_PREV) - } + this._slide(ORDER_PREV) } pause(event) { @@ -208,25 +207,11 @@ class Carousel extends BaseComponent { return } - const direction = index > activeIndex ? - DIRECTION_NEXT : - DIRECTION_PREV - - this._slide(direction, this._items[index]) - } - - dispose() { - EventHandler.off(this._element, EVENT_KEY) - - this._items = null - this._config = null - this._interval = null - this._isPaused = null - this._isSliding = null - this._activeElement = null - this._indicatorsElement = null + const order = index > activeIndex ? + ORDER_NEXT : + ORDER_PREV - super.dispose() + this._slide(order, this._items[index]) } // Private @@ -234,7 +219,8 @@ class Carousel extends BaseComponent { _getConfig(config) { config = { ...Default, - ...config + ...Manipulator.getDataAttributes(this._element), + ...(typeof config === 'object' ? config : {}) } typeCheckConfig(NAME, config, DefaultType) return config @@ -251,23 +237,11 @@ class Carousel extends BaseComponent { this.touchDeltaX = 0 - // swipe left - if (direction > 0) { - if (isRTL()) { - this.next() - } else { - this.prev() - } + if (!direction) { + return } - // swipe right - if (direction < 0) { - if (isRTL()) { - this.prev() - } else { - this.next() - } - } + this._slide(direction > 0 ? DIRECTION_RIGHT : DIRECTION_LEFT) } _addEventListeners() { @@ -286,8 +260,13 @@ class Carousel extends BaseComponent { } _addTouchEventListeners() { + const hasPointerPenTouch = event => { + return this._pointerEvent && + (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH) + } + const start = event => { - if (this._pointerEvent && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)) { + if (hasPointerPenTouch(event)) { this.touchStartX = event.clientX } else if (!this._pointerEvent) { this.touchStartX = event.touches[0].clientX @@ -296,15 +275,13 @@ class Carousel extends BaseComponent { const move = event => { // ensure swiping with one touch and not pinching - if (event.touches && event.touches.length > 1) { - this.touchDeltaX = 0 - } else { - this.touchDeltaX = event.touches[0].clientX - this.touchStartX - } + this.touchDeltaX = event.touches && event.touches.length > 1 ? + 0 : + event.touches[0].clientX - this.touchStartX } const end = event => { - if (this._pointerEvent && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)) { + if (hasPointerPenTouch(event)) { this.touchDeltaX = event.clientX - this.touchStartX } @@ -348,20 +325,10 @@ class Carousel extends BaseComponent { return } - if (event.key === ARROW_LEFT_KEY) { + const direction = KEY_TO_DIRECTION[event.key] + if (direction) { event.preventDefault() - if (isRTL()) { - this.next() - } else { - this.prev() - } - } else if (event.key === ARROW_RIGHT_KEY) { - event.preventDefault() - if (isRTL()) { - this.prev() - } else { - this.next() - } + this._slide(direction) } } @@ -373,24 +340,9 @@ class Carousel extends BaseComponent { return this._items.indexOf(element) } - _getItemByDirection(direction, activeElement) { - const isNextDirection = direction === DIRECTION_NEXT - const isPrevDirection = direction === DIRECTION_PREV - const activeIndex = this._getItemIndex(activeElement) - const lastItemIndex = this._items.length - 1 - const isGoingToWrap = (isPrevDirection && activeIndex === 0) || - (isNextDirection && activeIndex === lastItemIndex) - - if (isGoingToWrap && !this._config.wrap) { - return activeElement - } - - const delta = direction === DIRECTION_PREV ? -1 : 1 - const itemIndex = (activeIndex + delta) % this._items.length - - return itemIndex === -1 ? - this._items[this._items.length - 1] : - this._items[itemIndex] + _getItemByOrder(order, activeElement) { + const isNext = order === ORDER_NEXT + return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap) } _triggerSlideEvent(relatedTarget, eventDirectionName) { @@ -441,23 +393,29 @@ class Carousel extends BaseComponent { } } - _slide(direction, element) { + _slide(directionOrOrder, element) { + const order = this._directionToOrder(directionOrOrder) const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element) const activeElementIndex = this._getItemIndex(activeElement) - const nextElement = element || (activeElement && this._getItemByDirection(direction, activeElement)) + const nextElement = element || this._getItemByOrder(order, activeElement) const nextElementIndex = this._getItemIndex(nextElement) const isCycling = Boolean(this._interval) - const directionalClassName = direction === DIRECTION_NEXT ? CLASS_NAME_START : CLASS_NAME_END - const orderClassName = direction === DIRECTION_NEXT ? CLASS_NAME_NEXT : CLASS_NAME_PREV - const eventDirectionName = direction === DIRECTION_NEXT ? DIRECTION_LEFT : DIRECTION_RIGHT + const isNext = order === ORDER_NEXT + const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END + const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV + const eventDirectionName = this._orderToDirection(order) if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE)) { this._isSliding = false return } + if (this._isSliding) { + return + } + const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName) if (slideEvent.defaultPrevented) { return @@ -477,6 +435,15 @@ class Carousel extends BaseComponent { this._setActiveIndicatorElement(nextElement) this._activeElement = nextElement + const triggerSlidEvent = () => { + EventHandler.trigger(this._element, EVENT_SLID, { + relatedTarget: nextElement, + direction: eventDirectionName, + from: activeElementIndex, + to: nextElementIndex + }) + } + if (this._element.classList.contains(CLASS_NAME_SLIDE)) { nextElement.classList.add(orderClassName) @@ -485,9 +452,7 @@ class Carousel extends BaseComponent { activeElement.classList.add(directionalClassName) nextElement.classList.add(directionalClassName) - const transitionDuration = getTransitionDurationFromElement(activeElement) - - EventHandler.one(activeElement, 'transitionend', () => { + const completeCallBack = () => { nextElement.classList.remove(directionalClassName, orderClassName) nextElement.classList.add(CLASS_NAME_ACTIVE) @@ -495,28 +460,16 @@ class Carousel extends BaseComponent { this._isSliding = false - setTimeout(() => { - EventHandler.trigger(this._element, EVENT_SLID, { - relatedTarget: nextElement, - direction: eventDirectionName, - from: activeElementIndex, - to: nextElementIndex - }) - }, 0) - }) + setTimeout(triggerSlidEvent, 0) + } - emulateTransitionEnd(activeElement, transitionDuration) + this._queueCallback(completeCallBack, activeElement, true) } else { activeElement.classList.remove(CLASS_NAME_ACTIVE) nextElement.classList.add(CLASS_NAME_ACTIVE) this._isSliding = false - EventHandler.trigger(this._element, EVENT_SLID, { - relatedTarget: nextElement, - direction: eventDirectionName, - from: activeElementIndex, - to: nextElementIndex - }) + triggerSlidEvent() } if (isCycling) { @@ -524,15 +477,36 @@ class Carousel extends BaseComponent { } } + _directionToOrder(direction) { + if (![DIRECTION_RIGHT, DIRECTION_LEFT].includes(direction)) { + return direction + } + + if (isRTL()) { + return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT + } + + return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV + } + + _orderToDirection(order) { + if (![ORDER_NEXT, ORDER_PREV].includes(order)) { + return order + } + + if (isRTL()) { + return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT + } + + return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT + } + // Static static carouselInterface(element, config) { - let data = Data.getData(element, DATA_KEY) - let _config = { - ...Default, - ...Manipulator.getDataAttributes(element) - } + const data = Carousel.getOrCreateInstance(element, config) + let { _config } = data if (typeof config === 'object') { _config = { ..._config, @@ -542,10 +516,6 @@ class Carousel extends BaseComponent { const action = typeof config === 'string' ? config : _config.slide - if (!data) { - data = new Carousel(element, _config) - } - if (typeof config === 'number') { data.to(config) } else if (typeof action === 'string') { @@ -586,7 +556,7 @@ class Carousel extends BaseComponent { Carousel.carouselInterface(target, config) if (slideIndex) { - Data.getData(target, DATA_KEY).to(slideIndex) + Carousel.getInstance(target).to(slideIndex) } event.preventDefault() @@ -605,7 +575,7 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => { const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE) for (let i = 0, len = carousels.length; i < len; i++) { - Carousel.carouselInterface(carousels[i], Data.getData(carousels[i], DATA_KEY)) + Carousel.carouselInterface(carousels[i], Carousel.getInstance(carousels[i])) } }) @@ -616,6 +586,6 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => { * add .Carousel to jQuery only if jQuery is present */ -defineJQueryPlugin(NAME, Carousel) +defineJQueryPlugin(Carousel) export default Carousel |
