2 * Bootstrap v5.3.2 (https://getbootstrap.com/)
3 * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 (function (global
, factory
) {
7 typeof exports
=== 'object' && typeof module
!== 'undefined' ? module
.exports
= factory(require('@popperjs/core')) :
8 typeof define
=== 'function' && define
.amd
? define(['@popperjs/core'], factory
) :
9 (global
= typeof globalThis
!== 'undefined' ? globalThis : global
|| self
, global
.bootstrap
= factory(global
.Popper
));
10 })(this, (function (Popper
) { 'use strict';
12 function _interopNamespaceDefault(e
) {
13 const n
= Object
.create(null, { [Symbol
.toStringTag
]: { value: 'Module' } });
16 if (k
!== 'default') {
17 const d
= Object
.getOwnPropertyDescriptor(e
, k
);
18 Object
.defineProperty(n
, k
, d
.get ? d : {
26 return Object
.freeze(n
);
29 const Popper__namespace
= /*#__PURE__*/_interopNamespaceDefault(Popper
);
32 * --------------------------------------------------------------------------
33 * Bootstrap dom/data.js
34 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
35 * --------------------------------------------------------------------------
42 const elementMap
= new Map();
44 set(element
, key
, instance
) {
45 if (!elementMap
.has(element
)) {
46 elementMap
.set(element
, new Map());
48 const instanceMap
= elementMap
.get(element
);
50 // make it clear we only want one instance per element
51 // can be removed later when multiple key/instances are fine to be used
52 if (!instanceMap
.has(key
) && instanceMap
.size
!== 0) {
53 // eslint-disable-next-line no-console
54 console
.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);
57 instanceMap
.set(key
, instance
);
60 if (elementMap
.has(element
)) {
61 return elementMap
.get(element
).get(key
) || null;
65 remove(element
, key
) {
66 if (!elementMap
.has(element
)) {
69 const instanceMap
= elementMap
.get(element
);
70 instanceMap
.delete(key
);
72 // free up element references if there are no instances left for an element
73 if (instanceMap
.size
=== 0) {
74 elementMap
.delete(element
);
80 * --------------------------------------------------------------------------
81 * Bootstrap util/index.js
82 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
83 * --------------------------------------------------------------------------
86 const MAX_UID
= 1000000;
87 const MILLISECONDS_MULTIPLIER
= 1000;
88 const TRANSITION_END
= 'transitionend';
91 * Properly escape IDs selectors to handle weird IDs
92 * @param {string} selector
95 const parseSelector
= selector
=> {
96 if (selector
&& window
.CSS
&& window
.CSS
.escape
) {
97 // document.querySelector needs escaping to handle IDs (html5+) containing for instance /
98 selector
= selector
.replace(/#([^\s"#']+)/g, (match
, id
) => `#${CSS.escape(id)}`);
103 // Shout-out Angus Croll (https://goo.gl/pxwQGp)
104 const toType
= object
=> {
105 if (object
=== null || object
=== undefined) {
108 return Object
.prototype.toString
.call(object
).match(/\s([a-z]+)/i)[1].toLowerCase();
115 const getUID
= prefix
=> {
117 prefix
+= Math
.floor(Math
.random() * MAX_UID
);
118 } while (document
.getElementById(prefix
));
121 const getTransitionDurationFromElement
= element
=> {
126 // Get transition-duration of the element
130 } = window
.getComputedStyle(element
);
131 const floatTransitionDuration
= Number
.parseFloat(transitionDuration
);
132 const floatTransitionDelay
= Number
.parseFloat(transitionDelay
);
134 // Return 0 if element or transition duration is not found
135 if (!floatTransitionDuration
&& !floatTransitionDelay
) {
139 // If multiple durations are defined, take the first
140 transitionDuration
= transitionDuration
.split(',')[0];
141 transitionDelay
= transitionDelay
.split(',')[0];
142 return (Number
.parseFloat(transitionDuration
) + Number
.parseFloat(transitionDelay
)) * MILLISECONDS_MULTIPLIER
;
144 const triggerTransitionEnd
= element
=> {
145 element
.dispatchEvent(new Event(TRANSITION_END
));
147 const isElement
= object
=> {
148 if (!object
|| typeof object
!== 'object') {
151 if (typeof object
.jquery
!== 'undefined') {
154 return typeof object
.nodeType
!== 'undefined';
156 const getElement
= object
=> {
157 // it's a jQuery object or a node element
158 if (isElement(object
)) {
159 return object
.jquery
? object
[0] : object
;
161 if (typeof object
=== 'string' && object
.length
> 0) {
162 return document
.querySelector(parseSelector(object
));
166 const isVisible
= element
=> {
167 if (!isElement(element
) || element
.getClientRects().length
=== 0) {
170 const elementIsVisible
= getComputedStyle(element
).getPropertyValue('visibility') === 'visible';
171 // Handle `details` element as its content may falsie appear visible when it is closed
172 const closedDetails
= element
.closest('details:not([open])');
173 if (!closedDetails
) {
174 return elementIsVisible
;
176 if (closedDetails
!== element
) {
177 const summary
= element
.closest('summary');
178 if (summary
&& summary
.parentNode
!== closedDetails
) {
181 if (summary
=== null) {
185 return elementIsVisible
;
187 const isDisabled
= element
=> {
188 if (!element
|| element
.nodeType
!== Node
.ELEMENT_NODE
) {
191 if (element
.classList
.contains('disabled')) {
194 if (typeof element
.disabled
!== 'undefined') {
195 return element
.disabled
;
197 return element
.hasAttribute('disabled') && element
.getAttribute('disabled') !== 'false';
199 const findShadowRoot
= element
=> {
200 if (!document
.documentElement
.attachShadow
) {
204 // Can find the shadow root otherwise it'll return the document
205 if (typeof element
.getRootNode
=== 'function') {
206 const root
= element
.getRootNode();
207 return root
instanceof ShadowRoot
? root : null;
209 if (element
instanceof ShadowRoot
) {
213 // when we don't find a shadow root
214 if (!element
.parentNode
) {
217 return findShadowRoot(element
.parentNode
);
219 const noop
= () => {};
222 * Trick to restart an element's animation
224 * @param {HTMLElement} element
227 * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
229 const reflow
= element
=> {
230 element
.offsetHeight
; // eslint-disable-line no-unused-expressions
233 const getjQuery
= () => {
234 if (window
.jQuery
&& !document
.body
.hasAttribute('data-bs-no-jquery')) {
235 return window
.jQuery
;
239 const DOMContentLoadedCallbacks
= [];
240 const onDOMContentLoaded
= callback
=> {
241 if (document
.readyState
=== 'loading') {
242 // add listener on the first call when the document is in loading state
243 if (!DOMContentLoadedCallbacks
.length
) {
244 document
.addEventListener('DOMContentLoaded', () => {
245 for (const callback
of DOMContentLoadedCallbacks
) {
250 DOMContentLoadedCallbacks
.push(callback
);
255 const isRTL
= () => document
.documentElement
.dir
=== 'rtl';
256 const defineJQueryPlugin
= plugin
=> {
257 onDOMContentLoaded(() => {
258 const $ = getjQuery();
259 /* istanbul ignore if */
261 const name
= plugin
.NAME
;
262 const JQUERY_NO_CONFLICT
= $.fn
[name
];
263 $.fn
[name
] = plugin
.jQueryInterface
;
264 $.fn
[name
].Constructor
= plugin
;
265 $.fn
[name
].noConflict
= () => {
266 $.fn
[name
] = JQUERY_NO_CONFLICT
;
267 return plugin
.jQueryInterface
;
272 const execute
= (possibleCallback
, args
= [], defaultValue
= possibleCallback
) => {
273 return typeof possibleCallback
=== 'function' ? possibleCallback(...args
) : defaultValue
;
275 const executeAfterTransition
= (callback
, transitionElement
, waitForTransition
= true) => {
276 if (!waitForTransition
) {
280 const durationPadding
= 5;
281 const emulatedDuration
= getTransitionDurationFromElement(transitionElement
) + durationPadding
;
286 if (target
!== transitionElement
) {
290 transitionElement
.removeEventListener(TRANSITION_END
, handler
);
293 transitionElement
.addEventListener(TRANSITION_END
, handler
);
296 triggerTransitionEnd(transitionElement
);
298 }, emulatedDuration
);
302 * Return the previous/next element of a list.
304 * @param {array} list The list of elements
305 * @param activeElement The active element
306 * @param shouldGetNext Choose to get next or previous element
307 * @param isCycleAllowed
308 * @return {Element|elem} The proper element
310 const getNextActiveElement
= (list
, activeElement
, shouldGetNext
, isCycleAllowed
) => {
311 const listLength
= list
.length
;
312 let index
= list
.indexOf(activeElement
);
314 // if the element does not exist in the list return an element
315 // depending on the direction and if cycle is allowed
317 return !shouldGetNext
&& isCycleAllowed
? list
[listLength
- 1] : list
[0];
319 index
+= shouldGetNext
? 1 : -1;
320 if (isCycleAllowed
) {
321 index
= (index
+ listLength
) % listLength
;
323 return list
[Math
.max(0, Math
.min(index
, listLength
- 1))];
327 * --------------------------------------------------------------------------
328 * Bootstrap dom/event-handler.js
329 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
330 * --------------------------------------------------------------------------
338 const namespaceRegex
= /[^.]*(?=\..*)\.|.*/;
339 const stripNameRegex
= /\..*/;
340 const stripUidRegex
= /::\d+$/;
341 const eventRegistry
= {}; // Events storage
343 const customEvents
= {
344 mouseenter: 'mouseover',
345 mouseleave: 'mouseout'
347 const nativeEvents
= new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']);
353 function makeEventUid(element
, uid
) {
354 return uid
&& `${uid}::${uidEvent++}` || element
.uidEvent
|| uidEvent
++;
356 function getElementEvents(element
) {
357 const uid
= makeEventUid(element
);
358 element
.uidEvent
= uid
;
359 eventRegistry
[uid
] = eventRegistry
[uid
] || {};
360 return eventRegistry
[uid
];
362 function bootstrapHandler(element
, fn
) {
363 return function handler(event
) {
365 delegateTarget: element
367 if (handler
.oneOff
) {
368 EventHandler
.off(element
, event
.type
, fn
);
370 return fn
.apply(element
, [event
]);
373 function bootstrapDelegationHandler(element
, selector
, fn
) {
374 return function handler(event
) {
375 const domElements
= element
.querySelectorAll(selector
);
378 } = event
; target
&& target
!== this; target
= target
.parentNode
) {
379 for (const domElement
of domElements
) {
380 if (domElement
!== target
) {
384 delegateTarget: target
386 if (handler
.oneOff
) {
387 EventHandler
.off(element
, event
.type
, selector
, fn
);
389 return fn
.apply(target
, [event
]);
394 function findHandler(events
, callable
, delegationSelector
= null) {
395 return Object
.values(events
).find(event
=> event
.callable
=== callable
&& event
.delegationSelector
=== delegationSelector
);
397 function normalizeParameters(originalTypeEvent
, handler
, delegationFunction
) {
398 const isDelegated
= typeof handler
=== 'string';
399 // TODO: tooltip passes `false` instead of selector, so we need to check
400 const callable
= isDelegated
? delegationFunction : handler
|| delegationFunction
;
401 let typeEvent
= getTypeEvent(originalTypeEvent
);
402 if (!nativeEvents
.has(typeEvent
)) {
403 typeEvent
= originalTypeEvent
;
405 return [isDelegated
, callable
, typeEvent
];
407 function addHandler(element
, originalTypeEvent
, handler
, delegationFunction
, oneOff
) {
408 if (typeof originalTypeEvent
!== 'string' || !element
) {
411 let [isDelegated
, callable
, typeEvent
] = normalizeParameters(originalTypeEvent
, handler
, delegationFunction
);
413 // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
414 // this prevents the handler from being dispatched the same way as mouseover or mouseout does
415 if (originalTypeEvent
in customEvents
) {
416 const wrapFunction
= fn
=> {
417 return function (event
) {
418 if (!event
.relatedTarget
|| event
.relatedTarget
!== event
.delegateTarget
&& !event
.delegateTarget
.contains(event
.relatedTarget
)) {
419 return fn
.call(this, event
);
423 callable
= wrapFunction(callable
);
425 const events
= getElementEvents(element
);
426 const handlers
= events
[typeEvent
] || (events
[typeEvent
] = {});
427 const previousFunction
= findHandler(handlers
, callable
, isDelegated
? handler : null);
428 if (previousFunction
) {
429 previousFunction
.oneOff
= previousFunction
.oneOff
&& oneOff
;
432 const uid
= makeEventUid(callable
, originalTypeEvent
.replace(namespaceRegex
, ''));
433 const fn
= isDelegated
? bootstrapDelegationHandler(element
, handler
, callable
) : bootstrapHandler(element
, callable
);
434 fn
.delegationSelector
= isDelegated
? handler : null;
435 fn
.callable
= callable
;
439 element
.addEventListener(typeEvent
, fn
, isDelegated
);
441 function removeHandler(element
, events
, typeEvent
, handler
, delegationSelector
) {
442 const fn
= findHandler(events
[typeEvent
], handler
, delegationSelector
);
446 element
.removeEventListener(typeEvent
, fn
, Boolean(delegationSelector
));
447 delete events
[typeEvent
][fn
.uidEvent
];
449 function removeNamespacedHandlers(element
, events
, typeEvent
, namespace) {
450 const storeElementEvent
= events
[typeEvent
] || {};
451 for (const [handlerKey
, event
] of Object
.entries(storeElementEvent
)) {
452 if (handlerKey
.includes(namespace)) {
453 removeHandler(element
, events
, typeEvent
, event
.callable
, event
.delegationSelector
);
457 function getTypeEvent(event
) {
458 // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
459 event
= event
.replace(stripNameRegex
, '');
460 return customEvents
[event
] || event
;
462 const EventHandler
= {
463 on(element
, event
, handler
, delegationFunction
) {
464 addHandler(element
, event
, handler
, delegationFunction
, false);
466 one(element
, event
, handler
, delegationFunction
) {
467 addHandler(element
, event
, handler
, delegationFunction
, true);
469 off(element
, originalTypeEvent
, handler
, delegationFunction
) {
470 if (typeof originalTypeEvent
!== 'string' || !element
) {
473 const [isDelegated
, callable
, typeEvent
] = normalizeParameters(originalTypeEvent
, handler
, delegationFunction
);
474 const inNamespace
= typeEvent
!== originalTypeEvent
;
475 const events
= getElementEvents(element
);
476 const storeElementEvent
= events
[typeEvent
] || {};
477 const isNamespace
= originalTypeEvent
.startsWith('.');
478 if (typeof callable
!== 'undefined') {
479 // Simplest case: handler is passed, remove that listener ONLY.
480 if (!Object
.keys(storeElementEvent
).length
) {
483 removeHandler(element
, events
, typeEvent
, callable
, isDelegated
? handler : null);
487 for (const elementEvent
of Object
.keys(events
)) {
488 removeNamespacedHandlers(element
, events
, elementEvent
, originalTypeEvent
.slice(1));
491 for (const [keyHandlers
, event
] of Object
.entries(storeElementEvent
)) {
492 const handlerKey
= keyHandlers
.replace(stripUidRegex
, '');
493 if (!inNamespace
|| originalTypeEvent
.includes(handlerKey
)) {
494 removeHandler(element
, events
, typeEvent
, event
.callable
, event
.delegationSelector
);
498 trigger(element
, event
, args
) {
499 if (typeof event
!== 'string' || !element
) {
502 const $ = getjQuery();
503 const typeEvent
= getTypeEvent(event
);
504 const inNamespace
= event
!== typeEvent
;
505 let jQueryEvent
= null;
507 let nativeDispatch
= true;
508 let defaultPrevented
= false;
509 if (inNamespace
&& $) {
510 jQueryEvent
= $.Event(event
, args
);
511 $(element
).trigger(jQueryEvent
);
512 bubbles
= !jQueryEvent
.isPropagationStopped();
513 nativeDispatch
= !jQueryEvent
.isImmediatePropagationStopped();
514 defaultPrevented
= jQueryEvent
.isDefaultPrevented();
516 const evt
= hydrateObj(new Event(event
, {
520 if (defaultPrevented
) {
521 evt
.preventDefault();
523 if (nativeDispatch
) {
524 element
.dispatchEvent(evt
);
526 if (evt
.defaultPrevented
&& jQueryEvent
) {
527 jQueryEvent
.preventDefault();
532 function hydrateObj(obj
, meta
= {}) {
533 for (const [key
, value
] of Object
.entries(meta
)) {
537 Object
.defineProperty(obj
, key
, {
549 * --------------------------------------------------------------------------
550 * Bootstrap dom/manipulator.js
551 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
552 * --------------------------------------------------------------------------
555 function normalizeData(value
) {
556 if (value
=== 'true') {
559 if (value
=== 'false') {
562 if (value
=== Number(value
).toString()) {
563 return Number(value
);
565 if (value
=== '' || value
=== 'null') {
568 if (typeof value
!== 'string') {
572 return JSON
.parse(decodeURIComponent(value
));
577 function normalizeDataKey(key
) {
578 return key
.replace(/[A-Z]/g, chr
=> `-${chr.toLowerCase()}`);
580 const Manipulator
= {
581 setDataAttribute(element
, key
, value
) {
582 element
.setAttribute(`data-bs-${normalizeDataKey(key)}`, value
);
584 removeDataAttribute(element
, key
) {
585 element
.removeAttribute(`data-bs-${normalizeDataKey(key)}`);
587 getDataAttributes(element
) {
591 const attributes
= {};
592 const bsKeys
= Object
.keys(element
.dataset
).filter(key
=> key
.startsWith('bs') && !key
.startsWith('bsConfig'));
593 for (const key
of bsKeys
) {
594 let pureKey
= key
.replace(/^bs/, '');
595 pureKey
= pureKey
.charAt(0).toLowerCase() + pureKey
.slice(1, pureKey
.length
);
596 attributes
[pureKey
] = normalizeData(element
.dataset
[key
]);
600 getDataAttribute(element
, key
) {
601 return normalizeData(element
.getAttribute(`data-bs-${normalizeDataKey(key)}`));
606 * --------------------------------------------------------------------------
607 * Bootstrap util/config.js
608 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
609 * --------------------------------------------------------------------------
619 static get Default() {
622 static get DefaultType() {
626 throw new Error('You have to implement the static method "NAME", for each component!');
629 config
= this._mergeConfigObj(config
);
630 config
= this._configAfterMerge(config
);
631 this._typeCheckConfig(config
);
634 _configAfterMerge(config
) {
637 _mergeConfigObj(config
, element
) {
638 const jsonConfig
= isElement(element
) ? Manipulator
.getDataAttribute(element
, 'config') : {}; // try to parse
641 ...this.constructor.Default
,
642 ...(typeof jsonConfig
=== 'object' ? jsonConfig : {}),
643 ...(isElement(element
) ? Manipulator
.getDataAttributes(element
) : {}),
644 ...(typeof config
=== 'object' ? config : {})
647 _typeCheckConfig(config
, configTypes
= this.constructor.DefaultType
) {
648 for (const [property
, expectedTypes
] of Object
.entries(configTypes
)) {
649 const value
= config
[property
];
650 const valueType
= isElement(value
) ? 'element' : toType(value
);
651 if (!new RegExp(expectedTypes
).test(valueType
)) {
652 throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
659 * --------------------------------------------------------------------------
660 * Bootstrap base-component.js
661 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
662 * --------------------------------------------------------------------------
670 const VERSION
= '5.3.2';
676 class BaseComponent
extends Config
{
677 constructor(element
, config
) {
679 element
= getElement(element
);
683 this._element
= element
;
684 this._config
= this._getConfig(config
);
685 Data
.set(this._element
, this.constructor.DATA_KEY
, this);
690 Data
.remove(this._element
, this.constructor.DATA_KEY
);
691 EventHandler
.off(this._element
, this.constructor.EVENT_KEY
);
692 for (const propertyName
of Object
.getOwnPropertyNames(this)) {
693 this[propertyName
] = null;
696 _queueCallback(callback
, element
, isAnimated
= true) {
697 executeAfterTransition(callback
, element
, isAnimated
);
700 config
= this._mergeConfigObj(config
, this._element
);
701 config
= this._configAfterMerge(config
);
702 this._typeCheckConfig(config
);
707 static getInstance(element
) {
708 return Data
.get(getElement(element
), this.DATA_KEY
);
710 static getOrCreateInstance(element
, config
= {}) {
711 return this.getInstance(element
) || new this(element
, typeof config
=== 'object' ? config : null);
713 static get VERSION() {
716 static get DATA_KEY() {
717 return `bs.${this.NAME}`;
719 static get EVENT_KEY() {
720 return `.${this.DATA_KEY}`;
722 static eventName(name
) {
723 return `${name}${this.EVENT_KEY}`;
728 * --------------------------------------------------------------------------
729 * Bootstrap dom/selector-engine.js
730 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
731 * --------------------------------------------------------------------------
734 const getSelector
= element
=> {
735 let selector
= element
.getAttribute('data-bs-target');
736 if (!selector
|| selector
=== '#') {
737 let hrefAttribute
= element
.getAttribute('href');
739 // The only valid content that could double as a selector are IDs or classes,
740 // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
741 // `document.querySelector` will rightfully complain it is invalid.
742 // See https://github.com/twbs/bootstrap/issues/32273
743 if (!hrefAttribute
|| !hrefAttribute
.includes('#') && !hrefAttribute
.startsWith('.')) {
747 // Just in case some CMS puts out a full URL with the anchor appended
748 if (hrefAttribute
.includes('#') && !hrefAttribute
.startsWith('#')) {
749 hrefAttribute
= `#${hrefAttribute.split('#')[1]}`;
751 selector
= hrefAttribute
&& hrefAttribute
!== '#' ? parseSelector(hrefAttribute
.trim()) : null;
755 const SelectorEngine
= {
756 find(selector
, element
= document
.documentElement
) {
757 return [].concat(...Element
.prototype.querySelectorAll
.call(element
, selector
));
759 findOne(selector
, element
= document
.documentElement
) {
760 return Element
.prototype.querySelector
.call(element
, selector
);
762 children(element
, selector
) {
763 return [].concat(...element
.children
).filter(child
=> child
.matches(selector
));
765 parents(element
, selector
) {
767 let ancestor
= element
.parentNode
.closest(selector
);
769 parents
.push(ancestor
);
770 ancestor
= ancestor
.parentNode
.closest(selector
);
774 prev(element
, selector
) {
775 let previous
= element
.previousElementSibling
;
777 if (previous
.matches(selector
)) {
780 previous
= previous
.previousElementSibling
;
784 // TODO: this is now unused; remove later along with prev()
785 next(element
, selector
) {
786 let next
= element
.nextElementSibling
;
788 if (next
.matches(selector
)) {
791 next
= next
.nextElementSibling
;
795 focusableChildren(element
) {
796 const focusables
= ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector
=> `${selector}:not([tabindex^="-"])`).join(',');
797 return this.find(focusables
, element
).filter(el
=> !isDisabled(el
) && isVisible(el
));
799 getSelectorFromElement(element
) {
800 const selector
= getSelector(element
);
802 return SelectorEngine
.findOne(selector
) ? selector : null;
806 getElementFromSelector(element
) {
807 const selector
= getSelector(element
);
808 return selector
? SelectorEngine
.findOne(selector
) : null;
810 getMultipleElementsFromSelector(element
) {
811 const selector
= getSelector(element
);
812 return selector
? SelectorEngine
.find(selector
) : [];
817 * --------------------------------------------------------------------------
818 * Bootstrap util/component-functions.js
819 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
820 * --------------------------------------------------------------------------
823 const enableDismissTrigger
= (component
, method
= 'hide') => {
824 const clickEvent
= `click.dismiss${component.EVENT_KEY}`;
825 const name
= component
.NAME
;
826 EventHandler
.on(document
, clickEvent
, `[data-bs-dismiss="${name}"]`, function (event
) {
827 if (['A', 'AREA'].includes(this.tagName
)) {
828 event
.preventDefault();
830 if (isDisabled(this)) {
833 const target
= SelectorEngine
.getElementFromSelector(this) || this.closest(`.${name}`);
834 const instance
= component
.getOrCreateInstance(target
);
836 // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
842 * --------------------------------------------------------------------------
844 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
845 * --------------------------------------------------------------------------
853 const NAME
$f
= 'alert';
854 const DATA_KEY
$a
= 'bs.alert';
855 const EVENT_KEY
$b
= `.${DATA_KEY$a}`;
856 const EVENT_CLOSE
= `close${EVENT_KEY$b}`;
857 const EVENT_CLOSED
= `closed${EVENT_KEY$b}`;
858 const CLASS_NAME_FADE
$5 = 'fade';
859 const CLASS_NAME_SHOW
$8 = 'show';
865 class Alert
extends BaseComponent
{
873 const closeEvent
= EventHandler
.trigger(this._element
, EVENT_CLOSE
);
874 if (closeEvent
.defaultPrevented
) {
877 this._element
.classList
.remove(CLASS_NAME_SHOW
$8);
878 const isAnimated
= this._element
.classList
.contains(CLASS_NAME_FADE
$5);
879 this._queueCallback(() => this._destroyElement(), this._element
, isAnimated
);
884 this._element
.remove();
885 EventHandler
.trigger(this._element
, EVENT_CLOSED
);
890 static jQueryInterface(config
) {
891 return this.each(function () {
892 const data
= Alert
.getOrCreateInstance(this);
893 if (typeof config
!== 'string') {
896 if (data
[config
] === undefined || config
.startsWith('_') || config
=== 'constructor') {
897 throw new TypeError(`No method named "${config}"`);
905 * Data API implementation
908 enableDismissTrigger(Alert
, 'close');
914 defineJQueryPlugin(Alert
);
917 * --------------------------------------------------------------------------
918 * Bootstrap button.js
919 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
920 * --------------------------------------------------------------------------
928 const NAME
$e
= 'button';
929 const DATA_KEY
$9 = 'bs.button';
930 const EVENT_KEY
$a
= `.${DATA_KEY$9}`;
931 const DATA_API_KEY
$6 = '.data-api';
932 const CLASS_NAME_ACTIVE
$3 = 'active';
933 const SELECTOR_DATA_TOGGLE
$5 = '[data-bs-toggle="button"]';
934 const EVENT_CLICK_DATA_API
$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`;
940 class Button
extends BaseComponent
{
948 // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method
949 this._element
.setAttribute('aria-pressed', this._element
.classList
.toggle(CLASS_NAME_ACTIVE
$3));
953 static jQueryInterface(config
) {
954 return this.each(function () {
955 const data
= Button
.getOrCreateInstance(this);
956 if (config
=== 'toggle') {
964 * Data API implementation
967 EventHandler
.on(document
, EVENT_CLICK_DATA_API
$6, SELECTOR_DATA_TOGGLE
$5, event
=> {
968 event
.preventDefault();
969 const button
= event
.target
.closest(SELECTOR_DATA_TOGGLE
$5);
970 const data
= Button
.getOrCreateInstance(button
);
978 defineJQueryPlugin(Button
);
981 * --------------------------------------------------------------------------
982 * Bootstrap util/swipe.js
983 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
984 * --------------------------------------------------------------------------
992 const NAME
$d
= 'swipe';
993 const EVENT_KEY
$9 = '.bs.swipe';
994 const EVENT_TOUCHSTART
= `touchstart${EVENT_KEY$9}`;
995 const EVENT_TOUCHMOVE
= `touchmove${EVENT_KEY$9}`;
996 const EVENT_TOUCHEND
= `touchend${EVENT_KEY$9}`;
997 const EVENT_POINTERDOWN
= `pointerdown${EVENT_KEY$9}`;
998 const EVENT_POINTERUP
= `pointerup${EVENT_KEY$9}`;
999 const POINTER_TYPE_TOUCH
= 'touch';
1000 const POINTER_TYPE_PEN
= 'pen';
1001 const CLASS_NAME_POINTER_EVENT
= 'pointer-event';
1002 const SWIPE_THRESHOLD
= 40;
1008 const DefaultType
$c
= {
1009 endCallback: '(function|null)',
1010 leftCallback: '(function|null)',
1011 rightCallback: '(function|null)'
1018 class Swipe
extends Config
{
1019 constructor(element
, config
) {
1021 this._element
= element
;
1022 if (!element
|| !Swipe
.isSupported()) {
1025 this._config
= this._getConfig(config
);
1027 this._supportPointerEvents
= Boolean(window
.PointerEvent
);
1032 static get Default() {
1035 static get DefaultType() {
1036 return DefaultType
$c
;
1044 EventHandler
.off(this._element
, EVENT_KEY
$9);
1049 if (!this._supportPointerEvents
) {
1050 this._deltaX
= event
.touches
[0].clientX
;
1053 if (this._eventIsPointerPenTouch(event
)) {
1054 this._deltaX
= event
.clientX
;
1058 if (this._eventIsPointerPenTouch(event
)) {
1059 this._deltaX
= event
.clientX
- this._deltaX
;
1061 this._handleSwipe();
1062 execute(this._config
.endCallback
);
1065 this._deltaX
= event
.touches
&& event
.touches
.length
> 1 ? 0 : event
.touches
[0].clientX
- this._deltaX
;
1068 const absDeltaX
= Math
.abs(this._deltaX
);
1069 if (absDeltaX
<= SWIPE_THRESHOLD
) {
1072 const direction
= absDeltaX
/ this._deltaX
;
1077 execute(direction
> 0 ? this._config
.rightCallback : this._config
.leftCallback
);
1080 if (this._supportPointerEvents
) {
1081 EventHandler
.on(this._element
, EVENT_POINTERDOWN
, event
=> this._start(event
));
1082 EventHandler
.on(this._element
, EVENT_POINTERUP
, event
=> this._end(event
));
1083 this._element
.classList
.add(CLASS_NAME_POINTER_EVENT
);
1085 EventHandler
.on(this._element
, EVENT_TOUCHSTART
, event
=> this._start(event
));
1086 EventHandler
.on(this._element
, EVENT_TOUCHMOVE
, event
=> this._move(event
));
1087 EventHandler
.on(this._element
, EVENT_TOUCHEND
, event
=> this._end(event
));
1090 _eventIsPointerPenTouch(event
) {
1091 return this._supportPointerEvents
&& (event
.pointerType
=== POINTER_TYPE_PEN
|| event
.pointerType
=== POINTER_TYPE_TOUCH
);
1095 static isSupported() {
1096 return 'ontouchstart' in document
.documentElement
|| navigator
.maxTouchPoints
> 0;
1101 * --------------------------------------------------------------------------
1102 * Bootstrap carousel.js
1103 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
1104 * --------------------------------------------------------------------------
1112 const NAME
$c
= 'carousel';
1113 const DATA_KEY
$8 = 'bs.carousel';
1114 const EVENT_KEY
$8 = `.${DATA_KEY$8}`;
1115 const DATA_API_KEY
$5 = '.data-api';
1116 const ARROW_LEFT_KEY
$1 = 'ArrowLeft';
1117 const ARROW_RIGHT_KEY
$1 = 'ArrowRight';
1118 const TOUCHEVENT_COMPAT_WAIT
= 500; // Time for mouse compat events to fire after touch
1120 const ORDER_NEXT
= 'next';
1121 const ORDER_PREV
= 'prev';
1122 const DIRECTION_LEFT
= 'left';
1123 const DIRECTION_RIGHT
= 'right';
1124 const EVENT_SLIDE
= `slide${EVENT_KEY$8}`;
1125 const EVENT_SLID
= `slid${EVENT_KEY$8}`;
1126 const EVENT_KEYDOWN
$1 = `keydown${EVENT_KEY$8}`;
1127 const EVENT_MOUSEENTER
$1 = `mouseenter${EVENT_KEY$8}`;
1128 const EVENT_MOUSELEAVE
$1 = `mouseleave${EVENT_KEY$8}`;
1129 const EVENT_DRAG_START
= `dragstart${EVENT_KEY$8}`;
1130 const EVENT_LOAD_DATA_API
$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`;
1131 const EVENT_CLICK_DATA_API
$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`;
1132 const CLASS_NAME_CAROUSEL
= 'carousel';
1133 const CLASS_NAME_ACTIVE
$2 = 'active';
1134 const CLASS_NAME_SLIDE
= 'slide';
1135 const CLASS_NAME_END
= 'carousel-item-end';
1136 const CLASS_NAME_START
= 'carousel-item-start';
1137 const CLASS_NAME_NEXT
= 'carousel-item-next';
1138 const CLASS_NAME_PREV
= 'carousel-item-prev';
1139 const SELECTOR_ACTIVE
= '.active';
1140 const SELECTOR_ITEM
= '.carousel-item';
1141 const SELECTOR_ACTIVE_ITEM
= SELECTOR_ACTIVE
+ SELECTOR_ITEM
;
1142 const SELECTOR_ITEM_IMG
= '.carousel-item img';
1143 const SELECTOR_INDICATORS
= '.carousel-indicators';
1144 const SELECTOR_DATA_SLIDE
= '[data-bs-slide], [data-bs-slide-to]';
1145 const SELECTOR_DATA_RIDE
= '[data-bs-ride="carousel"]';
1146 const KEY_TO_DIRECTION
= {
1147 [ARROW_LEFT_KEY
$1]: DIRECTION_RIGHT
,
1148 [ARROW_RIGHT_KEY
$1]: DIRECTION_LEFT
1158 const DefaultType
$b
= {
1159 interval: '(number|boolean)',
1160 // TODO:v6 remove boolean support
1161 keyboard: 'boolean',
1162 pause: '(string|boolean)',
1163 ride: '(boolean|string)',
1172 class Carousel
extends BaseComponent
{
1173 constructor(element
, config
) {
1174 super(element
, config
);
1175 this._interval
= null;
1176 this._activeElement
= null;
1177 this._isSliding
= false;
1178 this.touchTimeout
= null;
1179 this._swipeHelper
= null;
1180 this._indicatorsElement
= SelectorEngine
.findOne(SELECTOR_INDICATORS
, this._element
);
1181 this._addEventListeners();
1182 if (this._config
.ride
=== CLASS_NAME_CAROUSEL
) {
1188 static get Default() {
1191 static get DefaultType() {
1192 return DefaultType
$b
;
1200 this._slide(ORDER_NEXT
);
1203 // FIXME TODO use `document.visibilityState`
1204 // Don't call next when the page isn't visible
1205 // or the carousel or its parent isn't visible
1206 if (!document
.hidden
&& isVisible(this._element
)) {
1211 this._slide(ORDER_PREV
);
1214 if (this._isSliding
) {
1215 triggerTransitionEnd(this._element
);
1217 this._clearInterval();
1220 this._clearInterval();
1221 this._updateInterval();
1222 this._interval
= setInterval(() => this.nextWhenVisible(), this._config
.interval
);
1224 _maybeEnableCycle() {
1225 if (!this._config
.ride
) {
1228 if (this._isSliding
) {
1229 EventHandler
.one(this._element
, EVENT_SLID
, () => this.cycle());
1235 const items
= this._getItems();
1236 if (index
> items
.length
- 1 || index
< 0) {
1239 if (this._isSliding
) {
1240 EventHandler
.one(this._element
, EVENT_SLID
, () => this.to(index
));
1243 const activeIndex
= this._getItemIndex(this._getActive());
1244 if (activeIndex
=== index
) {
1247 const order
= index
> activeIndex
? ORDER_NEXT : ORDER_PREV
;
1248 this._slide(order
, items
[index
]);
1251 if (this._swipeHelper
) {
1252 this._swipeHelper
.dispose();
1258 _configAfterMerge(config
) {
1259 config
.defaultInterval
= config
.interval
;
1262 _addEventListeners() {
1263 if (this._config
.keyboard
) {
1264 EventHandler
.on(this._element
, EVENT_KEYDOWN
$1, event
=> this._keydown(event
));
1266 if (this._config
.pause
=== 'hover') {
1267 EventHandler
.on(this._element
, EVENT_MOUSEENTER
$1, () => this.pause());
1268 EventHandler
.on(this._element
, EVENT_MOUSELEAVE
$1, () => this._maybeEnableCycle());
1270 if (this._config
.touch
&& Swipe
.isSupported()) {
1271 this._addTouchEventListeners();
1274 _addTouchEventListeners() {
1275 for (const img
of SelectorEngine
.find(SELECTOR_ITEM_IMG
, this._element
)) {
1276 EventHandler
.on(img
, EVENT_DRAG_START
, event
=> event
.preventDefault());
1278 const endCallBack
= () => {
1279 if (this._config
.pause
!== 'hover') {
1283 // If it's a touch-enabled device, mouseenter/leave are fired as
1284 // part of the mouse compatibility events on first tap - the carousel
1285 // would stop cycling until user tapped out of it;
1286 // here, we listen for touchend, explicitly pause the carousel
1287 // (as if it's the second time we tap on it, mouseenter compat event
1288 // is NOT fired) and after a timeout (to allow for mouse compatibility
1289 // events to fire) we explicitly restart cycling
1292 if (this.touchTimeout
) {
1293 clearTimeout(this.touchTimeout
);
1295 this.touchTimeout
= setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT
+ this._config
.interval
);
1297 const swipeConfig
= {
1298 leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT
)),
1299 rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT
)),
1300 endCallback: endCallBack
1302 this._swipeHelper
= new Swipe(this._element
, swipeConfig
);
1305 if (/input|textarea/i.test(event
.target
.tagName
)) {
1308 const direction
= KEY_TO_DIRECTION
[event
.key
];
1310 event
.preventDefault();
1311 this._slide(this._directionToOrder(direction
));
1314 _getItemIndex(element
) {
1315 return this._getItems().indexOf(element
);
1317 _setActiveIndicatorElement(index
) {
1318 if (!this._indicatorsElement
) {
1321 const activeIndicator
= SelectorEngine
.findOne(SELECTOR_ACTIVE
, this._indicatorsElement
);
1322 activeIndicator
.classList
.remove(CLASS_NAME_ACTIVE
$2);
1323 activeIndicator
.removeAttribute('aria-current');
1324 const newActiveIndicator
= SelectorEngine
.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement
);
1325 if (newActiveIndicator
) {
1326 newActiveIndicator
.classList
.add(CLASS_NAME_ACTIVE
$2);
1327 newActiveIndicator
.setAttribute('aria-current', 'true');
1331 const element
= this._activeElement
|| this._getActive();
1335 const elementInterval
= Number
.parseInt(element
.getAttribute('data-bs-interval'), 10);
1336 this._config
.interval
= elementInterval
|| this._config
.defaultInterval
;
1338 _slide(order
, element
= null) {
1339 if (this._isSliding
) {
1342 const activeElement
= this._getActive();
1343 const isNext
= order
=== ORDER_NEXT
;
1344 const nextElement
= element
|| getNextActiveElement(this._getItems(), activeElement
, isNext
, this._config
.wrap
);
1345 if (nextElement
=== activeElement
) {
1348 const nextElementIndex
= this._getItemIndex(nextElement
);
1349 const triggerEvent
= eventName
=> {
1350 return EventHandler
.trigger(this._element
, eventName
, {
1351 relatedTarget: nextElement
,
1352 direction: this._orderToDirection(order
),
1353 from: this._getItemIndex(activeElement
),
1354 to: nextElementIndex
1357 const slideEvent
= triggerEvent(EVENT_SLIDE
);
1358 if (slideEvent
.defaultPrevented
) {
1361 if (!activeElement
|| !nextElement
) {
1362 // Some weirdness is happening, so we bail
1363 // TODO: change tests that use empty divs to avoid this check
1366 const isCycling
= Boolean(this._interval
);
1368 this._isSliding
= true;
1369 this._setActiveIndicatorElement(nextElementIndex
);
1370 this._activeElement
= nextElement
;
1371 const directionalClassName
= isNext
? CLASS_NAME_START : CLASS_NAME_END
;
1372 const orderClassName
= isNext
? CLASS_NAME_NEXT : CLASS_NAME_PREV
;
1373 nextElement
.classList
.add(orderClassName
);
1374 reflow(nextElement
);
1375 activeElement
.classList
.add(directionalClassName
);
1376 nextElement
.classList
.add(directionalClassName
);
1377 const completeCallBack
= () => {
1378 nextElement
.classList
.remove(directionalClassName
, orderClassName
);
1379 nextElement
.classList
.add(CLASS_NAME_ACTIVE
$2);
1380 activeElement
.classList
.remove(CLASS_NAME_ACTIVE
$2, orderClassName
, directionalClassName
);
1381 this._isSliding
= false;
1382 triggerEvent(EVENT_SLID
);
1384 this._queueCallback(completeCallBack
, activeElement
, this._isAnimated());
1390 return this._element
.classList
.contains(CLASS_NAME_SLIDE
);
1393 return SelectorEngine
.findOne(SELECTOR_ACTIVE_ITEM
, this._element
);
1396 return SelectorEngine
.find(SELECTOR_ITEM
, this._element
);
1399 if (this._interval
) {
1400 clearInterval(this._interval
);
1401 this._interval
= null;
1404 _directionToOrder(direction
) {
1406 return direction
=== DIRECTION_LEFT
? ORDER_PREV : ORDER_NEXT
;
1408 return direction
=== DIRECTION_LEFT
? ORDER_NEXT : ORDER_PREV
;
1410 _orderToDirection(order
) {
1412 return order
=== ORDER_PREV
? DIRECTION_LEFT : DIRECTION_RIGHT
;
1414 return order
=== ORDER_PREV
? DIRECTION_RIGHT : DIRECTION_LEFT
;
1418 static jQueryInterface(config
) {
1419 return this.each(function () {
1420 const data
= Carousel
.getOrCreateInstance(this, config
);
1421 if (typeof config
=== 'number') {
1425 if (typeof config
=== 'string') {
1426 if (data
[config
] === undefined || config
.startsWith('_') || config
=== 'constructor') {
1427 throw new TypeError(`No method named "${config}"`);
1436 * Data API implementation
1439 EventHandler
.on(document
, EVENT_CLICK_DATA_API
$5, SELECTOR_DATA_SLIDE
, function (event
) {
1440 const target
= SelectorEngine
.getElementFromSelector(this);
1441 if (!target
|| !target
.classList
.contains(CLASS_NAME_CAROUSEL
)) {
1444 event
.preventDefault();
1445 const carousel
= Carousel
.getOrCreateInstance(target
);
1446 const slideIndex
= this.getAttribute('data-bs-slide-to');
1448 carousel
.to(slideIndex
);
1449 carousel
._maybeEnableCycle();
1452 if (Manipulator
.getDataAttribute(this, 'slide') === 'next') {
1454 carousel
._maybeEnableCycle();
1458 carousel
._maybeEnableCycle();
1460 EventHandler
.on(window
, EVENT_LOAD_DATA_API
$3, () => {
1461 const carousels
= SelectorEngine
.find(SELECTOR_DATA_RIDE
);
1462 for (const carousel
of carousels
) {
1463 Carousel
.getOrCreateInstance(carousel
);
1471 defineJQueryPlugin(Carousel
);
1474 * --------------------------------------------------------------------------
1475 * Bootstrap collapse.js
1476 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
1477 * --------------------------------------------------------------------------
1485 const NAME
$b
= 'collapse';
1486 const DATA_KEY
$7 = 'bs.collapse';
1487 const EVENT_KEY
$7 = `.${DATA_KEY$7}`;
1488 const DATA_API_KEY
$4 = '.data-api';
1489 const EVENT_SHOW
$6 = `show${EVENT_KEY$7}`;
1490 const EVENT_SHOWN
$6 = `shown${EVENT_KEY$7}`;
1491 const EVENT_HIDE
$6 = `hide${EVENT_KEY$7}`;
1492 const EVENT_HIDDEN
$6 = `hidden${EVENT_KEY$7}`;
1493 const EVENT_CLICK_DATA_API
$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`;
1494 const CLASS_NAME_SHOW
$7 = 'show';
1495 const CLASS_NAME_COLLAPSE
= 'collapse';
1496 const CLASS_NAME_COLLAPSING
= 'collapsing';
1497 const CLASS_NAME_COLLAPSED
= 'collapsed';
1498 const CLASS_NAME_DEEPER_CHILDREN
= `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;
1499 const CLASS_NAME_HORIZONTAL
= 'collapse-horizontal';
1500 const WIDTH
= 'width';
1501 const HEIGHT
= 'height';
1502 const SELECTOR_ACTIVES
= '.collapse.show, .collapse.collapsing';
1503 const SELECTOR_DATA_TOGGLE
$4 = '[data-bs-toggle="collapse"]';
1508 const DefaultType
$a
= {
1509 parent: '(null|element)',
1517 class Collapse
extends BaseComponent
{
1518 constructor(element
, config
) {
1519 super(element
, config
);
1520 this._isTransitioning
= false;
1521 this._triggerArray
= [];
1522 const toggleList
= SelectorEngine
.find(SELECTOR_DATA_TOGGLE
$4);
1523 for (const elem
of toggleList
) {
1524 const selector
= SelectorEngine
.getSelectorFromElement(elem
);
1525 const filterElement
= SelectorEngine
.find(selector
).filter(foundElement
=> foundElement
=== this._element
);
1526 if (selector
!== null && filterElement
.length
) {
1527 this._triggerArray
.push(elem
);
1530 this._initializeChildren();
1531 if (!this._config
.parent
) {
1532 this._addAriaAndCollapsedClass(this._triggerArray
, this._isShown());
1534 if (this._config
.toggle
) {
1540 static get Default() {
1543 static get DefaultType() {
1544 return DefaultType
$a
;
1552 if (this._isShown()) {
1559 if (this._isTransitioning
|| this._isShown()) {
1562 let activeChildren
= [];
1564 // find active children
1565 if (this._config
.parent
) {
1566 activeChildren
= this._getFirstLevelChildren(SELECTOR_ACTIVES
).filter(element
=> element
!== this._element
).map(element
=> Collapse
.getOrCreateInstance(element
, {
1570 if (activeChildren
.length
&& activeChildren
[0]._isTransitioning
) {
1573 const startEvent
= EventHandler
.trigger(this._element
, EVENT_SHOW
$6);
1574 if (startEvent
.defaultPrevented
) {
1577 for (const activeInstance
of activeChildren
) {
1578 activeInstance
.hide();
1580 const dimension
= this._getDimension();
1581 this._element
.classList
.remove(CLASS_NAME_COLLAPSE
);
1582 this._element
.classList
.add(CLASS_NAME_COLLAPSING
);
1583 this._element
.style
[dimension
] = 0;
1584 this._addAriaAndCollapsedClass(this._triggerArray
, true);
1585 this._isTransitioning
= true;
1586 const complete
= () => {
1587 this._isTransitioning
= false;
1588 this._element
.classList
.remove(CLASS_NAME_COLLAPSING
);
1589 this._element
.classList
.add(CLASS_NAME_COLLAPSE
, CLASS_NAME_SHOW
$7);
1590 this._element
.style
[dimension
] = '';
1591 EventHandler
.trigger(this._element
, EVENT_SHOWN
$6);
1593 const capitalizedDimension
= dimension
[0].toUpperCase() + dimension
.slice(1);
1594 const scrollSize
= `scroll${capitalizedDimension}`;
1595 this._queueCallback(complete
, this._element
, true);
1596 this._element
.style
[dimension
] = `${this._element[scrollSize]}px`;
1599 if (this._isTransitioning
|| !this._isShown()) {
1602 const startEvent
= EventHandler
.trigger(this._element
, EVENT_HIDE
$6);
1603 if (startEvent
.defaultPrevented
) {
1606 const dimension
= this._getDimension();
1607 this._element
.style
[dimension
] = `${this._element.getBoundingClientRect()[dimension]}px`;
1608 reflow(this._element
);
1609 this._element
.classList
.add(CLASS_NAME_COLLAPSING
);
1610 this._element
.classList
.remove(CLASS_NAME_COLLAPSE
, CLASS_NAME_SHOW
$7);
1611 for (const trigger
of this._triggerArray
) {
1612 const element
= SelectorEngine
.getElementFromSelector(trigger
);
1613 if (element
&& !this._isShown(element
)) {
1614 this._addAriaAndCollapsedClass([trigger
], false);
1617 this._isTransitioning
= true;
1618 const complete
= () => {
1619 this._isTransitioning
= false;
1620 this._element
.classList
.remove(CLASS_NAME_COLLAPSING
);
1621 this._element
.classList
.add(CLASS_NAME_COLLAPSE
);
1622 EventHandler
.trigger(this._element
, EVENT_HIDDEN
$6);
1624 this._element
.style
[dimension
] = '';
1625 this._queueCallback(complete
, this._element
, true);
1627 _isShown(element
= this._element
) {
1628 return element
.classList
.contains(CLASS_NAME_SHOW
$7);
1632 _configAfterMerge(config
) {
1633 config
.toggle
= Boolean(config
.toggle
); // Coerce string values
1634 config
.parent
= getElement(config
.parent
);
1638 return this._element
.classList
.contains(CLASS_NAME_HORIZONTAL
) ? WIDTH : HEIGHT
;
1640 _initializeChildren() {
1641 if (!this._config
.parent
) {
1644 const children
= this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE
$4);
1645 for (const element
of children
) {
1646 const selected
= SelectorEngine
.getElementFromSelector(element
);
1648 this._addAriaAndCollapsedClass([element
], this._isShown(selected
));
1652 _getFirstLevelChildren(selector
) {
1653 const children
= SelectorEngine
.find(CLASS_NAME_DEEPER_CHILDREN
, this._config
.parent
);
1654 // remove children if greater depth
1655 return SelectorEngine
.find(selector
, this._config
.parent
).filter(element
=> !children
.includes(element
));
1657 _addAriaAndCollapsedClass(triggerArray
, isOpen
) {
1658 if (!triggerArray
.length
) {
1661 for (const element
of triggerArray
) {
1662 element
.classList
.toggle(CLASS_NAME_COLLAPSED
, !isOpen
);
1663 element
.setAttribute('aria-expanded', isOpen
);
1668 static jQueryInterface(config
) {
1670 if (typeof config
=== 'string' && /show|hide/.test(config
)) {
1671 _config
.toggle
= false;
1673 return this.each(function () {
1674 const data
= Collapse
.getOrCreateInstance(this, _config
);
1675 if (typeof config
=== 'string') {
1676 if (typeof data
[config
] === 'undefined') {
1677 throw new TypeError(`No method named "${config}"`);
1686 * Data API implementation
1689 EventHandler
.on(document
, EVENT_CLICK_DATA_API
$4, SELECTOR_DATA_TOGGLE
$4, function (event
) {
1690 // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
1691 if (event
.target
.tagName
=== 'A' || event
.delegateTarget
&& event
.delegateTarget
.tagName
=== 'A') {
1692 event
.preventDefault();
1694 for (const element
of SelectorEngine
.getMultipleElementsFromSelector(this)) {
1695 Collapse
.getOrCreateInstance(element
, {
1705 defineJQueryPlugin(Collapse
);
1708 * --------------------------------------------------------------------------
1709 * Bootstrap dropdown.js
1710 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
1711 * --------------------------------------------------------------------------
1719 const NAME
$a
= 'dropdown';
1720 const DATA_KEY
$6 = 'bs.dropdown';
1721 const EVENT_KEY
$6 = `.${DATA_KEY$6}`;
1722 const DATA_API_KEY
$3 = '.data-api';
1723 const ESCAPE_KEY
$2 = 'Escape';
1724 const TAB_KEY
$1 = 'Tab';
1725 const ARROW_UP_KEY
$1 = 'ArrowUp';
1726 const ARROW_DOWN_KEY
$1 = 'ArrowDown';
1727 const RIGHT_MOUSE_BUTTON
= 2; // MouseEvent.button value for the secondary button, usually the right button
1729 const EVENT_HIDE
$5 = `hide${EVENT_KEY$6}`;
1730 const EVENT_HIDDEN
$5 = `hidden${EVENT_KEY$6}`;
1731 const EVENT_SHOW
$5 = `show${EVENT_KEY$6}`;
1732 const EVENT_SHOWN
$5 = `shown${EVENT_KEY$6}`;
1733 const EVENT_CLICK_DATA_API
$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`;
1734 const EVENT_KEYDOWN_DATA_API
= `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`;
1735 const EVENT_KEYUP_DATA_API
= `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`;
1736 const CLASS_NAME_SHOW
$6 = 'show';
1737 const CLASS_NAME_DROPUP
= 'dropup';
1738 const CLASS_NAME_DROPEND
= 'dropend';
1739 const CLASS_NAME_DROPSTART
= 'dropstart';
1740 const CLASS_NAME_DROPUP_CENTER
= 'dropup-center';
1741 const CLASS_NAME_DROPDOWN_CENTER
= 'dropdown-center';
1742 const SELECTOR_DATA_TOGGLE
$3 = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)';
1743 const SELECTOR_DATA_TOGGLE_SHOWN
= `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`;
1744 const SELECTOR_MENU
= '.dropdown-menu';
1745 const SELECTOR_NAVBAR
= '.navbar';
1746 const SELECTOR_NAVBAR_NAV
= '.navbar-nav';
1747 const SELECTOR_VISIBLE_ITEMS
= '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';
1748 const PLACEMENT_TOP
= isRTL() ? 'top-end' : 'top-start';
1749 const PLACEMENT_TOPEND
= isRTL() ? 'top-start' : 'top-end';
1750 const PLACEMENT_BOTTOM
= isRTL() ? 'bottom-end' : 'bottom-start';
1751 const PLACEMENT_BOTTOMEND
= isRTL() ? 'bottom-start' : 'bottom-end';
1752 const PLACEMENT_RIGHT
= isRTL() ? 'left-start' : 'right-start';
1753 const PLACEMENT_LEFT
= isRTL() ? 'right-start' : 'left-start';
1754 const PLACEMENT_TOPCENTER
= 'top';
1755 const PLACEMENT_BOTTOMCENTER
= 'bottom';
1758 boundary: 'clippingParents',
1764 const DefaultType
$9 = {
1765 autoClose: '(boolean|string)',
1766 boundary: '(string|element)',
1768 offset: '(array|string|function)',
1769 popperConfig: '(null|object|function)',
1770 reference: '(string|element|object)'
1777 class Dropdown
extends BaseComponent
{
1778 constructor(element
, config
) {
1779 super(element
, config
);
1780 this._popper
= null;
1781 this._parent
= this._element
.parentNode
; // dropdown wrapper
1782 // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
1783 this._menu
= SelectorEngine
.next(this._element
, SELECTOR_MENU
)[0] || SelectorEngine
.prev(this._element
, SELECTOR_MENU
)[0] || SelectorEngine
.findOne(SELECTOR_MENU
, this._parent
);
1784 this._inNavbar
= this._detectNavbar();
1788 static get Default() {
1791 static get DefaultType() {
1792 return DefaultType
$9;
1800 return this._isShown() ? this.hide() : this.show();
1803 if (isDisabled(this._element
) || this._isShown()) {
1806 const relatedTarget
= {
1807 relatedTarget: this._element
1809 const showEvent
= EventHandler
.trigger(this._element
, EVENT_SHOW
$5, relatedTarget
);
1810 if (showEvent
.defaultPrevented
) {
1813 this._createPopper();
1815 // If this is a touch-enabled device we add extra
1816 // empty mouseover listeners to the body's immediate children;
1817 // only needed because of broken event delegation on iOS
1818 // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
1819 if ('ontouchstart' in document
.documentElement
&& !this._parent
.closest(SELECTOR_NAVBAR_NAV
)) {
1820 for (const element
of [].concat(...document
.body
.children
)) {
1821 EventHandler
.on(element
, 'mouseover', noop
);
1824 this._element
.focus();
1825 this._element
.setAttribute('aria-expanded', true);
1826 this._menu
.classList
.add(CLASS_NAME_SHOW
$6);
1827 this._element
.classList
.add(CLASS_NAME_SHOW
$6);
1828 EventHandler
.trigger(this._element
, EVENT_SHOWN
$5, relatedTarget
);
1831 if (isDisabled(this._element
) || !this._isShown()) {
1834 const relatedTarget
= {
1835 relatedTarget: this._element
1837 this._completeHide(relatedTarget
);
1841 this._popper
.destroy();
1846 this._inNavbar
= this._detectNavbar();
1848 this._popper
.update();
1853 _completeHide(relatedTarget
) {
1854 const hideEvent
= EventHandler
.trigger(this._element
, EVENT_HIDE
$5, relatedTarget
);
1855 if (hideEvent
.defaultPrevented
) {
1859 // If this is a touch-enabled device we remove the extra
1860 // empty mouseover listeners we added for iOS support
1861 if ('ontouchstart' in document
.documentElement
) {
1862 for (const element
of [].concat(...document
.body
.children
)) {
1863 EventHandler
.off(element
, 'mouseover', noop
);
1867 this._popper
.destroy();
1869 this._menu
.classList
.remove(CLASS_NAME_SHOW
$6);
1870 this._element
.classList
.remove(CLASS_NAME_SHOW
$6);
1871 this._element
.setAttribute('aria-expanded', 'false');
1872 Manipulator
.removeDataAttribute(this._menu
, 'popper');
1873 EventHandler
.trigger(this._element
, EVENT_HIDDEN
$5, relatedTarget
);
1875 _getConfig(config
) {
1876 config
= super._getConfig(config
);
1877 if (typeof config
.reference
=== 'object' && !isElement(config
.reference
) && typeof config
.reference
.getBoundingClientRect
!== 'function') {
1878 // Popper virtual elements require a getBoundingClientRect method
1879 throw new TypeError(`${NAME$a.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);
1884 if (typeof Popper__namespace
=== 'undefined') {
1885 throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)');
1887 let referenceElement
= this._element
;
1888 if (this._config
.reference
=== 'parent') {
1889 referenceElement
= this._parent
;
1890 } else if (isElement(this._config
.reference
)) {
1891 referenceElement
= getElement(this._config
.reference
);
1892 } else if (typeof this._config
.reference
=== 'object') {
1893 referenceElement
= this._config
.reference
;
1895 const popperConfig
= this._getPopperConfig();
1896 this._popper
= Popper__namespace
.createPopper(referenceElement
, this._menu
, popperConfig
);
1899 return this._menu
.classList
.contains(CLASS_NAME_SHOW
$6);
1902 const parentDropdown
= this._parent
;
1903 if (parentDropdown
.classList
.contains(CLASS_NAME_DROPEND
)) {
1904 return PLACEMENT_RIGHT
;
1906 if (parentDropdown
.classList
.contains(CLASS_NAME_DROPSTART
)) {
1907 return PLACEMENT_LEFT
;
1909 if (parentDropdown
.classList
.contains(CLASS_NAME_DROPUP_CENTER
)) {
1910 return PLACEMENT_TOPCENTER
;
1912 if (parentDropdown
.classList
.contains(CLASS_NAME_DROPDOWN_CENTER
)) {
1913 return PLACEMENT_BOTTOMCENTER
;
1916 // We need to trim the value because custom properties can also include spaces
1917 const isEnd
= getComputedStyle(this._menu
).getPropertyValue('--bs-position').trim() === 'end';
1918 if (parentDropdown
.classList
.contains(CLASS_NAME_DROPUP
)) {
1919 return isEnd
? PLACEMENT_TOPEND : PLACEMENT_TOP
;
1921 return isEnd
? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM
;
1924 return this._element
.closest(SELECTOR_NAVBAR
) !== null;
1930 if (typeof offset
=== 'string') {
1931 return offset
.split(',').map(value
=> Number
.parseInt(value
, 10));
1933 if (typeof offset
=== 'function') {
1934 return popperData
=> offset(popperData
, this._element
);
1938 _getPopperConfig() {
1939 const defaultBsPopperConfig
= {
1940 placement: this._getPlacement(),
1942 name: 'preventOverflow',
1944 boundary: this._config
.boundary
1949 offset: this._getOffset()
1954 // Disable Popper if we have a static display or Dropdown is in Navbar
1955 if (this._inNavbar
|| this._config
.display
=== 'static') {
1956 Manipulator
.setDataAttribute(this._menu
, 'popper', 'static'); // TODO: v6 remove
1957 defaultBsPopperConfig
.modifiers
= [{
1958 name: 'applyStyles',
1963 ...defaultBsPopperConfig
,
1964 ...execute(this._config
.popperConfig
, [defaultBsPopperConfig
])
1971 const items
= SelectorEngine
.find(SELECTOR_VISIBLE_ITEMS
, this._menu
).filter(element
=> isVisible(element
));
1972 if (!items
.length
) {
1976 // if target isn't included in items (e.g. when expanding the dropdown)
1977 // allow cycling to get the last item in case key equals ARROW_UP_KEY
1978 getNextActiveElement(items
, target
, key
=== ARROW_DOWN_KEY
$1, !items
.includes(target
)).focus();
1982 static jQueryInterface(config
) {
1983 return this.each(function () {
1984 const data
= Dropdown
.getOrCreateInstance(this, config
);
1985 if (typeof config
!== 'string') {
1988 if (typeof data
[config
] === 'undefined') {
1989 throw new TypeError(`No method named "${config}"`);
1994 static clearMenus(event
) {
1995 if (event
.button
=== RIGHT_MOUSE_BUTTON
|| event
.type
=== 'keyup' && event
.key
!== TAB_KEY
$1) {
1998 const openToggles
= SelectorEngine
.find(SELECTOR_DATA_TOGGLE_SHOWN
);
1999 for (const toggle
of openToggles
) {
2000 const context
= Dropdown
.getInstance(toggle
);
2001 if (!context
|| context
._config
.autoClose
=== false) {
2004 const composedPath
= event
.composedPath();
2005 const isMenuTarget
= composedPath
.includes(context
._menu
);
2006 if (composedPath
.includes(context
._element
) || context
._config
.autoClose
=== 'inside' && !isMenuTarget
|| context
._config
.autoClose
=== 'outside' && isMenuTarget
) {
2010 // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
2011 if (context
._menu
.contains(event
.target
) && (event
.type
=== 'keyup' && event
.key
=== TAB_KEY
$1 || /input|select|option|textarea|form/i.test(event
.target
.tagName
))) {
2014 const relatedTarget
= {
2015 relatedTarget: context
._element
2017 if (event
.type
=== 'click') {
2018 relatedTarget
.clickEvent
= event
;
2020 context
._completeHide(relatedTarget
);
2023 static dataApiKeydownHandler(event
) {
2024 // If not an UP | DOWN | ESCAPE key => not a dropdown command
2025 // If input/textarea && if key is other than ESCAPE => not a dropdown command
2027 const isInput
= /input|textarea/i.test(event
.target
.tagName
);
2028 const isEscapeEvent
= event
.key
=== ESCAPE_KEY
$2;
2029 const isUpOrDownEvent
= [ARROW_UP_KEY
$1, ARROW_DOWN_KEY
$1].includes(event
.key
);
2030 if (!isUpOrDownEvent
&& !isEscapeEvent
) {
2033 if (isInput
&& !isEscapeEvent
) {
2036 event
.preventDefault();
2038 // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
2039 const getToggleButton
= this.matches(SELECTOR_DATA_TOGGLE
$3) ? this : SelectorEngine
.prev(this, SELECTOR_DATA_TOGGLE
$3)[0] || SelectorEngine
.next(this, SELECTOR_DATA_TOGGLE
$3)[0] || SelectorEngine
.findOne(SELECTOR_DATA_TOGGLE
$3, event
.delegateTarget
.parentNode
);
2040 const instance
= Dropdown
.getOrCreateInstance(getToggleButton
);
2041 if (isUpOrDownEvent
) {
2042 event
.stopPropagation();
2044 instance
._selectMenuItem(event
);
2047 if (instance
._isShown()) {
2048 // else is escape and we check if it is shown
2049 event
.stopPropagation();
2051 getToggleButton
.focus();
2057 * Data API implementation
2060 EventHandler
.on(document
, EVENT_KEYDOWN_DATA_API
, SELECTOR_DATA_TOGGLE
$3, Dropdown
.dataApiKeydownHandler
);
2061 EventHandler
.on(document
, EVENT_KEYDOWN_DATA_API
, SELECTOR_MENU
, Dropdown
.dataApiKeydownHandler
);
2062 EventHandler
.on(document
, EVENT_CLICK_DATA_API
$3, Dropdown
.clearMenus
);
2063 EventHandler
.on(document
, EVENT_KEYUP_DATA_API
, Dropdown
.clearMenus
);
2064 EventHandler
.on(document
, EVENT_CLICK_DATA_API
$3, SELECTOR_DATA_TOGGLE
$3, function (event
) {
2065 event
.preventDefault();
2066 Dropdown
.getOrCreateInstance(this).toggle();
2073 defineJQueryPlugin(Dropdown
);
2076 * --------------------------------------------------------------------------
2077 * Bootstrap util/backdrop.js
2078 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
2079 * --------------------------------------------------------------------------
2087 const NAME
$9 = 'backdrop';
2088 const CLASS_NAME_FADE
$4 = 'fade';
2089 const CLASS_NAME_SHOW
$5 = 'show';
2090 const EVENT_MOUSEDOWN
= `mousedown.bs.${NAME$9}`;
2092 className: 'modal-backdrop',
2093 clickCallback: null,
2096 // if false, we use the backdrop helper without adding any element to the dom
2097 rootElement: 'body' // give the choice to place backdrop under different elements
2100 const DefaultType
$8 = {
2101 className: 'string',
2102 clickCallback: '(function|null)',
2103 isAnimated: 'boolean',
2104 isVisible: 'boolean',
2105 rootElement: '(element|string)'
2112 class Backdrop
extends Config
{
2113 constructor(config
) {
2115 this._config
= this._getConfig(config
);
2116 this._isAppended
= false;
2117 this._element
= null;
2121 static get Default() {
2124 static get DefaultType() {
2125 return DefaultType
$8;
2133 if (!this._config
.isVisible
) {
2138 const element
= this._getElement();
2139 if (this._config
.isAnimated
) {
2142 element
.classList
.add(CLASS_NAME_SHOW
$5);
2143 this._emulateAnimation(() => {
2148 if (!this._config
.isVisible
) {
2152 this._getElement().classList
.remove(CLASS_NAME_SHOW
$5);
2153 this._emulateAnimation(() => {
2159 if (!this._isAppended
) {
2162 EventHandler
.off(this._element
, EVENT_MOUSEDOWN
);
2163 this._element
.remove();
2164 this._isAppended
= false;
2169 if (!this._element
) {
2170 const backdrop
= document
.createElement('div');
2171 backdrop
.className
= this._config
.className
;
2172 if (this._config
.isAnimated
) {
2173 backdrop
.classList
.add(CLASS_NAME_FADE
$4);
2175 this._element
= backdrop
;
2177 return this._element
;
2179 _configAfterMerge(config
) {
2180 // use getElement() with the default "body" to get a fresh Element on each instantiation
2181 config
.rootElement
= getElement(config
.rootElement
);
2185 if (this._isAppended
) {
2188 const element
= this._getElement();
2189 this._config
.rootElement
.append(element
);
2190 EventHandler
.on(element
, EVENT_MOUSEDOWN
, () => {
2191 execute(this._config
.clickCallback
);
2193 this._isAppended
= true;
2195 _emulateAnimation(callback
) {
2196 executeAfterTransition(callback
, this._getElement(), this._config
.isAnimated
);
2201 * --------------------------------------------------------------------------
2202 * Bootstrap util/focustrap.js
2203 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
2204 * --------------------------------------------------------------------------
2212 const NAME
$8 = 'focustrap';
2213 const DATA_KEY
$5 = 'bs.focustrap';
2214 const EVENT_KEY
$5 = `.${DATA_KEY$5}`;
2215 const EVENT_FOCUSIN
$2 = `focusin${EVENT_KEY$5}`;
2216 const EVENT_KEYDOWN_TAB
= `keydown.tab${EVENT_KEY$5}`;
2217 const TAB_KEY
= 'Tab';
2218 const TAB_NAV_FORWARD
= 'forward';
2219 const TAB_NAV_BACKWARD
= 'backward';
2222 trapElement: null // The element to trap focus inside of
2225 const DefaultType
$7 = {
2226 autofocus: 'boolean',
2227 trapElement: 'element'
2234 class FocusTrap
extends Config
{
2235 constructor(config
) {
2237 this._config
= this._getConfig(config
);
2238 this._isActive
= false;
2239 this._lastTabNavDirection
= null;
2243 static get Default() {
2246 static get DefaultType() {
2247 return DefaultType
$7;
2255 if (this._isActive
) {
2258 if (this._config
.autofocus
) {
2259 this._config
.trapElement
.focus();
2261 EventHandler
.off(document
, EVENT_KEY
$5); // guard against infinite focus loop
2262 EventHandler
.on(document
, EVENT_FOCUSIN
$2, event
=> this._handleFocusin(event
));
2263 EventHandler
.on(document
, EVENT_KEYDOWN_TAB
, event
=> this._handleKeydown(event
));
2264 this._isActive
= true;
2267 if (!this._isActive
) {
2270 this._isActive
= false;
2271 EventHandler
.off(document
, EVENT_KEY
$5);
2275 _handleFocusin(event
) {
2279 if (event
.target
=== document
|| event
.target
=== trapElement
|| trapElement
.contains(event
.target
)) {
2282 const elements
= SelectorEngine
.focusableChildren(trapElement
);
2283 if (elements
.length
=== 0) {
2284 trapElement
.focus();
2285 } else if (this._lastTabNavDirection
=== TAB_NAV_BACKWARD
) {
2286 elements
[elements
.length
- 1].focus();
2288 elements
[0].focus();
2291 _handleKeydown(event
) {
2292 if (event
.key
!== TAB_KEY
) {
2295 this._lastTabNavDirection
= event
.shiftKey
? TAB_NAV_BACKWARD : TAB_NAV_FORWARD
;
2300 * --------------------------------------------------------------------------
2301 * Bootstrap util/scrollBar.js
2302 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
2303 * --------------------------------------------------------------------------
2311 const SELECTOR_FIXED_CONTENT
= '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
2312 const SELECTOR_STICKY_CONTENT
= '.sticky-top';
2313 const PROPERTY_PADDING
= 'padding-right';
2314 const PROPERTY_MARGIN
= 'margin-right';
2320 class ScrollBarHelper
{
2322 this._element
= document
.body
;
2327 // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
2328 const documentWidth
= document
.documentElement
.clientWidth
;
2329 return Math
.abs(window
.innerWidth
- documentWidth
);
2332 const width
= this.getWidth();
2333 this._disableOverFlow();
2334 // give padding to element to balance the hidden scrollbar width
2335 this._setElementAttributes(this._element
, PROPERTY_PADDING
, calculatedValue
=> calculatedValue
+ width
);
2336 // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
2337 this._setElementAttributes(SELECTOR_FIXED_CONTENT
, PROPERTY_PADDING
, calculatedValue
=> calculatedValue
+ width
);
2338 this._setElementAttributes(SELECTOR_STICKY_CONTENT
, PROPERTY_MARGIN
, calculatedValue
=> calculatedValue
- width
);
2341 this._resetElementAttributes(this._element
, 'overflow');
2342 this._resetElementAttributes(this._element
, PROPERTY_PADDING
);
2343 this._resetElementAttributes(SELECTOR_FIXED_CONTENT
, PROPERTY_PADDING
);
2344 this._resetElementAttributes(SELECTOR_STICKY_CONTENT
, PROPERTY_MARGIN
);
2347 return this.getWidth() > 0;
2351 _disableOverFlow() {
2352 this._saveInitialAttribute(this._element
, 'overflow');
2353 this._element
.style
.overflow
= 'hidden';
2355 _setElementAttributes(selector
, styleProperty
, callback
) {
2356 const scrollbarWidth
= this.getWidth();
2357 const manipulationCallBack
= element
=> {
2358 if (element
!== this._element
&& window
.innerWidth
> element
.clientWidth
+ scrollbarWidth
) {
2361 this._saveInitialAttribute(element
, styleProperty
);
2362 const calculatedValue
= window
.getComputedStyle(element
).getPropertyValue(styleProperty
);
2363 element
.style
.setProperty(styleProperty
, `${callback(Number.parseFloat(calculatedValue))}px`);
2365 this._applyManipulationCallback(selector
, manipulationCallBack
);
2367 _saveInitialAttribute(element
, styleProperty
) {
2368 const actualValue
= element
.style
.getPropertyValue(styleProperty
);
2370 Manipulator
.setDataAttribute(element
, styleProperty
, actualValue
);
2373 _resetElementAttributes(selector
, styleProperty
) {
2374 const manipulationCallBack
= element
=> {
2375 const value
= Manipulator
.getDataAttribute(element
, styleProperty
);
2376 // We only want to remove the property if the value is `null`; the value can also be zero
2377 if (value
=== null) {
2378 element
.style
.removeProperty(styleProperty
);
2381 Manipulator
.removeDataAttribute(element
, styleProperty
);
2382 element
.style
.setProperty(styleProperty
, value
);
2384 this._applyManipulationCallback(selector
, manipulationCallBack
);
2386 _applyManipulationCallback(selector
, callBack
) {
2387 if (isElement(selector
)) {
2391 for (const sel
of SelectorEngine
.find(selector
, this._element
)) {
2398 * --------------------------------------------------------------------------
2399 * Bootstrap modal.js
2400 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
2401 * --------------------------------------------------------------------------
2409 const NAME
$7 = 'modal';
2410 const DATA_KEY
$4 = 'bs.modal';
2411 const EVENT_KEY
$4 = `.${DATA_KEY$4}`;
2412 const DATA_API_KEY
$2 = '.data-api';
2413 const ESCAPE_KEY
$1 = 'Escape';
2414 const EVENT_HIDE
$4 = `hide${EVENT_KEY$4}`;
2415 const EVENT_HIDE_PREVENTED
$1 = `hidePrevented${EVENT_KEY$4}`;
2416 const EVENT_HIDDEN
$4 = `hidden${EVENT_KEY$4}`;
2417 const EVENT_SHOW
$4 = `show${EVENT_KEY$4}`;
2418 const EVENT_SHOWN
$4 = `shown${EVENT_KEY$4}`;
2419 const EVENT_RESIZE
$1 = `resize${EVENT_KEY$4}`;
2420 const EVENT_CLICK_DISMISS
= `click.dismiss${EVENT_KEY$4}`;
2421 const EVENT_MOUSEDOWN_DISMISS
= `mousedown.dismiss${EVENT_KEY$4}`;
2422 const EVENT_KEYDOWN_DISMISS
$1 = `keydown.dismiss${EVENT_KEY$4}`;
2423 const EVENT_CLICK_DATA_API
$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`;
2424 const CLASS_NAME_OPEN
= 'modal-open';
2425 const CLASS_NAME_FADE
$3 = 'fade';
2426 const CLASS_NAME_SHOW
$4 = 'show';
2427 const CLASS_NAME_STATIC
= 'modal-static';
2428 const OPEN_SELECTOR
$1 = '.modal.show';
2429 const SELECTOR_DIALOG
= '.modal-dialog';
2430 const SELECTOR_MODAL_BODY
= '.modal-body';
2431 const SELECTOR_DATA_TOGGLE
$2 = '[data-bs-toggle="modal"]';
2437 const DefaultType
$6 = {
2438 backdrop: '(boolean|string)',
2447 class Modal
extends BaseComponent
{
2448 constructor(element
, config
) {
2449 super(element
, config
);
2450 this._dialog
= SelectorEngine
.findOne(SELECTOR_DIALOG
, this._element
);
2451 this._backdrop
= this._initializeBackDrop();
2452 this._focustrap
= this._initializeFocusTrap();
2453 this._isShown
= false;
2454 this._isTransitioning
= false;
2455 this._scrollBar
= new ScrollBarHelper();
2456 this._addEventListeners();
2460 static get Default() {
2463 static get DefaultType() {
2464 return DefaultType
$6;
2471 toggle(relatedTarget
) {
2472 return this._isShown
? this.hide() : this.show(relatedTarget
);
2474 show(relatedTarget
) {
2475 if (this._isShown
|| this._isTransitioning
) {
2478 const showEvent
= EventHandler
.trigger(this._element
, EVENT_SHOW
$4, {
2481 if (showEvent
.defaultPrevented
) {
2484 this._isShown
= true;
2485 this._isTransitioning
= true;
2486 this._scrollBar
.hide();
2487 document
.body
.classList
.add(CLASS_NAME_OPEN
);
2488 this._adjustDialog();
2489 this._backdrop
.show(() => this._showElement(relatedTarget
));
2492 if (!this._isShown
|| this._isTransitioning
) {
2495 const hideEvent
= EventHandler
.trigger(this._element
, EVENT_HIDE
$4);
2496 if (hideEvent
.defaultPrevented
) {
2499 this._isShown
= false;
2500 this._isTransitioning
= true;
2501 this._focustrap
.deactivate();
2502 this._element
.classList
.remove(CLASS_NAME_SHOW
$4);
2503 this._queueCallback(() => this._hideModal(), this._element
, this._isAnimated());
2506 EventHandler
.off(window
, EVENT_KEY
$4);
2507 EventHandler
.off(this._dialog
, EVENT_KEY
$4);
2508 this._backdrop
.dispose();
2509 this._focustrap
.deactivate();
2513 this._adjustDialog();
2517 _initializeBackDrop() {
2518 return new Backdrop({
2519 isVisible: Boolean(this._config
.backdrop
),
2520 // 'static' option will be translated to true, and booleans will keep their value,
2521 isAnimated: this._isAnimated()
2524 _initializeFocusTrap() {
2525 return new FocusTrap({
2526 trapElement: this._element
2529 _showElement(relatedTarget
) {
2530 // try to append dynamic modal
2531 if (!document
.body
.contains(this._element
)) {
2532 document
.body
.append(this._element
);
2534 this._element
.style
.display
= 'block';
2535 this._element
.removeAttribute('aria-hidden');
2536 this._element
.setAttribute('aria-modal', true);
2537 this._element
.setAttribute('role', 'dialog');
2538 this._element
.scrollTop
= 0;
2539 const modalBody
= SelectorEngine
.findOne(SELECTOR_MODAL_BODY
, this._dialog
);
2541 modalBody
.scrollTop
= 0;
2543 reflow(this._element
);
2544 this._element
.classList
.add(CLASS_NAME_SHOW
$4);
2545 const transitionComplete
= () => {
2546 if (this._config
.focus
) {
2547 this._focustrap
.activate();
2549 this._isTransitioning
= false;
2550 EventHandler
.trigger(this._element
, EVENT_SHOWN
$4, {
2554 this._queueCallback(transitionComplete
, this._dialog
, this._isAnimated());
2556 _addEventListeners() {
2557 EventHandler
.on(this._element
, EVENT_KEYDOWN_DISMISS
$1, event
=> {
2558 if (event
.key
!== ESCAPE_KEY
$1) {
2561 if (this._config
.keyboard
) {
2565 this._triggerBackdropTransition();
2567 EventHandler
.on(window
, EVENT_RESIZE
$1, () => {
2568 if (this._isShown
&& !this._isTransitioning
) {
2569 this._adjustDialog();
2572 EventHandler
.on(this._element
, EVENT_MOUSEDOWN_DISMISS
, event
=> {
2573 // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks
2574 EventHandler
.one(this._element
, EVENT_CLICK_DISMISS
, event2
=> {
2575 if (this._element
!== event
.target
|| this._element
!== event2
.target
) {
2578 if (this._config
.backdrop
=== 'static') {
2579 this._triggerBackdropTransition();
2582 if (this._config
.backdrop
) {
2589 this._element
.style
.display
= 'none';
2590 this._element
.setAttribute('aria-hidden', true);
2591 this._element
.removeAttribute('aria-modal');
2592 this._element
.removeAttribute('role');
2593 this._isTransitioning
= false;
2594 this._backdrop
.hide(() => {
2595 document
.body
.classList
.remove(CLASS_NAME_OPEN
);
2596 this._resetAdjustments();
2597 this._scrollBar
.reset();
2598 EventHandler
.trigger(this._element
, EVENT_HIDDEN
$4);
2602 return this._element
.classList
.contains(CLASS_NAME_FADE
$3);
2604 _triggerBackdropTransition() {
2605 const hideEvent
= EventHandler
.trigger(this._element
, EVENT_HIDE_PREVENTED
$1);
2606 if (hideEvent
.defaultPrevented
) {
2609 const isModalOverflowing
= this._element
.scrollHeight
> document
.documentElement
.clientHeight
;
2610 const initialOverflowY
= this._element
.style
.overflowY
;
2611 // return if the following background transition hasn't yet completed
2612 if (initialOverflowY
=== 'hidden' || this._element
.classList
.contains(CLASS_NAME_STATIC
)) {
2615 if (!isModalOverflowing
) {
2616 this._element
.style
.overflowY
= 'hidden';
2618 this._element
.classList
.add(CLASS_NAME_STATIC
);
2619 this._queueCallback(() => {
2620 this._element
.classList
.remove(CLASS_NAME_STATIC
);
2621 this._queueCallback(() => {
2622 this._element
.style
.overflowY
= initialOverflowY
;
2625 this._element
.focus();
2629 * The following methods are used to handle overflowing modals
2633 const isModalOverflowing
= this._element
.scrollHeight
> document
.documentElement
.clientHeight
;
2634 const scrollbarWidth
= this._scrollBar
.getWidth();
2635 const isBodyOverflowing
= scrollbarWidth
> 0;
2636 if (isBodyOverflowing
&& !isModalOverflowing
) {
2637 const property
= isRTL() ? 'paddingLeft' : 'paddingRight';
2638 this._element
.style
[property
] = `${scrollbarWidth}px`;
2640 if (!isBodyOverflowing
&& isModalOverflowing
) {
2641 const property
= isRTL() ? 'paddingRight' : 'paddingLeft';
2642 this._element
.style
[property
] = `${scrollbarWidth}px`;
2645 _resetAdjustments() {
2646 this._element
.style
.paddingLeft
= '';
2647 this._element
.style
.paddingRight
= '';
2651 static jQueryInterface(config
, relatedTarget
) {
2652 return this.each(function () {
2653 const data
= Modal
.getOrCreateInstance(this, config
);
2654 if (typeof config
!== 'string') {
2657 if (typeof data
[config
] === 'undefined') {
2658 throw new TypeError(`No method named "${config}"`);
2660 data
[config
](relatedTarget
);
2666 * Data API implementation
2669 EventHandler
.on(document
, EVENT_CLICK_DATA_API
$2, SELECTOR_DATA_TOGGLE
$2, function (event
) {
2670 const target
= SelectorEngine
.getElementFromSelector(this);
2671 if (['A', 'AREA'].includes(this.tagName
)) {
2672 event
.preventDefault();
2674 EventHandler
.one(target
, EVENT_SHOW
$4, showEvent
=> {
2675 if (showEvent
.defaultPrevented
) {
2676 // only register focus restorer if modal will actually get shown
2679 EventHandler
.one(target
, EVENT_HIDDEN
$4, () => {
2680 if (isVisible(this)) {
2686 // avoid conflict when clicking modal toggler while another one is open
2687 const alreadyOpen
= SelectorEngine
.findOne(OPEN_SELECTOR
$1);
2689 Modal
.getInstance(alreadyOpen
).hide();
2691 const data
= Modal
.getOrCreateInstance(target
);
2694 enableDismissTrigger(Modal
);
2700 defineJQueryPlugin(Modal
);
2703 * --------------------------------------------------------------------------
2704 * Bootstrap offcanvas.js
2705 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
2706 * --------------------------------------------------------------------------
2714 const NAME
$6 = 'offcanvas';
2715 const DATA_KEY
$3 = 'bs.offcanvas';
2716 const EVENT_KEY
$3 = `.${DATA_KEY$3}`;
2717 const DATA_API_KEY
$1 = '.data-api';
2718 const EVENT_LOAD_DATA_API
$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`;
2719 const ESCAPE_KEY
= 'Escape';
2720 const CLASS_NAME_SHOW
$3 = 'show';
2721 const CLASS_NAME_SHOWING
$1 = 'showing';
2722 const CLASS_NAME_HIDING
= 'hiding';
2723 const CLASS_NAME_BACKDROP
= 'offcanvas-backdrop';
2724 const OPEN_SELECTOR
= '.offcanvas.show';
2725 const EVENT_SHOW
$3 = `show${EVENT_KEY$3}`;
2726 const EVENT_SHOWN
$3 = `shown${EVENT_KEY$3}`;
2727 const EVENT_HIDE
$3 = `hide${EVENT_KEY$3}`;
2728 const EVENT_HIDE_PREVENTED
= `hidePrevented${EVENT_KEY$3}`;
2729 const EVENT_HIDDEN
$3 = `hidden${EVENT_KEY$3}`;
2730 const EVENT_RESIZE
= `resize${EVENT_KEY$3}`;
2731 const EVENT_CLICK_DATA_API
$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`;
2732 const EVENT_KEYDOWN_DISMISS
= `keydown.dismiss${EVENT_KEY$3}`;
2733 const SELECTOR_DATA_TOGGLE
$1 = '[data-bs-toggle="offcanvas"]';
2739 const DefaultType
$5 = {
2740 backdrop: '(boolean|string)',
2741 keyboard: 'boolean',
2749 class Offcanvas
extends BaseComponent
{
2750 constructor(element
, config
) {
2751 super(element
, config
);
2752 this._isShown
= false;
2753 this._backdrop
= this._initializeBackDrop();
2754 this._focustrap
= this._initializeFocusTrap();
2755 this._addEventListeners();
2759 static get Default() {
2762 static get DefaultType() {
2763 return DefaultType
$5;
2770 toggle(relatedTarget
) {
2771 return this._isShown
? this.hide() : this.show(relatedTarget
);
2773 show(relatedTarget
) {
2774 if (this._isShown
) {
2777 const showEvent
= EventHandler
.trigger(this._element
, EVENT_SHOW
$3, {
2780 if (showEvent
.defaultPrevented
) {
2783 this._isShown
= true;
2784 this._backdrop
.show();
2785 if (!this._config
.scroll
) {
2786 new ScrollBarHelper().hide();
2788 this._element
.setAttribute('aria-modal', true);
2789 this._element
.setAttribute('role', 'dialog');
2790 this._element
.classList
.add(CLASS_NAME_SHOWING
$1);
2791 const completeCallBack
= () => {
2792 if (!this._config
.scroll
|| this._config
.backdrop
) {
2793 this._focustrap
.activate();
2795 this._element
.classList
.add(CLASS_NAME_SHOW
$3);
2796 this._element
.classList
.remove(CLASS_NAME_SHOWING
$1);
2797 EventHandler
.trigger(this._element
, EVENT_SHOWN
$3, {
2801 this._queueCallback(completeCallBack
, this._element
, true);
2804 if (!this._isShown
) {
2807 const hideEvent
= EventHandler
.trigger(this._element
, EVENT_HIDE
$3);
2808 if (hideEvent
.defaultPrevented
) {
2811 this._focustrap
.deactivate();
2812 this._element
.blur();
2813 this._isShown
= false;
2814 this._element
.classList
.add(CLASS_NAME_HIDING
);
2815 this._backdrop
.hide();
2816 const completeCallback
= () => {
2817 this._element
.classList
.remove(CLASS_NAME_SHOW
$3, CLASS_NAME_HIDING
);
2818 this._element
.removeAttribute('aria-modal');
2819 this._element
.removeAttribute('role');
2820 if (!this._config
.scroll
) {
2821 new ScrollBarHelper().reset();
2823 EventHandler
.trigger(this._element
, EVENT_HIDDEN
$3);
2825 this._queueCallback(completeCallback
, this._element
, true);
2828 this._backdrop
.dispose();
2829 this._focustrap
.deactivate();
2834 _initializeBackDrop() {
2835 const clickCallback
= () => {
2836 if (this._config
.backdrop
=== 'static') {
2837 EventHandler
.trigger(this._element
, EVENT_HIDE_PREVENTED
);
2843 // 'static' option will be translated to true, and booleans will keep their value
2844 const isVisible
= Boolean(this._config
.backdrop
);
2845 return new Backdrop({
2846 className: CLASS_NAME_BACKDROP
,
2849 rootElement: this._element
.parentNode
,
2850 clickCallback: isVisible
? clickCallback : null
2853 _initializeFocusTrap() {
2854 return new FocusTrap({
2855 trapElement: this._element
2858 _addEventListeners() {
2859 EventHandler
.on(this._element
, EVENT_KEYDOWN_DISMISS
, event
=> {
2860 if (event
.key
!== ESCAPE_KEY
) {
2863 if (this._config
.keyboard
) {
2867 EventHandler
.trigger(this._element
, EVENT_HIDE_PREVENTED
);
2872 static jQueryInterface(config
) {
2873 return this.each(function () {
2874 const data
= Offcanvas
.getOrCreateInstance(this, config
);
2875 if (typeof config
!== 'string') {
2878 if (data
[config
] === undefined || config
.startsWith('_') || config
=== 'constructor') {
2879 throw new TypeError(`No method named "${config}"`);
2887 * Data API implementation
2890 EventHandler
.on(document
, EVENT_CLICK_DATA_API
$1, SELECTOR_DATA_TOGGLE
$1, function (event
) {
2891 const target
= SelectorEngine
.getElementFromSelector(this);
2892 if (['A', 'AREA'].includes(this.tagName
)) {
2893 event
.preventDefault();
2895 if (isDisabled(this)) {
2898 EventHandler
.one(target
, EVENT_HIDDEN
$3, () => {
2899 // focus on trigger when it is closed
2900 if (isVisible(this)) {
2905 // avoid conflict when clicking a toggler of an offcanvas, while another is open
2906 const alreadyOpen
= SelectorEngine
.findOne(OPEN_SELECTOR
);
2907 if (alreadyOpen
&& alreadyOpen
!== target
) {
2908 Offcanvas
.getInstance(alreadyOpen
).hide();
2910 const data
= Offcanvas
.getOrCreateInstance(target
);
2913 EventHandler
.on(window
, EVENT_LOAD_DATA_API
$2, () => {
2914 for (const selector
of SelectorEngine
.find(OPEN_SELECTOR
)) {
2915 Offcanvas
.getOrCreateInstance(selector
).show();
2918 EventHandler
.on(window
, EVENT_RESIZE
, () => {
2919 for (const element
of SelectorEngine
.find('[aria-modal][class*=show][class*=offcanvas-]')) {
2920 if (getComputedStyle(element
).position
!== 'fixed') {
2921 Offcanvas
.getOrCreateInstance(element
).hide();
2925 enableDismissTrigger(Offcanvas
);
2931 defineJQueryPlugin(Offcanvas
);
2934 * --------------------------------------------------------------------------
2935 * Bootstrap util/sanitizer.js
2936 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
2937 * --------------------------------------------------------------------------
2940 // js-docs-start allow-list
2941 const ARIA_ATTRIBUTE_PATTERN
= /^aria-[\w-]*$/i;
2942 const DefaultAllowlist
= {
2943 // Global attributes allowed on any supplied element below.
2944 '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN
],
2945 a: ['target', 'href', 'title', 'rel'],
2961 img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
2975 // js-docs-end allow-list
2977 const uriAttributes
= new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
2980 * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
2983 * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
2985 // eslint-disable-next-line unicorn/better-regex
2986 const SAFE_URL_PATTERN
= /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
2987 const allowedAttribute
= (attribute
, allowedAttributeList
) => {
2988 const attributeName
= attribute
.nodeName
.toLowerCase();
2989 if (allowedAttributeList
.includes(attributeName
)) {
2990 if (uriAttributes
.has(attributeName
)) {
2991 return Boolean(SAFE_URL_PATTERN
.test(attribute
.nodeValue
));
2996 // Check if a regular expression validates the attribute.
2997 return allowedAttributeList
.filter(attributeRegex
=> attributeRegex
instanceof RegExp
).some(regex
=> regex
.test(attributeName
));
2999 function sanitizeHtml(unsafeHtml
, allowList
, sanitizeFunction
) {
3000 if (!unsafeHtml
.length
) {
3003 if (sanitizeFunction
&& typeof sanitizeFunction
=== 'function') {
3004 return sanitizeFunction(unsafeHtml
);
3006 const domParser
= new window
.DOMParser();
3007 const createdDocument
= domParser
.parseFromString(unsafeHtml
, 'text/html');
3008 const elements
= [].concat(...createdDocument
.body
.querySelectorAll('*'));
3009 for (const element
of elements
) {
3010 const elementName
= element
.nodeName
.toLowerCase();
3011 if (!Object
.keys(allowList
).includes(elementName
)) {
3015 const attributeList
= [].concat(...element
.attributes
);
3016 const allowedAttributes
= [].concat(allowList
['*'] || [], allowList
[elementName
] || []);
3017 for (const attribute
of attributeList
) {
3018 if (!allowedAttribute(attribute
, allowedAttributes
)) {
3019 element
.removeAttribute(attribute
.nodeName
);
3023 return createdDocument
.body
.innerHTML
;
3027 * --------------------------------------------------------------------------
3028 * Bootstrap util/template-factory.js
3029 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
3030 * --------------------------------------------------------------------------
3038 const NAME
$5 = 'TemplateFactory';
3040 allowList: DefaultAllowlist
,
3042 // { selector : text , selector2 : text2 , }
3047 template: '<div></div>'
3049 const DefaultType
$4 = {
3050 allowList: 'object',
3052 extraClass: '(string|function)',
3054 sanitize: 'boolean',
3055 sanitizeFn: '(null|function)',
3058 const DefaultContentType
= {
3059 entry: '(string|element|function|null)',
3060 selector: '(string|element)'
3067 class TemplateFactory
extends Config
{
3068 constructor(config
) {
3070 this._config
= this._getConfig(config
);
3074 static get Default() {
3077 static get DefaultType() {
3078 return DefaultType
$4;
3086 return Object
.values(this._config
.content
).map(config
=> this._resolvePossibleFunction(config
)).filter(Boolean
);
3089 return this.getContent().length
> 0;
3091 changeContent(content
) {
3092 this._checkContent(content
);
3093 this._config
.content
= {
3094 ...this._config
.content
,
3100 const templateWrapper
= document
.createElement('div');
3101 templateWrapper
.innerHTML
= this._maybeSanitize(this._config
.template
);
3102 for (const [selector
, text
] of Object
.entries(this._config
.content
)) {
3103 this._setContent(templateWrapper
, text
, selector
);
3105 const template
= templateWrapper
.children
[0];
3106 const extraClass
= this._resolvePossibleFunction(this._config
.extraClass
);
3108 template
.classList
.add(...extraClass
.split(' '));
3114 _typeCheckConfig(config
) {
3115 super._typeCheckConfig(config
);
3116 this._checkContent(config
.content
);
3118 _checkContent(arg
) {
3119 for (const [selector
, content
] of Object
.entries(arg
)) {
3120 super._typeCheckConfig({
3123 }, DefaultContentType
);
3126 _setContent(template
, content
, selector
) {
3127 const templateElement
= SelectorEngine
.findOne(selector
, template
);
3128 if (!templateElement
) {
3131 content
= this._resolvePossibleFunction(content
);
3133 templateElement
.remove();
3136 if (isElement(content
)) {
3137 this._putElementInTemplate(getElement(content
), templateElement
);
3140 if (this._config
.html
) {
3141 templateElement
.innerHTML
= this._maybeSanitize(content
);
3144 templateElement
.textContent
= content
;
3146 _maybeSanitize(arg
) {
3147 return this._config
.sanitize
? sanitizeHtml(arg
, this._config
.allowList
, this._config
.sanitizeFn
) : arg
;
3149 _resolvePossibleFunction(arg
) {
3150 return execute(arg
, [this]);
3152 _putElementInTemplate(element
, templateElement
) {
3153 if (this._config
.html
) {
3154 templateElement
.innerHTML
= '';
3155 templateElement
.append(element
);
3158 templateElement
.textContent
= element
.textContent
;
3163 * --------------------------------------------------------------------------
3164 * Bootstrap tooltip.js
3165 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
3166 * --------------------------------------------------------------------------
3174 const NAME
$4 = 'tooltip';
3175 const DISALLOWED_ATTRIBUTES
= new Set(['sanitize', 'allowList', 'sanitizeFn']);
3176 const CLASS_NAME_FADE
$2 = 'fade';
3177 const CLASS_NAME_MODAL
= 'modal';
3178 const CLASS_NAME_SHOW
$2 = 'show';
3179 const SELECTOR_TOOLTIP_INNER
= '.tooltip-inner';
3180 const SELECTOR_MODAL
= `.${CLASS_NAME_MODAL}`;
3181 const EVENT_MODAL_HIDE
= 'hide.bs.modal';
3182 const TRIGGER_HOVER
= 'hover';
3183 const TRIGGER_FOCUS
= 'focus';
3184 const TRIGGER_CLICK
= 'click';
3185 const TRIGGER_MANUAL
= 'manual';
3186 const EVENT_HIDE
$2 = 'hide';
3187 const EVENT_HIDDEN
$2 = 'hidden';
3188 const EVENT_SHOW
$2 = 'show';
3189 const EVENT_SHOWN
$2 = 'shown';
3190 const EVENT_INSERTED
= 'inserted';
3191 const EVENT_CLICK
$1 = 'click';
3192 const EVENT_FOCUSIN
$1 = 'focusin';
3193 const EVENT_FOCUSOUT
$1 = 'focusout';
3194 const EVENT_MOUSEENTER
= 'mouseenter';
3195 const EVENT_MOUSELEAVE
= 'mouseleave';
3196 const AttachmentMap
= {
3199 RIGHT: isRTL() ? 'left' : 'right',
3201 LEFT: isRTL() ? 'right' : 'left'
3204 allowList: DefaultAllowlist
,
3206 boundary: 'clippingParents',
3210 fallbackPlacements: ['top', 'right', 'bottom', 'left'],
3218 template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>',
3220 trigger: 'hover focus'
3222 const DefaultType
$3 = {
3223 allowList: 'object',
3224 animation: 'boolean',
3225 boundary: '(string|element)',
3226 container: '(string|element|boolean)',
3227 customClass: '(string|function)',
3228 delay: '(number|object)',
3229 fallbackPlacements: 'array',
3231 offset: '(array|string|function)',
3232 placement: '(string|function)',
3233 popperConfig: '(null|object|function)',
3234 sanitize: 'boolean',
3235 sanitizeFn: '(null|function)',
3236 selector: '(string|boolean)',
3238 title: '(string|element|function)',
3246 class Tooltip
extends BaseComponent
{
3247 constructor(element
, config
) {
3248 if (typeof Popper__namespace
=== 'undefined') {
3249 throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)');
3251 super(element
, config
);
3254 this._isEnabled
= true;
3256 this._isHovered
= null;
3257 this._activeTrigger
= {};
3258 this._popper
= null;
3259 this._templateFactory
= null;
3260 this._newContent
= null;
3264 this._setListeners();
3265 if (!this._config
.selector
) {
3271 static get Default() {
3274 static get DefaultType() {
3275 return DefaultType
$3;
3283 this._isEnabled
= true;
3286 this._isEnabled
= false;
3289 this._isEnabled
= !this._isEnabled
;
3292 if (!this._isEnabled
) {
3295 this._activeTrigger
.click
= !this._activeTrigger
.click
;
3296 if (this._isShown()) {
3303 clearTimeout(this._timeout
);
3304 EventHandler
.off(this._element
.closest(SELECTOR_MODAL
), EVENT_MODAL_HIDE
, this._hideModalHandler
);
3305 if (this._element
.getAttribute('data-bs-original-title')) {
3306 this._element
.setAttribute('title', this._element
.getAttribute('data-bs-original-title'));
3308 this._disposePopper();
3312 if (this._element
.style
.display
=== 'none') {
3313 throw new Error('Please use show on visible elements');
3315 if (!(this._isWithContent() && this._isEnabled
)) {
3318 const showEvent
= EventHandler
.trigger(this._element
, this.constructor.eventName(EVENT_SHOW
$2));
3319 const shadowRoot
= findShadowRoot(this._element
);
3320 const isInTheDom
= (shadowRoot
|| this._element
.ownerDocument
.documentElement
).contains(this._element
);
3321 if (showEvent
.defaultPrevented
|| !isInTheDom
) {
3325 // TODO: v6 remove this or make it optional
3326 this._disposePopper();
3327 const tip
= this._getTipElement();
3328 this._element
.setAttribute('aria-describedby', tip
.getAttribute('id'));
3332 if (!this._element
.ownerDocument
.documentElement
.contains(this.tip
)) {
3333 container
.append(tip
);
3334 EventHandler
.trigger(this._element
, this.constructor.eventName(EVENT_INSERTED
));
3336 this._popper
= this._createPopper(tip
);
3337 tip
.classList
.add(CLASS_NAME_SHOW
$2);
3339 // If this is a touch-enabled device we add extra
3340 // empty mouseover listeners to the body's immediate children;
3341 // only needed because of broken event delegation on iOS
3342 // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
3343 if ('ontouchstart' in document
.documentElement
) {
3344 for (const element
of [].concat(...document
.body
.children
)) {
3345 EventHandler
.on(element
, 'mouseover', noop
);
3348 const complete
= () => {
3349 EventHandler
.trigger(this._element
, this.constructor.eventName(EVENT_SHOWN
$2));
3350 if (this._isHovered
=== false) {
3353 this._isHovered
= false;
3355 this._queueCallback(complete
, this.tip
, this._isAnimated());
3358 if (!this._isShown()) {
3361 const hideEvent
= EventHandler
.trigger(this._element
, this.constructor.eventName(EVENT_HIDE
$2));
3362 if (hideEvent
.defaultPrevented
) {
3365 const tip
= this._getTipElement();
3366 tip
.classList
.remove(CLASS_NAME_SHOW
$2);
3368 // If this is a touch-enabled device we remove the extra
3369 // empty mouseover listeners we added for iOS support
3370 if ('ontouchstart' in document
.documentElement
) {
3371 for (const element
of [].concat(...document
.body
.children
)) {
3372 EventHandler
.off(element
, 'mouseover', noop
);
3375 this._activeTrigger
[TRIGGER_CLICK
] = false;
3376 this._activeTrigger
[TRIGGER_FOCUS
] = false;
3377 this._activeTrigger
[TRIGGER_HOVER
] = false;
3378 this._isHovered
= null; // it is a trick to support manual triggering
3380 const complete
= () => {
3381 if (this._isWithActiveTrigger()) {
3384 if (!this._isHovered
) {
3385 this._disposePopper();
3387 this._element
.removeAttribute('aria-describedby');
3388 EventHandler
.trigger(this._element
, this.constructor.eventName(EVENT_HIDDEN
$2));
3390 this._queueCallback(complete
, this.tip
, this._isAnimated());
3394 this._popper
.update();
3400 return Boolean(this._getTitle());
3404 this.tip
= this._createTipElement(this._newContent
|| this._getContentForTemplate());
3408 _createTipElement(content
) {
3409 const tip
= this._getTemplateFactory(content
).toHtml();
3411 // TODO: remove this check in v6
3415 tip
.classList
.remove(CLASS_NAME_FADE
$2, CLASS_NAME_SHOW
$2);
3416 // TODO: v6 the following can be achieved with CSS only
3417 tip
.classList
.add(`bs-${this.constructor.NAME}-auto`);
3418 const tipId
= getUID(this.constructor.NAME
).toString();
3419 tip
.setAttribute('id', tipId
);
3420 if (this._isAnimated()) {
3421 tip
.classList
.add(CLASS_NAME_FADE
$2);
3425 setContent(content
) {
3426 this._newContent
= content
;
3427 if (this._isShown()) {
3428 this._disposePopper();
3432 _getTemplateFactory(content
) {
3433 if (this._templateFactory
) {
3434 this._templateFactory
.changeContent(content
);
3436 this._templateFactory
= new TemplateFactory({
3438 // the `content` var has to be after `this._config`
3439 // to override config.content in case of popover
3441 extraClass: this._resolvePossibleFunction(this._config
.customClass
)
3444 return this._templateFactory
;
3446 _getContentForTemplate() {
3448 [SELECTOR_TOOLTIP_INNER
]: this._getTitle()
3452 return this._resolvePossibleFunction(this._config
.title
) || this._element
.getAttribute('data-bs-original-title');
3456 _initializeOnDelegatedTarget(event
) {
3457 return this.constructor.getOrCreateInstance(event
.delegateTarget
, this._getDelegateConfig());
3460 return this._config
.animation
|| this.tip
&& this.tip
.classList
.contains(CLASS_NAME_FADE
$2);
3463 return this.tip
&& this.tip
.classList
.contains(CLASS_NAME_SHOW
$2);
3465 _createPopper(tip
) {
3466 const placement
= execute(this._config
.placement
, [this, tip
, this._element
]);
3467 const attachment
= AttachmentMap
[placement
.toUpperCase()];
3468 return Popper__namespace
.createPopper(this._element
, tip
, this._getPopperConfig(attachment
));
3474 if (typeof offset
=== 'string') {
3475 return offset
.split(',').map(value
=> Number
.parseInt(value
, 10));
3477 if (typeof offset
=== 'function') {
3478 return popperData
=> offset(popperData
, this._element
);
3482 _resolvePossibleFunction(arg
) {
3483 return execute(arg
, [this._element
]);
3485 _getPopperConfig(attachment
) {
3486 const defaultBsPopperConfig
= {
3487 placement: attachment
,
3491 fallbackPlacements: this._config
.fallbackPlacements
3496 offset: this._getOffset()
3499 name: 'preventOverflow',
3501 boundary: this._config
.boundary
3506 element: `.${this.constructor.NAME}-arrow`
3509 name: 'preSetPlacement',
3511 phase: 'beforeMain',
3513 // Pre-set Popper's placement attribute in order to read the arrow sizes properly.
3514 // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement
3515 this._getTipElement().setAttribute('data-popper-placement', data
.state
.placement
);
3520 ...defaultBsPopperConfig
,
3521 ...execute(this._config
.popperConfig
, [defaultBsPopperConfig
])
3525 const triggers
= this._config
.trigger
.split(' ');
3526 for (const trigger
of triggers
) {
3527 if (trigger
=== 'click') {
3528 EventHandler
.on(this._element
, this.constructor.eventName(EVENT_CLICK
$1), this._config
.selector
, event
=> {
3529 const context
= this._initializeOnDelegatedTarget(event
);
3532 } else if (trigger
!== TRIGGER_MANUAL
) {
3533 const eventIn
= trigger
=== TRIGGER_HOVER
? this.constructor.eventName(EVENT_MOUSEENTER
) : this.constructor.eventName(EVENT_FOCUSIN
$1);
3534 const eventOut
= trigger
=== TRIGGER_HOVER
? this.constructor.eventName(EVENT_MOUSELEAVE
) : this.constructor.eventName(EVENT_FOCUSOUT
$1);
3535 EventHandler
.on(this._element
, eventIn
, this._config
.selector
, event
=> {
3536 const context
= this._initializeOnDelegatedTarget(event
);
3537 context
._activeTrigger
[event
.type
=== 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER
] = true;
3540 EventHandler
.on(this._element
, eventOut
, this._config
.selector
, event
=> {
3541 const context
= this._initializeOnDelegatedTarget(event
);
3542 context
._activeTrigger
[event
.type
=== 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER
] = context
._element
.contains(event
.relatedTarget
);
3547 this._hideModalHandler
= () => {
3548 if (this._element
) {
3552 EventHandler
.on(this._element
.closest(SELECTOR_MODAL
), EVENT_MODAL_HIDE
, this._hideModalHandler
);
3555 const title
= this._element
.getAttribute('title');
3559 if (!this._element
.getAttribute('aria-label') && !this._element
.textContent
.trim()) {
3560 this._element
.setAttribute('aria-label', title
);
3562 this._element
.setAttribute('data-bs-original-title', title
); // DO NOT USE IT. Is only for backwards compatibility
3563 this._element
.removeAttribute('title');
3566 if (this._isShown() || this._isHovered
) {
3567 this._isHovered
= true;
3570 this._isHovered
= true;
3571 this._setTimeout(() => {
3572 if (this._isHovered
) {
3575 }, this._config
.delay
.show
);
3578 if (this._isWithActiveTrigger()) {
3581 this._isHovered
= false;
3582 this._setTimeout(() => {
3583 if (!this._isHovered
) {
3586 }, this._config
.delay
.hide
);
3588 _setTimeout(handler
, timeout
) {
3589 clearTimeout(this._timeout
);
3590 this._timeout
= setTimeout(handler
, timeout
);
3592 _isWithActiveTrigger() {
3593 return Object
.values(this._activeTrigger
).includes(true);
3595 _getConfig(config
) {
3596 const dataAttributes
= Manipulator
.getDataAttributes(this._element
);
3597 for (const dataAttribute
of Object
.keys(dataAttributes
)) {
3598 if (DISALLOWED_ATTRIBUTES
.has(dataAttribute
)) {
3599 delete dataAttributes
[dataAttribute
];
3604 ...(typeof config
=== 'object' && config
? config : {})
3606 config
= this._mergeConfigObj(config
);
3607 config
= this._configAfterMerge(config
);
3608 this._typeCheckConfig(config
);
3611 _configAfterMerge(config
) {
3612 config
.container
= config
.container
=== false ? document
.body : getElement(config
.container
);
3613 if (typeof config
.delay
=== 'number') {
3619 if (typeof config
.title
=== 'number') {
3620 config
.title
= config
.title
.toString();
3622 if (typeof config
.content
=== 'number') {
3623 config
.content
= config
.content
.toString();
3627 _getDelegateConfig() {
3629 for (const [key
, value
] of Object
.entries(this._config
)) {
3630 if (this.constructor.Default
[key
] !== value
) {
3631 config
[key
] = value
;
3634 config
.selector
= false;
3635 config
.trigger
= 'manual';
3637 // In the future can be replaced with:
3638 // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])
3639 // `Object.fromEntries(keysWithDifferentValues)`
3644 this._popper
.destroy();
3645 this._popper
= null;
3654 static jQueryInterface(config
) {
3655 return this.each(function () {
3656 const data
= Tooltip
.getOrCreateInstance(this, config
);
3657 if (typeof config
!== 'string') {
3660 if (typeof data
[config
] === 'undefined') {
3661 throw new TypeError(`No method named "${config}"`);
3672 defineJQueryPlugin(Tooltip
);
3675 * --------------------------------------------------------------------------
3676 * Bootstrap popover.js
3677 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
3678 * --------------------------------------------------------------------------
3686 const NAME
$3 = 'popover';
3687 const SELECTOR_TITLE
= '.popover-header';
3688 const SELECTOR_CONTENT
= '.popover-body';
3694 template: '<div class="popover" role="tooltip">' + '<div class="popover-arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div>' + '</div>',
3697 const DefaultType
$2 = {
3698 ...Tooltip
.DefaultType
,
3699 content: '(null|string|element|function)'
3706 class Popover
extends Tooltip
{
3708 static get Default() {
3711 static get DefaultType() {
3712 return DefaultType
$2;
3720 return this._getTitle() || this._getContent();
3724 _getContentForTemplate() {
3726 [SELECTOR_TITLE
]: this._getTitle(),
3727 [SELECTOR_CONTENT
]: this._getContent()
3731 return this._resolvePossibleFunction(this._config
.content
);
3735 static jQueryInterface(config
) {
3736 return this.each(function () {
3737 const data
= Popover
.getOrCreateInstance(this, config
);
3738 if (typeof config
!== 'string') {
3741 if (typeof data
[config
] === 'undefined') {
3742 throw new TypeError(`No method named "${config}"`);
3753 defineJQueryPlugin(Popover
);
3756 * --------------------------------------------------------------------------
3757 * Bootstrap scrollspy.js
3758 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
3759 * --------------------------------------------------------------------------
3767 const NAME
$2 = 'scrollspy';
3768 const DATA_KEY
$2 = 'bs.scrollspy';
3769 const EVENT_KEY
$2 = `.${DATA_KEY$2}`;
3770 const DATA_API_KEY
= '.data-api';
3771 const EVENT_ACTIVATE
= `activate${EVENT_KEY$2}`;
3772 const EVENT_CLICK
= `click${EVENT_KEY$2}`;
3773 const EVENT_LOAD_DATA_API
$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`;
3774 const CLASS_NAME_DROPDOWN_ITEM
= 'dropdown-item';
3775 const CLASS_NAME_ACTIVE
$1 = 'active';
3776 const SELECTOR_DATA_SPY
= '[data-bs-spy="scroll"]';
3777 const SELECTOR_TARGET_LINKS
= '[href]';
3778 const SELECTOR_NAV_LIST_GROUP
= '.nav, .list-group';
3779 const SELECTOR_NAV_LINKS
= '.nav-link';
3780 const SELECTOR_NAV_ITEMS
= '.nav-item';
3781 const SELECTOR_LIST_ITEMS
= '.list-group-item';
3782 const SELECTOR_LINK_ITEMS
= `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;
3783 const SELECTOR_DROPDOWN
= '.dropdown';
3784 const SELECTOR_DROPDOWN_TOGGLE
$1 = '.dropdown-toggle';
3787 // TODO: v6 @deprecated, keep it for backwards compatibility reasons
3788 rootMargin: '0px 0px -25%',
3789 smoothScroll: false,
3791 threshold: [0.1, 0.5, 1]
3793 const DefaultType
$1 = {
3794 offset: '(number|null)',
3795 // TODO v6 @deprecated, keep it for backwards compatibility reasons
3796 rootMargin: 'string',
3797 smoothScroll: 'boolean',
3806 class ScrollSpy
extends BaseComponent
{
3807 constructor(element
, config
) {
3808 super(element
, config
);
3810 // this._element is the observablesContainer and config.target the menu links wrapper
3811 this._targetLinks
= new Map();
3812 this._observableSections
= new Map();
3813 this._rootElement
= getComputedStyle(this._element
).overflowY
=== 'visible' ? null : this._element
;
3814 this._activeTarget
= null;
3815 this._observer
= null;
3816 this._previousScrollData
= {
3820 this.refresh(); // initialize
3824 static get Default() {
3827 static get DefaultType() {
3828 return DefaultType
$1;
3836 this._initializeTargetsAndObservables();
3837 this._maybeEnableSmoothScroll();
3838 if (this._observer
) {
3839 this._observer
.disconnect();
3841 this._observer
= this._getNewObserver();
3843 for (const section
of this._observableSections
.values()) {
3844 this._observer
.observe(section
);
3848 this._observer
.disconnect();
3853 _configAfterMerge(config
) {
3854 // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case
3855 config
.target
= getElement(config
.target
) || document
.body
;
3857 // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only
3858 config
.rootMargin
= config
.offset
? `${config.offset}px 0px -30%` : config
.rootMargin
;
3859 if (typeof config
.threshold
=== 'string') {
3860 config
.threshold
= config
.threshold
.split(',').map(value
=> Number
.parseFloat(value
));
3864 _maybeEnableSmoothScroll() {
3865 if (!this._config
.smoothScroll
) {
3869 // unregister any previous listeners
3870 EventHandler
.off(this._config
.target
, EVENT_CLICK
);
3871 EventHandler
.on(this._config
.target
, EVENT_CLICK
, SELECTOR_TARGET_LINKS
, event
=> {
3872 const observableSection
= this._observableSections
.get(event
.target
.hash
);
3873 if (observableSection
) {
3874 event
.preventDefault();
3875 const root
= this._rootElement
|| window
;
3876 const height
= observableSection
.offsetTop
- this._element
.offsetTop
;
3877 if (root
.scrollTo
) {
3885 // Chrome 60 doesn't support `scrollTo`
3886 root
.scrollTop
= height
;
3892 root: this._rootElement
,
3893 threshold: this._config
.threshold
,
3894 rootMargin: this._config
.rootMargin
3896 return new IntersectionObserver(entries
=> this._observerCallback(entries
), options
);
3899 // The logic of selection
3900 _observerCallback(entries
) {
3901 const targetElement
= entry
=> this._targetLinks
.get(`#${entry.target.id}`);
3902 const activate
= entry
=> {
3903 this._previousScrollData
.visibleEntryTop
= entry
.target
.offsetTop
;
3904 this._process(targetElement(entry
));
3906 const parentScrollTop
= (this._rootElement
|| document
.documentElement
).scrollTop
;
3907 const userScrollsDown
= parentScrollTop
>= this._previousScrollData
.parentScrollTop
;
3908 this._previousScrollData
.parentScrollTop
= parentScrollTop
;
3909 for (const entry
of entries
) {
3910 if (!entry
.isIntersecting
) {
3911 this._activeTarget
= null;
3912 this._clearActiveClass(targetElement(entry
));
3915 const entryIsLowerThanPrevious
= entry
.target
.offsetTop
>= this._previousScrollData
.visibleEntryTop
;
3916 // if we are scrolling down, pick the bigger offsetTop
3917 if (userScrollsDown
&& entryIsLowerThanPrevious
) {
3919 // if parent isn't scrolled, let's keep the first visible item, breaking the iteration
3920 if (!parentScrollTop
) {
3926 // if we are scrolling up, pick the smallest offsetTop
3927 if (!userScrollsDown
&& !entryIsLowerThanPrevious
) {
3932 _initializeTargetsAndObservables() {
3933 this._targetLinks
= new Map();
3934 this._observableSections
= new Map();
3935 const targetLinks
= SelectorEngine
.find(SELECTOR_TARGET_LINKS
, this._config
.target
);
3936 for (const anchor
of targetLinks
) {
3937 // ensure that the anchor has an id and is not disabled
3938 if (!anchor
.hash
|| isDisabled(anchor
)) {
3941 const observableSection
= SelectorEngine
.findOne(decodeURI(anchor
.hash
), this._element
);
3943 // ensure that the observableSection exists & is visible
3944 if (isVisible(observableSection
)) {
3945 this._targetLinks
.set(decodeURI(anchor
.hash
), anchor
);
3946 this._observableSections
.set(anchor
.hash
, observableSection
);
3951 if (this._activeTarget
=== target
) {
3954 this._clearActiveClass(this._config
.target
);
3955 this._activeTarget
= target
;
3956 target
.classList
.add(CLASS_NAME_ACTIVE
$1);
3957 this._activateParents(target
);
3958 EventHandler
.trigger(this._element
, EVENT_ACTIVATE
, {
3959 relatedTarget: target
3962 _activateParents(target
) {
3963 // Activate dropdown parents
3964 if (target
.classList
.contains(CLASS_NAME_DROPDOWN_ITEM
)) {
3965 SelectorEngine
.findOne(SELECTOR_DROPDOWN_TOGGLE
$1, target
.closest(SELECTOR_DROPDOWN
)).classList
.add(CLASS_NAME_ACTIVE
$1);
3968 for (const listGroup
of SelectorEngine
.parents(target
, SELECTOR_NAV_LIST_GROUP
)) {
3969 // Set triggered links parents as active
3970 // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
3971 for (const item
of SelectorEngine
.prev(listGroup
, SELECTOR_LINK_ITEMS
)) {
3972 item
.classList
.add(CLASS_NAME_ACTIVE
$1);
3976 _clearActiveClass(parent
) {
3977 parent
.classList
.remove(CLASS_NAME_ACTIVE
$1);
3978 const activeNodes
= SelectorEngine
.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE$1}`, parent
);
3979 for (const node
of activeNodes
) {
3980 node
.classList
.remove(CLASS_NAME_ACTIVE
$1);
3985 static jQueryInterface(config
) {
3986 return this.each(function () {
3987 const data
= ScrollSpy
.getOrCreateInstance(this, config
);
3988 if (typeof config
!== 'string') {
3991 if (data
[config
] === undefined || config
.startsWith('_') || config
=== 'constructor') {
3992 throw new TypeError(`No method named "${config}"`);
4000 * Data API implementation
4003 EventHandler
.on(window
, EVENT_LOAD_DATA_API
$1, () => {
4004 for (const spy
of SelectorEngine
.find(SELECTOR_DATA_SPY
)) {
4005 ScrollSpy
.getOrCreateInstance(spy
);
4013 defineJQueryPlugin(ScrollSpy
);
4016 * --------------------------------------------------------------------------
4018 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
4019 * --------------------------------------------------------------------------
4027 const NAME
$1 = 'tab';
4028 const DATA_KEY
$1 = 'bs.tab';
4029 const EVENT_KEY
$1 = `.${DATA_KEY$1}`;
4030 const EVENT_HIDE
$1 = `hide${EVENT_KEY$1}`;
4031 const EVENT_HIDDEN
$1 = `hidden${EVENT_KEY$1}`;
4032 const EVENT_SHOW
$1 = `show${EVENT_KEY$1}`;
4033 const EVENT_SHOWN
$1 = `shown${EVENT_KEY$1}`;
4034 const EVENT_CLICK_DATA_API
= `click${EVENT_KEY$1}`;
4035 const EVENT_KEYDOWN
= `keydown${EVENT_KEY$1}`;
4036 const EVENT_LOAD_DATA_API
= `load${EVENT_KEY$1}`;
4037 const ARROW_LEFT_KEY
= 'ArrowLeft';
4038 const ARROW_RIGHT_KEY
= 'ArrowRight';
4039 const ARROW_UP_KEY
= 'ArrowUp';
4040 const ARROW_DOWN_KEY
= 'ArrowDown';
4041 const HOME_KEY
= 'Home';
4042 const END_KEY
= 'End';
4043 const CLASS_NAME_ACTIVE
= 'active';
4044 const CLASS_NAME_FADE
$1 = 'fade';
4045 const CLASS_NAME_SHOW
$1 = 'show';
4046 const CLASS_DROPDOWN
= 'dropdown';
4047 const SELECTOR_DROPDOWN_TOGGLE
= '.dropdown-toggle';
4048 const SELECTOR_DROPDOWN_MENU
= '.dropdown-menu';
4049 const NOT_SELECTOR_DROPDOWN_TOGGLE
= `:not(${SELECTOR_DROPDOWN_TOGGLE})`;
4050 const SELECTOR_TAB_PANEL
= '.list-group, .nav, [role="tablist"]';
4051 const SELECTOR_OUTER
= '.nav-item, .list-group-item';
4052 const SELECTOR_INNER
= `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`;
4053 const SELECTOR_DATA_TOGGLE
= '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // TODO: could only be `tab` in v6
4054 const SELECTOR_INNER_ELEM
= `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`;
4055 const SELECTOR_DATA_TOGGLE_ACTIVE
= `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="list"]`;
4061 class Tab
extends BaseComponent
{
4062 constructor(element
) {
4064 this._parent
= this._element
.closest(SELECTOR_TAB_PANEL
);
4065 if (!this._parent
) {
4067 // TODO: should throw exception in v6
4068 // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
4071 // Set up initial aria attributes
4072 this._setInitialAttributes(this._parent
, this._getChildren());
4073 EventHandler
.on(this._element
, EVENT_KEYDOWN
, event
=> this._keydown(event
));
4083 // Shows this elem and deactivate the active sibling if exists
4084 const innerElem
= this._element
;
4085 if (this._elemIsActive(innerElem
)) {
4089 // Search for active tab on same parent to deactivate it
4090 const active
= this._getActiveElem();
4091 const hideEvent
= active
? EventHandler
.trigger(active
, EVENT_HIDE
$1, {
4092 relatedTarget: innerElem
4094 const showEvent
= EventHandler
.trigger(innerElem
, EVENT_SHOW
$1, {
4095 relatedTarget: active
4097 if (showEvent
.defaultPrevented
|| hideEvent
&& hideEvent
.defaultPrevented
) {
4100 this._deactivate(active
, innerElem
);
4101 this._activate(innerElem
, active
);
4105 _activate(element
, relatedElem
) {
4109 element
.classList
.add(CLASS_NAME_ACTIVE
);
4110 this._activate(SelectorEngine
.getElementFromSelector(element
)); // Search and activate/show the proper section
4112 const complete
= () => {
4113 if (element
.getAttribute('role') !== 'tab') {
4114 element
.classList
.add(CLASS_NAME_SHOW
$1);
4117 element
.removeAttribute('tabindex');
4118 element
.setAttribute('aria-selected', true);
4119 this._toggleDropDown(element
, true);
4120 EventHandler
.trigger(element
, EVENT_SHOWN
$1, {
4121 relatedTarget: relatedElem
4124 this._queueCallback(complete
, element
, element
.classList
.contains(CLASS_NAME_FADE
$1));
4126 _deactivate(element
, relatedElem
) {
4130 element
.classList
.remove(CLASS_NAME_ACTIVE
);
4132 this._deactivate(SelectorEngine
.getElementFromSelector(element
)); // Search and deactivate the shown section too
4134 const complete
= () => {
4135 if (element
.getAttribute('role') !== 'tab') {
4136 element
.classList
.remove(CLASS_NAME_SHOW
$1);
4139 element
.setAttribute('aria-selected', false);
4140 element
.setAttribute('tabindex', '-1');
4141 this._toggleDropDown(element
, false);
4142 EventHandler
.trigger(element
, EVENT_HIDDEN
$1, {
4143 relatedTarget: relatedElem
4146 this._queueCallback(complete
, element
, element
.classList
.contains(CLASS_NAME_FADE
$1));
4149 if (![ARROW_LEFT_KEY
, ARROW_RIGHT_KEY
, ARROW_UP_KEY
, ARROW_DOWN_KEY
, HOME_KEY
, END_KEY
].includes(event
.key
)) {
4152 event
.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page
4153 event
.preventDefault();
4154 const children
= this._getChildren().filter(element
=> !isDisabled(element
));
4155 let nextActiveElement
;
4156 if ([HOME_KEY
, END_KEY
].includes(event
.key
)) {
4157 nextActiveElement
= children
[event
.key
=== HOME_KEY
? 0 : children
.length
- 1];
4159 const isNext
= [ARROW_RIGHT_KEY
, ARROW_DOWN_KEY
].includes(event
.key
);
4160 nextActiveElement
= getNextActiveElement(children
, event
.target
, isNext
, true);
4162 if (nextActiveElement
) {
4163 nextActiveElement
.focus({
4166 Tab
.getOrCreateInstance(nextActiveElement
).show();
4170 // collection of inner elements
4171 return SelectorEngine
.find(SELECTOR_INNER_ELEM
, this._parent
);
4174 return this._getChildren().find(child
=> this._elemIsActive(child
)) || null;
4176 _setInitialAttributes(parent
, children
) {
4177 this._setAttributeIfNotExists(parent
, 'role', 'tablist');
4178 for (const child
of children
) {
4179 this._setInitialAttributesOnChild(child
);
4182 _setInitialAttributesOnChild(child
) {
4183 child
= this._getInnerElement(child
);
4184 const isActive
= this._elemIsActive(child
);
4185 const outerElem
= this._getOuterElement(child
);
4186 child
.setAttribute('aria-selected', isActive
);
4187 if (outerElem
!== child
) {
4188 this._setAttributeIfNotExists(outerElem
, 'role', 'presentation');
4191 child
.setAttribute('tabindex', '-1');
4193 this._setAttributeIfNotExists(child
, 'role', 'tab');
4195 // set attributes to the related panel too
4196 this._setInitialAttributesOnTargetPanel(child
);
4198 _setInitialAttributesOnTargetPanel(child
) {
4199 const target
= SelectorEngine
.getElementFromSelector(child
);
4203 this._setAttributeIfNotExists(target
, 'role', 'tabpanel');
4205 this._setAttributeIfNotExists(target
, 'aria-labelledby', `${child.id}`);
4208 _toggleDropDown(element
, open
) {
4209 const outerElem
= this._getOuterElement(element
);
4210 if (!outerElem
.classList
.contains(CLASS_DROPDOWN
)) {
4213 const toggle
= (selector
, className
) => {
4214 const element
= SelectorEngine
.findOne(selector
, outerElem
);
4216 element
.classList
.toggle(className
, open
);
4219 toggle(SELECTOR_DROPDOWN_TOGGLE
, CLASS_NAME_ACTIVE
);
4220 toggle(SELECTOR_DROPDOWN_MENU
, CLASS_NAME_SHOW
$1);
4221 outerElem
.setAttribute('aria-expanded', open
);
4223 _setAttributeIfNotExists(element
, attribute
, value
) {
4224 if (!element
.hasAttribute(attribute
)) {
4225 element
.setAttribute(attribute
, value
);
4228 _elemIsActive(elem
) {
4229 return elem
.classList
.contains(CLASS_NAME_ACTIVE
);
4232 // Try to get the inner element (usually the .nav-link)
4233 _getInnerElement(elem
) {
4234 return elem
.matches(SELECTOR_INNER_ELEM
) ? elem : SelectorEngine
.findOne(SELECTOR_INNER_ELEM
, elem
);
4237 // Try to get the outer element (usually the .nav-item)
4238 _getOuterElement(elem
) {
4239 return elem
.closest(SELECTOR_OUTER
) || elem
;
4243 static jQueryInterface(config
) {
4244 return this.each(function () {
4245 const data
= Tab
.getOrCreateInstance(this);
4246 if (typeof config
!== 'string') {
4249 if (data
[config
] === undefined || config
.startsWith('_') || config
=== 'constructor') {
4250 throw new TypeError(`No method named "${config}"`);
4258 * Data API implementation
4261 EventHandler
.on(document
, EVENT_CLICK_DATA_API
, SELECTOR_DATA_TOGGLE
, function (event
) {
4262 if (['A', 'AREA'].includes(this.tagName
)) {
4263 event
.preventDefault();
4265 if (isDisabled(this)) {
4268 Tab
.getOrCreateInstance(this).show();
4272 * Initialize on focus
4274 EventHandler
.on(window
, EVENT_LOAD_DATA_API
, () => {
4275 for (const element
of SelectorEngine
.find(SELECTOR_DATA_TOGGLE_ACTIVE
)) {
4276 Tab
.getOrCreateInstance(element
);
4283 defineJQueryPlugin(Tab
);
4286 * --------------------------------------------------------------------------
4287 * Bootstrap toast.js
4288 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
4289 * --------------------------------------------------------------------------
4297 const NAME
= 'toast';
4298 const DATA_KEY
= 'bs.toast';
4299 const EVENT_KEY
= `.${DATA_KEY}`;
4300 const EVENT_MOUSEOVER
= `mouseover${EVENT_KEY}`;
4301 const EVENT_MOUSEOUT
= `mouseout${EVENT_KEY}`;
4302 const EVENT_FOCUSIN
= `focusin${EVENT_KEY}`;
4303 const EVENT_FOCUSOUT
= `focusout${EVENT_KEY}`;
4304 const EVENT_HIDE
= `hide${EVENT_KEY}`;
4305 const EVENT_HIDDEN
= `hidden${EVENT_KEY}`;
4306 const EVENT_SHOW
= `show${EVENT_KEY}`;
4307 const EVENT_SHOWN
= `shown${EVENT_KEY}`;
4308 const CLASS_NAME_FADE
= 'fade';
4309 const CLASS_NAME_HIDE
= 'hide'; // @deprecated - kept here only for backwards compatibility
4310 const CLASS_NAME_SHOW
= 'show';
4311 const CLASS_NAME_SHOWING
= 'showing';
4312 const DefaultType
= {
4313 animation: 'boolean',
4314 autohide: 'boolean',
4327 class Toast
extends BaseComponent
{
4328 constructor(element
, config
) {
4329 super(element
, config
);
4330 this._timeout
= null;
4331 this._hasMouseInteraction
= false;
4332 this._hasKeyboardInteraction
= false;
4333 this._setListeners();
4337 static get Default() {
4340 static get DefaultType() {
4349 const showEvent
= EventHandler
.trigger(this._element
, EVENT_SHOW
);
4350 if (showEvent
.defaultPrevented
) {
4353 this._clearTimeout();
4354 if (this._config
.animation
) {
4355 this._element
.classList
.add(CLASS_NAME_FADE
);
4357 const complete
= () => {
4358 this._element
.classList
.remove(CLASS_NAME_SHOWING
);
4359 EventHandler
.trigger(this._element
, EVENT_SHOWN
);
4360 this._maybeScheduleHide();
4362 this._element
.classList
.remove(CLASS_NAME_HIDE
); // @deprecated
4363 reflow(this._element
);
4364 this._element
.classList
.add(CLASS_NAME_SHOW
, CLASS_NAME_SHOWING
);
4365 this._queueCallback(complete
, this._element
, this._config
.animation
);
4368 if (!this.isShown()) {
4371 const hideEvent
= EventHandler
.trigger(this._element
, EVENT_HIDE
);
4372 if (hideEvent
.defaultPrevented
) {
4375 const complete
= () => {
4376 this._element
.classList
.add(CLASS_NAME_HIDE
); // @deprecated
4377 this._element
.classList
.remove(CLASS_NAME_SHOWING
, CLASS_NAME_SHOW
);
4378 EventHandler
.trigger(this._element
, EVENT_HIDDEN
);
4380 this._element
.classList
.add(CLASS_NAME_SHOWING
);
4381 this._queueCallback(complete
, this._element
, this._config
.animation
);
4384 this._clearTimeout();
4385 if (this.isShown()) {
4386 this._element
.classList
.remove(CLASS_NAME_SHOW
);
4391 return this._element
.classList
.contains(CLASS_NAME_SHOW
);
4396 _maybeScheduleHide() {
4397 if (!this._config
.autohide
) {
4400 if (this._hasMouseInteraction
|| this._hasKeyboardInteraction
) {
4403 this._timeout
= setTimeout(() => {
4405 }, this._config
.delay
);
4407 _onInteraction(event
, isInteracting
) {
4408 switch (event
.type
) {
4412 this._hasMouseInteraction
= isInteracting
;
4418 this._hasKeyboardInteraction
= isInteracting
;
4422 if (isInteracting
) {
4423 this._clearTimeout();
4426 const nextElement
= event
.relatedTarget
;
4427 if (this._element
=== nextElement
|| this._element
.contains(nextElement
)) {
4430 this._maybeScheduleHide();
4433 EventHandler
.on(this._element
, EVENT_MOUSEOVER
, event
=> this._onInteraction(event
, true));
4434 EventHandler
.on(this._element
, EVENT_MOUSEOUT
, event
=> this._onInteraction(event
, false));
4435 EventHandler
.on(this._element
, EVENT_FOCUSIN
, event
=> this._onInteraction(event
, true));
4436 EventHandler
.on(this._element
, EVENT_FOCUSOUT
, event
=> this._onInteraction(event
, false));
4439 clearTimeout(this._timeout
);
4440 this._timeout
= null;
4444 static jQueryInterface(config
) {
4445 return this.each(function () {
4446 const data
= Toast
.getOrCreateInstance(this, config
);
4447 if (typeof config
=== 'string') {
4448 if (typeof data
[config
] === 'undefined') {
4449 throw new TypeError(`No method named "${config}"`);
4458 * Data API implementation
4461 enableDismissTrigger(Toast
);
4467 defineJQueryPlugin(Toast
);
4470 * --------------------------------------------------------------------------
4471 * Bootstrap index.umd.js
4472 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
4473 * --------------------------------------------------------------------------
4494 //# sourceMappingURL=bootstrap.js.map