From 1b183e2ff796fc22aba8a8cac074a306c083d018 Mon Sep 17 00:00:00 2001 From: fat Date: Thu, 7 May 2015 22:26:40 -0700 Subject: [PATCH] carousel -> es6 --- Gruntfile.js | 1 + js/button.js | 120 ---------- js/dist/alert.js | 6 +- js/dist/alert.js.map | Bin 7182 -> 7128 bytes js/dist/button.js | 16 +- js/dist/button.js.map | Bin 7577 -> 7558 bytes js/dist/carousel.js | 418 +++++++++++++++++++++++++++++++++ js/dist/carousel.js.map | Bin 0 -> 21004 bytes js/dist/util.js | 6 +- js/dist/util.js.map | Bin 5189 -> 5361 bytes js/src/alert.js | 6 +- js/src/button.js | 18 +- js/src/carousel.js | 426 ++++++++++++++++++++++++++++++++++ js/src/util.js | 6 +- js/tests/index.html | 2 +- js/tests/unit/carousel.js | 160 ++++++------- js/tests/visual/carousel.html | 10 +- 17 files changed, 962 insertions(+), 233 deletions(-) delete mode 100644 js/button.js create mode 100644 js/dist/carousel.js create mode 100644 js/dist/carousel.js.map create mode 100644 js/src/carousel.js diff --git a/Gruntfile.js b/Gruntfile.js index c32f79f0e..b058bf3a0 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -66,6 +66,7 @@ module.exports = function (grunt) { 'js/dist/util.js': 'js/src/util.js', 'js/dist/alert.js': 'js/src/alert.js', 'js/dist/button.js': 'js/src/button.js', + 'js/dist/carousel.js': 'js/src/carousel.js', } } }, diff --git a/js/button.js b/js/button.js deleted file mode 100644 index 3e2e34512..000000000 --- a/js/button.js +++ /dev/null @@ -1,120 +0,0 @@ -/* ======================================================================== - * Bootstrap: button.js v3.3.4 - * http://getbootstrap.com/javascript/#buttons - * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // BUTTON PUBLIC CLASS DEFINITION - // ============================== - - var Button = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Button.DEFAULTS, options) - this.isLoading = false - } - - Button.VERSION = '3.3.4' - - Button.DEFAULTS = { - loadingText: 'loading...' - } - - Button.prototype.setState = function (state) { - var d = 'disabled' - var $el = this.$element - var val = $el.is('input') ? 'val' : 'html' - var data = $el.data() - - state += 'Text' - - if (data.resetText == null) $el.data('resetText', $el[val]()) - - // push to event loop to allow forms to submit - setTimeout($.proxy(function () { - $el[val](data[state] == null ? this.options[state] : data[state]) - - if (state == 'loadingText') { - this.isLoading = true - $el.addClass(d).attr(d, d) - } else if (this.isLoading) { - this.isLoading = false - $el.removeClass(d).removeAttr(d) - } - }, this), 0) - } - - Button.prototype.toggle = function () { - var changed = true - var $parent = this.$element.closest('[data-toggle="buttons"]') - - if ($parent.length) { - var $input = this.$element.find('input') - if ($input.prop('type') == 'radio') { - if ($input.prop('checked')) changed = false - $parent.find('.active').removeClass('active') - this.$element.addClass('active') - } else if ($input.prop('type') == 'checkbox') { - if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false - this.$element.toggleClass('active') - } - $input.prop('checked', this.$element.hasClass('active')) - if (changed) $input.trigger('change') - } else { - this.$element.attr('aria-pressed', !this.$element.hasClass('active')) - this.$element.toggleClass('active') - } - } - - - // BUTTON PLUGIN DEFINITION - // ======================== - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.button') - var options = typeof option == 'object' && option - - if (!data) $this.data('bs.button', (data = new Button(this, options))) - - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) - }) - } - - var old = $.fn.button - - $.fn.button = Plugin - $.fn.button.Constructor = Button - - - // BUTTON NO CONFLICT - // ================== - - $.fn.button.noConflict = function () { - $.fn.button = old - return this - } - - - // BUTTON DATA-API - // =============== - - $(document) - .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - Plugin.call($btn, 'toggle') - if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault() - }) - .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { - $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) - }) - -}(jQuery); diff --git a/js/dist/alert.js b/js/dist/alert.js index 4226dd61a..35e19874c 100644 --- a/js/dist/alert.js +++ b/js/dist/alert.js @@ -51,9 +51,7 @@ var Alert = (function ($) { function Alert(element) { _classCallCheck(this, Alert); - if (element) { - this.element = element; - } + this._element = element; } _createClass(Alert, [{ @@ -62,7 +60,7 @@ var Alert = (function ($) { // public value: function close(element) { - element = element || this.element; + element = element || this._element; var rootElement = this._getRootElement(element); var customEvent = this._triggerCloseEvent(rootElement); diff --git a/js/dist/alert.js.map b/js/dist/alert.js.map index aa106df1e8a16ce4b0677f1cb539872cac5717da..4d8c6173e5393c3617b9ecedd346f92f3ed8cc9e 100644 GIT binary patch delta 222 zcmeCPxM98_j42>c$JNo%)!M|#(JjYG$J^1-+uGXE(LF#X)X~vX$Jx=*StroZF;K@H zD5&G_=;#j;bF}t$bgpo+w$5~N^m2#lvbMHPbPS%npUH$DtOKkLXqIcvWGiOr&9cmY zSh)QmwgFAm->kwR%_L#zhNK;60#JRWdxVbrnlV3iF delta 266 zcmca%-e<8PjH%vV$JNo%)!M|#(JjkK$J^1-+uGXE(LF#X)X~vX$KTNrs=(3FIYK8A zB<2icLL}UQ3Lz|@n4`77qjQ;)wYQ_Qo3(YOlcS$I)HrKv>qN(JFP&7lMzEDYUXsq_ zJxp@^U|YaO0Ihb-nyknyJ$VJ2%w`4V2Q1va5C;NPTW;p&kY*Cea7Qv2Xf{xf(Pk^I zcWje6MYx$W(-bB%iU><6D3oMm7VD+vq~@mPl_=OMKv|OyN{CDj6ZG7?Kv0==^ARx- FRsgViNoW87 diff --git a/js/dist/button.js b/js/dist/button.js index 76aa09a7f..20be59dc7 100644 --- a/js/dist/button.js +++ b/js/dist/button.js @@ -54,7 +54,7 @@ var Button = (function ($) { function Button(element) { _classCallCheck(this, Button); - this.element = element; + this._element = element; } _createClass(Button, [{ @@ -64,14 +64,14 @@ var Button = (function ($) { value: function toggle() { var triggerChangeEvent = true; - var rootElement = $(this.element).closest(Selector.DATA_TOGGLE)[0]; + var rootElement = $(this._element).closest(Selector.DATA_TOGGLE)[0]; if (rootElement) { - var input = $(this.element).find(Selector.INPUT)[0]; + var input = $(this._element).find(Selector.INPUT)[0]; if (input) { if (input.type === 'radio') { - if (input.checked && $(this.element).hasClass(ClassName.ACTIVE)) { + if (input.checked && $(this._element).hasClass(ClassName.ACTIVE)) { triggerChangeEvent = false; } else { var activeElement = $(rootElement).find(Selector.ACTIVE)[0]; @@ -83,16 +83,16 @@ var Button = (function ($) { } if (triggerChangeEvent) { - input.checked = !$(this.element).hasClass(ClassName.ACTIVE); - $(this.element).trigger('change'); + input.checked = !$(this._element).hasClass(ClassName.ACTIVE); + $(this._element).trigger('change'); } } } else { - this.element.setAttribute('aria-pressed', !$(this.element).hasClass(ClassName.ACTIVE)); + this._element.setAttribute('aria-pressed', !$(this._element).hasClass(ClassName.ACTIVE)); } if (triggerChangeEvent) { - $(this.element).toggleClass(ClassName.ACTIVE); + $(this._element).toggleClass(ClassName.ACTIVE); } } }], [{ diff --git a/js/dist/button.js.map b/js/dist/button.js.map index 690b5e0dc8997a55e38f6e91e3b7ac1ed831392f..ac111ccf4335bb53b1d378dafecfc34f8b216ad4 100644 GIT binary patch delta 349 zcmbPf-DW)@h|zyyupVRZ#wHski9kokKpl5SM|T~6M@N4hXGcdzYi~#AipkfQ(jbyR zA!m@dGfV|gGK4vU1*CKG0cJc6ZD?E znD_bQ&w_EApYidtFvd^*D%1!h%Y;jSK=Ou|%H|a!`HWzu^5l4Nj>+XByg;76 aSRjyGAZ7uUNd%IX;`xmBn^%Z`WCZ}AQfGJo delta 361 zcmZp(o@qTHh%t0xupVRJ#wHsk34cdNe;s#6M|T}C%h}P<(c0V5xoq+^rZk8oP{>&a zOh8otB}14qSU|kV2bdih^CmN~iP=q770=&1Rs16>05FSgW&i*H diff --git a/js/dist/carousel.js b/js/dist/carousel.js new file mode 100644 index 000000000..55fd16024 --- /dev/null +++ b/js/dist/carousel.js @@ -0,0 +1,418 @@ +'use strict'; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): carousel.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + +var Carousel = (function ($) { + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + var NAME = 'carousel'; + var VERSION = '4.0.0'; + var DATA_KEY = 'bs.carousel'; + var JQUERY_NO_CONFLICT = $.fn[NAME]; + var TRANSITION_DURATION = 600; + + var Defaults = { + 'interval': 5000, + 'keyboard': true, + 'slide': false, + 'pause': 'hover', + 'wrap': true + }; + + var Direction = { + NEXT: 'next', + PREVIOUS: 'prev' + }; + + var Event = { + SLIDE: 'slide.bs.carousel', + SLID: 'slid.bs.carousel', + CLICK: 'click.bs.carousel.data-api', + LOAD: 'load' + }; + + var ClassName = { + CAROUSEL: 'carousel', + ACTIVE: 'active', + SLIDE: 'slide', + RIGHT: 'right', + LEFT: 'left', + ITEM: 'carousel-item' + }; + + var Selector = { + ACTIVE: '.active', + ACTIVE_ITEM: '.active.carousel-item', + ITEM: '.carousel-item', + NEXT_PREV: '.next, .prev', + INDICATORS: '.carousel-indicators', + DATA_SLIDE: '[data-slide], [data-slide-to]', + DATA_RIDE: '[data-ride="carousel"]' + }; + + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + var Carousel = (function () { + function Carousel(element, config) { + _classCallCheck(this, Carousel); + + this._items = null; + this._interval = null; + this._activeElement = null; + + this._isPaused = false; + this._isSliding = false; + + this._config = config; + this._element = $(element)[0]; + this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0]; + + this._addEventListeners(); + } + + _createClass(Carousel, [{ + key: 'next', + + // public + + value: function next() { + if (!this._isSliding) { + this._slide(Direction.NEXT); + } + } + }, { + key: 'prev', + value: function prev() { + if (!this._isSliding) { + this._slide(Direction.PREVIOUS); + } + } + }, { + key: 'pause', + value: function pause(event) { + if (!event) { + this._isPaused = true; + } + + if ($(this._element).find(Selector.NEXT_PREV)[0] && Util.supportsTransitionEnd()) { + Util.triggerTransitionEnd(this._element); + this.cycle(true); + } + + clearInterval(this._interval); + this._interval = null; + } + }, { + key: 'cycle', + value: function cycle(event) { + if (!event) { + this._isPaused = false; + } + + if (this._interval) { + clearInterval(this._interval); + this._interval = null; + } + + if (this._config.interval && !this._isPaused) { + this._interval = setInterval(this.next.bind(this), this._config.interval); + } + } + }, { + key: 'to', + value: function to(index) { + var _this = this; + + this._activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0]; + + var activeIndex = this._getItemIndex(this._activeElement); + + if (index > this._items.length - 1 || index < 0) { + return; + } + + if (this._isSliding) { + $(this._element).one(Event.SLID, function () { + return _this.to(index); + }); + return; + } + + if (activeIndex == index) { + this.pause(); + this.cycle(); + return; + } + + var direction = index > activeIndex ? Direction.NEXT : Direction.PREVIOUS; + + this._slide(direction, this._items[index]); + } + }, { + key: '_addEventListeners', + + // private + + value: function _addEventListeners() { + if (this._config.keyboard) { + $(this._element).on('keydown.bs.carousel', this._keydown.bind(this)); + } + + if (this._config.pause == 'hover' && !('ontouchstart' in document.documentElement)) { + $(this._element).on('mouseenter.bs.carousel', this.pause.bind(this)).on('mouseleave.bs.carousel', this.cycle.bind(this)); + } + } + }, { + key: '_keydown', + value: function _keydown(event) { + event.preventDefault(); + + if (/input|textarea/i.test(event.target.tagName)) return; + + switch (event.which) { + case 37: + this.prev();break; + case 39: + this.next();break; + default: + return; + } + } + }, { + key: '_getItemIndex', + value: function _getItemIndex(element) { + this._items = $.makeArray($(element).parent().find(Selector.ITEM)); + return this._items.indexOf(element); + } + }, { + key: '_getItemByDirection', + value: function _getItemByDirection(direction, activeElement) { + var isNextDirection = direction === Direction.NEXT; + var isPrevDirection = direction === Direction.PREVIOUS; + var activeIndex = this._getItemIndex(activeElement); + var lastItemIndex = this._items.length - 1; + var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex == lastItemIndex; + + if (isGoingToWrap && !this._config.wrap) { + return activeElement; + } + + var delta = direction == Direction.PREVIOUS ? -1 : 1; + var itemIndex = (activeIndex + delta) % this._items.length; + + return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex]; + } + }, { + key: '_triggerSlideEvent', + value: function _triggerSlideEvent(relatedTarget, directionalClassname) { + var slideEvent = $.Event(Event.SLIDE, { + relatedTarget: relatedTarget, + direction: directionalClassname + }); + + $(this._element).trigger(slideEvent); + + return slideEvent; + } + }, { + key: '_setActiveIndicatorElement', + value: function _setActiveIndicatorElement(element) { + if (this._indicatorsElement) { + $(this._indicatorsElement).find(Selector.ACTIVE).removeClass(ClassName.ACTIVE); + + var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)]; + + if (nextIndicator) { + $(nextIndicator).addClass(ClassName.ACTIVE); + } + } + } + }, { + key: '_slide', + value: function _slide(direction, element) { + var _this2 = this; + + var activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0]; + var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement); + + var isCycling = !!this._interval; + + var directionalClassName = direction == Direction.NEXT ? ClassName.LEFT : ClassName.RIGHT; + + if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) { + this._isSliding = false; + return; + } + + var slideEvent = this._triggerSlideEvent(nextElement, directionalClassName); + if (slideEvent.isDefaultPrevented()) { + return; + } + + if (!activeElement || !nextElement) { + // some weirdness is happening, so we bail + return; + } + + this._isSliding = true; + + if (isCycling) { + this.pause(); + } + + this._setActiveIndicatorElement(nextElement); + + var slidEvent = $.Event(Event.SLID, { + relatedTarget: nextElement, + direction: directionalClassName + }); + + if (Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.SLIDE)) { + + $(nextElement).addClass(direction); + + Util.reflow(nextElement); + + $(activeElement).addClass(directionalClassName); + $(nextElement).addClass(directionalClassName); + + $(activeElement).one(Util.TRANSITION_END, function () { + $(nextElement).removeClass(directionalClassName).removeClass(direction); + + $(nextElement).addClass(ClassName.ACTIVE); + + $(activeElement).removeClass(ClassName.ACTIVE).removeClass(direction).removeClass(directionalClassName); + + _this2._isSliding = false; + + setTimeout(function () { + return $(_this2._element).trigger(slidEvent); + }, 0); + }).emulateTransitionEnd(TRANSITION_DURATION); + } else { + $(activeElement).removeClass(ClassName.ACTIVE); + $(nextElement).addClass(ClassName.ACTIVE); + + this._isSliding = false; + $(this._element).trigger(slidEvent); + } + + if (isCycling) { + this.cycle(); + } + } + }], [{ + key: '_jQueryInterface', + + // static + + value: function _jQueryInterface(config) { + return this.each(function () { + var data = $(this).data(DATA_KEY); + var _config = $.extend({}, Defaults, $(this).data()); + + if (typeof config === 'object') { + $.extend(_config, config); + } + + var action = typeof config === 'string' ? config : _config.slide; + + if (!data) { + data = new Carousel(this, _config); + $(this).data(DATA_KEY, data); + } + + if (typeof config == 'number') { + data.to(config); + } else if (action) { + data[action](); + } else if (_config.interval) { + data.pause(); + data.cycle(); + } + }); + } + }, { + key: '_dataApiClickHandler', + value: function _dataApiClickHandler(event) { + var selector = Util.getSelectorFromElement(this); + + if (!selector) { + return; + } + + var target = $(selector)[0]; + + if (!target || !$(target).hasClass(ClassName.CAROUSEL)) { + return; + } + + var config = $.extend({}, $(target).data(), $(this).data()); + + var 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(); + } + }]); + + return Carousel; + })(); + + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + $(document).on(Event.CLICK, Selector.DATA_SLIDE, Carousel._dataApiClickHandler); + + $(window).on(Event.LOAD, function () { + $(Selector.DATA_RIDE).each(function () { + var $carousel = $(this); + 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; + }; + + return Carousel; +})(jQuery); +//# sourceMappingURL=carousel.js.map \ No newline at end of file diff --git a/js/dist/carousel.js.map b/js/dist/carousel.js.map new file mode 100644 index 0000000000000000000000000000000000000000..12b48721a09c5cc84ef8f3a9363c5e3a55ce44a0 GIT binary patch literal 21004 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 D%E~~@ delta 51 zcmeyUc~oOVHVbF4qocEqzoVn?WIqng&221`nKw6c{9$8L(J0BtES{_*BENYFe+0|q HP?0$R!weA( diff --git a/js/src/alert.js b/js/src/alert.js index 67a1ceda4..e5e8eeacb 100644 --- a/js/src/alert.js +++ b/js/src/alert.js @@ -49,16 +49,14 @@ const Alert = (($) => { class Alert { constructor(element) { - if (element) { - this.element = element - } + this._element = element } // public close(element) { - element = element || this.element + element = element || this._element let rootElement = this._getRootElement(element) let customEvent = this._triggerCloseEvent(rootElement) diff --git a/js/src/button.js b/js/src/button.js index 7e9344923..0f1dab2af 100644 --- a/js/src/button.js +++ b/js/src/button.js @@ -49,24 +49,24 @@ const Button = (($) => { class Button { constructor(element) { - this.element = element + this._element = element } // public toggle() { let triggerChangeEvent = true - let rootElement = $(this.element).closest( + let rootElement = $(this._element).closest( Selector.DATA_TOGGLE )[0] if (rootElement) { - let input = $(this.element).find(Selector.INPUT)[0] + let input = $(this._element).find(Selector.INPUT)[0] if (input) { if (input.type === 'radio') { if (input.checked && - $(this.element).hasClass(ClassName.ACTIVE)) { + $(this._element).hasClass(ClassName.ACTIVE)) { triggerChangeEvent = false } else { @@ -79,17 +79,17 @@ const Button = (($) => { } if (triggerChangeEvent) { - input.checked = !$(this.element).hasClass(ClassName.ACTIVE) - $(this.element).trigger('change') + input.checked = !$(this._element).hasClass(ClassName.ACTIVE) + $(this._element).trigger('change') } } } else { - this.element.setAttribute('aria-pressed', - !$(this.element).hasClass(ClassName.ACTIVE)) + this._element.setAttribute('aria-pressed', + !$(this._element).hasClass(ClassName.ACTIVE)) } if (triggerChangeEvent) { - $(this.element).toggleClass(ClassName.ACTIVE) + $(this._element).toggleClass(ClassName.ACTIVE) } } diff --git a/js/src/carousel.js b/js/src/carousel.js new file mode 100644 index 000000000..08476d666 --- /dev/null +++ b/js/src/carousel.js @@ -0,0 +1,426 @@ +import Util from './util' + + +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0): carousel.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + +const Carousel = (($) => { + + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME = 'carousel' + const VERSION = '4.0.0' + const DATA_KEY = 'bs.carousel' + const JQUERY_NO_CONFLICT = $.fn[NAME] + const TRANSITION_DURATION = 600 + + const Defaults = { + interval : 5000, + keyboard : true, + slide : false, + pause : 'hover', + wrap : true + } + + const Direction = { + NEXT : 'next', + PREVIOUS : 'prev' + } + + const Event = { + SLIDE : 'slide.bs.carousel', + SLID : 'slid.bs.carousel', + CLICK : 'click.bs.carousel.data-api', + LOAD : 'load' + } + + const ClassName = { + CAROUSEL : 'carousel', + ACTIVE : 'active', + SLIDE : 'slide', + RIGHT : 'right', + LEFT : 'left', + ITEM : 'carousel-item' + } + + const Selector = { + ACTIVE : '.active', + ACTIVE_ITEM : '.active.carousel-item', + ITEM : '.carousel-item', + NEXT_PREV : '.next, .prev', + INDICATORS : '.carousel-indicators', + DATA_SLIDE : '[data-slide], [data-slide-to]', + DATA_RIDE : '[data-ride="carousel"]' + } + + + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Carousel { + + constructor(element, config) { + + this._items = null + this._interval = null + this._activeElement = null + + this._isPaused = false + this._isSliding = false + + this._config = config + this._element = $(element)[0] + this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0] + + this._addEventListeners() + + } + + + // public + + next() { + if (!this._isSliding) { + this._slide(Direction.NEXT) + } + } + + prev() { + if (!this._isSliding) { + this._slide(Direction.PREVIOUS) + } + } + + pause(event) { + if (!event) { + this._isPaused = true + } + + if ($(this._element).find(Selector.NEXT_PREV)[0] && + Util.supportsTransitionEnd()) { + Util.triggerTransitionEnd(this._element) + this.cycle(true) + } + + clearInterval(this._interval) + this._interval = null + } + + cycle(event) { + if (!event) { + this._isPaused = false + } + + if (this._interval) { + clearInterval(this._interval) + this._interval = null + } + + if (this._config.interval && !this._isPaused) { + this._interval = setInterval( + this.next.bind(this), this._config.interval + ) + } + } + + to(index) { + this._activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0] + + let activeIndex = this._getItemIndex(this._activeElement) + + if (index > (this._items.length - 1) || index < 0) { + return + } + + if (this._isSliding) { + $(this._element).one(Event.SLID, () => this.to(index)) + return + } + + if (activeIndex == index) { + this.pause() + this.cycle() + return + } + + var direction = index > activeIndex ? + Direction.NEXT : + Direction.PREVIOUS + + this._slide(direction, this._items[index]) + } + + + // private + + _addEventListeners() { + if (this._config.keyboard) { + $(this._element) + .on('keydown.bs.carousel', this._keydown.bind(this)) + } + + if (this._config.pause == 'hover' && + !('ontouchstart' in document.documentElement)) { + $(this._element) + .on('mouseenter.bs.carousel', this.pause.bind(this)) + .on('mouseleave.bs.carousel', this.cycle.bind(this)) + } + } + + _keydown(event) { + event.preventDefault() + + if (/input|textarea/i.test(event.target.tagName)) return + + switch (event.which) { + case 37: this.prev(); break + case 39: this.next(); break + default: return + } + } + + _getItemIndex(element) { + this._items = $.makeArray($(element).parent().find(Selector.ITEM)) + return this._items.indexOf(element) + } + + _getItemByDirection(direction, activeElement) { + let isNextDirection = direction === Direction.NEXT + let isPrevDirection = direction === Direction.PREVIOUS + let activeIndex = this._getItemIndex(activeElement) + let lastItemIndex = (this._items.length - 1) + let isGoingToWrap = (isPrevDirection && activeIndex === 0) || + (isNextDirection && activeIndex == lastItemIndex) + + if (isGoingToWrap && !this._config.wrap) { + return activeElement + } + + let delta = direction == Direction.PREVIOUS ? -1 : 1 + let itemIndex = (activeIndex + delta) % this._items.length + + return itemIndex === -1 ? + this._items[this._items.length - 1] : this._items[itemIndex] + } + + + _triggerSlideEvent(relatedTarget, directionalClassname) { + let slideEvent = $.Event(Event.SLIDE, { + relatedTarget: relatedTarget, + direction: directionalClassname + }) + + $(this._element).trigger(slideEvent) + + return slideEvent + } + + _setActiveIndicatorElement(element) { + if (this._indicatorsElement) { + $(this._indicatorsElement) + .find(Selector.ACTIVE) + .removeClass(ClassName.ACTIVE) + + let nextIndicator = this._indicatorsElement.children[ + this._getItemIndex(element) + ] + + if (nextIndicator) { + $(nextIndicator).addClass(ClassName.ACTIVE) + } + } + } + + _slide(direction, element) { + let activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0] + let nextElement = element || activeElement && + this._getItemByDirection(direction, activeElement) + + let isCycling = !!this._interval + + let directionalClassName = direction == Direction.NEXT ? + ClassName.LEFT : + ClassName.RIGHT + + if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) { + this._isSliding = false + return + } + + let slideEvent = this._triggerSlideEvent(nextElement, directionalClassName) + if (slideEvent.isDefaultPrevented()) { + return + } + + if (!activeElement || !nextElement) { + // some weirdness is happening, so we bail + return + } + + this._isSliding = true + + if (isCycling) { + this.pause() + } + + this._setActiveIndicatorElement(nextElement) + + var slidEvent = $.Event(Event.SLID, { + relatedTarget: nextElement, + direction: directionalClassName + }) + + if (Util.supportsTransitionEnd() && + $(this._element).hasClass(ClassName.SLIDE)) { + + $(nextElement).addClass(direction) + + Util.reflow(nextElement) + + $(activeElement).addClass(directionalClassName) + $(nextElement).addClass(directionalClassName) + + $(activeElement) + .one(Util.TRANSITION_END, () => { + $(nextElement) + .removeClass(directionalClassName) + .removeClass(direction) + + $(nextElement).addClass(ClassName.ACTIVE) + + $(activeElement) + .removeClass(ClassName.ACTIVE) + .removeClass(direction) + .removeClass(directionalClassName) + + this._isSliding = false + + setTimeout(() => $(this._element).trigger(slidEvent), 0) + + }) + .emulateTransitionEnd(TRANSITION_DURATION) + + } else { + $(activeElement).removeClass(ClassName.ACTIVE) + $(nextElement).addClass(ClassName.ACTIVE) + + this._isSliding = false + $(this._element).trigger(slidEvent) + } + + if (isCycling) { + this.cycle() + } + } + + + // static + + static _jQueryInterface(config) { + return this.each(function () { + let data = $(this).data(DATA_KEY) + let _config = $.extend({}, Defaults, $(this).data()) + + if (typeof config === 'object') { + $.extend(_config, config) + } + + let action = typeof config === 'string' ? config : _config.slide + + if (!data) { + data = new Carousel(this, _config) + $(this).data(DATA_KEY, data) + } + + if (typeof config == 'number') { + data.to(config) + + } else if (action) { + data[action]() + + } else if (_config.interval) { + data.pause() + data.cycle() + } + }) + } + + static _dataApiClickHandler(event) { + let selector = Util.getSelectorFromElement(this) + + if (!selector) { + return + } + + let target = $(selector)[0] + + if (!target || !$(target).hasClass(ClassName.CAROUSEL)) { + return + } + + let config = $.extend({}, $(target).data(), $(this).data()) + + let 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, Selector.DATA_SLIDE, Carousel._dataApiClickHandler) + + $(window).on(Event.LOAD, function () { + $(Selector.DATA_RIDE).each(function () { + let $carousel = $(this) + 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 + } + + return Carousel + +})(jQuery) + +export default Carousel diff --git a/js/src/util.js b/js/src/util.js index abc548a45..c9ffbe555 100644 --- a/js/src/util.js +++ b/js/src/util.js @@ -60,7 +60,7 @@ const Util = (($) => { setTimeout(() => { if (!called) { - $(this).trigger(transition.end) + Util.triggerTransitionEnd(this) } }, duration) @@ -109,6 +109,10 @@ const Util = (($) => { new Function('bs', 'return bs')(element.offsetHeight) }, + triggerTransitionEnd(element) { + $(element).trigger(transition.end) + }, + supportsTransitionEnd() { return !!transition } diff --git a/js/tests/index.html b/js/tests/index.html index 29c84e2cc..0ba54e802 100644 --- a/js/tests/index.html +++ b/js/tests/index.html @@ -133,9 +133,9 @@ + - diff --git a/js/tests/unit/carousel.js b/js/tests/unit/carousel.js index 39d250598..a8a36ad32 100644 --- a/js/tests/unit/carousel.js +++ b/js/tests/unit/carousel.js @@ -56,13 +56,13 @@ $(function () { + '
  • ' + '' + '