carousel.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  2. 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; }; }();
  3. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4. /**
  5. * --------------------------------------------------------------------------
  6. * Bootstrap (v4.0.0-alpha.6): carousel.js
  7. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  8. * --------------------------------------------------------------------------
  9. */
  10. var Carousel = function ($) {
  11. /**
  12. * ------------------------------------------------------------------------
  13. * Constants
  14. * ------------------------------------------------------------------------
  15. */
  16. var NAME = 'carousel';
  17. var VERSION = '4.0.0-alpha.6';
  18. var DATA_KEY = 'bs.carousel';
  19. var EVENT_KEY = '.' + DATA_KEY;
  20. var DATA_API_KEY = '.data-api';
  21. var JQUERY_NO_CONFLICT = $.fn[NAME];
  22. var TRANSITION_DURATION = 600;
  23. var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key
  24. var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key
  25. var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
  26. var Default = {
  27. interval: 5000,
  28. keyboard: true,
  29. slide: false,
  30. pause: 'hover',
  31. wrap: true
  32. };
  33. var DefaultType = {
  34. interval: '(number|boolean)',
  35. keyboard: 'boolean',
  36. slide: '(boolean|string)',
  37. pause: '(string|boolean)',
  38. wrap: 'boolean'
  39. };
  40. var Direction = {
  41. NEXT: 'next',
  42. PREV: 'prev',
  43. LEFT: 'left',
  44. RIGHT: 'right'
  45. };
  46. var Event = {
  47. SLIDE: 'slide' + EVENT_KEY,
  48. SLID: 'slid' + EVENT_KEY,
  49. KEYDOWN: 'keydown' + EVENT_KEY,
  50. MOUSEENTER: 'mouseenter' + EVENT_KEY,
  51. MOUSELEAVE: 'mouseleave' + EVENT_KEY,
  52. TOUCHEND: 'touchend' + EVENT_KEY,
  53. LOAD_DATA_API: 'load' + EVENT_KEY + DATA_API_KEY,
  54. CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
  55. };
  56. var ClassName = {
  57. CAROUSEL: 'carousel',
  58. ACTIVE: 'active',
  59. SLIDE: 'slide',
  60. RIGHT: 'carousel-item-right',
  61. LEFT: 'carousel-item-left',
  62. NEXT: 'carousel-item-next',
  63. PREV: 'carousel-item-prev',
  64. ITEM: 'carousel-item'
  65. };
  66. var Selector = {
  67. ACTIVE: '.active',
  68. ACTIVE_ITEM: '.active.carousel-item',
  69. ITEM: '.carousel-item',
  70. NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
  71. INDICATORS: '.carousel-indicators',
  72. DATA_SLIDE: '[data-slide], [data-slide-to]',
  73. DATA_RIDE: '[data-ride="carousel"]'
  74. };
  75. /**
  76. * ------------------------------------------------------------------------
  77. * Class Definition
  78. * ------------------------------------------------------------------------
  79. */
  80. var Carousel = function () {
  81. function Carousel(element, config) {
  82. _classCallCheck(this, Carousel);
  83. this._items = null;
  84. this._interval = null;
  85. this._activeElement = null;
  86. this._isPaused = false;
  87. this._isSliding = false;
  88. this.touchTimeout = null;
  89. this._config = this._getConfig(config);
  90. this._element = $(element)[0];
  91. this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0];
  92. this._addEventListeners();
  93. }
  94. // getters
  95. // public
  96. Carousel.prototype.next = function next() {
  97. if (!this._isSliding) {
  98. this._slide(Direction.NEXT);
  99. }
  100. };
  101. Carousel.prototype.nextWhenVisible = function nextWhenVisible() {
  102. // Don't call next when the page isn't visible
  103. if (!document.hidden) {
  104. this.next();
  105. }
  106. };
  107. Carousel.prototype.prev = function prev() {
  108. if (!this._isSliding) {
  109. this._slide(Direction.PREV);
  110. }
  111. };
  112. Carousel.prototype.pause = function pause(event) {
  113. if (!event) {
  114. this._isPaused = true;
  115. }
  116. if ($(this._element).find(Selector.NEXT_PREV)[0] && Util.supportsTransitionEnd()) {
  117. Util.triggerTransitionEnd(this._element);
  118. this.cycle(true);
  119. }
  120. clearInterval(this._interval);
  121. this._interval = null;
  122. };
  123. Carousel.prototype.cycle = function cycle(event) {
  124. if (!event) {
  125. this._isPaused = false;
  126. }
  127. if (this._interval) {
  128. clearInterval(this._interval);
  129. this._interval = null;
  130. }
  131. if (this._config.interval && !this._isPaused) {
  132. this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
  133. }
  134. };
  135. Carousel.prototype.to = function to(index) {
  136. var _this = this;
  137. this._activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0];
  138. var activeIndex = this._getItemIndex(this._activeElement);
  139. if (index > this._items.length - 1 || index < 0) {
  140. return;
  141. }
  142. if (this._isSliding) {
  143. $(this._element).one(Event.SLID, function () {
  144. return _this.to(index);
  145. });
  146. return;
  147. }
  148. if (activeIndex === index) {
  149. this.pause();
  150. this.cycle();
  151. return;
  152. }
  153. var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;
  154. this._slide(direction, this._items[index]);
  155. };
  156. Carousel.prototype.dispose = function dispose() {
  157. $(this._element).off(EVENT_KEY);
  158. $.removeData(this._element, DATA_KEY);
  159. this._items = null;
  160. this._config = null;
  161. this._element = null;
  162. this._interval = null;
  163. this._isPaused = null;
  164. this._isSliding = null;
  165. this._activeElement = null;
  166. this._indicatorsElement = null;
  167. };
  168. // private
  169. Carousel.prototype._getConfig = function _getConfig(config) {
  170. config = $.extend({}, Default, config);
  171. Util.typeCheckConfig(NAME, config, DefaultType);
  172. return config;
  173. };
  174. Carousel.prototype._addEventListeners = function _addEventListeners() {
  175. var _this2 = this;
  176. if (this._config.keyboard) {
  177. $(this._element).on(Event.KEYDOWN, function (event) {
  178. return _this2._keydown(event);
  179. });
  180. }
  181. if (this._config.pause === 'hover') {
  182. $(this._element).on(Event.MOUSEENTER, function (event) {
  183. return _this2.pause(event);
  184. }).on(Event.MOUSELEAVE, function (event) {
  185. return _this2.cycle(event);
  186. });
  187. if ('ontouchstart' in document.documentElement) {
  188. // if it's a touch-enabled device, mouseenter/leave are fired as
  189. // part of the mouse compatibility events on first tap - the carousel
  190. // would stop cycling until user tapped out of it;
  191. // here, we listen for touchend, explicitly pause the carousel
  192. // (as if it's the second time we tap on it, mouseenter compat event
  193. // is NOT fired) and after a timeout (to allow for mouse compatibility
  194. // events to fire) we explicitly restart cycling
  195. $(this._element).on(Event.TOUCHEND, function () {
  196. _this2.pause();
  197. if (_this2.touchTimeout) {
  198. clearTimeout(_this2.touchTimeout);
  199. }
  200. _this2.touchTimeout = setTimeout(function (event) {
  201. return _this2.cycle(event);
  202. }, TOUCHEVENT_COMPAT_WAIT + _this2._config.interval);
  203. });
  204. }
  205. }
  206. };
  207. Carousel.prototype._keydown = function _keydown(event) {
  208. if (/input|textarea/i.test(event.target.tagName)) {
  209. return;
  210. }
  211. switch (event.which) {
  212. case ARROW_LEFT_KEYCODE:
  213. event.preventDefault();
  214. this.prev();
  215. break;
  216. case ARROW_RIGHT_KEYCODE:
  217. event.preventDefault();
  218. this.next();
  219. break;
  220. default:
  221. return;
  222. }
  223. };
  224. Carousel.prototype._getItemIndex = function _getItemIndex(element) {
  225. this._items = $.makeArray($(element).parent().find(Selector.ITEM));
  226. return this._items.indexOf(element);
  227. };
  228. Carousel.prototype._getItemByDirection = function _getItemByDirection(direction, activeElement) {
  229. var isNextDirection = direction === Direction.NEXT;
  230. var isPrevDirection = direction === Direction.PREV;
  231. var activeIndex = this._getItemIndex(activeElement);
  232. var lastItemIndex = this._items.length - 1;
  233. var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;
  234. if (isGoingToWrap && !this._config.wrap) {
  235. return activeElement;
  236. }
  237. var delta = direction === Direction.PREV ? -1 : 1;
  238. var itemIndex = (activeIndex + delta) % this._items.length;
  239. return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];
  240. };
  241. Carousel.prototype._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {
  242. var targetIndex = this._getItemIndex(relatedTarget);
  243. var fromIndex = this._getItemIndex($(this._element).find(Selector.ACTIVE_ITEM)[0]);
  244. var slideEvent = $.Event(Event.SLIDE, {
  245. relatedTarget: relatedTarget,
  246. direction: eventDirectionName,
  247. from: fromIndex,
  248. to: targetIndex
  249. });
  250. $(this._element).trigger(slideEvent);
  251. return slideEvent;
  252. };
  253. Carousel.prototype._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {
  254. if (this._indicatorsElement) {
  255. $(this._indicatorsElement).find(Selector.ACTIVE).removeClass(ClassName.ACTIVE);
  256. var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];
  257. if (nextIndicator) {
  258. $(nextIndicator).addClass(ClassName.ACTIVE);
  259. }
  260. }
  261. };
  262. Carousel.prototype._slide = function _slide(direction, element) {
  263. var _this3 = this;
  264. var activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0];
  265. var activeElementIndex = this._getItemIndex(activeElement);
  266. var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);
  267. var nextElementIndex = this._getItemIndex(nextElement);
  268. var isCycling = Boolean(this._interval);
  269. var directionalClassName = void 0;
  270. var orderClassName = void 0;
  271. var eventDirectionName = void 0;
  272. if (direction === Direction.NEXT) {
  273. directionalClassName = ClassName.LEFT;
  274. orderClassName = ClassName.NEXT;
  275. eventDirectionName = Direction.LEFT;
  276. } else {
  277. directionalClassName = ClassName.RIGHT;
  278. orderClassName = ClassName.PREV;
  279. eventDirectionName = Direction.RIGHT;
  280. }
  281. if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) {
  282. this._isSliding = false;
  283. return;
  284. }
  285. var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);
  286. if (slideEvent.isDefaultPrevented()) {
  287. return;
  288. }
  289. if (!activeElement || !nextElement) {
  290. // some weirdness is happening, so we bail
  291. return;
  292. }
  293. this._isSliding = true;
  294. if (isCycling) {
  295. this.pause();
  296. }
  297. this._setActiveIndicatorElement(nextElement);
  298. var slidEvent = $.Event(Event.SLID, {
  299. relatedTarget: nextElement,
  300. direction: eventDirectionName,
  301. from: activeElementIndex,
  302. to: nextElementIndex
  303. });
  304. if (Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.SLIDE)) {
  305. $(nextElement).addClass(orderClassName);
  306. Util.reflow(nextElement);
  307. $(activeElement).addClass(directionalClassName);
  308. $(nextElement).addClass(directionalClassName);
  309. $(activeElement).one(Util.TRANSITION_END, function () {
  310. $(nextElement).removeClass(directionalClassName + ' ' + orderClassName).addClass(ClassName.ACTIVE);
  311. $(activeElement).removeClass(ClassName.ACTIVE + ' ' + orderClassName + ' ' + directionalClassName);
  312. _this3._isSliding = false;
  313. setTimeout(function () {
  314. return $(_this3._element).trigger(slidEvent);
  315. }, 0);
  316. }).emulateTransitionEnd(TRANSITION_DURATION);
  317. } else {
  318. $(activeElement).removeClass(ClassName.ACTIVE);
  319. $(nextElement).addClass(ClassName.ACTIVE);
  320. this._isSliding = false;
  321. $(this._element).trigger(slidEvent);
  322. }
  323. if (isCycling) {
  324. this.cycle();
  325. }
  326. };
  327. // static
  328. Carousel._jQueryInterface = function _jQueryInterface(config) {
  329. return this.each(function () {
  330. var data = $(this).data(DATA_KEY);
  331. var _config = $.extend({}, Default, $(this).data());
  332. if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
  333. $.extend(_config, config);
  334. }
  335. var action = typeof config === 'string' ? config : _config.slide;
  336. if (!data) {
  337. data = new Carousel(this, _config);
  338. $(this).data(DATA_KEY, data);
  339. }
  340. if (typeof config === 'number') {
  341. data.to(config);
  342. } else if (typeof action === 'string') {
  343. if (data[action] === undefined) {
  344. throw new Error('No method named "' + action + '"');
  345. }
  346. data[action]();
  347. } else if (_config.interval) {
  348. data.pause();
  349. data.cycle();
  350. }
  351. });
  352. };
  353. Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {
  354. var selector = Util.getSelectorFromElement(this);
  355. if (!selector) {
  356. return;
  357. }
  358. var target = $(selector)[0];
  359. if (!target || !$(target).hasClass(ClassName.CAROUSEL)) {
  360. return;
  361. }
  362. var config = $.extend({}, $(target).data(), $(this).data());
  363. var slideIndex = this.getAttribute('data-slide-to');
  364. if (slideIndex) {
  365. config.interval = false;
  366. }
  367. Carousel._jQueryInterface.call($(target), config);
  368. if (slideIndex) {
  369. $(target).data(DATA_KEY).to(slideIndex);
  370. }
  371. event.preventDefault();
  372. };
  373. _createClass(Carousel, null, [{
  374. key: 'VERSION',
  375. get: function get() {
  376. return VERSION;
  377. }
  378. }, {
  379. key: 'Default',
  380. get: function get() {
  381. return Default;
  382. }
  383. }]);
  384. return Carousel;
  385. }();
  386. /**
  387. * ------------------------------------------------------------------------
  388. * Data Api implementation
  389. * ------------------------------------------------------------------------
  390. */
  391. $(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler);
  392. $(window).on(Event.LOAD_DATA_API, function () {
  393. $(Selector.DATA_RIDE).each(function () {
  394. var $carousel = $(this);
  395. Carousel._jQueryInterface.call($carousel, $carousel.data());
  396. });
  397. });
  398. /**
  399. * ------------------------------------------------------------------------
  400. * jQuery
  401. * ------------------------------------------------------------------------
  402. */
  403. $.fn[NAME] = Carousel._jQueryInterface;
  404. $.fn[NAME].Constructor = Carousel;
  405. $.fn[NAME].noConflict = function () {
  406. $.fn[NAME] = JQUERY_NO_CONFLICT;
  407. return Carousel._jQueryInterface;
  408. };
  409. return Carousel;
  410. }(jQuery);
  411. //# sourceMappingURL=carousel.js.map