]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
fix(carousel): arrow keys break animation if carousel sliding (#34307) 34330/head
authoralpadev <2838324+alpadev@users.noreply.github.com>
Tue, 22 Jun 2021 10:11:03 +0000 (12:11 +0200)
committerGitHub <noreply@github.com>
Tue, 22 Jun 2021 10:11:03 +0000 (13:11 +0300)
js/src/carousel.js
js/tests/unit/carousel.spec.js

index fa401535af6e08112c5878e6b6c988b4964b9f12..3c64829db3bc48be1e4c1f1e7438d69b4053566e 100644 (file)
@@ -59,6 +59,11 @@ 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}`
@@ -134,9 +139,7 @@ class Carousel extends BaseComponent {
   // Public
 
   next() {
-    if (!this._isSliding) {
-      this._slide(ORDER_NEXT)
-    }
+    this._slide(ORDER_NEXT)
   }
 
   nextWhenVisible() {
@@ -148,9 +151,7 @@ class Carousel extends BaseComponent {
   }
 
   prev() {
-    if (!this._isSliding) {
-      this._slide(ORDER_PREV)
-    }
+    this._slide(ORDER_PREV)
   }
 
   pause(event) {
@@ -319,12 +320,10 @@ class Carousel extends BaseComponent {
       return
     }
 
-    if (event.key === ARROW_LEFT_KEY) {
-      event.preventDefault()
-      this._slide(DIRECTION_RIGHT)
-    } else if (event.key === ARROW_RIGHT_KEY) {
+    const direction = KEY_TO_DIRECTION[event.key]
+    if (direction) {
       event.preventDefault()
-      this._slide(DIRECTION_LEFT)
+      this._slide(direction)
     }
   }
 
@@ -408,6 +407,10 @@ class Carousel extends BaseComponent {
       return
     }
 
+    if (this._isSliding) {
+      return
+    }
+
     const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)
     if (slideEvent.defaultPrevented) {
       return
index 74f82ce1f0ed1e4bc4c62f1893d40285ef3facde..97482537a0e9ceba473d53ff5b28dc80761f079b 100644 (file)
@@ -203,6 +203,26 @@ describe('Carousel', () => {
       expect(spySlide).not.toHaveBeenCalled()
     })
 
+    it('should not slide if arrow key is pressed and carousel is sliding', () => {
+      fixtureEl.innerHTML = '<div></div>'
+
+      const carouselEl = fixtureEl.querySelector('div')
+      const carousel = new Carousel(carouselEl, {})
+
+      spyOn(carousel, '_triggerSlideEvent')
+
+      carousel._isSliding = true;
+
+      ['ArrowLeft', 'ArrowRight'].forEach(key => {
+        const keydown = createEvent('keydown')
+        keydown.key = key
+
+        carouselEl.dispatchEvent(keydown)
+      })
+
+      expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
+    })
+
     it('should wrap around from end to start when wrap option is true', done => {
       fixtureEl.innerHTML = [
         '<div id="myCarousel" class="carousel slide">',
@@ -487,6 +507,49 @@ describe('Carousel', () => {
       })
     })
 
+    it('should not slide when swiping and carousel is sliding', done => {
+      Simulator.setType('touch')
+      clearPointerEvents()
+      document.documentElement.ontouchstart = () => {}
+
+      fixtureEl.innerHTML = [
+        '<div class="carousel" data-bs-interval="false">',
+        '  <div class="carousel-inner">',
+        '    <div id="item" class="carousel-item active">',
+        '      <img alt="">',
+        '    </div>',
+        '    <div class="carousel-item">',
+        '      <img alt="">',
+        '    </div>',
+        '  </div>',
+        '</div>'
+      ].join('')
+
+      const carouselEl = fixtureEl.querySelector('.carousel')
+      const carousel = new Carousel(carouselEl)
+      carousel._isSliding = true
+
+      spyOn(carousel, '_triggerSlideEvent')
+
+      Simulator.gestures.swipe(carouselEl, {
+        deltaX: 300,
+        deltaY: 0
+      })
+
+      Simulator.gestures.swipe(carouselEl, {
+        pos: [300, 10],
+        deltaX: -300,
+        deltaY: 0
+      })
+
+      setTimeout(() => {
+        expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
+        delete document.documentElement.ontouchstart
+        restorePointerEvents()
+        done()
+      }, 300)
+    })
+
     it('should not allow pinch with touch events', done => {
       Simulator.setType('touch')
       clearPointerEvents()
@@ -552,12 +615,12 @@ describe('Carousel', () => {
       const carouselEl = fixtureEl.querySelector('div')
       const carousel = new Carousel(carouselEl, {})
 
-      spyOn(carousel, '_slide')
+      spyOn(carousel, '_triggerSlideEvent')
 
       carousel._isSliding = true
       carousel.next()
 
-      expect(carousel._slide).not.toHaveBeenCalled()
+      expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
     })
 
     it('should not fire slid when slide is prevented', done => {
@@ -763,12 +826,12 @@ describe('Carousel', () => {
       const carouselEl = fixtureEl.querySelector('div')
       const carousel = new Carousel(carouselEl, {})
 
-      spyOn(carousel, '_slide')
+      spyOn(carousel, '_triggerSlideEvent')
 
       carousel._isSliding = true
       carousel.prev()
 
-      expect(carousel._slide).not.toHaveBeenCalled()
+      expect(carousel._triggerSlideEvent).not.toHaveBeenCalled()
     })
   })