aboutsummaryrefslogtreecommitdiff
path: root/js/src/carousel.js
diff options
context:
space:
mode:
authorXhmikosR <[email protected]>2021-08-18 07:29:56 +0300
committerGitHub <[email protected]>2021-08-18 07:29:56 +0300
commit433a148c9e61aa942801fd8101dfa5c4045fdaed (patch)
treef41db59fd06019169df5ea0338213ec0e298f226 /js/src/carousel.js
parentb97cfa163b5098db70e03b27c91fca5dde9c267e (diff)
parent18b3e1ac71f73d006756684a285c5a818e2d1454 (diff)
downloadbootstrap-global-focus-vars.tar.xz
bootstrap-global-focus-vars.zip
Merge branch 'main' into global-focus-varsglobal-focus-vars
Diffstat (limited to 'js/src/carousel.js')
-rw-r--r--js/src/carousel.js216
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