bootstrap 5.2.2 → 5.3.3

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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +61 -0
  3. data/CHANGELOG.md +4 -0
  4. data/Gemfile +1 -0
  5. data/README.md +9 -3
  6. data/Rakefile +17 -4
  7. data/assets/javascripts/bootstrap/alert.js +22 -32
  8. data/assets/javascripts/bootstrap/base-component.js +22 -38
  9. data/assets/javascripts/bootstrap/button.js +19 -22
  10. data/assets/javascripts/bootstrap/carousel.js +52 -135
  11. data/assets/javascripts/bootstrap/collapse.js +40 -102
  12. data/assets/javascripts/bootstrap/dom/data.js +8 -12
  13. data/assets/javascripts/bootstrap/dom/event-handler.js +19 -66
  14. data/assets/javascripts/bootstrap/dom/manipulator.js +4 -17
  15. data/assets/javascripts/bootstrap/dom/selector-engine.js +42 -24
  16. data/assets/javascripts/bootstrap/dropdown.js +74 -145
  17. data/assets/javascripts/bootstrap/modal.js +53 -133
  18. data/assets/javascripts/bootstrap/offcanvas.js +50 -102
  19. data/assets/javascripts/bootstrap/popover.js +23 -29
  20. data/assets/javascripts/bootstrap/scrollspy.js +53 -90
  21. data/assets/javascripts/bootstrap/tab.js +63 -112
  22. data/assets/javascripts/bootstrap/toast.js +31 -73
  23. data/assets/javascripts/bootstrap/tooltip.js +80 -191
  24. data/assets/javascripts/bootstrap/util/backdrop.js +27 -54
  25. data/assets/javascripts/bootstrap/util/component-functions.js +13 -18
  26. data/assets/javascripts/bootstrap/util/config.js +15 -27
  27. data/assets/javascripts/bootstrap/util/focustrap.js +19 -36
  28. data/assets/javascripts/bootstrap/util/index.js +42 -112
  29. data/assets/javascripts/bootstrap/util/sanitizer.js +33 -42
  30. data/assets/javascripts/bootstrap/util/scrollbar.js +24 -50
  31. data/assets/javascripts/bootstrap/util/swipe.js +27 -48
  32. data/assets/javascripts/bootstrap/util/template-factory.js +25 -52
  33. data/assets/javascripts/bootstrap-sprockets.js +8 -8
  34. data/assets/javascripts/bootstrap.js +686 -1450
  35. data/assets/javascripts/bootstrap.min.js +3 -3
  36. data/assets/stylesheets/_bootstrap-grid.scss +1 -3
  37. data/assets/stylesheets/_bootstrap-reboot.scss +1 -0
  38. data/assets/stylesheets/_bootstrap-utilities.scss +19 -0
  39. data/assets/stylesheets/_bootstrap.scss +1 -0
  40. data/assets/stylesheets/bootstrap/_accordion.scss +20 -11
  41. data/assets/stylesheets/bootstrap/_alert.scss +8 -11
  42. data/assets/stylesheets/bootstrap/_button-group.scss +2 -2
  43. data/assets/stylesheets/bootstrap/_buttons.scss +12 -3
  44. data/assets/stylesheets/bootstrap/_card.scss +5 -0
  45. data/assets/stylesheets/bootstrap/_carousel.scss +22 -15
  46. data/assets/stylesheets/bootstrap/_close.scss +32 -9
  47. data/assets/stylesheets/bootstrap/_dropdown.scss +1 -0
  48. data/assets/stylesheets/bootstrap/_functions.scss +2 -2
  49. data/assets/stylesheets/bootstrap/_grid.scss +6 -0
  50. data/assets/stylesheets/bootstrap/_helpers.scss +2 -0
  51. data/assets/stylesheets/bootstrap/_list-group.scss +12 -7
  52. data/assets/stylesheets/bootstrap/_maps.scss +120 -0
  53. data/assets/stylesheets/bootstrap/_mixins.scss +1 -2
  54. data/assets/stylesheets/bootstrap/_modal.scss +0 -1
  55. data/assets/stylesheets/bootstrap/_nav.scss +42 -17
  56. data/assets/stylesheets/bootstrap/_navbar.scss +15 -4
  57. data/assets/stylesheets/bootstrap/_offcanvas.scss +5 -6
  58. data/assets/stylesheets/bootstrap/_pagination.scss +1 -1
  59. data/assets/stylesheets/bootstrap/_progress.scss +10 -1
  60. data/assets/stylesheets/bootstrap/_reboot.scss +8 -7
  61. data/assets/stylesheets/bootstrap/_root.scss +124 -10
  62. data/assets/stylesheets/bootstrap/_tables.scss +19 -12
  63. data/assets/stylesheets/bootstrap/_tooltip.scss +4 -5
  64. data/assets/stylesheets/bootstrap/_utilities.scss +175 -16
  65. data/assets/stylesheets/bootstrap/_variables-dark.scss +87 -0
  66. data/assets/stylesheets/bootstrap/_variables.scss +289 -172
  67. data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +23 -3
  68. data/assets/stylesheets/bootstrap/forms/_form-check.scss +27 -13
  69. data/assets/stylesheets/bootstrap/forms/_form-control.scss +24 -4
  70. data/assets/stylesheets/bootstrap/forms/_form-range.scss +3 -3
  71. data/assets/stylesheets/bootstrap/forms/_form-select.scss +12 -3
  72. data/assets/stylesheets/bootstrap/forms/_input-group.scss +1 -1
  73. data/assets/stylesheets/bootstrap/helpers/_color-bg.scss +1 -4
  74. data/assets/stylesheets/bootstrap/helpers/_colored-links.scss +20 -2
  75. data/assets/stylesheets/bootstrap/helpers/_focus-ring.scss +5 -0
  76. data/assets/stylesheets/bootstrap/helpers/_icon-link.scss +25 -0
  77. data/assets/stylesheets/bootstrap/helpers/_vr.scss +1 -1
  78. data/assets/stylesheets/bootstrap/mixins/_alert.scss +4 -1
  79. data/assets/stylesheets/bootstrap/mixins/_banner.scss +2 -4
  80. data/assets/stylesheets/bootstrap/mixins/_caret.scss +30 -25
  81. data/assets/stylesheets/bootstrap/mixins/_color-mode.scss +21 -0
  82. data/assets/stylesheets/bootstrap/mixins/_forms.scss +20 -9
  83. data/assets/stylesheets/bootstrap/mixins/_grid.scss +2 -2
  84. data/assets/stylesheets/bootstrap/mixins/_list-group.scss +2 -0
  85. data/assets/stylesheets/bootstrap/mixins/_utilities.scss +1 -1
  86. data/assets/stylesheets/bootstrap/mixins/_visually-hidden.scss +5 -1
  87. data/assets/stylesheets/bootstrap/vendor/_rfs.scss +23 -29
  88. data/bootstrap.gemspec +4 -3
  89. data/lib/bootstrap/engine.rb +17 -1
  90. data/lib/bootstrap/version.rb +2 -2
  91. data/tasks/updater/js.rb +1 -1
  92. data/tasks/updater/network.rb +2 -2
  93. data/tasks/updater/scss.rb +2 -2
  94. data/test/gemfiles/rails_4_2.gemfile +2 -1
  95. data/test/gemfiles/rails_5_0.gemfile +1 -1
  96. data/test/gemfiles/rails_5_1.gemfile +1 -1
  97. data/test/gemfiles/rails_5_2.gemfile +8 -0
  98. data/test/gemfiles/rails_6_0.gemfile +1 -0
  99. data/test/gemfiles/rails_6_1.gemfile +1 -0
  100. data/test/gemfiles/rails_7_0_dartsass.gemfile +8 -0
  101. data/test/gemfiles/rails_7_0_sassc.gemfile +8 -0
  102. data/test/test_helper.rb +3 -2
  103. metadata +42 -18
  104. data/.travis.yml +0 -32
  105. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +0 -15
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * Bootstrap index.js v5.2.2 (https://getbootstrap.com/)
3
- * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap index.js v5.3.3 (https://getbootstrap.com/)
3
+ * Copyright 2011-2024 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) {
@@ -11,193 +11,146 @@
11
11
 
12
12
  /**
13
13
  * --------------------------------------------------------------------------
14
- * Bootstrap (v5.2.2): util/index.js
14
+ * Bootstrap util/index.js
15
15
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16
16
  * --------------------------------------------------------------------------
17
17
  */
18
+
18
19
  const MAX_UID = 1000000;
19
20
  const MILLISECONDS_MULTIPLIER = 1000;
20
- const TRANSITION_END = 'transitionend'; // Shout-out Angus Croll (https://goo.gl/pxwQGp)
21
+ const TRANSITION_END = 'transitionend';
22
+
23
+ /**
24
+ * Properly escape IDs selectors to handle weird IDs
25
+ * @param {string} selector
26
+ * @returns {string}
27
+ */
28
+ const parseSelector = selector => {
29
+ if (selector && window.CSS && window.CSS.escape) {
30
+ // document.querySelector needs escaping to handle IDs (html5+) containing for instance /
31
+ selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`);
32
+ }
33
+ return selector;
34
+ };
21
35
 
36
+ // Shout-out Angus Croll (https://goo.gl/pxwQGp)
22
37
  const toType = object => {
23
38
  if (object === null || object === undefined) {
24
39
  return `${object}`;
25
40
  }
26
-
27
41
  return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase();
28
42
  };
43
+
29
44
  /**
30
45
  * Public Util API
31
46
  */
32
47
 
33
-
34
48
  const getUID = prefix => {
35
49
  do {
36
50
  prefix += Math.floor(Math.random() * MAX_UID);
37
51
  } while (document.getElementById(prefix));
38
-
39
52
  return prefix;
40
53
  };
41
-
42
- const getSelector = element => {
43
- let selector = element.getAttribute('data-bs-target');
44
-
45
- if (!selector || selector === '#') {
46
- let hrefAttribute = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
47
- // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
48
- // `document.querySelector` will rightfully complain it is invalid.
49
- // See https://github.com/twbs/bootstrap/issues/32273
50
-
51
- if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) {
52
- return null;
53
- } // Just in case some CMS puts out a full URL with the anchor appended
54
-
55
-
56
- if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
57
- hrefAttribute = `#${hrefAttribute.split('#')[1]}`;
58
- }
59
-
60
- selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;
61
- }
62
-
63
- return selector;
64
- };
65
-
66
- const getSelectorFromElement = element => {
67
- const selector = getSelector(element);
68
-
69
- if (selector) {
70
- return document.querySelector(selector) ? selector : null;
71
- }
72
-
73
- return null;
74
- };
75
-
76
- const getElementFromSelector = element => {
77
- const selector = getSelector(element);
78
- return selector ? document.querySelector(selector) : null;
79
- };
80
-
81
54
  const getTransitionDurationFromElement = element => {
82
55
  if (!element) {
83
56
  return 0;
84
- } // Get transition-duration of the element
85
-
57
+ }
86
58
 
59
+ // Get transition-duration of the element
87
60
  let {
88
61
  transitionDuration,
89
62
  transitionDelay
90
63
  } = window.getComputedStyle(element);
91
64
  const floatTransitionDuration = Number.parseFloat(transitionDuration);
92
- const floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found
65
+ const floatTransitionDelay = Number.parseFloat(transitionDelay);
93
66
 
67
+ // Return 0 if element or transition duration is not found
94
68
  if (!floatTransitionDuration && !floatTransitionDelay) {
95
69
  return 0;
96
- } // If multiple durations are defined, take the first
97
-
70
+ }
98
71
 
72
+ // If multiple durations are defined, take the first
99
73
  transitionDuration = transitionDuration.split(',')[0];
100
74
  transitionDelay = transitionDelay.split(',')[0];
101
75
  return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
102
76
  };
103
-
104
77
  const triggerTransitionEnd = element => {
105
78
  element.dispatchEvent(new Event(TRANSITION_END));
106
79
  };
107
-
108
80
  const isElement = object => {
109
81
  if (!object || typeof object !== 'object') {
110
82
  return false;
111
83
  }
112
-
113
84
  if (typeof object.jquery !== 'undefined') {
114
85
  object = object[0];
115
86
  }
116
-
117
87
  return typeof object.nodeType !== 'undefined';
118
88
  };
119
-
120
89
  const getElement = object => {
121
90
  // it's a jQuery object or a node element
122
91
  if (isElement(object)) {
123
92
  return object.jquery ? object[0] : object;
124
93
  }
125
-
126
94
  if (typeof object === 'string' && object.length > 0) {
127
- return document.querySelector(object);
95
+ return document.querySelector(parseSelector(object));
128
96
  }
129
-
130
97
  return null;
131
98
  };
132
-
133
99
  const isVisible = element => {
134
100
  if (!isElement(element) || element.getClientRects().length === 0) {
135
101
  return false;
136
102
  }
137
-
138
- const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'; // Handle `details` element as its content may falsie appear visible when it is closed
139
-
103
+ const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';
104
+ // Handle `details` element as its content may falsie appear visible when it is closed
140
105
  const closedDetails = element.closest('details:not([open])');
141
-
142
106
  if (!closedDetails) {
143
107
  return elementIsVisible;
144
108
  }
145
-
146
109
  if (closedDetails !== element) {
147
110
  const summary = element.closest('summary');
148
-
149
111
  if (summary && summary.parentNode !== closedDetails) {
150
112
  return false;
151
113
  }
152
-
153
114
  if (summary === null) {
154
115
  return false;
155
116
  }
156
117
  }
157
-
158
118
  return elementIsVisible;
159
119
  };
160
-
161
120
  const isDisabled = element => {
162
121
  if (!element || element.nodeType !== Node.ELEMENT_NODE) {
163
122
  return true;
164
123
  }
165
-
166
124
  if (element.classList.contains('disabled')) {
167
125
  return true;
168
126
  }
169
-
170
127
  if (typeof element.disabled !== 'undefined') {
171
128
  return element.disabled;
172
129
  }
173
-
174
130
  return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';
175
131
  };
176
-
177
132
  const findShadowRoot = element => {
178
133
  if (!document.documentElement.attachShadow) {
179
134
  return null;
180
- } // Can find the shadow root otherwise it'll return the document
181
-
135
+ }
182
136
 
137
+ // Can find the shadow root otherwise it'll return the document
183
138
  if (typeof element.getRootNode === 'function') {
184
139
  const root = element.getRootNode();
185
140
  return root instanceof ShadowRoot ? root : null;
186
141
  }
187
-
188
142
  if (element instanceof ShadowRoot) {
189
143
  return element;
190
- } // when we don't find a shadow root
191
-
144
+ }
192
145
 
146
+ // when we don't find a shadow root
193
147
  if (!element.parentNode) {
194
148
  return null;
195
149
  }
196
-
197
150
  return findShadowRoot(element.parentNode);
198
151
  };
199
-
200
152
  const noop = () => {};
153
+
201
154
  /**
202
155
  * Trick to restart an element's animation
203
156
  *
@@ -206,22 +159,16 @@
206
159
  *
207
160
  * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
208
161
  */
209
-
210
-
211
162
  const reflow = element => {
212
163
  element.offsetHeight; // eslint-disable-line no-unused-expressions
213
164
  };
214
-
215
165
  const getjQuery = () => {
216
166
  if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
217
167
  return window.jQuery;
218
168
  }
219
-
220
169
  return null;
221
170
  };
222
-
223
171
  const DOMContentLoadedCallbacks = [];
224
-
225
172
  const onDOMContentLoaded = callback => {
226
173
  if (document.readyState === 'loading') {
227
174
  // add listener on the first call when the document is in loading state
@@ -232,26 +179,21 @@
232
179
  }
233
180
  });
234
181
  }
235
-
236
182
  DOMContentLoadedCallbacks.push(callback);
237
183
  } else {
238
184
  callback();
239
185
  }
240
186
  };
241
-
242
187
  const isRTL = () => document.documentElement.dir === 'rtl';
243
-
244
188
  const defineJQueryPlugin = plugin => {
245
189
  onDOMContentLoaded(() => {
246
190
  const $ = getjQuery();
247
191
  /* istanbul ignore if */
248
-
249
192
  if ($) {
250
193
  const name = plugin.NAME;
251
194
  const JQUERY_NO_CONFLICT = $.fn[name];
252
195
  $.fn[name] = plugin.jQueryInterface;
253
196
  $.fn[name].Constructor = plugin;
254
-
255
197
  $.fn[name].noConflict = () => {
256
198
  $.fn[name] = JQUERY_NO_CONFLICT;
257
199
  return plugin.jQueryInterface;
@@ -259,35 +201,27 @@
259
201
  }
260
202
  });
261
203
  };
262
-
263
- const execute = callback => {
264
- if (typeof callback === 'function') {
265
- callback();
266
- }
204
+ const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
205
+ return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue;
267
206
  };
268
-
269
207
  const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
270
208
  if (!waitForTransition) {
271
209
  execute(callback);
272
210
  return;
273
211
  }
274
-
275
212
  const durationPadding = 5;
276
213
  const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
277
214
  let called = false;
278
-
279
215
  const handler = ({
280
216
  target
281
217
  }) => {
282
218
  if (target !== transitionElement) {
283
219
  return;
284
220
  }
285
-
286
221
  called = true;
287
222
  transitionElement.removeEventListener(TRANSITION_END, handler);
288
223
  execute(callback);
289
224
  };
290
-
291
225
  transitionElement.addEventListener(TRANSITION_END, handler);
292
226
  setTimeout(() => {
293
227
  if (!called) {
@@ -295,6 +229,7 @@
295
229
  }
296
230
  }, emulatedDuration);
297
231
  };
232
+
298
233
  /**
299
234
  * Return the previous/next element of a list.
300
235
  *
@@ -304,23 +239,19 @@
304
239
  * @param isCycleAllowed
305
240
  * @return {Element|elem} The proper element
306
241
  */
307
-
308
-
309
242
  const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
310
243
  const listLength = list.length;
311
- let index = list.indexOf(activeElement); // if the element does not exist in the list return an element
312
- // depending on the direction and if cycle is allowed
244
+ let index = list.indexOf(activeElement);
313
245
 
246
+ // if the element does not exist in the list return an element
247
+ // depending on the direction and if cycle is allowed
314
248
  if (index === -1) {
315
249
  return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0];
316
250
  }
317
-
318
251
  index += shouldGetNext ? 1 : -1;
319
-
320
252
  if (isCycleAllowed) {
321
253
  index = (index + listLength) % listLength;
322
254
  }
323
-
324
255
  return list[Math.max(0, Math.min(index, listLength - 1))];
325
256
  };
326
257
 
@@ -329,9 +260,7 @@
329
260
  exports.executeAfterTransition = executeAfterTransition;
330
261
  exports.findShadowRoot = findShadowRoot;
331
262
  exports.getElement = getElement;
332
- exports.getElementFromSelector = getElementFromSelector;
333
263
  exports.getNextActiveElement = getNextActiveElement;
334
- exports.getSelectorFromElement = getSelectorFromElement;
335
264
  exports.getTransitionDurationFromElement = getTransitionDurationFromElement;
336
265
  exports.getUID = getUID;
337
266
  exports.getjQuery = getjQuery;
@@ -341,10 +270,11 @@
341
270
  exports.isVisible = isVisible;
342
271
  exports.noop = noop;
343
272
  exports.onDOMContentLoaded = onDOMContentLoaded;
273
+ exports.parseSelector = parseSelector;
344
274
  exports.reflow = reflow;
345
275
  exports.toType = toType;
346
276
  exports.triggerTransitionEnd = triggerTransitionEnd;
347
277
 
348
- Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
278
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
349
279
 
350
280
  }));
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * Bootstrap sanitizer.js v5.2.2 (https://getbootstrap.com/)
3
- * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap sanitizer.js v5.3.3 (https://getbootstrap.com/)
3
+ * Copyright 2011-2024 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) {
@@ -11,42 +11,13 @@
11
11
 
12
12
  /**
13
13
  * --------------------------------------------------------------------------
14
- * Bootstrap (v5.2.2): util/sanitizer.js
14
+ * Bootstrap util/sanitizer.js
15
15
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16
16
  * --------------------------------------------------------------------------
17
17
  */
18
- const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
19
- const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
20
- /**
21
- * A pattern that recognizes a commonly useful subset of URLs that are safe.
22
- *
23
- * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
24
- */
25
-
26
- const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i;
27
- /**
28
- * A pattern that matches safe data URLs. Only matches image, video and audio types.
29
- *
30
- * Shout-out to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
31
- */
32
-
33
- const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i;
34
-
35
- const allowedAttribute = (attribute, allowedAttributeList) => {
36
- const attributeName = attribute.nodeName.toLowerCase();
37
-
38
- if (allowedAttributeList.includes(attributeName)) {
39
- if (uriAttributes.has(attributeName)) {
40
- return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue));
41
- }
42
-
43
- return true;
44
- } // Check if a regular expression validates the attribute.
45
-
46
-
47
- return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));
48
- };
49
18
 
19
+ // js-docs-start allow-list
20
+ const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
50
21
  const DefaultAllowlist = {
51
22
  // Global attributes allowed on any supplied element below.
52
23
  '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
@@ -56,7 +27,10 @@
56
27
  br: [],
57
28
  col: [],
58
29
  code: [],
30
+ dd: [],
59
31
  div: [],
32
+ dl: [],
33
+ dt: [],
60
34
  em: [],
61
35
  hr: [],
62
36
  h1: [],
@@ -80,43 +54,60 @@
80
54
  u: [],
81
55
  ul: []
82
56
  };
57
+ // js-docs-end allow-list
58
+
59
+ const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
60
+
61
+ /**
62
+ * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
63
+ * contexts.
64
+ *
65
+ * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
66
+ */
67
+ // eslint-disable-next-line unicorn/better-regex
68
+ const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
69
+ const allowedAttribute = (attribute, allowedAttributeList) => {
70
+ const attributeName = attribute.nodeName.toLowerCase();
71
+ if (allowedAttributeList.includes(attributeName)) {
72
+ if (uriAttributes.has(attributeName)) {
73
+ return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));
74
+ }
75
+ return true;
76
+ }
77
+
78
+ // Check if a regular expression validates the attribute.
79
+ return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));
80
+ };
83
81
  function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
84
82
  if (!unsafeHtml.length) {
85
83
  return unsafeHtml;
86
84
  }
87
-
88
85
  if (sanitizeFunction && typeof sanitizeFunction === 'function') {
89
86
  return sanitizeFunction(unsafeHtml);
90
87
  }
91
-
92
88
  const domParser = new window.DOMParser();
93
89
  const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
94
90
  const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
95
-
96
91
  for (const element of elements) {
97
92
  const elementName = element.nodeName.toLowerCase();
98
-
99
93
  if (!Object.keys(allowList).includes(elementName)) {
100
94
  element.remove();
101
95
  continue;
102
96
  }
103
-
104
97
  const attributeList = [].concat(...element.attributes);
105
98
  const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
106
-
107
99
  for (const attribute of attributeList) {
108
100
  if (!allowedAttribute(attribute, allowedAttributes)) {
109
101
  element.removeAttribute(attribute.nodeName);
110
102
  }
111
103
  }
112
104
  }
113
-
114
105
  return createdDocument.body.innerHTML;
115
106
  }
116
107
 
117
108
  exports.DefaultAllowlist = DefaultAllowlist;
118
109
  exports.sanitizeHtml = sanitizeHtml;
119
110
 
120
- Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
111
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
121
112
 
122
113
  }));
@@ -1,25 +1,22 @@
1
1
  /*!
2
- * Bootstrap scrollbar.js v5.2.2 (https://getbootstrap.com/)
3
- * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap scrollbar.js v5.3.3 (https://getbootstrap.com/)
3
+ * Copyright 2011-2024 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/selector-engine'), require('../dom/manipulator'), require('./index')) :
8
- typeof define === 'function' && define.amd ? define(['../dom/selector-engine', '../dom/manipulator', './index'], factory) :
9
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Scrollbar = factory(global.SelectorEngine, global.Manipulator, global.Index));
10
- })(this, (function (SelectorEngine, Manipulator, index) { 'use strict';
11
-
12
- const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
13
-
14
- const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
15
- const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/manipulator.js'), require('../dom/selector-engine.js'), require('./index.js')) :
8
+ typeof define === 'function' && define.amd ? define(['../dom/manipulator', '../dom/selector-engine', './index'], factory) :
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Scrollbar = factory(global.Manipulator, global.SelectorEngine, global.Index));
10
+ })(this, (function (Manipulator, SelectorEngine, index_js) { 'use strict';
16
11
 
17
12
  /**
18
13
  * --------------------------------------------------------------------------
19
- * Bootstrap (v5.2.2): util/scrollBar.js
14
+ * Bootstrap util/scrollBar.js
20
15
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
21
16
  * --------------------------------------------------------------------------
22
17
  */
18
+
19
+
23
20
  /**
24
21
  * Constants
25
22
  */
@@ -28,6 +25,7 @@
28
25
  const SELECTOR_STICKY_CONTENT = '.sticky-top';
29
26
  const PROPERTY_PADDING = 'padding-right';
30
27
  const PROPERTY_MARGIN = 'margin-right';
28
+
31
29
  /**
32
30
  * Class definition
33
31
  */
@@ -35,102 +33,78 @@
35
33
  class ScrollBarHelper {
36
34
  constructor() {
37
35
  this._element = document.body;
38
- } // Public
39
-
36
+ }
40
37
 
38
+ // Public
41
39
  getWidth() {
42
40
  // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
43
41
  const documentWidth = document.documentElement.clientWidth;
44
42
  return Math.abs(window.innerWidth - documentWidth);
45
43
  }
46
-
47
44
  hide() {
48
45
  const width = this.getWidth();
49
-
50
- this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width
51
-
52
-
53
- this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
54
-
55
-
46
+ this._disableOverFlow();
47
+ // give padding to element to balance the hidden scrollbar width
48
+ this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
49
+ // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
56
50
  this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
57
-
58
51
  this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);
59
52
  }
60
-
61
53
  reset() {
62
54
  this._resetElementAttributes(this._element, 'overflow');
63
-
64
55
  this._resetElementAttributes(this._element, PROPERTY_PADDING);
65
-
66
56
  this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);
67
-
68
57
  this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);
69
58
  }
70
-
71
59
  isOverflowing() {
72
60
  return this.getWidth() > 0;
73
- } // Private
74
-
61
+ }
75
62
 
63
+ // Private
76
64
  _disableOverFlow() {
77
65
  this._saveInitialAttribute(this._element, 'overflow');
78
-
79
66
  this._element.style.overflow = 'hidden';
80
67
  }
81
-
82
68
  _setElementAttributes(selector, styleProperty, callback) {
83
69
  const scrollbarWidth = this.getWidth();
84
-
85
70
  const manipulationCallBack = element => {
86
71
  if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
87
72
  return;
88
73
  }
89
-
90
74
  this._saveInitialAttribute(element, styleProperty);
91
-
92
75
  const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);
93
76
  element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);
94
77
  };
95
-
96
78
  this._applyManipulationCallback(selector, manipulationCallBack);
97
79
  }
98
-
99
80
  _saveInitialAttribute(element, styleProperty) {
100
81
  const actualValue = element.style.getPropertyValue(styleProperty);
101
-
102
82
  if (actualValue) {
103
- Manipulator__default.default.setDataAttribute(element, styleProperty, actualValue);
83
+ Manipulator.setDataAttribute(element, styleProperty, actualValue);
104
84
  }
105
85
  }
106
-
107
86
  _resetElementAttributes(selector, styleProperty) {
108
87
  const manipulationCallBack = element => {
109
- const value = Manipulator__default.default.getDataAttribute(element, styleProperty); // We only want to remove the property if the value is `null`; the value can also be zero
110
-
88
+ const value = Manipulator.getDataAttribute(element, styleProperty);
89
+ // We only want to remove the property if the value is `null`; the value can also be zero
111
90
  if (value === null) {
112
91
  element.style.removeProperty(styleProperty);
113
92
  return;
114
93
  }
115
-
116
- Manipulator__default.default.removeDataAttribute(element, styleProperty);
94
+ Manipulator.removeDataAttribute(element, styleProperty);
117
95
  element.style.setProperty(styleProperty, value);
118
96
  };
119
-
120
97
  this._applyManipulationCallback(selector, manipulationCallBack);
121
98
  }
122
-
123
99
  _applyManipulationCallback(selector, callBack) {
124
- if (index.isElement(selector)) {
100
+ if (index_js.isElement(selector)) {
125
101
  callBack(selector);
126
102
  return;
127
103
  }
128
-
129
- for (const sel of SelectorEngine__default.default.find(selector, this._element)) {
104
+ for (const sel of SelectorEngine.find(selector, this._element)) {
130
105
  callBack(sel);
131
106
  }
132
107
  }
133
-
134
108
  }
135
109
 
136
110
  return ScrollBarHelper;