bootstrap 5.1.3 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -4
  3. data/assets/javascripts/bootstrap/alert.js +11 -146
  4. data/assets/javascripts/bootstrap/base-component.js +37 -120
  5. data/assets/javascripts/bootstrap/button.js +10 -74
  6. data/assets/javascripts/bootstrap/carousel.js +213 -485
  7. data/assets/javascripts/bootstrap/collapse.js +65 -249
  8. data/assets/javascripts/bootstrap/dom/data.js +3 -5
  9. data/assets/javascripts/bootstrap/dom/event-handler.js +94 -132
  10. data/assets/javascripts/bootstrap/dom/manipulator.js +23 -27
  11. data/assets/javascripts/bootstrap/dom/selector-engine.js +16 -58
  12. data/assets/javascripts/bootstrap/dropdown.js +103 -317
  13. data/assets/javascripts/bootstrap/modal.js +107 -749
  14. data/assets/javascripts/bootstrap/offcanvas.js +90 -659
  15. data/assets/javascripts/bootstrap/popover.js +36 -118
  16. data/assets/javascripts/bootstrap/scrollspy.js +183 -262
  17. data/assets/javascripts/bootstrap/tab.js +215 -214
  18. data/assets/javascripts/bootstrap/toast.js +28 -214
  19. data/assets/javascripts/bootstrap/tooltip.js +272 -611
  20. data/assets/javascripts/bootstrap/util/backdrop.js +165 -0
  21. data/assets/javascripts/bootstrap/util/component-functions.js +46 -0
  22. data/assets/javascripts/bootstrap/util/config.js +79 -0
  23. data/assets/javascripts/bootstrap/util/focustrap.js +129 -0
  24. data/assets/javascripts/bootstrap/util/index.js +350 -0
  25. data/assets/javascripts/bootstrap/util/sanitizer.js +122 -0
  26. data/assets/javascripts/bootstrap/util/scrollbar.js +138 -0
  27. data/assets/javascripts/bootstrap/util/swipe.js +155 -0
  28. data/assets/javascripts/bootstrap/util/template-factory.js +177 -0
  29. data/assets/javascripts/bootstrap-global-this-define.js +1 -1
  30. data/assets/javascripts/bootstrap-sprockets.js +10 -1
  31. data/assets/javascripts/bootstrap.js +2077 -1859
  32. data/assets/javascripts/bootstrap.min.js +3 -3
  33. data/assets/stylesheets/_bootstrap-grid.scss +3 -6
  34. data/assets/stylesheets/_bootstrap-reboot.scss +3 -7
  35. data/assets/stylesheets/_bootstrap.scss +4 -6
  36. data/assets/stylesheets/bootstrap/_accordion.scss +56 -25
  37. data/assets/stylesheets/bootstrap/_alert.scss +18 -4
  38. data/assets/stylesheets/bootstrap/_badge.scss +14 -5
  39. data/assets/stylesheets/bootstrap/_breadcrumb.scss +22 -10
  40. data/assets/stylesheets/bootstrap/_button-group.scss +4 -1
  41. data/assets/stylesheets/bootstrap/_buttons.scss +120 -30
  42. data/assets/stylesheets/bootstrap/_card.scss +55 -37
  43. data/assets/stylesheets/bootstrap/_close.scss +1 -1
  44. data/assets/stylesheets/bootstrap/_containers.scss +1 -1
  45. data/assets/stylesheets/bootstrap/_dropdown.scss +85 -76
  46. data/assets/stylesheets/bootstrap/_functions.scss +8 -8
  47. data/assets/stylesheets/bootstrap/_grid.scss +3 -3
  48. data/assets/stylesheets/bootstrap/_helpers.scss +1 -0
  49. data/assets/stylesheets/bootstrap/_list-group.scss +48 -30
  50. data/assets/stylesheets/bootstrap/_maps.scss +54 -0
  51. data/assets/stylesheets/bootstrap/_modal.scss +71 -43
  52. data/assets/stylesheets/bootstrap/_nav.scss +53 -20
  53. data/assets/stylesheets/bootstrap/_navbar.scss +93 -150
  54. data/assets/stylesheets/bootstrap/_offcanvas.scss +120 -59
  55. data/assets/stylesheets/bootstrap/_pagination.scss +66 -21
  56. data/assets/stylesheets/bootstrap/_placeholders.scss +1 -1
  57. data/assets/stylesheets/bootstrap/_popover.scss +90 -52
  58. data/assets/stylesheets/bootstrap/_progress.scss +20 -9
  59. data/assets/stylesheets/bootstrap/_reboot.scss +25 -40
  60. data/assets/stylesheets/bootstrap/_root.scss +40 -21
  61. data/assets/stylesheets/bootstrap/_spinners.scss +38 -22
  62. data/assets/stylesheets/bootstrap/_tables.scss +32 -23
  63. data/assets/stylesheets/bootstrap/_toasts.scss +36 -16
  64. data/assets/stylesheets/bootstrap/_tooltip.scss +61 -56
  65. data/assets/stylesheets/bootstrap/_type.scss +2 -0
  66. data/assets/stylesheets/bootstrap/_utilities.scss +43 -26
  67. data/assets/stylesheets/bootstrap/_variables.scss +128 -135
  68. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +3 -6
  69. data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +15 -3
  70. data/assets/stylesheets/bootstrap/forms/_form-check.scss +28 -5
  71. data/assets/stylesheets/bootstrap/forms/_form-control.scss +12 -37
  72. data/assets/stylesheets/bootstrap/forms/_form-select.scss +0 -1
  73. data/assets/stylesheets/bootstrap/forms/_input-group.scss +19 -8
  74. data/assets/stylesheets/bootstrap/helpers/_color-bg.scss +10 -0
  75. data/assets/stylesheets/bootstrap/helpers/_colored-links.scss +2 -2
  76. data/assets/stylesheets/bootstrap/helpers/_position.scss +7 -1
  77. data/assets/stylesheets/bootstrap/helpers/_ratio.scss +2 -2
  78. data/assets/stylesheets/bootstrap/helpers/_vr.scss +1 -1
  79. data/assets/stylesheets/bootstrap/mixins/_alert.scss +7 -3
  80. data/assets/stylesheets/bootstrap/mixins/_banner.scss +9 -0
  81. data/assets/stylesheets/bootstrap/mixins/_breakpoints.scss +8 -8
  82. data/assets/stylesheets/bootstrap/mixins/_buttons.scss +32 -95
  83. data/assets/stylesheets/bootstrap/mixins/_container.scss +4 -2
  84. data/assets/stylesheets/bootstrap/mixins/_forms.scss +18 -10
  85. data/assets/stylesheets/bootstrap/mixins/_gradients.scss +1 -1
  86. data/assets/stylesheets/bootstrap/mixins/_grid.scss +12 -12
  87. data/assets/stylesheets/bootstrap/mixins/_pagination.scss +4 -25
  88. data/assets/stylesheets/bootstrap/mixins/_reset-text.scss +1 -1
  89. data/assets/stylesheets/bootstrap/mixins/_table-variants.scss +12 -9
  90. data/assets/stylesheets/bootstrap/mixins/_utilities.scss +13 -5
  91. data/bootstrap.gemspec +1 -1
  92. data/lib/bootstrap/version.rb +2 -2
  93. data/tasks/updater/js.rb +10 -5
  94. metadata +16 -4
@@ -1,13 +1,13 @@
1
1
  /*!
2
- * Bootstrap tab.js v5.1.3 (https://getbootstrap.com/)
3
- * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap tab.js v5.2.1 (https://getbootstrap.com/)
3
+ * Copyright 2011-2022 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/selector-engine.js'), require('./base-component.js')) :
8
- typeof define === 'function' && define.amd ? define(['./dom/event-handler', './dom/selector-engine', './base-component'], factory) :
9
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tab = factory(global.EventHandler, global.SelectorEngine, global.Base));
10
- })(this, (function (EventHandler, SelectorEngine, BaseComponent) { 'use strict';
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./util/index'), require('./dom/event-handler'), require('./dom/selector-engine'), require('./base-component')) :
8
+ typeof define === 'function' && define.amd ? define(['./util/index', './dom/event-handler', './dom/selector-engine', './base-component'], factory) :
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tab = factory(global.Index, global.EventHandler, global.SelectorEngine, global.BaseComponent));
10
+ })(this, (function (index, EventHandler, SelectorEngine, BaseComponent) { 'use strict';
11
11
 
12
12
  const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
13
13
 
@@ -17,270 +17,266 @@
17
17
 
18
18
  /**
19
19
  * --------------------------------------------------------------------------
20
- * Bootstrap (v5.1.3): util/index.js
21
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
22
- * --------------------------------------------------------------------------
23
- */
24
-
25
- const getSelector = element => {
26
- let selector = element.getAttribute('data-bs-target');
27
-
28
- if (!selector || selector === '#') {
29
- let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
30
- // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
31
- // `document.querySelector` will rightfully complain it is invalid.
32
- // See https://github.com/twbs/bootstrap/issues/32273
33
-
34
- if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
35
- return null;
36
- } // Just in case some CMS puts out a full URL with the anchor appended
37
-
38
-
39
- if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
40
- hrefAttr = `#${hrefAttr.split('#')[1]}`;
41
- }
42
-
43
- selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
44
- }
45
-
46
- return selector;
47
- };
48
-
49
- const getElementFromSelector = element => {
50
- const selector = getSelector(element);
51
- return selector ? document.querySelector(selector) : null;
52
- };
53
-
54
- const isDisabled = element => {
55
- if (!element || element.nodeType !== Node.ELEMENT_NODE) {
56
- return true;
57
- }
58
-
59
- if (element.classList.contains('disabled')) {
60
- return true;
61
- }
62
-
63
- if (typeof element.disabled !== 'undefined') {
64
- return element.disabled;
65
- }
66
-
67
- return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
68
- };
69
- /**
70
- * Trick to restart an element's animation
71
- *
72
- * @param {HTMLElement} element
73
- * @return void
74
- *
75
- * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
76
- */
77
-
78
-
79
- const reflow = element => {
80
- // eslint-disable-next-line no-unused-expressions
81
- element.offsetHeight;
82
- };
83
-
84
- const getjQuery = () => {
85
- const {
86
- jQuery
87
- } = window;
88
-
89
- if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
90
- return jQuery;
91
- }
92
-
93
- return null;
94
- };
95
-
96
- const DOMContentLoadedCallbacks = [];
97
-
98
- const onDOMContentLoaded = callback => {
99
- if (document.readyState === 'loading') {
100
- // add listener on the first call when the document is in loading state
101
- if (!DOMContentLoadedCallbacks.length) {
102
- document.addEventListener('DOMContentLoaded', () => {
103
- DOMContentLoadedCallbacks.forEach(callback => callback());
104
- });
105
- }
106
-
107
- DOMContentLoadedCallbacks.push(callback);
108
- } else {
109
- callback();
110
- }
111
- };
112
-
113
- const defineJQueryPlugin = plugin => {
114
- onDOMContentLoaded(() => {
115
- const $ = getjQuery();
116
- /* istanbul ignore if */
117
-
118
- if ($) {
119
- const name = plugin.NAME;
120
- const JQUERY_NO_CONFLICT = $.fn[name];
121
- $.fn[name] = plugin.jQueryInterface;
122
- $.fn[name].Constructor = plugin;
123
-
124
- $.fn[name].noConflict = () => {
125
- $.fn[name] = JQUERY_NO_CONFLICT;
126
- return plugin.jQueryInterface;
127
- };
128
- }
129
- });
130
- };
131
-
132
- /**
133
- * --------------------------------------------------------------------------
134
- * Bootstrap (v5.1.3): tab.js
20
+ * Bootstrap (v5.2.1): tab.js
135
21
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
136
22
  * --------------------------------------------------------------------------
137
23
  */
138
24
  /**
139
- * ------------------------------------------------------------------------
140
25
  * Constants
141
- * ------------------------------------------------------------------------
142
26
  */
143
27
 
144
28
  const NAME = 'tab';
145
29
  const DATA_KEY = 'bs.tab';
146
30
  const EVENT_KEY = `.${DATA_KEY}`;
147
- const DATA_API_KEY = '.data-api';
148
31
  const EVENT_HIDE = `hide${EVENT_KEY}`;
149
32
  const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
150
33
  const EVENT_SHOW = `show${EVENT_KEY}`;
151
34
  const EVENT_SHOWN = `shown${EVENT_KEY}`;
152
- const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
153
- const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu';
35
+ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}`;
36
+ const EVENT_KEYDOWN = `keydown${EVENT_KEY}`;
37
+ const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`;
38
+ const ARROW_LEFT_KEY = 'ArrowLeft';
39
+ const ARROW_RIGHT_KEY = 'ArrowRight';
40
+ const ARROW_UP_KEY = 'ArrowUp';
41
+ const ARROW_DOWN_KEY = 'ArrowDown';
154
42
  const CLASS_NAME_ACTIVE = 'active';
155
43
  const CLASS_NAME_FADE = 'fade';
156
44
  const CLASS_NAME_SHOW = 'show';
157
- const SELECTOR_DROPDOWN = '.dropdown';
158
- const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
159
- const SELECTOR_ACTIVE = '.active';
160
- const SELECTOR_ACTIVE_UL = ':scope > li > .active';
161
- const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]';
45
+ const CLASS_DROPDOWN = 'dropdown';
162
46
  const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
163
- const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active';
47
+ const SELECTOR_DROPDOWN_MENU = '.dropdown-menu';
48
+ const SELECTOR_DROPDOWN_ITEM = '.dropdown-item';
49
+ const NOT_SELECTOR_DROPDOWN_TOGGLE = ':not(.dropdown-toggle)';
50
+ const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]';
51
+ const SELECTOR_OUTER = '.nav-item, .list-group-item';
52
+ const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
53
+ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // todo:v6: could be only `tab`
54
+
55
+ const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`;
56
+ const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="list"]`;
164
57
  /**
165
- * ------------------------------------------------------------------------
166
- * Class Definition
167
- * ------------------------------------------------------------------------
58
+ * Class definition
168
59
  */
169
60
 
170
61
  class Tab extends BaseComponent__default.default {
171
- // Getters
62
+ constructor(element) {
63
+ super(element);
64
+ this._parent = this._element.closest(SELECTOR_TAB_PANEL);
65
+
66
+ if (!this._parent) {
67
+ return; // todo: should Throw exception on v6
68
+ // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
69
+ } // Set up initial aria attributes
70
+
71
+
72
+ this._setInitialAttributes(this._parent, this._getChildren());
73
+
74
+ EventHandler__default.default.on(this._element, EVENT_KEYDOWN, event => this._keydown(event));
75
+ } // Getters
76
+
77
+
172
78
  static get NAME() {
173
79
  return NAME;
174
80
  } // Public
175
81
 
176
82
 
177
83
  show() {
178
- if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && this._element.classList.contains(CLASS_NAME_ACTIVE)) {
179
- return;
180
- }
84
+ // Shows this elem and deactivate the active sibling if exists
85
+ const innerElem = this._element;
181
86
 
182
- let previous;
183
- const target = getElementFromSelector(this._element);
87
+ if (this._elemIsActive(innerElem)) {
88
+ return;
89
+ } // Search for active tab on same parent to deactivate it
184
90
 
185
- const listElement = this._element.closest(SELECTOR_NAV_LIST_GROUP);
186
91
 
187
- if (listElement) {
188
- const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE;
189
- previous = SelectorEngine__default.default.find(itemSelector, listElement);
190
- previous = previous[previous.length - 1];
191
- }
92
+ const active = this._getActiveElem();
192
93
 
193
- const hideEvent = previous ? EventHandler__default.default.trigger(previous, EVENT_HIDE, {
194
- relatedTarget: this._element
94
+ const hideEvent = active ? EventHandler__default.default.trigger(active, EVENT_HIDE, {
95
+ relatedTarget: innerElem
195
96
  }) : null;
196
- const showEvent = EventHandler__default.default.trigger(this._element, EVENT_SHOW, {
197
- relatedTarget: previous
97
+ const showEvent = EventHandler__default.default.trigger(innerElem, EVENT_SHOW, {
98
+ relatedTarget: active
198
99
  });
199
100
 
200
- if (showEvent.defaultPrevented || hideEvent !== null && hideEvent.defaultPrevented) {
101
+ if (showEvent.defaultPrevented || hideEvent && hideEvent.defaultPrevented) {
201
102
  return;
202
103
  }
203
104
 
204
- this._activate(this._element, listElement);
105
+ this._deactivate(active, innerElem);
106
+
107
+ this._activate(innerElem, active);
108
+ } // Private
109
+
110
+
111
+ _activate(element, relatedElem) {
112
+ if (!element) {
113
+ return;
114
+ }
115
+
116
+ element.classList.add(CLASS_NAME_ACTIVE);
117
+
118
+ this._activate(index.getElementFromSelector(element)); // Search and activate/show the proper section
119
+
205
120
 
206
121
  const complete = () => {
207
- EventHandler__default.default.trigger(previous, EVENT_HIDDEN, {
208
- relatedTarget: this._element
122
+ if (element.getAttribute('role') !== 'tab') {
123
+ element.classList.add(CLASS_NAME_SHOW);
124
+ return;
125
+ }
126
+
127
+ element.focus();
128
+ element.removeAttribute('tabindex');
129
+ element.setAttribute('aria-selected', true);
130
+
131
+ this._toggleDropDown(element, true);
132
+
133
+ EventHandler__default.default.trigger(element, EVENT_SHOWN, {
134
+ relatedTarget: relatedElem
209
135
  });
210
- EventHandler__default.default.trigger(this._element, EVENT_SHOWN, {
211
- relatedTarget: previous
136
+ };
137
+
138
+ this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
139
+ }
140
+
141
+ _deactivate(element, relatedElem) {
142
+ if (!element) {
143
+ return;
144
+ }
145
+
146
+ element.classList.remove(CLASS_NAME_ACTIVE);
147
+ element.blur();
148
+
149
+ this._deactivate(index.getElementFromSelector(element)); // Search and deactivate the shown section too
150
+
151
+
152
+ const complete = () => {
153
+ if (element.getAttribute('role') !== 'tab') {
154
+ element.classList.remove(CLASS_NAME_SHOW);
155
+ return;
156
+ }
157
+
158
+ element.setAttribute('aria-selected', false);
159
+ element.setAttribute('tabindex', '-1');
160
+
161
+ this._toggleDropDown(element, false);
162
+
163
+ EventHandler__default.default.trigger(element, EVENT_HIDDEN, {
164
+ relatedTarget: relatedElem
212
165
  });
213
166
  };
214
167
 
215
- if (target) {
216
- this._activate(target, target.parentNode, complete);
217
- } else {
218
- complete();
168
+ this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE));
169
+ }
170
+
171
+ _keydown(event) {
172
+ if (![ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)) {
173
+ return;
219
174
  }
220
- } // Private
221
175
 
176
+ event.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page
222
177
 
223
- _activate(element, container, callback) {
224
- const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? SelectorEngine__default.default.find(SELECTOR_ACTIVE_UL, container) : SelectorEngine__default.default.children(container, SELECTOR_ACTIVE);
225
- const active = activeElements[0];
226
- const isTransitioning = callback && active && active.classList.contains(CLASS_NAME_FADE);
178
+ event.preventDefault();
179
+ const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key);
180
+ const nextActiveElement = index.getNextActiveElement(this._getChildren().filter(element => !index.isDisabled(element)), event.target, isNext, true);
227
181
 
228
- const complete = () => this._transitionComplete(element, active, callback);
182
+ if (nextActiveElement) {
183
+ Tab.getOrCreateInstance(nextActiveElement).show();
184
+ }
185
+ }
229
186
 
230
- if (active && isTransitioning) {
231
- active.classList.remove(CLASS_NAME_SHOW);
187
+ _getChildren() {
188
+ // collection of inner elements
189
+ return SelectorEngine__default.default.find(SELECTOR_INNER_ELEM, this._parent);
190
+ }
232
191
 
233
- this._queueCallback(complete, element, true);
234
- } else {
235
- complete();
192
+ _getActiveElem() {
193
+ return this._getChildren().find(child => this._elemIsActive(child)) || null;
194
+ }
195
+
196
+ _setInitialAttributes(parent, children) {
197
+ this._setAttributeIfNotExists(parent, 'role', 'tablist');
198
+
199
+ for (const child of children) {
200
+ this._setInitialAttributesOnChild(child);
236
201
  }
237
202
  }
238
203
 
239
- _transitionComplete(element, active, callback) {
240
- if (active) {
241
- active.classList.remove(CLASS_NAME_ACTIVE);
242
- const dropdownChild = SelectorEngine__default.default.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode);
204
+ _setInitialAttributesOnChild(child) {
205
+ child = this._getInnerElement(child);
243
206
 
244
- if (dropdownChild) {
245
- dropdownChild.classList.remove(CLASS_NAME_ACTIVE);
246
- }
207
+ const isActive = this._elemIsActive(child);
247
208
 
248
- if (active.getAttribute('role') === 'tab') {
249
- active.setAttribute('aria-selected', false);
250
- }
209
+ const outerElem = this._getOuterElement(child);
210
+
211
+ child.setAttribute('aria-selected', isActive);
212
+
213
+ if (outerElem !== child) {
214
+ this._setAttributeIfNotExists(outerElem, 'role', 'presentation');
251
215
  }
252
216
 
253
- element.classList.add(CLASS_NAME_ACTIVE);
217
+ if (!isActive) {
218
+ child.setAttribute('tabindex', '-1');
219
+ }
254
220
 
255
- if (element.getAttribute('role') === 'tab') {
256
- element.setAttribute('aria-selected', true);
221
+ this._setAttributeIfNotExists(child, 'role', 'tab'); // set attributes to the related panel too
222
+
223
+
224
+ this._setInitialAttributesOnTargetPanel(child);
225
+ }
226
+
227
+ _setInitialAttributesOnTargetPanel(child) {
228
+ const target = index.getElementFromSelector(child);
229
+
230
+ if (!target) {
231
+ return;
257
232
  }
258
233
 
259
- reflow(element);
234
+ this._setAttributeIfNotExists(target, 'role', 'tabpanel');
260
235
 
261
- if (element.classList.contains(CLASS_NAME_FADE)) {
262
- element.classList.add(CLASS_NAME_SHOW);
236
+ if (child.id) {
237
+ this._setAttributeIfNotExists(target, 'aria-labelledby', `#${child.id}`);
263
238
  }
239
+ }
264
240
 
265
- let parent = element.parentNode;
241
+ _toggleDropDown(element, open) {
242
+ const outerElem = this._getOuterElement(element);
266
243
 
267
- if (parent && parent.nodeName === 'LI') {
268
- parent = parent.parentNode;
244
+ if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
245
+ return;
269
246
  }
270
247
 
271
- if (parent && parent.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {
272
- const dropdownElement = element.closest(SELECTOR_DROPDOWN);
248
+ const toggle = (selector, className) => {
249
+ const element = SelectorEngine__default.default.findOne(selector, outerElem);
273
250
 
274
- if (dropdownElement) {
275
- SelectorEngine__default.default.find(SELECTOR_DROPDOWN_TOGGLE, dropdownElement).forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE));
251
+ if (element) {
252
+ element.classList.toggle(className, open);
276
253
  }
254
+ };
277
255
 
278
- element.setAttribute('aria-expanded', true);
279
- }
256
+ toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE);
257
+ toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW);
258
+ toggle(SELECTOR_DROPDOWN_ITEM, CLASS_NAME_ACTIVE);
259
+ outerElem.setAttribute('aria-expanded', open);
260
+ }
280
261
 
281
- if (callback) {
282
- callback();
262
+ _setAttributeIfNotExists(element, attribute, value) {
263
+ if (!element.hasAttribute(attribute)) {
264
+ element.setAttribute(attribute, value);
283
265
  }
266
+ }
267
+
268
+ _elemIsActive(elem) {
269
+ return elem.classList.contains(CLASS_NAME_ACTIVE);
270
+ } // Try to get the inner element (usually the .nav-link)
271
+
272
+
273
+ _getInnerElement(elem) {
274
+ return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine__default.default.findOne(SELECTOR_INNER_ELEM, elem);
275
+ } // Try to get the outer element (usually the .nav-item)
276
+
277
+
278
+ _getOuterElement(elem) {
279
+ return elem.closest(SELECTOR_OUTER) || elem;
284
280
  } // Static
285
281
 
286
282
 
@@ -288,21 +284,21 @@
288
284
  return this.each(function () {
289
285
  const data = Tab.getOrCreateInstance(this);
290
286
 
291
- if (typeof config === 'string') {
292
- if (typeof data[config] === 'undefined') {
293
- throw new TypeError(`No method named "${config}"`);
294
- }
287
+ if (typeof config !== 'string') {
288
+ return;
289
+ }
295
290
 
296
- data[config]();
291
+ if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
292
+ throw new TypeError(`No method named "${config}"`);
297
293
  }
294
+
295
+ data[config]();
298
296
  });
299
297
  }
300
298
 
301
299
  }
302
300
  /**
303
- * ------------------------------------------------------------------------
304
- * Data Api implementation
305
- * ------------------------------------------------------------------------
301
+ * Data API implementation
306
302
  */
307
303
 
308
304
 
@@ -311,21 +307,26 @@
311
307
  event.preventDefault();
312
308
  }
313
309
 
314
- if (isDisabled(this)) {
310
+ if (index.isDisabled(this)) {
315
311
  return;
316
312
  }
317
313
 
318
- const data = Tab.getOrCreateInstance(this);
319
- data.show();
314
+ Tab.getOrCreateInstance(this).show();
315
+ });
316
+ /**
317
+ * Initialize on focus
318
+ */
319
+
320
+ EventHandler__default.default.on(window, EVENT_LOAD_DATA_API, () => {
321
+ for (const element of SelectorEngine__default.default.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {
322
+ Tab.getOrCreateInstance(element);
323
+ }
320
324
  });
321
325
  /**
322
- * ------------------------------------------------------------------------
323
326
  * jQuery
324
- * ------------------------------------------------------------------------
325
- * add .Tab to jQuery only if jQuery is present
326
327
  */
327
328
 
328
- defineJQueryPlugin(Tab);
329
+ index.defineJQueryPlugin(Tab);
329
330
 
330
331
  return Tab;
331
332