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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +61 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -0
- data/README.md +35 -14
- data/Rakefile +16 -5
- data/assets/javascripts/bootstrap/alert.js +22 -167
- data/assets/javascripts/bootstrap/base-component.js +34 -133
- data/assets/javascripts/bootstrap/button.js +19 -86
- data/assets/javascripts/bootstrap/carousel.js +209 -564
- data/assets/javascripts/bootstrap/collapse.js +78 -324
- data/assets/javascripts/bootstrap/dom/data.js +8 -14
- data/assets/javascripts/bootstrap/dom/event-handler.js +89 -174
- data/assets/javascripts/bootstrap/dom/manipulator.js +22 -39
- data/assets/javascripts/bootstrap/dom/selector-engine.js +47 -71
- data/assets/javascripts/bootstrap/dropdown.js +135 -420
- data/assets/javascripts/bootstrap/modal.js +115 -837
- data/assets/javascripts/bootstrap/offcanvas.js +93 -714
- data/assets/javascripts/bootstrap/popover.js +42 -130
- data/assets/javascripts/bootstrap/scrollspy.js +180 -296
- data/assets/javascripts/bootstrap/tab.js +197 -245
- data/assets/javascripts/bootstrap/toast.js +52 -276
- data/assets/javascripts/bootstrap/tooltip.js +283 -744
- data/assets/javascripts/bootstrap/util/backdrop.js +138 -0
- data/assets/javascripts/bootstrap/util/component-functions.js +41 -0
- data/assets/javascripts/bootstrap/util/config.js +67 -0
- data/assets/javascripts/bootstrap/util/focustrap.js +112 -0
- data/assets/javascripts/bootstrap/util/index.js +280 -0
- data/assets/javascripts/bootstrap/util/sanitizer.js +113 -0
- data/assets/javascripts/bootstrap/util/scrollbar.js +112 -0
- data/assets/javascripts/bootstrap/util/swipe.js +134 -0
- data/assets/javascripts/bootstrap/util/template-factory.js +150 -0
- data/assets/javascripts/bootstrap-global-this-define.js +1 -1
- data/assets/javascripts/bootstrap-sprockets.js +15 -6
- data/assets/javascripts/bootstrap.js +2278 -2831
- data/assets/javascripts/bootstrap.min.js +3 -3
- data/assets/stylesheets/_bootstrap-grid.scss +4 -9
- data/assets/stylesheets/_bootstrap-reboot.scss +4 -7
- data/assets/stylesheets/_bootstrap-utilities.scss +19 -0
- data/assets/stylesheets/_bootstrap.scss +5 -6
- data/assets/stylesheets/bootstrap/_accordion.scss +68 -33
- data/assets/stylesheets/bootstrap/_alert.scss +25 -14
- data/assets/stylesheets/bootstrap/_badge.scss +14 -5
- data/assets/stylesheets/bootstrap/_breadcrumb.scss +22 -10
- data/assets/stylesheets/bootstrap/_button-group.scss +12 -4
- data/assets/stylesheets/bootstrap/_buttons.scss +133 -28
- data/assets/stylesheets/bootstrap/_card.scss +61 -39
- data/assets/stylesheets/bootstrap/_carousel.scss +22 -25
- data/assets/stylesheets/bootstrap/_close.scss +36 -10
- data/assets/stylesheets/bootstrap/_containers.scss +1 -1
- data/assets/stylesheets/bootstrap/_dropdown.scss +86 -76
- data/assets/stylesheets/bootstrap/_functions.scss +10 -10
- data/assets/stylesheets/bootstrap/_grid.scss +9 -3
- data/assets/stylesheets/bootstrap/_helpers.scss +3 -0
- data/assets/stylesheets/bootstrap/_list-group.scss +81 -56
- data/assets/stylesheets/bootstrap/_maps.scss +174 -0
- data/assets/stylesheets/bootstrap/_mixins.scss +1 -2
- data/assets/stylesheets/bootstrap/_modal.scss +76 -45
- data/assets/stylesheets/bootstrap/_nav.scss +87 -29
- data/assets/stylesheets/bootstrap/_navbar.scss +102 -148
- data/assets/stylesheets/bootstrap/_offcanvas.scss +125 -61
- data/assets/stylesheets/bootstrap/_pagination.scss +66 -21
- data/assets/stylesheets/bootstrap/_placeholders.scss +1 -1
- data/assets/stylesheets/bootstrap/_popover.scss +90 -52
- data/assets/stylesheets/bootstrap/_progress.scss +31 -11
- data/assets/stylesheets/bootstrap/_reboot.scss +32 -46
- data/assets/stylesheets/bootstrap/_root.scss +155 -22
- data/assets/stylesheets/bootstrap/_spinners.scss +38 -22
- data/assets/stylesheets/bootstrap/_tables.scss +40 -24
- data/assets/stylesheets/bootstrap/_toasts.scss +38 -16
- data/assets/stylesheets/bootstrap/_tooltip.scss +60 -56
- data/assets/stylesheets/bootstrap/_type.scss +3 -1
- data/assets/stylesheets/bootstrap/_utilities.scss +209 -33
- data/assets/stylesheets/bootstrap/_variables-dark.scss +102 -0
- data/assets/stylesheets/bootstrap/_variables.scss +415 -303
- data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +39 -5
- data/assets/stylesheets/bootstrap/forms/_form-check.scss +51 -14
- data/assets/stylesheets/bootstrap/forms/_form-control.scss +36 -41
- data/assets/stylesheets/bootstrap/forms/_form-range.scss +3 -3
- data/assets/stylesheets/bootstrap/forms/_form-select.scss +12 -4
- data/assets/stylesheets/bootstrap/forms/_input-group.scss +20 -9
- data/assets/stylesheets/bootstrap/helpers/_color-bg.scss +7 -0
- data/assets/stylesheets/bootstrap/helpers/_colored-links.scss +20 -2
- data/assets/stylesheets/bootstrap/helpers/_focus-ring.scss +5 -0
- data/assets/stylesheets/bootstrap/helpers/_icon-link.scss +25 -0
- data/assets/stylesheets/bootstrap/helpers/_position.scss +7 -1
- data/assets/stylesheets/bootstrap/helpers/_ratio.scss +2 -2
- data/assets/stylesheets/bootstrap/helpers/_vr.scss +2 -2
- data/assets/stylesheets/bootstrap/mixins/_alert.scss +11 -4
- data/assets/stylesheets/bootstrap/mixins/_banner.scss +7 -0
- data/assets/stylesheets/bootstrap/mixins/_breakpoints.scss +8 -8
- data/assets/stylesheets/bootstrap/mixins/_buttons.scss +32 -95
- data/assets/stylesheets/bootstrap/mixins/_caret.scss +30 -25
- data/assets/stylesheets/bootstrap/mixins/_color-mode.scss +21 -0
- data/assets/stylesheets/bootstrap/mixins/_container.scss +4 -2
- data/assets/stylesheets/bootstrap/mixins/_forms.scss +38 -19
- data/assets/stylesheets/bootstrap/mixins/_gradients.scss +1 -1
- data/assets/stylesheets/bootstrap/mixins/_grid.scss +15 -15
- data/assets/stylesheets/bootstrap/mixins/_list-group.scss +2 -0
- data/assets/stylesheets/bootstrap/mixins/_pagination.scss +4 -25
- data/assets/stylesheets/bootstrap/mixins/_reset-text.scss +1 -1
- data/assets/stylesheets/bootstrap/mixins/_table-variants.scss +12 -9
- data/assets/stylesheets/bootstrap/mixins/_utilities.scss +14 -6
- data/assets/stylesheets/bootstrap/mixins/_visually-hidden.scss +6 -2
- data/assets/stylesheets/bootstrap/vendor/_rfs.scss +23 -29
- data/bootstrap.gemspec +3 -3
- data/lib/bootstrap/engine.rb +17 -2
- data/lib/bootstrap/version.rb +2 -2
- data/tasks/updater/js.rb +10 -5
- data/tasks/updater/network.rb +2 -2
- data/tasks/updater/scss.rb +2 -2
- data/tasks/updater.rb +2 -2
- data/test/dummy_rails/config/application.rb +0 -2
- data/test/dummy_rails/public/favicon.ico +0 -0
- data/test/gemfiles/rails_4_2.gemfile +2 -1
- data/test/gemfiles/rails_5_0.gemfile +1 -2
- data/test/gemfiles/rails_5_1.gemfile +1 -2
- data/test/gemfiles/rails_5_2.gemfile +7 -0
- data/test/gemfiles/rails_6_0.gemfile +1 -1
- data/test/gemfiles/rails_6_1.gemfile +1 -1
- data/test/gemfiles/rails_7_0_dartsass.gemfile +7 -0
- data/test/gemfiles/rails_7_0_sassc.gemfile +7 -0
- data/test/rails_test.rb +0 -5
- data/test/test_helper.rb +3 -2
- metadata +49 -29
- data/.travis.yml +0 -32
- data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +0 -18
|
@@ -1,389 +1,273 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Bootstrap scrollspy.js v5.
|
|
3
|
-
* Copyright 2011-
|
|
2
|
+
* Bootstrap scrollspy.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('./
|
|
8
|
-
typeof define === 'function' && define.amd ? define(['./
|
|
9
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.
|
|
10
|
-
})(this, (function (
|
|
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/selector-engine.js'), require('./util/index.js')) :
|
|
8
|
+
typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './dom/selector-engine', './util/index'], factory) :
|
|
9
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Scrollspy = factory(global.BaseComponent, global.EventHandler, global.SelectorEngine, global.Index));
|
|
10
|
+
})(this, (function (BaseComponent, EventHandler, SelectorEngine, index_js) { 'use strict';
|
|
18
11
|
|
|
19
12
|
/**
|
|
20
13
|
* --------------------------------------------------------------------------
|
|
21
|
-
* Bootstrap
|
|
14
|
+
* Bootstrap scrollspy.js
|
|
22
15
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
23
16
|
* --------------------------------------------------------------------------
|
|
24
17
|
*/
|
|
25
18
|
|
|
26
|
-
const toType = obj => {
|
|
27
|
-
if (obj === null || obj === undefined) {
|
|
28
|
-
return `${obj}`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const getSelector = element => {
|
|
35
|
-
let selector = element.getAttribute('data-bs-target');
|
|
36
|
-
|
|
37
|
-
if (!selector || selector === '#') {
|
|
38
|
-
let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
|
|
39
|
-
// so everything starting with `#` or `.`. If a "real" URL is used as the selector,
|
|
40
|
-
// `document.querySelector` will rightfully complain it is invalid.
|
|
41
|
-
// See https://github.com/twbs/bootstrap/issues/32273
|
|
42
|
-
|
|
43
|
-
if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
|
|
44
|
-
return null;
|
|
45
|
-
} // Just in case some CMS puts out a full URL with the anchor appended
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
|
|
49
|
-
hrefAttr = `#${hrefAttr.split('#')[1]}`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return selector;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const getSelectorFromElement = element => {
|
|
59
|
-
const selector = getSelector(element);
|
|
60
|
-
|
|
61
|
-
if (selector) {
|
|
62
|
-
return document.querySelector(selector) ? selector : null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return null;
|
|
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 getElement = obj => {
|
|
81
|
-
if (isElement(obj)) {
|
|
82
|
-
// it's a jQuery object or a node element
|
|
83
|
-
return obj.jquery ? obj[0] : obj;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (typeof obj === 'string' && obj.length > 0) {
|
|
87
|
-
return document.querySelector(obj);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return null;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const typeCheckConfig = (componentName, config, configTypes) => {
|
|
94
|
-
Object.keys(configTypes).forEach(property => {
|
|
95
|
-
const expectedTypes = configTypes[property];
|
|
96
|
-
const value = config[property];
|
|
97
|
-
const valueType = value && isElement(value) ? 'element' : toType(value);
|
|
98
|
-
|
|
99
|
-
if (!new RegExp(expectedTypes).test(valueType)) {
|
|
100
|
-
throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const getjQuery = () => {
|
|
106
|
-
const {
|
|
107
|
-
jQuery
|
|
108
|
-
} = window;
|
|
109
|
-
|
|
110
|
-
if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
|
|
111
|
-
return jQuery;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return null;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const DOMContentLoadedCallbacks = [];
|
|
118
|
-
|
|
119
|
-
const onDOMContentLoaded = callback => {
|
|
120
|
-
if (document.readyState === 'loading') {
|
|
121
|
-
// add listener on the first call when the document is in loading state
|
|
122
|
-
if (!DOMContentLoadedCallbacks.length) {
|
|
123
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
124
|
-
DOMContentLoadedCallbacks.forEach(callback => callback());
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
DOMContentLoadedCallbacks.push(callback);
|
|
129
|
-
} else {
|
|
130
|
-
callback();
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const defineJQueryPlugin = plugin => {
|
|
135
|
-
onDOMContentLoaded(() => {
|
|
136
|
-
const $ = getjQuery();
|
|
137
|
-
/* istanbul ignore if */
|
|
138
|
-
|
|
139
|
-
if ($) {
|
|
140
|
-
const name = plugin.NAME;
|
|
141
|
-
const JQUERY_NO_CONFLICT = $.fn[name];
|
|
142
|
-
$.fn[name] = plugin.jQueryInterface;
|
|
143
|
-
$.fn[name].Constructor = plugin;
|
|
144
|
-
|
|
145
|
-
$.fn[name].noConflict = () => {
|
|
146
|
-
$.fn[name] = JQUERY_NO_CONFLICT;
|
|
147
|
-
return plugin.jQueryInterface;
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
};
|
|
152
19
|
|
|
153
20
|
/**
|
|
154
|
-
* --------------------------------------------------------------------------
|
|
155
|
-
* Bootstrap (v5.1.3): scrollspy.js
|
|
156
|
-
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
157
|
-
* --------------------------------------------------------------------------
|
|
158
|
-
*/
|
|
159
|
-
/**
|
|
160
|
-
* ------------------------------------------------------------------------
|
|
161
21
|
* Constants
|
|
162
|
-
* ------------------------------------------------------------------------
|
|
163
22
|
*/
|
|
164
23
|
|
|
165
24
|
const NAME = 'scrollspy';
|
|
166
25
|
const DATA_KEY = 'bs.scrollspy';
|
|
167
26
|
const EVENT_KEY = `.${DATA_KEY}`;
|
|
168
27
|
const DATA_API_KEY = '.data-api';
|
|
169
|
-
const Default = {
|
|
170
|
-
offset: 10,
|
|
171
|
-
method: 'auto',
|
|
172
|
-
target: ''
|
|
173
|
-
};
|
|
174
|
-
const DefaultType = {
|
|
175
|
-
offset: 'number',
|
|
176
|
-
method: 'string',
|
|
177
|
-
target: '(string|element)'
|
|
178
|
-
};
|
|
179
28
|
const EVENT_ACTIVATE = `activate${EVENT_KEY}`;
|
|
180
|
-
const
|
|
29
|
+
const EVENT_CLICK = `click${EVENT_KEY}`;
|
|
181
30
|
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
|
|
182
31
|
const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';
|
|
183
32
|
const CLASS_NAME_ACTIVE = 'active';
|
|
184
33
|
const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]';
|
|
34
|
+
const SELECTOR_TARGET_LINKS = '[href]';
|
|
185
35
|
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';
|
|
186
36
|
const SELECTOR_NAV_LINKS = '.nav-link';
|
|
187
37
|
const SELECTOR_NAV_ITEMS = '.nav-item';
|
|
188
38
|
const SELECTOR_LIST_ITEMS = '.list-group-item';
|
|
189
|
-
const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${
|
|
39
|
+
const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;
|
|
190
40
|
const SELECTOR_DROPDOWN = '.dropdown';
|
|
191
41
|
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';
|
|
192
|
-
const
|
|
193
|
-
|
|
42
|
+
const Default = {
|
|
43
|
+
offset: null,
|
|
44
|
+
// TODO: v6 @deprecated, keep it for backwards compatibility reasons
|
|
45
|
+
rootMargin: '0px 0px -25%',
|
|
46
|
+
smoothScroll: false,
|
|
47
|
+
target: null,
|
|
48
|
+
threshold: [0.1, 0.5, 1]
|
|
49
|
+
};
|
|
50
|
+
const DefaultType = {
|
|
51
|
+
offset: '(number|null)',
|
|
52
|
+
// TODO v6 @deprecated, keep it for backwards compatibility reasons
|
|
53
|
+
rootMargin: 'string',
|
|
54
|
+
smoothScroll: 'boolean',
|
|
55
|
+
target: 'element',
|
|
56
|
+
threshold: 'array'
|
|
57
|
+
};
|
|
58
|
+
|
|
194
59
|
/**
|
|
195
|
-
*
|
|
196
|
-
* Class Definition
|
|
197
|
-
* ------------------------------------------------------------------------
|
|
60
|
+
* Class definition
|
|
198
61
|
*/
|
|
199
62
|
|
|
200
|
-
class ScrollSpy extends
|
|
63
|
+
class ScrollSpy extends BaseComponent {
|
|
201
64
|
constructor(element, config) {
|
|
202
|
-
super(element);
|
|
203
|
-
this._scrollElement = this._element.tagName === 'BODY' ? window : this._element;
|
|
204
|
-
this._config = this._getConfig(config);
|
|
205
|
-
this._offsets = [];
|
|
206
|
-
this._targets = [];
|
|
207
|
-
this._activeTarget = null;
|
|
208
|
-
this._scrollHeight = 0;
|
|
209
|
-
EventHandler__default.default.on(this._scrollElement, EVENT_SCROLL, () => this._process());
|
|
210
|
-
this.refresh();
|
|
211
|
-
|
|
212
|
-
this._process();
|
|
213
|
-
} // Getters
|
|
65
|
+
super(element, config);
|
|
214
66
|
|
|
67
|
+
// this._element is the observablesContainer and config.target the menu links wrapper
|
|
68
|
+
this._targetLinks = new Map();
|
|
69
|
+
this._observableSections = new Map();
|
|
70
|
+
this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element;
|
|
71
|
+
this._activeTarget = null;
|
|
72
|
+
this._observer = null;
|
|
73
|
+
this._previousScrollData = {
|
|
74
|
+
visibleEntryTop: 0,
|
|
75
|
+
parentScrollTop: 0
|
|
76
|
+
};
|
|
77
|
+
this.refresh(); // initialize
|
|
78
|
+
}
|
|
215
79
|
|
|
80
|
+
// Getters
|
|
216
81
|
static get Default() {
|
|
217
82
|
return Default;
|
|
218
83
|
}
|
|
219
|
-
|
|
84
|
+
static get DefaultType() {
|
|
85
|
+
return DefaultType;
|
|
86
|
+
}
|
|
220
87
|
static get NAME() {
|
|
221
88
|
return NAME;
|
|
222
|
-
}
|
|
223
|
-
|
|
89
|
+
}
|
|
224
90
|
|
|
91
|
+
// Public
|
|
225
92
|
refresh() {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (target) {
|
|
238
|
-
const targetBCR = target.getBoundingClientRect();
|
|
239
|
-
|
|
240
|
-
if (targetBCR.width || targetBCR.height) {
|
|
241
|
-
return [Manipulator__default.default[offsetMethod](target).top + offsetBase, targetSelector];
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return null;
|
|
246
|
-
}).filter(item => item).sort((a, b) => a[0] - b[0]).forEach(item => {
|
|
247
|
-
this._offsets.push(item[0]);
|
|
248
|
-
|
|
249
|
-
this._targets.push(item[1]);
|
|
250
|
-
});
|
|
93
|
+
this._initializeTargetsAndObservables();
|
|
94
|
+
this._maybeEnableSmoothScroll();
|
|
95
|
+
if (this._observer) {
|
|
96
|
+
this._observer.disconnect();
|
|
97
|
+
} else {
|
|
98
|
+
this._observer = this._getNewObserver();
|
|
99
|
+
}
|
|
100
|
+
for (const section of this._observableSections.values()) {
|
|
101
|
+
this._observer.observe(section);
|
|
102
|
+
}
|
|
251
103
|
}
|
|
252
|
-
|
|
253
104
|
dispose() {
|
|
254
|
-
|
|
105
|
+
this._observer.disconnect();
|
|
255
106
|
super.dispose();
|
|
256
|
-
}
|
|
107
|
+
}
|
|
257
108
|
|
|
109
|
+
// Private
|
|
110
|
+
_configAfterMerge(config) {
|
|
111
|
+
// TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case
|
|
112
|
+
config.target = index_js.getElement(config.target) || document.body;
|
|
258
113
|
|
|
259
|
-
|
|
260
|
-
config = {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
config.target = getElement(config.target) || document.documentElement;
|
|
265
|
-
typeCheckConfig(NAME, config, DefaultType);
|
|
114
|
+
// TODO: v6 Only for backwards compatibility reasons. Use rootMargin only
|
|
115
|
+
config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin;
|
|
116
|
+
if (typeof config.threshold === 'string') {
|
|
117
|
+
config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value));
|
|
118
|
+
}
|
|
266
119
|
return config;
|
|
267
120
|
}
|
|
121
|
+
_maybeEnableSmoothScroll() {
|
|
122
|
+
if (!this._config.smoothScroll) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
268
125
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
126
|
+
// unregister any previous listeners
|
|
127
|
+
EventHandler.off(this._config.target, EVENT_CLICK);
|
|
128
|
+
EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {
|
|
129
|
+
const observableSection = this._observableSections.get(event.target.hash);
|
|
130
|
+
if (observableSection) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
const root = this._rootElement || window;
|
|
133
|
+
const height = observableSection.offsetTop - this._element.offsetTop;
|
|
134
|
+
if (root.scrollTo) {
|
|
135
|
+
root.scrollTo({
|
|
136
|
+
top: height,
|
|
137
|
+
behavior: 'smooth'
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
272
141
|
|
|
273
|
-
|
|
274
|
-
|
|
142
|
+
// Chrome 60 doesn't support `scrollTo`
|
|
143
|
+
root.scrollTop = height;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
275
146
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
147
|
+
_getNewObserver() {
|
|
148
|
+
const options = {
|
|
149
|
+
root: this._rootElement,
|
|
150
|
+
threshold: this._config.threshold,
|
|
151
|
+
rootMargin: this._config.rootMargin
|
|
152
|
+
};
|
|
153
|
+
return new IntersectionObserver(entries => this._observerCallback(entries), options);
|
|
279
154
|
}
|
|
280
155
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
156
|
+
// The logic of selection
|
|
157
|
+
_observerCallback(entries) {
|
|
158
|
+
const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`);
|
|
159
|
+
const activate = entry => {
|
|
160
|
+
this._previousScrollData.visibleEntryTop = entry.target.offsetTop;
|
|
161
|
+
this._process(targetElement(entry));
|
|
162
|
+
};
|
|
163
|
+
const parentScrollTop = (this._rootElement || document.documentElement).scrollTop;
|
|
164
|
+
const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;
|
|
165
|
+
this._previousScrollData.parentScrollTop = parentScrollTop;
|
|
166
|
+
for (const entry of entries) {
|
|
167
|
+
if (!entry.isIntersecting) {
|
|
168
|
+
this._activeTarget = null;
|
|
169
|
+
this._clearActiveClass(targetElement(entry));
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop;
|
|
173
|
+
// if we are scrolling down, pick the bigger offsetTop
|
|
174
|
+
if (userScrollsDown && entryIsLowerThanPrevious) {
|
|
175
|
+
activate(entry);
|
|
176
|
+
// if parent isn't scrolled, let's keep the first visible item, breaking the iteration
|
|
177
|
+
if (!parentScrollTop) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
287
182
|
|
|
288
|
-
|
|
289
|
-
|
|
183
|
+
// if we are scrolling up, pick the smallest offsetTop
|
|
184
|
+
if (!userScrollsDown && !entryIsLowerThanPrevious) {
|
|
185
|
+
activate(entry);
|
|
186
|
+
}
|
|
290
187
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
188
|
+
}
|
|
189
|
+
_initializeTargetsAndObservables() {
|
|
190
|
+
this._targetLinks = new Map();
|
|
191
|
+
this._observableSections = new Map();
|
|
192
|
+
const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target);
|
|
193
|
+
for (const anchor of targetLinks) {
|
|
194
|
+
// ensure that the anchor has an id and is not disabled
|
|
195
|
+
if (!anchor.hash || index_js.isDisabled(anchor)) {
|
|
196
|
+
continue;
|
|
297
197
|
}
|
|
198
|
+
const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element);
|
|
298
199
|
|
|
200
|
+
// ensure that the observableSection exists & is visible
|
|
201
|
+
if (index_js.isVisible(observableSection)) {
|
|
202
|
+
this._targetLinks.set(decodeURI(anchor.hash), anchor);
|
|
203
|
+
this._observableSections.set(anchor.hash, observableSection);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
_process(target) {
|
|
208
|
+
if (this._activeTarget === target) {
|
|
299
209
|
return;
|
|
300
210
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
211
|
+
this._clearActiveClass(this._config.target);
|
|
212
|
+
this._activeTarget = target;
|
|
213
|
+
target.classList.add(CLASS_NAME_ACTIVE);
|
|
214
|
+
this._activateParents(target);
|
|
215
|
+
EventHandler.trigger(this._element, EVENT_ACTIVATE, {
|
|
216
|
+
relatedTarget: target
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
_activateParents(target) {
|
|
220
|
+
// Activate dropdown parents
|
|
221
|
+
if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
|
|
222
|
+
SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE);
|
|
307
223
|
return;
|
|
308
224
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
this._activate(this._targets[i]);
|
|
225
|
+
for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {
|
|
226
|
+
// Set triggered links parents as active
|
|
227
|
+
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
|
|
228
|
+
for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {
|
|
229
|
+
item.classList.add(CLASS_NAME_ACTIVE);
|
|
315
230
|
}
|
|
316
231
|
}
|
|
317
232
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const queries = SELECTOR_LINK_ITEMS.split(',').map(selector => `${selector}[data-bs-target="${target}"],${selector}[href="${target}"]`);
|
|
325
|
-
const link = SelectorEngine__default.default.findOne(queries.join(','), this._config.target);
|
|
326
|
-
link.classList.add(CLASS_NAME_ACTIVE);
|
|
327
|
-
|
|
328
|
-
if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
|
|
329
|
-
SelectorEngine__default.default.findOne(SELECTOR_DROPDOWN_TOGGLE, link.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE);
|
|
330
|
-
} else {
|
|
331
|
-
SelectorEngine__default.default.parents(link, SELECTOR_NAV_LIST_GROUP).forEach(listGroup => {
|
|
332
|
-
// Set triggered links parents as active
|
|
333
|
-
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
|
|
334
|
-
SelectorEngine__default.default.prev(listGroup, `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`).forEach(item => item.classList.add(CLASS_NAME_ACTIVE)); // Handle special case when .nav-link is inside .nav-item
|
|
335
|
-
|
|
336
|
-
SelectorEngine__default.default.prev(listGroup, SELECTOR_NAV_ITEMS).forEach(navItem => {
|
|
337
|
-
SelectorEngine__default.default.children(navItem, SELECTOR_NAV_LINKS).forEach(item => item.classList.add(CLASS_NAME_ACTIVE));
|
|
338
|
-
});
|
|
339
|
-
});
|
|
233
|
+
_clearActiveClass(parent) {
|
|
234
|
+
parent.classList.remove(CLASS_NAME_ACTIVE);
|
|
235
|
+
const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent);
|
|
236
|
+
for (const node of activeNodes) {
|
|
237
|
+
node.classList.remove(CLASS_NAME_ACTIVE);
|
|
340
238
|
}
|
|
341
|
-
|
|
342
|
-
EventHandler__default.default.trigger(this._scrollElement, EVENT_ACTIVATE, {
|
|
343
|
-
relatedTarget: target
|
|
344
|
-
});
|
|
345
239
|
}
|
|
346
240
|
|
|
347
|
-
|
|
348
|
-
SelectorEngine__default.default.find(SELECTOR_LINK_ITEMS, this._config.target).filter(node => node.classList.contains(CLASS_NAME_ACTIVE)).forEach(node => node.classList.remove(CLASS_NAME_ACTIVE));
|
|
349
|
-
} // Static
|
|
350
|
-
|
|
351
|
-
|
|
241
|
+
// Static
|
|
352
242
|
static jQueryInterface(config) {
|
|
353
243
|
return this.each(function () {
|
|
354
244
|
const data = ScrollSpy.getOrCreateInstance(this, config);
|
|
355
|
-
|
|
356
245
|
if (typeof config !== 'string') {
|
|
357
246
|
return;
|
|
358
247
|
}
|
|
359
|
-
|
|
360
|
-
if (typeof data[config] === 'undefined') {
|
|
248
|
+
if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
|
|
361
249
|
throw new TypeError(`No method named "${config}"`);
|
|
362
250
|
}
|
|
363
|
-
|
|
364
251
|
data[config]();
|
|
365
252
|
});
|
|
366
253
|
}
|
|
367
|
-
|
|
368
254
|
}
|
|
255
|
+
|
|
369
256
|
/**
|
|
370
|
-
*
|
|
371
|
-
* Data Api implementation
|
|
372
|
-
* ------------------------------------------------------------------------
|
|
257
|
+
* Data API implementation
|
|
373
258
|
*/
|
|
374
259
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
260
|
+
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
|
|
261
|
+
for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {
|
|
262
|
+
ScrollSpy.getOrCreateInstance(spy);
|
|
263
|
+
}
|
|
378
264
|
});
|
|
265
|
+
|
|
379
266
|
/**
|
|
380
|
-
* ------------------------------------------------------------------------
|
|
381
267
|
* jQuery
|
|
382
|
-
* ------------------------------------------------------------------------
|
|
383
|
-
* add .ScrollSpy to jQuery only if jQuery is present
|
|
384
268
|
*/
|
|
385
269
|
|
|
386
|
-
defineJQueryPlugin(ScrollSpy);
|
|
270
|
+
index_js.defineJQueryPlugin(ScrollSpy);
|
|
387
271
|
|
|
388
272
|
return ScrollSpy;
|
|
389
273
|
|