bootstrap 5.2.0 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +55 -0
  3. data/README.md +25 -5
  4. data/assets/javascripts/bootstrap/alert.js +22 -32
  5. data/assets/javascripts/bootstrap/base-component.js +22 -38
  6. data/assets/javascripts/bootstrap/button.js +19 -22
  7. data/assets/javascripts/bootstrap/carousel.js +52 -135
  8. data/assets/javascripts/bootstrap/collapse.js +40 -102
  9. data/assets/javascripts/bootstrap/dom/data.js +8 -12
  10. data/assets/javascripts/bootstrap/dom/event-handler.js +19 -66
  11. data/assets/javascripts/bootstrap/dom/manipulator.js +4 -17
  12. data/assets/javascripts/bootstrap/dom/selector-engine.js +42 -24
  13. data/assets/javascripts/bootstrap/dropdown.js +74 -143
  14. data/assets/javascripts/bootstrap/modal.js +66 -143
  15. data/assets/javascripts/bootstrap/offcanvas.js +50 -102
  16. data/assets/javascripts/bootstrap/popover.js +23 -29
  17. data/assets/javascripts/bootstrap/scrollspy.js +64 -97
  18. data/assets/javascripts/bootstrap/tab.js +55 -112
  19. data/assets/javascripts/bootstrap/toast.js +39 -77
  20. data/assets/javascripts/bootstrap/tooltip.js +99 -216
  21. data/assets/javascripts/bootstrap/util/backdrop.js +28 -54
  22. data/assets/javascripts/bootstrap/util/component-functions.js +13 -18
  23. data/assets/javascripts/bootstrap/util/config.js +15 -27
  24. data/assets/javascripts/bootstrap/util/focustrap.js +20 -36
  25. data/assets/javascripts/bootstrap/util/index.js +42 -111
  26. data/assets/javascripts/bootstrap/util/sanitizer.js +30 -42
  27. data/assets/javascripts/bootstrap/util/scrollbar.js +24 -50
  28. data/assets/javascripts/bootstrap/util/swipe.js +27 -48
  29. data/assets/javascripts/bootstrap/util/template-factory.js +25 -52
  30. data/assets/javascripts/bootstrap-sprockets.js +12 -12
  31. data/assets/javascripts/bootstrap.js +764 -1529
  32. data/assets/javascripts/bootstrap.min.js +3 -3
  33. data/assets/stylesheets/_bootstrap-grid.scss +1 -3
  34. data/assets/stylesheets/_bootstrap-reboot.scss +1 -0
  35. data/assets/stylesheets/_bootstrap.scss +1 -0
  36. data/assets/stylesheets/bootstrap/_accordion.scss +16 -4
  37. data/assets/stylesheets/bootstrap/_alert.scss +8 -11
  38. data/assets/stylesheets/bootstrap/_button-group.scss +3 -3
  39. data/assets/stylesheets/bootstrap/_buttons.scss +31 -10
  40. data/assets/stylesheets/bootstrap/_card.scss +5 -0
  41. data/assets/stylesheets/bootstrap/_carousel.scss +20 -5
  42. data/assets/stylesheets/bootstrap/_close.scss +32 -9
  43. data/assets/stylesheets/bootstrap/_dropdown.scss +3 -1
  44. data/assets/stylesheets/bootstrap/_functions.scss +3 -3
  45. data/assets/stylesheets/bootstrap/_grid.scss +6 -0
  46. data/assets/stylesheets/bootstrap/_helpers.scss +2 -0
  47. data/assets/stylesheets/bootstrap/_list-group.scss +18 -12
  48. data/assets/stylesheets/bootstrap/_maps.scss +120 -0
  49. data/assets/stylesheets/bootstrap/_mixins.scss +1 -2
  50. data/assets/stylesheets/bootstrap/_modal.scss +1 -1
  51. data/assets/stylesheets/bootstrap/_nav.scss +42 -5
  52. data/assets/stylesheets/bootstrap/_navbar.scss +17 -4
  53. data/assets/stylesheets/bootstrap/_offcanvas.scss +9 -6
  54. data/assets/stylesheets/bootstrap/_pagination.scss +1 -1
  55. data/assets/stylesheets/bootstrap/_popover.scss +5 -5
  56. data/assets/stylesheets/bootstrap/_progress.scss +10 -1
  57. data/assets/stylesheets/bootstrap/_reboot.scss +3 -3
  58. data/assets/stylesheets/bootstrap/_root.scss +121 -10
  59. data/assets/stylesheets/bootstrap/_tables.scss +18 -11
  60. data/assets/stylesheets/bootstrap/_toasts.scss +5 -2
  61. data/assets/stylesheets/bootstrap/_tooltip.scss +4 -5
  62. data/assets/stylesheets/bootstrap/_utilities.scss +172 -13
  63. data/assets/stylesheets/bootstrap/_variables-dark.scss +85 -0
  64. data/assets/stylesheets/bootstrap/_variables.scss +272 -162
  65. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +4 -0
  66. data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +23 -3
  67. data/assets/stylesheets/bootstrap/forms/_form-check.scss +24 -11
  68. data/assets/stylesheets/bootstrap/forms/_form-control.scss +23 -3
  69. data/assets/stylesheets/bootstrap/forms/_form-select.scss +11 -2
  70. data/assets/stylesheets/bootstrap/forms/_input-group.scss +7 -4
  71. data/assets/stylesheets/bootstrap/helpers/_color-bg.scss +0 -2
  72. data/assets/stylesheets/bootstrap/helpers/_colored-links.scss +20 -2
  73. data/assets/stylesheets/bootstrap/helpers/_focus-ring.scss +5 -0
  74. data/assets/stylesheets/bootstrap/helpers/_icon-link.scss +25 -0
  75. data/assets/stylesheets/bootstrap/mixins/_alert.scss +4 -1
  76. data/assets/stylesheets/bootstrap/mixins/_banner.scss +3 -5
  77. data/assets/stylesheets/bootstrap/mixins/_caret.scss +30 -25
  78. data/assets/stylesheets/bootstrap/mixins/_color-mode.scss +21 -0
  79. data/assets/stylesheets/bootstrap/mixins/_forms.scss +18 -17
  80. data/assets/stylesheets/bootstrap/mixins/_list-group.scss +2 -0
  81. data/assets/stylesheets/bootstrap/mixins/_table-variants.scss +2 -2
  82. data/assets/stylesheets/bootstrap/mixins/_utilities.scss +2 -2
  83. data/assets/stylesheets/bootstrap/mixins/_visually-hidden.scss +5 -1
  84. data/assets/stylesheets/bootstrap/vendor/_rfs.scss +23 -29
  85. data/bootstrap.gemspec +1 -1
  86. data/lib/bootstrap/version.rb +2 -2
  87. data/tasks/updater/js.rb +2 -2
  88. data/tasks/updater/network.rb +2 -2
  89. data/tasks/updater/scss.rb +1 -1
  90. data/tasks/updater.rb +2 -2
  91. data/test/gemfiles/rails_5_2.gemfile +8 -0
  92. data/test/gemfiles/rails_7_0.gemfile +7 -0
  93. data/test/test_helper.rb +3 -2
  94. metadata +17 -9
  95. data/.travis.yml +0 -32
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * Bootstrap index.js v5.2.0 (https://getbootstrap.com/)
3
- * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap index.js v5.3.0 (https://getbootstrap.com/)
3
+ * Copyright 2011-2023 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.0): 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,8 +159,6 @@
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
  };
@@ -216,12 +167,9 @@
216
167
  if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
217
168
  return window.jQuery;
218
169
  }
219
-
220
170
  return null;
221
171
  };
222
-
223
172
  const DOMContentLoadedCallbacks = [];
224
-
225
173
  const onDOMContentLoaded = callback => {
226
174
  if (document.readyState === 'loading') {
227
175
  // add listener on the first call when the document is in loading state
@@ -232,26 +180,21 @@
232
180
  }
233
181
  });
234
182
  }
235
-
236
183
  DOMContentLoadedCallbacks.push(callback);
237
184
  } else {
238
185
  callback();
239
186
  }
240
187
  };
241
-
242
188
  const isRTL = () => document.documentElement.dir === 'rtl';
243
-
244
189
  const defineJQueryPlugin = plugin => {
245
190
  onDOMContentLoaded(() => {
246
191
  const $ = getjQuery();
247
192
  /* istanbul ignore if */
248
-
249
193
  if ($) {
250
194
  const name = plugin.NAME;
251
195
  const JQUERY_NO_CONFLICT = $.fn[name];
252
196
  $.fn[name] = plugin.jQueryInterface;
253
197
  $.fn[name].Constructor = plugin;
254
-
255
198
  $.fn[name].noConflict = () => {
256
199
  $.fn[name] = JQUERY_NO_CONFLICT;
257
200
  return plugin.jQueryInterface;
@@ -259,35 +202,27 @@
259
202
  }
260
203
  });
261
204
  };
262
-
263
- const execute = callback => {
264
- if (typeof callback === 'function') {
265
- callback();
266
- }
205
+ const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
206
+ return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue;
267
207
  };
268
-
269
208
  const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
270
209
  if (!waitForTransition) {
271
210
  execute(callback);
272
211
  return;
273
212
  }
274
-
275
213
  const durationPadding = 5;
276
214
  const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;
277
215
  let called = false;
278
-
279
216
  const handler = ({
280
217
  target
281
218
  }) => {
282
219
  if (target !== transitionElement) {
283
220
  return;
284
221
  }
285
-
286
222
  called = true;
287
223
  transitionElement.removeEventListener(TRANSITION_END, handler);
288
224
  execute(callback);
289
225
  };
290
-
291
226
  transitionElement.addEventListener(TRANSITION_END, handler);
292
227
  setTimeout(() => {
293
228
  if (!called) {
@@ -295,6 +230,7 @@
295
230
  }
296
231
  }, emulatedDuration);
297
232
  };
233
+
298
234
  /**
299
235
  * Return the previous/next element of a list.
300
236
  *
@@ -304,23 +240,19 @@
304
240
  * @param isCycleAllowed
305
241
  * @return {Element|elem} The proper element
306
242
  */
307
-
308
-
309
243
  const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
310
244
  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
245
+ let index = list.indexOf(activeElement);
313
246
 
247
+ // if the element does not exist in the list return an element
248
+ // depending on the direction and if cycle is allowed
314
249
  if (index === -1) {
315
250
  return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0];
316
251
  }
317
-
318
252
  index += shouldGetNext ? 1 : -1;
319
-
320
253
  if (isCycleAllowed) {
321
254
  index = (index + listLength) % listLength;
322
255
  }
323
-
324
256
  return list[Math.max(0, Math.min(index, listLength - 1))];
325
257
  };
326
258
 
@@ -329,9 +261,7 @@
329
261
  exports.executeAfterTransition = executeAfterTransition;
330
262
  exports.findShadowRoot = findShadowRoot;
331
263
  exports.getElement = getElement;
332
- exports.getElementFromSelector = getElementFromSelector;
333
264
  exports.getNextActiveElement = getNextActiveElement;
334
- exports.getSelectorFromElement = getSelectorFromElement;
335
265
  exports.getTransitionDurationFromElement = getTransitionDurationFromElement;
336
266
  exports.getUID = getUID;
337
267
  exports.getjQuery = getjQuery;
@@ -341,10 +271,11 @@
341
271
  exports.isVisible = isVisible;
342
272
  exports.noop = noop;
343
273
  exports.onDOMContentLoaded = onDOMContentLoaded;
274
+ exports.parseSelector = parseSelector;
344
275
  exports.reflow = reflow;
345
276
  exports.toType = toType;
346
277
  exports.triggerTransitionEnd = triggerTransitionEnd;
347
278
 
348
- Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
279
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
349
280
 
350
281
  }));
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * Bootstrap sanitizer.js v5.2.0 (https://getbootstrap.com/)
3
- * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap sanitizer.js v5.3.0 (https://getbootstrap.com/)
3
+ * Copyright 2011-2023 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.0): 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],
@@ -80,43 +51,60 @@
80
51
  u: [],
81
52
  ul: []
82
53
  };
54
+ // js-docs-end allow-list
55
+
56
+ const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
57
+
58
+ /**
59
+ * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
60
+ * contexts.
61
+ *
62
+ * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
63
+ */
64
+ // eslint-disable-next-line unicorn/better-regex
65
+ const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
66
+ const allowedAttribute = (attribute, allowedAttributeList) => {
67
+ const attributeName = attribute.nodeName.toLowerCase();
68
+ if (allowedAttributeList.includes(attributeName)) {
69
+ if (uriAttributes.has(attributeName)) {
70
+ return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));
71
+ }
72
+ return true;
73
+ }
74
+
75
+ // Check if a regular expression validates the attribute.
76
+ return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));
77
+ };
83
78
  function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
84
79
  if (!unsafeHtml.length) {
85
80
  return unsafeHtml;
86
81
  }
87
-
88
82
  if (sanitizeFunction && typeof sanitizeFunction === 'function') {
89
83
  return sanitizeFunction(unsafeHtml);
90
84
  }
91
-
92
85
  const domParser = new window.DOMParser();
93
86
  const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
94
87
  const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
95
-
96
88
  for (const element of elements) {
97
89
  const elementName = element.nodeName.toLowerCase();
98
-
99
90
  if (!Object.keys(allowList).includes(elementName)) {
100
91
  element.remove();
101
92
  continue;
102
93
  }
103
-
104
94
  const attributeList = [].concat(...element.attributes);
105
95
  const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
106
-
107
96
  for (const attribute of attributeList) {
108
97
  if (!allowedAttribute(attribute, allowedAttributes)) {
109
98
  element.removeAttribute(attribute.nodeName);
110
99
  }
111
100
  }
112
101
  }
113
-
114
102
  return createdDocument.body.innerHTML;
115
103
  }
116
104
 
117
105
  exports.DefaultAllowlist = DefaultAllowlist;
118
106
  exports.sanitizeHtml = sanitizeHtml;
119
107
 
120
- Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
108
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
121
109
 
122
110
  }));
@@ -1,25 +1,22 @@
1
1
  /*!
2
- * Bootstrap scrollbar.js v5.2.0 (https://getbootstrap.com/)
3
- * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap scrollbar.js v5.3.0 (https://getbootstrap.com/)
3
+ * Copyright 2011-2023 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.0): 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;