bootstrap 5.2.2 → 5.3.3

Sign up to get free protection for your applications and to get access to all the features.
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;