bootstrap 5.1.3 → 5.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +61 -0
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +1 -0
  5. data/README.md +35 -14
  6. data/Rakefile +16 -5
  7. data/assets/javascripts/bootstrap/alert.js +22 -167
  8. data/assets/javascripts/bootstrap/base-component.js +34 -133
  9. data/assets/javascripts/bootstrap/button.js +19 -86
  10. data/assets/javascripts/bootstrap/carousel.js +209 -564
  11. data/assets/javascripts/bootstrap/collapse.js +78 -324
  12. data/assets/javascripts/bootstrap/dom/data.js +8 -14
  13. data/assets/javascripts/bootstrap/dom/event-handler.js +89 -174
  14. data/assets/javascripts/bootstrap/dom/manipulator.js +22 -39
  15. data/assets/javascripts/bootstrap/dom/selector-engine.js +47 -71
  16. data/assets/javascripts/bootstrap/dropdown.js +135 -420
  17. data/assets/javascripts/bootstrap/modal.js +115 -837
  18. data/assets/javascripts/bootstrap/offcanvas.js +93 -714
  19. data/assets/javascripts/bootstrap/popover.js +42 -130
  20. data/assets/javascripts/bootstrap/scrollspy.js +180 -296
  21. data/assets/javascripts/bootstrap/tab.js +197 -245
  22. data/assets/javascripts/bootstrap/toast.js +52 -276
  23. data/assets/javascripts/bootstrap/tooltip.js +283 -744
  24. data/assets/javascripts/bootstrap/util/backdrop.js +138 -0
  25. data/assets/javascripts/bootstrap/util/component-functions.js +41 -0
  26. data/assets/javascripts/bootstrap/util/config.js +67 -0
  27. data/assets/javascripts/bootstrap/util/focustrap.js +112 -0
  28. data/assets/javascripts/bootstrap/util/index.js +280 -0
  29. data/assets/javascripts/bootstrap/util/sanitizer.js +113 -0
  30. data/assets/javascripts/bootstrap/util/scrollbar.js +112 -0
  31. data/assets/javascripts/bootstrap/util/swipe.js +134 -0
  32. data/assets/javascripts/bootstrap/util/template-factory.js +150 -0
  33. data/assets/javascripts/bootstrap-global-this-define.js +1 -1
  34. data/assets/javascripts/bootstrap-sprockets.js +15 -6
  35. data/assets/javascripts/bootstrap.js +2278 -2831
  36. data/assets/javascripts/bootstrap.min.js +3 -3
  37. data/assets/stylesheets/_bootstrap-grid.scss +4 -9
  38. data/assets/stylesheets/_bootstrap-reboot.scss +4 -7
  39. data/assets/stylesheets/_bootstrap-utilities.scss +19 -0
  40. data/assets/stylesheets/_bootstrap.scss +5 -6
  41. data/assets/stylesheets/bootstrap/_accordion.scss +68 -33
  42. data/assets/stylesheets/bootstrap/_alert.scss +25 -14
  43. data/assets/stylesheets/bootstrap/_badge.scss +14 -5
  44. data/assets/stylesheets/bootstrap/_breadcrumb.scss +22 -10
  45. data/assets/stylesheets/bootstrap/_button-group.scss +12 -4
  46. data/assets/stylesheets/bootstrap/_buttons.scss +133 -28
  47. data/assets/stylesheets/bootstrap/_card.scss +61 -39
  48. data/assets/stylesheets/bootstrap/_carousel.scss +22 -25
  49. data/assets/stylesheets/bootstrap/_close.scss +36 -10
  50. data/assets/stylesheets/bootstrap/_containers.scss +1 -1
  51. data/assets/stylesheets/bootstrap/_dropdown.scss +86 -76
  52. data/assets/stylesheets/bootstrap/_functions.scss +10 -10
  53. data/assets/stylesheets/bootstrap/_grid.scss +9 -3
  54. data/assets/stylesheets/bootstrap/_helpers.scss +3 -0
  55. data/assets/stylesheets/bootstrap/_list-group.scss +81 -56
  56. data/assets/stylesheets/bootstrap/_maps.scss +174 -0
  57. data/assets/stylesheets/bootstrap/_mixins.scss +1 -2
  58. data/assets/stylesheets/bootstrap/_modal.scss +76 -45
  59. data/assets/stylesheets/bootstrap/_nav.scss +87 -29
  60. data/assets/stylesheets/bootstrap/_navbar.scss +102 -148
  61. data/assets/stylesheets/bootstrap/_offcanvas.scss +125 -61
  62. data/assets/stylesheets/bootstrap/_pagination.scss +66 -21
  63. data/assets/stylesheets/bootstrap/_placeholders.scss +1 -1
  64. data/assets/stylesheets/bootstrap/_popover.scss +90 -52
  65. data/assets/stylesheets/bootstrap/_progress.scss +31 -11
  66. data/assets/stylesheets/bootstrap/_reboot.scss +32 -46
  67. data/assets/stylesheets/bootstrap/_root.scss +155 -22
  68. data/assets/stylesheets/bootstrap/_spinners.scss +38 -22
  69. data/assets/stylesheets/bootstrap/_tables.scss +40 -24
  70. data/assets/stylesheets/bootstrap/_toasts.scss +38 -16
  71. data/assets/stylesheets/bootstrap/_tooltip.scss +60 -56
  72. data/assets/stylesheets/bootstrap/_type.scss +3 -1
  73. data/assets/stylesheets/bootstrap/_utilities.scss +209 -33
  74. data/assets/stylesheets/bootstrap/_variables-dark.scss +102 -0
  75. data/assets/stylesheets/bootstrap/_variables.scss +415 -303
  76. data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +39 -5
  77. data/assets/stylesheets/bootstrap/forms/_form-check.scss +51 -14
  78. data/assets/stylesheets/bootstrap/forms/_form-control.scss +36 -41
  79. data/assets/stylesheets/bootstrap/forms/_form-range.scss +3 -3
  80. data/assets/stylesheets/bootstrap/forms/_form-select.scss +12 -4
  81. data/assets/stylesheets/bootstrap/forms/_input-group.scss +20 -9
  82. data/assets/stylesheets/bootstrap/helpers/_color-bg.scss +7 -0
  83. data/assets/stylesheets/bootstrap/helpers/_colored-links.scss +20 -2
  84. data/assets/stylesheets/bootstrap/helpers/_focus-ring.scss +5 -0
  85. data/assets/stylesheets/bootstrap/helpers/_icon-link.scss +25 -0
  86. data/assets/stylesheets/bootstrap/helpers/_position.scss +7 -1
  87. data/assets/stylesheets/bootstrap/helpers/_ratio.scss +2 -2
  88. data/assets/stylesheets/bootstrap/helpers/_vr.scss +2 -2
  89. data/assets/stylesheets/bootstrap/mixins/_alert.scss +11 -4
  90. data/assets/stylesheets/bootstrap/mixins/_banner.scss +7 -0
  91. data/assets/stylesheets/bootstrap/mixins/_breakpoints.scss +8 -8
  92. data/assets/stylesheets/bootstrap/mixins/_buttons.scss +32 -95
  93. data/assets/stylesheets/bootstrap/mixins/_caret.scss +30 -25
  94. data/assets/stylesheets/bootstrap/mixins/_color-mode.scss +21 -0
  95. data/assets/stylesheets/bootstrap/mixins/_container.scss +4 -2
  96. data/assets/stylesheets/bootstrap/mixins/_forms.scss +38 -19
  97. data/assets/stylesheets/bootstrap/mixins/_gradients.scss +1 -1
  98. data/assets/stylesheets/bootstrap/mixins/_grid.scss +15 -15
  99. data/assets/stylesheets/bootstrap/mixins/_list-group.scss +2 -0
  100. data/assets/stylesheets/bootstrap/mixins/_pagination.scss +4 -25
  101. data/assets/stylesheets/bootstrap/mixins/_reset-text.scss +1 -1
  102. data/assets/stylesheets/bootstrap/mixins/_table-variants.scss +12 -9
  103. data/assets/stylesheets/bootstrap/mixins/_utilities.scss +14 -6
  104. data/assets/stylesheets/bootstrap/mixins/_visually-hidden.scss +6 -2
  105. data/assets/stylesheets/bootstrap/vendor/_rfs.scss +23 -29
  106. data/bootstrap.gemspec +3 -3
  107. data/lib/bootstrap/engine.rb +17 -2
  108. data/lib/bootstrap/version.rb +2 -2
  109. data/tasks/updater/js.rb +10 -5
  110. data/tasks/updater/network.rb +2 -2
  111. data/tasks/updater/scss.rb +2 -2
  112. data/tasks/updater.rb +2 -2
  113. data/test/dummy_rails/config/application.rb +0 -2
  114. data/test/dummy_rails/public/favicon.ico +0 -0
  115. data/test/gemfiles/rails_4_2.gemfile +2 -1
  116. data/test/gemfiles/rails_5_0.gemfile +1 -2
  117. data/test/gemfiles/rails_5_1.gemfile +1 -2
  118. data/test/gemfiles/rails_5_2.gemfile +7 -0
  119. data/test/gemfiles/rails_6_0.gemfile +1 -1
  120. data/test/gemfiles/rails_6_1.gemfile +1 -1
  121. data/test/gemfiles/rails_7_0_dartsass.gemfile +7 -0
  122. data/test/gemfiles/rails_7_0_sassc.gemfile +7 -0
  123. data/test/rails_test.rb +0 -5
  124. data/test/test_helper.rb +3 -2
  125. metadata +49 -29
  126. data/.travis.yml +0 -32
  127. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +0 -18
@@ -1,203 +1,24 @@
1
1
  /*!
2
- * Bootstrap carousel.js v5.1.3 (https://getbootstrap.com/)
3
- * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap carousel.js v5.3.5 (https://getbootstrap.com/)
3
+ * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4
4
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
5
  */
6
6
  (function (global, factory) {
7
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
8
- typeof define === 'function' && define.amd ? define(['./dom/event-handler', './dom/manipulator', './dom/selector-engine', './base-component'], factory) :
9
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Carousel = factory(global.EventHandler, global.Manipulator, global.SelectorEngine, global.Base));
10
- })(this, (function (EventHandler, Manipulator, SelectorEngine, BaseComponent) { 'use strict';
11
-
12
- const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
13
-
14
- const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
15
- const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
16
- const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
17
- const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./util/index.js'), require('./util/swipe.js')) :
8
+ typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './util/index', './util/swipe'], factory) :
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Carousel = factory(global.BaseComponent, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Index, global.Swipe));
10
+ })(this, (function (BaseComponent, EventHandler, Manipulator, SelectorEngine, index_js, Swipe) { 'use strict';
18
11
 
19
12
  /**
20
13
  * --------------------------------------------------------------------------
21
- * Bootstrap (v5.1.3): util/index.js
14
+ * Bootstrap carousel.js
22
15
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
23
16
  * --------------------------------------------------------------------------
24
17
  */
25
- const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
26
-
27
- const toType = obj => {
28
- if (obj === null || obj === undefined) {
29
- return `${obj}`;
30
- }
31
-
32
- return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
33
- };
34
-
35
- const getSelector = element => {
36
- let selector = element.getAttribute('data-bs-target');
37
-
38
- if (!selector || selector === '#') {
39
- let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
40
- // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
41
- // `document.querySelector` will rightfully complain it is invalid.
42
- // See https://github.com/twbs/bootstrap/issues/32273
43
-
44
- if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
45
- return null;
46
- } // Just in case some CMS puts out a full URL with the anchor appended
47
-
48
-
49
- if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
50
- hrefAttr = `#${hrefAttr.split('#')[1]}`;
51
- }
52
-
53
- selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
54
- }
55
-
56
- return selector;
57
- };
58
-
59
- const getElementFromSelector = element => {
60
- const selector = getSelector(element);
61
- return selector ? document.querySelector(selector) : null;
62
- };
63
-
64
- const triggerTransitionEnd = element => {
65
- element.dispatchEvent(new Event(TRANSITION_END));
66
- };
67
-
68
- const isElement = obj => {
69
- if (!obj || typeof obj !== 'object') {
70
- return false;
71
- }
72
-
73
- if (typeof obj.jquery !== 'undefined') {
74
- obj = obj[0];
75
- }
76
-
77
- return typeof obj.nodeType !== 'undefined';
78
- };
79
-
80
- const typeCheckConfig = (componentName, config, configTypes) => {
81
- Object.keys(configTypes).forEach(property => {
82
- const expectedTypes = configTypes[property];
83
- const value = config[property];
84
- const valueType = value && isElement(value) ? 'element' : toType(value);
85
-
86
- if (!new RegExp(expectedTypes).test(valueType)) {
87
- throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
88
- }
89
- });
90
- };
91
-
92
- const isVisible = element => {
93
- if (!isElement(element) || element.getClientRects().length === 0) {
94
- return false;
95
- }
96
-
97
- return getComputedStyle(element).getPropertyValue('visibility') === 'visible';
98
- };
99
- /**
100
- * Trick to restart an element's animation
101
- *
102
- * @param {HTMLElement} element
103
- * @return void
104
- *
105
- * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
106
- */
107
-
108
-
109
- const reflow = element => {
110
- // eslint-disable-next-line no-unused-expressions
111
- element.offsetHeight;
112
- };
113
-
114
- const getjQuery = () => {
115
- const {
116
- jQuery
117
- } = window;
118
-
119
- if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
120
- return jQuery;
121
- }
122
-
123
- return null;
124
- };
125
-
126
- const DOMContentLoadedCallbacks = [];
127
-
128
- const onDOMContentLoaded = callback => {
129
- if (document.readyState === 'loading') {
130
- // add listener on the first call when the document is in loading state
131
- if (!DOMContentLoadedCallbacks.length) {
132
- document.addEventListener('DOMContentLoaded', () => {
133
- DOMContentLoadedCallbacks.forEach(callback => callback());
134
- });
135
- }
136
-
137
- DOMContentLoadedCallbacks.push(callback);
138
- } else {
139
- callback();
140
- }
141
- };
142
-
143
- const isRTL = () => document.documentElement.dir === 'rtl';
144
-
145
- const defineJQueryPlugin = plugin => {
146
- onDOMContentLoaded(() => {
147
- const $ = getjQuery();
148
- /* istanbul ignore if */
149
-
150
- if ($) {
151
- const name = plugin.NAME;
152
- const JQUERY_NO_CONFLICT = $.fn[name];
153
- $.fn[name] = plugin.jQueryInterface;
154
- $.fn[name].Constructor = plugin;
155
-
156
- $.fn[name].noConflict = () => {
157
- $.fn[name] = JQUERY_NO_CONFLICT;
158
- return plugin.jQueryInterface;
159
- };
160
- }
161
- });
162
- };
163
- /**
164
- * Return the previous/next element of a list.
165
- *
166
- * @param {array} list The list of elements
167
- * @param activeElement The active element
168
- * @param shouldGetNext Choose to get next or previous element
169
- * @param isCycleAllowed
170
- * @return {Element|elem} The proper element
171
- */
172
-
173
-
174
- const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
175
- let index = list.indexOf(activeElement); // if the element does not exist in the list return an element depending on the direction and if cycle is allowed
176
-
177
- if (index === -1) {
178
- return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0];
179
- }
180
-
181
- const listLength = list.length;
182
- index += shouldGetNext ? 1 : -1;
183
-
184
- if (isCycleAllowed) {
185
- index = (index + listLength) % listLength;
186
- }
187
18
 
188
- return list[Math.max(0, Math.min(index, listLength - 1))];
189
- };
190
19
 
191
20
  /**
192
- * --------------------------------------------------------------------------
193
- * Bootstrap (v5.1.3): carousel.js
194
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
195
- * --------------------------------------------------------------------------
196
- */
197
- /**
198
- * ------------------------------------------------------------------------
199
21
  * Constants
200
- * ------------------------------------------------------------------------
201
22
  */
202
23
 
203
24
  const NAME = 'carousel';
@@ -208,41 +29,15 @@
208
29
  const ARROW_RIGHT_KEY = 'ArrowRight';
209
30
  const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
210
31
 
211
- const SWIPE_THRESHOLD = 40;
212
- const Default = {
213
- interval: 5000,
214
- keyboard: true,
215
- slide: false,
216
- pause: 'hover',
217
- wrap: true,
218
- touch: true
219
- };
220
- const DefaultType = {
221
- interval: '(number|boolean)',
222
- keyboard: 'boolean',
223
- slide: '(boolean|string)',
224
- pause: '(string|boolean)',
225
- wrap: 'boolean',
226
- touch: 'boolean'
227
- };
228
32
  const ORDER_NEXT = 'next';
229
33
  const ORDER_PREV = 'prev';
230
34
  const DIRECTION_LEFT = 'left';
231
35
  const DIRECTION_RIGHT = 'right';
232
- const KEY_TO_DIRECTION = {
233
- [ARROW_LEFT_KEY]: DIRECTION_RIGHT,
234
- [ARROW_RIGHT_KEY]: DIRECTION_LEFT
235
- };
236
36
  const EVENT_SLIDE = `slide${EVENT_KEY}`;
237
37
  const EVENT_SLID = `slid${EVENT_KEY}`;
238
38
  const EVENT_KEYDOWN = `keydown${EVENT_KEY}`;
239
39
  const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`;
240
40
  const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`;
241
- const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`;
242
- const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`;
243
- const EVENT_TOUCHEND = `touchend${EVENT_KEY}`;
244
- const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`;
245
- const EVENT_POINTERUP = `pointerup${EVENT_KEY}`;
246
41
  const EVENT_DRAG_START = `dragstart${EVENT_KEY}`;
247
42
  const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
248
43
  const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
@@ -253,489 +48,339 @@
253
48
  const CLASS_NAME_START = 'carousel-item-start';
254
49
  const CLASS_NAME_NEXT = 'carousel-item-next';
255
50
  const CLASS_NAME_PREV = 'carousel-item-prev';
256
- const CLASS_NAME_POINTER_EVENT = 'pointer-event';
257
51
  const SELECTOR_ACTIVE = '.active';
258
- const SELECTOR_ACTIVE_ITEM = '.active.carousel-item';
259
52
  const SELECTOR_ITEM = '.carousel-item';
53
+ const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;
260
54
  const SELECTOR_ITEM_IMG = '.carousel-item img';
261
- const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev';
262
55
  const SELECTOR_INDICATORS = '.carousel-indicators';
263
- const SELECTOR_INDICATOR = '[data-bs-target]';
264
56
  const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';
265
57
  const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]';
266
- const POINTER_TYPE_TOUCH = 'touch';
267
- const POINTER_TYPE_PEN = 'pen';
58
+ const KEY_TO_DIRECTION = {
59
+ [ARROW_LEFT_KEY]: DIRECTION_RIGHT,
60
+ [ARROW_RIGHT_KEY]: DIRECTION_LEFT
61
+ };
62
+ const Default = {
63
+ interval: 5000,
64
+ keyboard: true,
65
+ pause: 'hover',
66
+ ride: false,
67
+ touch: true,
68
+ wrap: true
69
+ };
70
+ const DefaultType = {
71
+ interval: '(number|boolean)',
72
+ // TODO:v6 remove boolean support
73
+ keyboard: 'boolean',
74
+ pause: '(string|boolean)',
75
+ ride: '(boolean|string)',
76
+ touch: 'boolean',
77
+ wrap: 'boolean'
78
+ };
79
+
268
80
  /**
269
- * ------------------------------------------------------------------------
270
- * Class Definition
271
- * ------------------------------------------------------------------------
81
+ * Class definition
272
82
  */
273
83
 
274
- class Carousel extends BaseComponent__default.default {
84
+ class Carousel extends BaseComponent {
275
85
  constructor(element, config) {
276
- super(element);
277
- this._items = null;
86
+ super(element, config);
278
87
  this._interval = null;
279
88
  this._activeElement = null;
280
- this._isPaused = false;
281
89
  this._isSliding = false;
282
90
  this.touchTimeout = null;
283
- this.touchStartX = 0;
284
- this.touchDeltaX = 0;
285
- this._config = this._getConfig(config);
286
- this._indicatorsElement = SelectorEngine__default.default.findOne(SELECTOR_INDICATORS, this._element);
287
- this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
288
- this._pointerEvent = Boolean(window.PointerEvent);
289
-
91
+ this._swipeHelper = null;
92
+ this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);
290
93
  this._addEventListeners();
291
- } // Getters
292
-
94
+ if (this._config.ride === CLASS_NAME_CAROUSEL) {
95
+ this.cycle();
96
+ }
97
+ }
293
98
 
99
+ // Getters
294
100
  static get Default() {
295
101
  return Default;
296
102
  }
297
-
103
+ static get DefaultType() {
104
+ return DefaultType;
105
+ }
298
106
  static get NAME() {
299
107
  return NAME;
300
- } // Public
301
-
108
+ }
302
109
 
110
+ // Public
303
111
  next() {
304
112
  this._slide(ORDER_NEXT);
305
113
  }
306
-
307
114
  nextWhenVisible() {
115
+ // FIXME TODO use `document.visibilityState`
308
116
  // Don't call next when the page isn't visible
309
117
  // or the carousel or its parent isn't visible
310
- if (!document.hidden && isVisible(this._element)) {
118
+ if (!document.hidden && index_js.isVisible(this._element)) {
311
119
  this.next();
312
120
  }
313
121
  }
314
-
315
122
  prev() {
316
123
  this._slide(ORDER_PREV);
317
124
  }
318
-
319
- pause(event) {
320
- if (!event) {
321
- this._isPaused = true;
322
- }
323
-
324
- if (SelectorEngine__default.default.findOne(SELECTOR_NEXT_PREV, this._element)) {
325
- triggerTransitionEnd(this._element);
326
- this.cycle(true);
125
+ pause() {
126
+ if (this._isSliding) {
127
+ index_js.triggerTransitionEnd(this._element);
327
128
  }
328
-
329
- clearInterval(this._interval);
330
- this._interval = null;
129
+ this._clearInterval();
331
130
  }
332
-
333
- cycle(event) {
334
- if (!event) {
335
- this._isPaused = false;
336
- }
337
-
338
- if (this._interval) {
339
- clearInterval(this._interval);
340
- this._interval = null;
131
+ cycle() {
132
+ this._clearInterval();
133
+ this._updateInterval();
134
+ this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);
135
+ }
136
+ _maybeEnableCycle() {
137
+ if (!this._config.ride) {
138
+ return;
341
139
  }
342
-
343
- if (this._config && this._config.interval && !this._isPaused) {
344
- this._updateInterval();
345
-
346
- this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
140
+ if (this._isSliding) {
141
+ EventHandler.one(this._element, EVENT_SLID, () => this.cycle());
142
+ return;
347
143
  }
144
+ this.cycle();
348
145
  }
349
-
350
146
  to(index) {
351
- this._activeElement = SelectorEngine__default.default.findOne(SELECTOR_ACTIVE_ITEM, this._element);
352
-
353
- const activeIndex = this._getItemIndex(this._activeElement);
354
-
355
- if (index > this._items.length - 1 || index < 0) {
147
+ const items = this._getItems();
148
+ if (index > items.length - 1 || index < 0) {
356
149
  return;
357
150
  }
358
-
359
151
  if (this._isSliding) {
360
- EventHandler__default.default.one(this._element, EVENT_SLID, () => this.to(index));
152
+ EventHandler.one(this._element, EVENT_SLID, () => this.to(index));
361
153
  return;
362
154
  }
363
-
155
+ const activeIndex = this._getItemIndex(this._getActive());
364
156
  if (activeIndex === index) {
365
- this.pause();
366
- this.cycle();
367
157
  return;
368
158
  }
369
-
370
159
  const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;
371
-
372
- this._slide(order, this._items[index]);
373
- } // Private
374
-
375
-
376
- _getConfig(config) {
377
- config = { ...Default,
378
- ...Manipulator__default.default.getDataAttributes(this._element),
379
- ...(typeof config === 'object' ? config : {})
380
- };
381
- typeCheckConfig(NAME, config, DefaultType);
382
- return config;
160
+ this._slide(order, items[index]);
383
161
  }
384
-
385
- _handleSwipe() {
386
- const absDeltax = Math.abs(this.touchDeltaX);
387
-
388
- if (absDeltax <= SWIPE_THRESHOLD) {
389
- return;
162
+ dispose() {
163
+ if (this._swipeHelper) {
164
+ this._swipeHelper.dispose();
390
165
  }
391
-
392
- const direction = absDeltax / this.touchDeltaX;
393
- this.touchDeltaX = 0;
394
-
395
- if (!direction) {
396
- return;
397
- }
398
-
399
- this._slide(direction > 0 ? DIRECTION_RIGHT : DIRECTION_LEFT);
166
+ super.dispose();
400
167
  }
401
168
 
169
+ // Private
170
+ _configAfterMerge(config) {
171
+ config.defaultInterval = config.interval;
172
+ return config;
173
+ }
402
174
  _addEventListeners() {
403
175
  if (this._config.keyboard) {
404
- EventHandler__default.default.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
176
+ EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
405
177
  }
406
-
407
178
  if (this._config.pause === 'hover') {
408
- EventHandler__default.default.on(this._element, EVENT_MOUSEENTER, event => this.pause(event));
409
- EventHandler__default.default.on(this._element, EVENT_MOUSELEAVE, event => this.cycle(event));
179
+ EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause());
180
+ EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle());
410
181
  }
411
-
412
- if (this._config.touch && this._touchSupported) {
182
+ if (this._config.touch && Swipe.isSupported()) {
413
183
  this._addTouchEventListeners();
414
184
  }
415
185
  }
416
-
417
186
  _addTouchEventListeners() {
418
- const hasPointerPenTouch = event => {
419
- return this._pointerEvent && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);
420
- };
421
-
422
- const start = event => {
423
- if (hasPointerPenTouch(event)) {
424
- this.touchStartX = event.clientX;
425
- } else if (!this._pointerEvent) {
426
- this.touchStartX = event.touches[0].clientX;
427
- }
428
- };
429
-
430
- const move = event => {
431
- // ensure swiping with one touch and not pinching
432
- this.touchDeltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this.touchStartX;
433
- };
434
-
435
- const end = event => {
436
- if (hasPointerPenTouch(event)) {
437
- this.touchDeltaX = event.clientX - this.touchStartX;
187
+ for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {
188
+ EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault());
189
+ }
190
+ const endCallBack = () => {
191
+ if (this._config.pause !== 'hover') {
192
+ return;
438
193
  }
439
194
 
440
- this._handleSwipe();
441
-
442
- if (this._config.pause === 'hover') {
443
- // If it's a touch-enabled device, mouseenter/leave are fired as
444
- // part of the mouse compatibility events on first tap - the carousel
445
- // would stop cycling until user tapped out of it;
446
- // here, we listen for touchend, explicitly pause the carousel
447
- // (as if it's the second time we tap on it, mouseenter compat event
448
- // is NOT fired) and after a timeout (to allow for mouse compatibility
449
- // events to fire) we explicitly restart cycling
450
- this.pause();
451
-
452
- if (this.touchTimeout) {
453
- clearTimeout(this.touchTimeout);
454
- }
195
+ // If it's a touch-enabled device, mouseenter/leave are fired as
196
+ // part of the mouse compatibility events on first tap - the carousel
197
+ // would stop cycling until user tapped out of it;
198
+ // here, we listen for touchend, explicitly pause the carousel
199
+ // (as if it's the second time we tap on it, mouseenter compat event
200
+ // is NOT fired) and after a timeout (to allow for mouse compatibility
201
+ // events to fire) we explicitly restart cycling
455
202
 
456
- this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval);
203
+ this.pause();
204
+ if (this.touchTimeout) {
205
+ clearTimeout(this.touchTimeout);
457
206
  }
207
+ this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval);
458
208
  };
459
-
460
- SelectorEngine__default.default.find(SELECTOR_ITEM_IMG, this._element).forEach(itemImg => {
461
- EventHandler__default.default.on(itemImg, EVENT_DRAG_START, event => event.preventDefault());
462
- });
463
-
464
- if (this._pointerEvent) {
465
- EventHandler__default.default.on(this._element, EVENT_POINTERDOWN, event => start(event));
466
- EventHandler__default.default.on(this._element, EVENT_POINTERUP, event => end(event));
467
-
468
- this._element.classList.add(CLASS_NAME_POINTER_EVENT);
469
- } else {
470
- EventHandler__default.default.on(this._element, EVENT_TOUCHSTART, event => start(event));
471
- EventHandler__default.default.on(this._element, EVENT_TOUCHMOVE, event => move(event));
472
- EventHandler__default.default.on(this._element, EVENT_TOUCHEND, event => end(event));
473
- }
209
+ const swipeConfig = {
210
+ leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),
211
+ rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),
212
+ endCallback: endCallBack
213
+ };
214
+ this._swipeHelper = new Swipe(this._element, swipeConfig);
474
215
  }
475
-
476
216
  _keydown(event) {
477
217
  if (/input|textarea/i.test(event.target.tagName)) {
478
218
  return;
479
219
  }
480
-
481
220
  const direction = KEY_TO_DIRECTION[event.key];
482
-
483
221
  if (direction) {
484
222
  event.preventDefault();
485
-
486
- this._slide(direction);
223
+ this._slide(this._directionToOrder(direction));
487
224
  }
488
225
  }
489
-
490
226
  _getItemIndex(element) {
491
- this._items = element && element.parentNode ? SelectorEngine__default.default.find(SELECTOR_ITEM, element.parentNode) : [];
492
- return this._items.indexOf(element);
493
- }
494
-
495
- _getItemByOrder(order, activeElement) {
496
- const isNext = order === ORDER_NEXT;
497
- return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap);
498
- }
499
-
500
- _triggerSlideEvent(relatedTarget, eventDirectionName) {
501
- const targetIndex = this._getItemIndex(relatedTarget);
502
-
503
- const fromIndex = this._getItemIndex(SelectorEngine__default.default.findOne(SELECTOR_ACTIVE_ITEM, this._element));
504
-
505
- return EventHandler__default.default.trigger(this._element, EVENT_SLIDE, {
506
- relatedTarget,
507
- direction: eventDirectionName,
508
- from: fromIndex,
509
- to: targetIndex
510
- });
227
+ return this._getItems().indexOf(element);
511
228
  }
512
-
513
- _setActiveIndicatorElement(element) {
514
- if (this._indicatorsElement) {
515
- const activeIndicator = SelectorEngine__default.default.findOne(SELECTOR_ACTIVE, this._indicatorsElement);
516
- activeIndicator.classList.remove(CLASS_NAME_ACTIVE);
517
- activeIndicator.removeAttribute('aria-current');
518
- const indicators = SelectorEngine__default.default.find(SELECTOR_INDICATOR, this._indicatorsElement);
519
-
520
- for (let i = 0; i < indicators.length; i++) {
521
- if (Number.parseInt(indicators[i].getAttribute('data-bs-slide-to'), 10) === this._getItemIndex(element)) {
522
- indicators[i].classList.add(CLASS_NAME_ACTIVE);
523
- indicators[i].setAttribute('aria-current', 'true');
524
- break;
525
- }
526
- }
229
+ _setActiveIndicatorElement(index) {
230
+ if (!this._indicatorsElement) {
231
+ return;
232
+ }
233
+ const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);
234
+ activeIndicator.classList.remove(CLASS_NAME_ACTIVE);
235
+ activeIndicator.removeAttribute('aria-current');
236
+ const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement);
237
+ if (newActiveIndicator) {
238
+ newActiveIndicator.classList.add(CLASS_NAME_ACTIVE);
239
+ newActiveIndicator.setAttribute('aria-current', 'true');
527
240
  }
528
241
  }
529
-
530
242
  _updateInterval() {
531
- const element = this._activeElement || SelectorEngine__default.default.findOne(SELECTOR_ACTIVE_ITEM, this._element);
532
-
243
+ const element = this._activeElement || this._getActive();
533
244
  if (!element) {
534
245
  return;
535
246
  }
536
-
537
247
  const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);
538
-
539
- if (elementInterval) {
540
- this._config.defaultInterval = this._config.defaultInterval || this._config.interval;
541
- this._config.interval = elementInterval;
542
- } else {
543
- this._config.interval = this._config.defaultInterval || this._config.interval;
544
- }
248
+ this._config.interval = elementInterval || this._config.defaultInterval;
545
249
  }
546
-
547
- _slide(directionOrOrder, element) {
548
- const order = this._directionToOrder(directionOrOrder);
549
-
550
- const activeElement = SelectorEngine__default.default.findOne(SELECTOR_ACTIVE_ITEM, this._element);
551
-
552
- const activeElementIndex = this._getItemIndex(activeElement);
553
-
554
- const nextElement = element || this._getItemByOrder(order, activeElement);
555
-
556
- const nextElementIndex = this._getItemIndex(nextElement);
557
-
558
- const isCycling = Boolean(this._interval);
559
- const isNext = order === ORDER_NEXT;
560
- const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;
561
- const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;
562
-
563
- const eventDirectionName = this._orderToDirection(order);
564
-
565
- if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE)) {
566
- this._isSliding = false;
250
+ _slide(order, element = null) {
251
+ if (this._isSliding) {
567
252
  return;
568
253
  }
569
-
570
- if (this._isSliding) {
254
+ const activeElement = this._getActive();
255
+ const isNext = order === ORDER_NEXT;
256
+ const nextElement = element || index_js.getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);
257
+ if (nextElement === activeElement) {
571
258
  return;
572
259
  }
573
-
574
- const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);
575
-
260
+ const nextElementIndex = this._getItemIndex(nextElement);
261
+ const triggerEvent = eventName => {
262
+ return EventHandler.trigger(this._element, eventName, {
263
+ relatedTarget: nextElement,
264
+ direction: this._orderToDirection(order),
265
+ from: this._getItemIndex(activeElement),
266
+ to: nextElementIndex
267
+ });
268
+ };
269
+ const slideEvent = triggerEvent(EVENT_SLIDE);
576
270
  if (slideEvent.defaultPrevented) {
577
271
  return;
578
272
  }
579
-
580
273
  if (!activeElement || !nextElement) {
581
274
  // Some weirdness is happening, so we bail
275
+ // TODO: change tests that use empty divs to avoid this check
582
276
  return;
583
277
  }
584
-
278
+ const isCycling = Boolean(this._interval);
279
+ this.pause();
585
280
  this._isSliding = true;
586
-
587
- if (isCycling) {
588
- this.pause();
589
- }
590
-
591
- this._setActiveIndicatorElement(nextElement);
592
-
281
+ this._setActiveIndicatorElement(nextElementIndex);
593
282
  this._activeElement = nextElement;
594
-
595
- const triggerSlidEvent = () => {
596
- EventHandler__default.default.trigger(this._element, EVENT_SLID, {
597
- relatedTarget: nextElement,
598
- direction: eventDirectionName,
599
- from: activeElementIndex,
600
- to: nextElementIndex
601
- });
602
- };
603
-
604
- if (this._element.classList.contains(CLASS_NAME_SLIDE)) {
605
- nextElement.classList.add(orderClassName);
606
- reflow(nextElement);
607
- activeElement.classList.add(directionalClassName);
608
- nextElement.classList.add(directionalClassName);
609
-
610
- const completeCallBack = () => {
611
- nextElement.classList.remove(directionalClassName, orderClassName);
612
- nextElement.classList.add(CLASS_NAME_ACTIVE);
613
- activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName);
614
- this._isSliding = false;
615
- setTimeout(triggerSlidEvent, 0);
616
- };
617
-
618
- this._queueCallback(completeCallBack, activeElement, true);
619
- } else {
620
- activeElement.classList.remove(CLASS_NAME_ACTIVE);
283
+ const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;
284
+ const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;
285
+ nextElement.classList.add(orderClassName);
286
+ index_js.reflow(nextElement);
287
+ activeElement.classList.add(directionalClassName);
288
+ nextElement.classList.add(directionalClassName);
289
+ const completeCallBack = () => {
290
+ nextElement.classList.remove(directionalClassName, orderClassName);
621
291
  nextElement.classList.add(CLASS_NAME_ACTIVE);
292
+ activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName);
622
293
  this._isSliding = false;
623
- triggerSlidEvent();
624
- }
625
-
294
+ triggerEvent(EVENT_SLID);
295
+ };
296
+ this._queueCallback(completeCallBack, activeElement, this._isAnimated());
626
297
  if (isCycling) {
627
298
  this.cycle();
628
299
  }
629
300
  }
630
-
631
- _directionToOrder(direction) {
632
- if (![DIRECTION_RIGHT, DIRECTION_LEFT].includes(direction)) {
633
- return direction;
301
+ _isAnimated() {
302
+ return this._element.classList.contains(CLASS_NAME_SLIDE);
303
+ }
304
+ _getActive() {
305
+ return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);
306
+ }
307
+ _getItems() {
308
+ return SelectorEngine.find(SELECTOR_ITEM, this._element);
309
+ }
310
+ _clearInterval() {
311
+ if (this._interval) {
312
+ clearInterval(this._interval);
313
+ this._interval = null;
634
314
  }
635
-
636
- if (isRTL()) {
315
+ }
316
+ _directionToOrder(direction) {
317
+ if (index_js.isRTL()) {
637
318
  return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;
638
319
  }
639
-
640
320
  return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;
641
321
  }
642
-
643
322
  _orderToDirection(order) {
644
- if (![ORDER_NEXT, ORDER_PREV].includes(order)) {
645
- return order;
646
- }
647
-
648
- if (isRTL()) {
323
+ if (index_js.isRTL()) {
649
324
  return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;
650
325
  }
651
-
652
326
  return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;
653
- } // Static
654
-
655
-
656
- static carouselInterface(element, config) {
657
- const data = Carousel.getOrCreateInstance(element, config);
658
- let {
659
- _config
660
- } = data;
661
-
662
- if (typeof config === 'object') {
663
- _config = { ..._config,
664
- ...config
665
- };
666
- }
667
-
668
- const action = typeof config === 'string' ? config : _config.slide;
669
-
670
- if (typeof config === 'number') {
671
- data.to(config);
672
- } else if (typeof action === 'string') {
673
- if (typeof data[action] === 'undefined') {
674
- throw new TypeError(`No method named "${action}"`);
675
- }
676
-
677
- data[action]();
678
- } else if (_config.interval && _config.ride) {
679
- data.pause();
680
- data.cycle();
681
- }
682
327
  }
683
328
 
329
+ // Static
684
330
  static jQueryInterface(config) {
685
331
  return this.each(function () {
686
- Carousel.carouselInterface(this, config);
332
+ const data = Carousel.getOrCreateInstance(this, config);
333
+ if (typeof config === 'number') {
334
+ data.to(config);
335
+ return;
336
+ }
337
+ if (typeof config === 'string') {
338
+ if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
339
+ throw new TypeError(`No method named "${config}"`);
340
+ }
341
+ data[config]();
342
+ }
687
343
  });
688
344
  }
689
-
690
- static dataApiClickHandler(event) {
691
- const target = getElementFromSelector(this);
692
-
693
- if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
694
- return;
695
- }
696
-
697
- const config = { ...Manipulator__default.default.getDataAttributes(target),
698
- ...Manipulator__default.default.getDataAttributes(this)
699
- };
700
- const slideIndex = this.getAttribute('data-bs-slide-to');
701
-
702
- if (slideIndex) {
703
- config.interval = false;
704
- }
705
-
706
- Carousel.carouselInterface(target, config);
707
-
708
- if (slideIndex) {
709
- Carousel.getInstance(target).to(slideIndex);
710
- }
711
-
712
- event.preventDefault();
713
- }
714
-
715
345
  }
346
+
716
347
  /**
717
- * ------------------------------------------------------------------------
718
- * Data Api implementation
719
- * ------------------------------------------------------------------------
348
+ * Data API implementation
720
349
  */
721
350
 
722
-
723
- EventHandler__default.default.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler);
724
- EventHandler__default.default.on(window, EVENT_LOAD_DATA_API, () => {
725
- const carousels = SelectorEngine__default.default.find(SELECTOR_DATA_RIDE);
726
-
727
- for (let i = 0, len = carousels.length; i < len; i++) {
728
- Carousel.carouselInterface(carousels[i], Carousel.getInstance(carousels[i]));
351
+ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {
352
+ const target = SelectorEngine.getElementFromSelector(this);
353
+ if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
354
+ return;
355
+ }
356
+ event.preventDefault();
357
+ const carousel = Carousel.getOrCreateInstance(target);
358
+ const slideIndex = this.getAttribute('data-bs-slide-to');
359
+ if (slideIndex) {
360
+ carousel.to(slideIndex);
361
+ carousel._maybeEnableCycle();
362
+ return;
363
+ }
364
+ if (Manipulator.getDataAttribute(this, 'slide') === 'next') {
365
+ carousel.next();
366
+ carousel._maybeEnableCycle();
367
+ return;
368
+ }
369
+ carousel.prev();
370
+ carousel._maybeEnableCycle();
371
+ });
372
+ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
373
+ const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);
374
+ for (const carousel of carousels) {
375
+ Carousel.getOrCreateInstance(carousel);
729
376
  }
730
377
  });
378
+
731
379
  /**
732
- * ------------------------------------------------------------------------
733
380
  * jQuery
734
- * ------------------------------------------------------------------------
735
- * add .Carousel to jQuery only if jQuery is present
736
381
  */
737
382
 
738
- defineJQueryPlugin(Carousel);
383
+ index_js.defineJQueryPlugin(Carousel);
739
384
 
740
385
  return Carousel;
741
386