diff --git a/build/build-plugins.js b/build/build-plugins.js index 5d8c429635..f380d77dc1 100644 --- a/build/build-plugins.js +++ b/build/build-plugins.js @@ -34,7 +34,7 @@ const bsPlugins = { SelectorEngine: path.resolve(__dirname, '../js/src/dom/selector-engine.js'), Alert: path.resolve(__dirname, '../js/src/alert/alert.js'), Button: path.resolve(__dirname, '../js/src/button/button.js'), - Carousel: path.resolve(__dirname, '../js/src/carousel.js'), + Carousel: path.resolve(__dirname, '../js/src/carousel/carousel.js'), Collapse: path.resolve(__dirname, '../js/src/collapse.js'), Dropdown: path.resolve(__dirname, '../js/src/dropdown.js'), Modal: path.resolve(__dirname, '../js/src/modal.js'), diff --git a/js/index.esm.js b/js/index.esm.js index ca47d7405e..4f5058560d 100644 --- a/js/index.esm.js +++ b/js/index.esm.js @@ -7,7 +7,7 @@ import Alert from './src/alert/alert' import Button from './src/button/button' -import Carousel from './src/carousel' +import Carousel from './src/carousel/carousel' import Collapse from './src/collapse' import Dropdown from './src/dropdown' import Modal from './src/modal' diff --git a/js/index.umd.js b/js/index.umd.js index 2cb90696da..f3b81377e5 100644 --- a/js/index.umd.js +++ b/js/index.umd.js @@ -7,7 +7,7 @@ import Alert from './src/alert/alert' import Button from './src/button/button' -import Carousel from './src/carousel' +import Carousel from './src/carousel/carousel' import Collapse from './src/collapse' import Dropdown from './src/dropdown' import Modal from './src/modal' diff --git a/js/src/carousel.js b/js/src/carousel/carousel.js similarity index 98% rename from js/src/carousel.js rename to js/src/carousel/carousel.js index 7cd790f85d..0e1bad14ac 100644 --- a/js/src/carousel.js +++ b/js/src/carousel/carousel.js @@ -16,11 +16,11 @@ import { 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' +} 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' /** * ------------------------------------------------------------------------ @@ -283,16 +283,12 @@ class Carousel { .on(this._element, Event.MOUSELEAVE, event => this.cycle(event)) } - if (this._config.touch) { + if (this._config.touch && this._touchSupported) { this._addTouchEventListeners() } } _addTouchEventListeners() { - if (!this._touchSupported) { - return - } - const start = event => { if (this._pointerEvent && PointerType[event.pointerType.toUpperCase()]) { this.touchStartX = event.clientX @@ -631,7 +627,7 @@ EventHandler.on(window, Event.LOAD_DATA_API, () => { * ------------------------------------------------------------------------ * add .carousel to jQuery only if jQuery is present */ - +/* istanbul ignore if */ if (typeof $ !== 'undefined') { const JQUERY_NO_CONFLICT = $.fn[NAME] $.fn[NAME] = Carousel._jQueryInterface diff --git a/js/src/carousel/carousel.spec.js b/js/src/carousel/carousel.spec.js new file mode 100644 index 0000000000..9f897110d5 --- /dev/null +++ b/js/src/carousel/carousel.spec.js @@ -0,0 +1,1197 @@ +import Carousel from './carousel' +import EventHandler from '../dom/event-handler' + +/** Test helpers */ +import { getFixture, clearFixture, createEvent, jQueryMock } from '../../tests/helpers/fixture' + +describe('Carousel', () => { + const { Simulator, PointerEvent, MSPointerEvent } = window + const originWinPointerEvent = PointerEvent || MSPointerEvent + const supportPointerEvent = Boolean(PointerEvent || MSPointerEvent) + + window.MSPointerEvent = null + const cssStyleCarousel = '.carousel.pointer-event { -ms-touch-action: none; touch-action: none; }' + + const stylesCarousel = document.createElement('style') + stylesCarousel.type = 'text/css' + stylesCarousel.appendChild(document.createTextNode(cssStyleCarousel)) + + const clearPointerEvents = () => { + window.PointerEvent = null + } + + const restorePointerEvents = () => { + window.PointerEvent = originWinPointerEvent + } + + let fixtureEl + + beforeAll(() => { + fixtureEl = getFixture() + }) + + afterEach(() => { + clearFixture() + }) + + describe('VERSION', () => { + it('should return plugin version', () => { + expect(Carousel.VERSION).toEqual(jasmine.any(String)) + }) + }) + + describe('Default', () => { + it('should return plugin default config', () => { + expect(Carousel.Default).toEqual(jasmine.any(Object)) + }) + }) + + describe('constructor', () => { + it('should go to next item if right arrow key is pressed', done => { + fixtureEl.innerHTML = [ + '
' + ].join('') + + const carouselEl = fixtureEl.querySelector('#myCarousel') + const carousel = new Carousel(carouselEl, { + keyboard: true + }) + + spyOn(carousel, '_keydown').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', () => { + expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item2')) + expect(carousel._keydown).toHaveBeenCalled() + done() + }) + + const keyDown = createEvent('keydown') + keyDown.which = 39 + + carouselEl.dispatchEvent(keyDown) + }) + + it('should go to previous item if left arrow key is pressed', done => { + fixtureEl.innerHTML = [ + ' ' + ].join('') + + const carouselEl = fixtureEl.querySelector('#myCarousel') + const carousel = new Carousel(carouselEl, { + keyboard: true + }) + + spyOn(carousel, '_keydown').and.callThrough() + + carouselEl.addEventListener('slid.bs.carousel', () => { + expect(fixtureEl.querySelector('.active')).toEqual(fixtureEl.querySelector('#item1')) + expect(carousel._keydown).toHaveBeenCalled() + done() + }) + + const keyDown = createEvent('keydown') + keyDown.which = 37 + + carouselEl.dispatchEvent(keyDown) + }) + + it('should not prevent keydown if key is not ARROW_LEFT or ARROW_RIGHT', done => { + fixtureEl.innerHTML = [ + ' ' + ].join('') + + const carouselEl = fixtureEl.querySelector('#myCarousel') + const carousel = new Carousel(carouselEl, { + keyboard: true + }) + + spyOn(carousel, '_keydown').and.callThrough() + + carouselEl.addEventListener('keydown', event => { + expect(carousel._keydown).toHaveBeenCalled() + expect(event.defaultPrevented).toEqual(false) + done() + }) + + const keyDown = createEvent('keydown') + keyDown.which = 40 + + carouselEl.dispatchEvent(keyDown) + }) + + it('should ignore keyboard events within s and