diff options
Diffstat (limited to 'vendor/twbs/bootstrap/js/src/carousel.js')
-rw-r--r-- | vendor/twbs/bootstrap/js/src/carousel.js | 882 |
1 files changed, 484 insertions, 398 deletions
diff --git a/vendor/twbs/bootstrap/js/src/carousel.js b/vendor/twbs/bootstrap/js/src/carousel.js index 62af5cdb1..36176dd9c 100644 --- a/vendor/twbs/bootstrap/js/src/carousel.js +++ b/vendor/twbs/bootstrap/js/src/carousel.js @@ -1,520 +1,606 @@ -import $ from 'jquery' -import Util from './util' - /** * -------------------------------------------------------------------------- - * Bootstrap (v4.1.3): carousel.js + * Bootstrap (v4.3.1): carousel.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * -------------------------------------------------------------------------- */ -const Carousel = (($) => { - /** - * ------------------------------------------------------------------------ - * Constants - * ------------------------------------------------------------------------ - */ - - const NAME = 'carousel' - const VERSION = '4.1.3' - const DATA_KEY = 'bs.carousel' - const EVENT_KEY = `.${DATA_KEY}` - const DATA_API_KEY = '.data-api' - const JQUERY_NO_CONFLICT = $.fn[NAME] - const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key - const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key - const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch - - const Default = { - interval : 5000, - keyboard : true, - slide : false, - pause : 'hover', - wrap : true - } +import $ from 'jquery' +import Util from './util' - const DefaultType = { - interval : '(number|boolean)', - keyboard : 'boolean', - slide : '(boolean|string)', - pause : '(string|boolean)', - wrap : 'boolean' - } +/** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ - const Direction = { - NEXT : 'next', - PREV : 'prev', - LEFT : 'left', - RIGHT : 'right' - } +const NAME = 'carousel' +const VERSION = '4.3.1' +const DATA_KEY = 'bs.carousel' +const EVENT_KEY = `.${DATA_KEY}` +const DATA_API_KEY = '.data-api' +const JQUERY_NO_CONFLICT = $.fn[NAME] +const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key +const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key +const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch +const SWIPE_THRESHOLD = 40 + +const Default = { + interval : 5000, + keyboard : true, + slide : false, + pause : 'hover', + wrap : true, + touch : true +} + +const DefaultType = { + interval : '(number|boolean)', + keyboard : 'boolean', + slide : '(boolean|string)', + pause : '(string|boolean)', + wrap : 'boolean', + touch : 'boolean' +} + +const Direction = { + NEXT : 'next', + PREV : 'prev', + LEFT : 'left', + RIGHT : 'right' +} + +const Event = { + SLIDE : `slide${EVENT_KEY}`, + SLID : `slid${EVENT_KEY}`, + KEYDOWN : `keydown${EVENT_KEY}`, + MOUSEENTER : `mouseenter${EVENT_KEY}`, + MOUSELEAVE : `mouseleave${EVENT_KEY}`, + TOUCHSTART : `touchstart${EVENT_KEY}`, + TOUCHMOVE : `touchmove${EVENT_KEY}`, + TOUCHEND : `touchend${EVENT_KEY}`, + POINTERDOWN : `pointerdown${EVENT_KEY}`, + POINTERUP : `pointerup${EVENT_KEY}`, + DRAG_START : `dragstart${EVENT_KEY}`, + LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}`, + CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` +} + +const ClassName = { + CAROUSEL : 'carousel', + ACTIVE : 'active', + SLIDE : 'slide', + RIGHT : 'carousel-item-right', + LEFT : 'carousel-item-left', + NEXT : 'carousel-item-next', + PREV : 'carousel-item-prev', + ITEM : 'carousel-item', + POINTER_EVENT : 'pointer-event' +} + +const Selector = { + ACTIVE : '.active', + ACTIVE_ITEM : '.active.carousel-item', + ITEM : '.carousel-item', + ITEM_IMG : '.carousel-item img', + NEXT_PREV : '.carousel-item-next, .carousel-item-prev', + INDICATORS : '.carousel-indicators', + DATA_SLIDE : '[data-slide], [data-slide-to]', + DATA_RIDE : '[data-ride="carousel"]' +} + +const PointerType = { + TOUCH : 'touch', + PEN : 'pen' +} - const Event = { - SLIDE : `slide${EVENT_KEY}`, - SLID : `slid${EVENT_KEY}`, - KEYDOWN : `keydown${EVENT_KEY}`, - MOUSEENTER : `mouseenter${EVENT_KEY}`, - MOUSELEAVE : `mouseleave${EVENT_KEY}`, - TOUCHEND : `touchend${EVENT_KEY}`, - LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}`, - CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` +/** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ +class Carousel { + constructor(element, config) { + this._items = null + this._interval = null + this._activeElement = null + this._isPaused = false + this._isSliding = false + this.touchTimeout = null + this.touchStartX = 0 + this.touchDeltaX = 0 + + this._config = this._getConfig(config) + this._element = element + this._indicatorsElement = this._element.querySelector(Selector.INDICATORS) + this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 + this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent) + + this._addEventListeners() } - const ClassName = { - CAROUSEL : 'carousel', - ACTIVE : 'active', - SLIDE : 'slide', - RIGHT : 'carousel-item-right', - LEFT : 'carousel-item-left', - NEXT : 'carousel-item-next', - PREV : 'carousel-item-prev', - ITEM : 'carousel-item' + // Getters + + static get VERSION() { + return VERSION } - const Selector = { - ACTIVE : '.active', - ACTIVE_ITEM : '.active.carousel-item', - ITEM : '.carousel-item', - NEXT_PREV : '.carousel-item-next, .carousel-item-prev', - INDICATORS : '.carousel-indicators', - DATA_SLIDE : '[data-slide], [data-slide-to]', - DATA_RIDE : '[data-ride="carousel"]' + static get Default() { + return Default } - /** - * ------------------------------------------------------------------------ - * Class Definition - * ------------------------------------------------------------------------ - */ + // Public - class Carousel { - constructor(element, config) { - this._items = null - this._interval = null - this._activeElement = null + next() { + if (!this._isSliding) { + this._slide(Direction.NEXT) + } + } - this._isPaused = false - this._isSliding = false + nextWhenVisible() { + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && + ($(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden')) { + this.next() + } + } - this.touchTimeout = null + prev() { + if (!this._isSliding) { + this._slide(Direction.PREV) + } + } - this._config = this._getConfig(config) - this._element = $(element)[0] - this._indicatorsElement = this._element.querySelector(Selector.INDICATORS) + pause(event) { + if (!event) { + this._isPaused = true + } - this._addEventListeners() + if (this._element.querySelector(Selector.NEXT_PREV)) { + Util.triggerTransitionEnd(this._element) + this.cycle(true) } - // Getters + clearInterval(this._interval) + this._interval = null + } - static get VERSION() { - return VERSION + cycle(event) { + if (!event) { + this._isPaused = false } - static get Default() { - return Default + if (this._interval) { + clearInterval(this._interval) + this._interval = null } - // Public - - next() { - if (!this._isSliding) { - this._slide(Direction.NEXT) - } + if (this._config.interval && !this._isPaused) { + this._interval = setInterval( + (document.visibilityState ? this.nextWhenVisible : this.next).bind(this), + this._config.interval + ) } + } - nextWhenVisible() { - // Don't call next when the page isn't visible - // or the carousel or its parent isn't visible - if (!document.hidden && - ($(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden')) { - this.next() - } + to(index) { + this._activeElement = this._element.querySelector(Selector.ACTIVE_ITEM) + + const activeIndex = this._getItemIndex(this._activeElement) + + if (index > this._items.length - 1 || index < 0) { + return } - prev() { - if (!this._isSliding) { - this._slide(Direction.PREV) - } + if (this._isSliding) { + $(this._element).one(Event.SLID, () => this.to(index)) + return } - pause(event) { - if (!event) { - this._isPaused = true - } + if (activeIndex === index) { + this.pause() + this.cycle() + return + } - if (this._element.querySelector(Selector.NEXT_PREV)) { - Util.triggerTransitionEnd(this._element) - this.cycle(true) - } + const direction = index > activeIndex + ? Direction.NEXT + : Direction.PREV - clearInterval(this._interval) - this._interval = null - } + this._slide(direction, this._items[index]) + } - cycle(event) { - if (!event) { - this._isPaused = false - } + dispose() { + $(this._element).off(EVENT_KEY) + $.removeData(this._element, DATA_KEY) + + this._items = null + this._config = null + this._element = null + this._interval = null + this._isPaused = null + this._isSliding = null + this._activeElement = null + this._indicatorsElement = null + } - if (this._interval) { - clearInterval(this._interval) - this._interval = null - } + // Private - if (this._config.interval && !this._isPaused) { - this._interval = setInterval( - (document.visibilityState ? this.nextWhenVisible : this.next).bind(this), - this._config.interval - ) - } + _getConfig(config) { + config = { + ...Default, + ...config } + Util.typeCheckConfig(NAME, config, DefaultType) + return config + } - to(index) { - this._activeElement = this._element.querySelector(Selector.ACTIVE_ITEM) + _handleSwipe() { + const absDeltax = Math.abs(this.touchDeltaX) - const activeIndex = this._getItemIndex(this._activeElement) + if (absDeltax <= SWIPE_THRESHOLD) { + return + } - if (index > this._items.length - 1 || index < 0) { - return - } + const direction = absDeltax / this.touchDeltaX - if (this._isSliding) { - $(this._element).one(Event.SLID, () => this.to(index)) - return - } + // swipe left + if (direction > 0) { + this.prev() + } - if (activeIndex === index) { - this.pause() - this.cycle() - return - } + // swipe right + if (direction < 0) { + this.next() + } + } - const direction = index > activeIndex - ? Direction.NEXT - : Direction.PREV + _addEventListeners() { + if (this._config.keyboard) { + $(this._element) + .on(Event.KEYDOWN, (event) => this._keydown(event)) + } - this._slide(direction, this._items[index]) + if (this._config.pause === 'hover') { + $(this._element) + .on(Event.MOUSEENTER, (event) => this.pause(event)) + .on(Event.MOUSELEAVE, (event) => this.cycle(event)) } - dispose() { - $(this._element).off(EVENT_KEY) - $.removeData(this._element, DATA_KEY) + if (this._config.touch) { + this._addTouchEventListeners() + } + } - this._items = null - this._config = null - this._element = null - this._interval = null - this._isPaused = null - this._isSliding = null - this._activeElement = null - this._indicatorsElement = null + _addTouchEventListeners() { + if (!this._touchSupported) { + return } - // Private + const start = (event) => { + if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { + this.touchStartX = event.originalEvent.clientX + } else if (!this._pointerEvent) { + this.touchStartX = event.originalEvent.touches[0].clientX + } + } - _getConfig(config) { - config = { - ...Default, - ...config + const move = (event) => { + // ensure swiping with one touch and not pinching + if (event.originalEvent.touches && event.originalEvent.touches.length > 1) { + this.touchDeltaX = 0 + } else { + this.touchDeltaX = event.originalEvent.touches[0].clientX - this.touchStartX } - Util.typeCheckConfig(NAME, config, DefaultType) - return config } - _addEventListeners() { - if (this._config.keyboard) { - $(this._element) - .on(Event.KEYDOWN, (event) => this._keydown(event)) + const end = (event) => { + if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { + this.touchDeltaX = event.originalEvent.clientX - this.touchStartX } + this._handleSwipe() if (this._config.pause === 'hover') { - $(this._element) - .on(Event.MOUSEENTER, (event) => this.pause(event)) - .on(Event.MOUSELEAVE, (event) => this.cycle(event)) - if ('ontouchstart' in document.documentElement) { - // If it's a touch-enabled device, mouseenter/leave are fired as - // part of the mouse compatibility events on first tap - the carousel - // would stop cycling until user tapped out of it; - // here, we listen for touchend, explicitly pause the carousel - // (as if it's the second time we tap on it, mouseenter compat event - // is NOT fired) and after a timeout (to allow for mouse compatibility - // events to fire) we explicitly restart cycling - $(this._element).on(Event.TOUCHEND, () => { - this.pause() - if (this.touchTimeout) { - clearTimeout(this.touchTimeout) - } - this.touchTimeout = setTimeout((event) => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval) - }) + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + + this.pause() + if (this.touchTimeout) { + clearTimeout(this.touchTimeout) } + this.touchTimeout = setTimeout((event) => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval) } } - _keydown(event) { - if (/input|textarea/i.test(event.target.tagName)) { - return - } + $(this._element.querySelectorAll(Selector.ITEM_IMG)).on(Event.DRAG_START, (e) => e.preventDefault()) + if (this._pointerEvent) { + $(this._element).on(Event.POINTERDOWN, (event) => start(event)) + $(this._element).on(Event.POINTERUP, (event) => end(event)) - switch (event.which) { - case ARROW_LEFT_KEYCODE: - event.preventDefault() - this.prev() - break - case ARROW_RIGHT_KEYCODE: - event.preventDefault() - this.next() - break - default: - } + this._element.classList.add(ClassName.POINTER_EVENT) + } else { + $(this._element).on(Event.TOUCHSTART, (event) => start(event)) + $(this._element).on(Event.TOUCHMOVE, (event) => move(event)) + $(this._element).on(Event.TOUCHEND, (event) => end(event)) } + } - _getItemIndex(element) { - this._items = element && element.parentNode - ? [].slice.call(element.parentNode.querySelectorAll(Selector.ITEM)) - : [] - return this._items.indexOf(element) + _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return } - _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] + switch (event.which) { + case ARROW_LEFT_KEYCODE: + event.preventDefault() + this.prev() + break + case ARROW_RIGHT_KEYCODE: + event.preventDefault() + this.next() + break + default: } + } - _triggerSlideEvent(relatedTarget, eventDirectionName) { - const targetIndex = this._getItemIndex(relatedTarget) - const fromIndex = this._getItemIndex(this._element.querySelector(Selector.ACTIVE_ITEM)) - const slideEvent = $.Event(Event.SLIDE, { - relatedTarget, - direction: eventDirectionName, - from: fromIndex, - to: targetIndex - }) + _getItemIndex(element) { + this._items = element && element.parentNode + ? [].slice.call(element.parentNode.querySelectorAll(Selector.ITEM)) + : [] + return this._items.indexOf(element) + } - $(this._element).trigger(slideEvent) + _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 - return slideEvent + if (isGoingToWrap && !this._config.wrap) { + return activeElement } - _setActiveIndicatorElement(element) { - if (this._indicatorsElement) { - const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector.ACTIVE)) - $(indicators) - .removeClass(ClassName.ACTIVE) + const delta = direction === Direction.PREV ? -1 : 1 + const itemIndex = (activeIndex + delta) % this._items.length - const nextIndicator = this._indicatorsElement.children[ - this._getItemIndex(element) - ] + return itemIndex === -1 + ? this._items[this._items.length - 1] : this._items[itemIndex] + } - if (nextIndicator) { - $(nextIndicator).addClass(ClassName.ACTIVE) - } - } - } + _triggerSlideEvent(relatedTarget, eventDirectionName) { + const targetIndex = this._getItemIndex(relatedTarget) + const fromIndex = this._getItemIndex(this._element.querySelector(Selector.ACTIVE_ITEM)) + const slideEvent = $.Event(Event.SLIDE, { + relatedTarget, + direction: eventDirectionName, + from: fromIndex, + to: targetIndex + }) - _slide(direction, element) { - const activeElement = this._element.querySelector(Selector.ACTIVE_ITEM) - const activeElementIndex = this._getItemIndex(activeElement) - const nextElement = element || activeElement && - this._getItemByDirection(direction, activeElement) - const nextElementIndex = this._getItemIndex(nextElement) - const isCycling = Boolean(this._interval) + $(this._element).trigger(slideEvent) - let directionalClassName - let orderClassName - let eventDirectionName + return slideEvent + } - if (direction === Direction.NEXT) { - directionalClassName = ClassName.LEFT - orderClassName = ClassName.NEXT - eventDirectionName = Direction.LEFT - } else { - directionalClassName = ClassName.RIGHT - orderClassName = ClassName.PREV - eventDirectionName = Direction.RIGHT - } + _setActiveIndicatorElement(element) { + if (this._indicatorsElement) { + const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector.ACTIVE)) + $(indicators) + .removeClass(ClassName.ACTIVE) - if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) { - this._isSliding = false - return - } + const nextIndicator = this._indicatorsElement.children[ + this._getItemIndex(element) + ] - const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName) - if (slideEvent.isDefaultPrevented()) { - return - } - - if (!activeElement || !nextElement) { - // Some weirdness is happening, so we bail - return + if (nextIndicator) { + $(nextIndicator).addClass(ClassName.ACTIVE) } + } + } - this._isSliding = true + _slide(direction, element) { + const activeElement = this._element.querySelector(Selector.ACTIVE_ITEM) + const activeElementIndex = this._getItemIndex(activeElement) + const nextElement = element || activeElement && + this._getItemByDirection(direction, activeElement) + const nextElementIndex = this._getItemIndex(nextElement) + const isCycling = Boolean(this._interval) + + let directionalClassName + let orderClassName + let eventDirectionName + + if (direction === Direction.NEXT) { + directionalClassName = ClassName.LEFT + orderClassName = ClassName.NEXT + eventDirectionName = Direction.LEFT + } else { + directionalClassName = ClassName.RIGHT + orderClassName = ClassName.PREV + eventDirectionName = Direction.RIGHT + } - if (isCycling) { - this.pause() - } + if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) { + this._isSliding = false + return + } - this._setActiveIndicatorElement(nextElement) + const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName) + if (slideEvent.isDefaultPrevented()) { + return + } - const slidEvent = $.Event(Event.SLID, { - relatedTarget: nextElement, - direction: eventDirectionName, - from: activeElementIndex, - to: nextElementIndex - }) + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + return + } - if ($(this._element).hasClass(ClassName.SLIDE)) { - $(nextElement).addClass(orderClassName) + this._isSliding = true - Util.reflow(nextElement) + if (isCycling) { + this.pause() + } - $(activeElement).addClass(directionalClassName) - $(nextElement).addClass(directionalClassName) + this._setActiveIndicatorElement(nextElement) - const transitionDuration = Util.getTransitionDurationFromElement(activeElement) + const slidEvent = $.Event(Event.SLID, { + relatedTarget: nextElement, + direction: eventDirectionName, + from: activeElementIndex, + to: nextElementIndex + }) - $(activeElement) - .one(Util.TRANSITION_END, () => { - $(nextElement) - .removeClass(`${directionalClassName} ${orderClassName}`) - .addClass(ClassName.ACTIVE) + if ($(this._element).hasClass(ClassName.SLIDE)) { + $(nextElement).addClass(orderClassName) - $(activeElement).removeClass(`${ClassName.ACTIVE} ${orderClassName} ${directionalClassName}`) + Util.reflow(nextElement) - this._isSliding = false + $(activeElement).addClass(directionalClassName) + $(nextElement).addClass(directionalClassName) - setTimeout(() => $(this._element).trigger(slidEvent), 0) - }) - .emulateTransitionEnd(transitionDuration) + const nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10) + if (nextElementInterval) { + this._config.defaultInterval = this._config.defaultInterval || this._config.interval + this._config.interval = nextElementInterval } else { - $(activeElement).removeClass(ClassName.ACTIVE) - $(nextElement).addClass(ClassName.ACTIVE) - - this._isSliding = false - $(this._element).trigger(slidEvent) + this._config.interval = this._config.defaultInterval || this._config.interval } - if (isCycling) { - this.cycle() - } - } + const transitionDuration = Util.getTransitionDurationFromElement(activeElement) - // Static + $(activeElement) + .one(Util.TRANSITION_END, () => { + $(nextElement) + .removeClass(`${directionalClassName} ${orderClassName}`) + .addClass(ClassName.ACTIVE) - static _jQueryInterface(config) { - return this.each(function () { - let data = $(this).data(DATA_KEY) - let _config = { - ...Default, - ...$(this).data() - } + $(activeElement).removeClass(`${ClassName.ACTIVE} ${orderClassName} ${directionalClassName}`) - if (typeof config === 'object') { - _config = { - ..._config, - ...config - } - } + this._isSliding = false - const action = typeof config === 'string' ? config : _config.slide + setTimeout(() => $(this._element).trigger(slidEvent), 0) + }) + .emulateTransitionEnd(transitionDuration) + } else { + $(activeElement).removeClass(ClassName.ACTIVE) + $(nextElement).addClass(ClassName.ACTIVE) - if (!data) { - data = new Carousel(this, _config) - $(this).data(DATA_KEY, data) - } + this._isSliding = false + $(this._element).trigger(slidEvent) + } - if (typeof config === 'number') { - data.to(config) - } else if (typeof action === 'string') { - if (typeof data[action] === 'undefined') { - throw new TypeError(`No method named "${action}"`) - } - data[action]() - } else if (_config.interval) { - data.pause() - data.cycle() - } - }) + if (isCycling) { + this.cycle() } + } - static _dataApiClickHandler(event) { - const selector = Util.getSelectorFromElement(this) + // Static - if (!selector) { - return + static _jQueryInterface(config) { + return this.each(function () { + let data = $(this).data(DATA_KEY) + let _config = { + ...Default, + ...$(this).data() } - const target = $(selector)[0] - - if (!target || !$(target).hasClass(ClassName.CAROUSEL)) { - return + if (typeof config === 'object') { + _config = { + ..._config, + ...config + } } - const config = { - ...$(target).data(), - ...$(this).data() + const action = typeof config === 'string' ? config : _config.slide + + if (!data) { + data = new Carousel(this, _config) + $(this).data(DATA_KEY, data) } - const slideIndex = this.getAttribute('data-slide-to') - if (slideIndex) { - config.interval = false + if (typeof config === 'number') { + data.to(config) + } else if (typeof action === 'string') { + if (typeof data[action] === 'undefined') { + throw new TypeError(`No method named "${action}"`) + } + data[action]() + } else if (_config.interval && _config.ride) { + data.pause() + data.cycle() } + }) + } - Carousel._jQueryInterface.call($(target), config) + static _dataApiClickHandler(event) { + const selector = Util.getSelectorFromElement(this) - if (slideIndex) { - $(target).data(DATA_KEY).to(slideIndex) - } + if (!selector) { + return + } + + const target = $(selector)[0] - event.preventDefault() + if (!target || !$(target).hasClass(ClassName.CAROUSEL)) { + return } + + const config = { + ...$(target).data(), + ...$(this).data() + } + const slideIndex = this.getAttribute('data-slide-to') + + if (slideIndex) { + config.interval = false + } + + Carousel._jQueryInterface.call($(target), config) + + if (slideIndex) { + $(target).data(DATA_KEY).to(slideIndex) + } + + event.preventDefault() } +} - /** - * ------------------------------------------------------------------------ - * Data Api implementation - * ------------------------------------------------------------------------ - */ - - $(document) - .on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler) - - $(window).on(Event.LOAD_DATA_API, () => { - const carousels = [].slice.call(document.querySelectorAll(Selector.DATA_RIDE)) - for (let i = 0, len = carousels.length; i < len; i++) { - const $carousel = $(carousels[i]) - Carousel._jQueryInterface.call($carousel, $carousel.data()) - } - }) - - /** - * ------------------------------------------------------------------------ - * jQuery - * ------------------------------------------------------------------------ - */ - - $.fn[NAME] = Carousel._jQueryInterface - $.fn[NAME].Constructor = Carousel - $.fn[NAME].noConflict = function () { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Carousel._jQueryInterface +/** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + +$(document) + .on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler) + +$(window).on(Event.LOAD_DATA_API, () => { + const carousels = [].slice.call(document.querySelectorAll(Selector.DATA_RIDE)) + for (let i = 0, len = carousels.length; i < len; i++) { + const $carousel = $(carousels[i]) + Carousel._jQueryInterface.call($carousel, $carousel.data()) } +}) + +/** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ - return Carousel -})($) +$.fn[NAME] = Carousel._jQueryInterface +$.fn[NAME].Constructor = Carousel +$.fn[NAME].noConflict = () => { + $.fn[NAME] = JQUERY_NO_CONFLICT + return Carousel._jQueryInterface +} export default Carousel |